Совместное использование текстур между QOpenGLContext и собственным контекстом OpenGL не работает с драйверами Mesa

#c #opengl #textures #mesa #qopenglfunctions

#c #opengl #Текстуры #mesa #qopenglфункции

Вопрос:

Я пытаюсь добавить пользовательский интерфейс в качестве плагина к существующему приложению, используя OpenGL. Для этого я превращаю пользовательский интерфейс в текстуру и рисую эту текстуру поверх 3D-сцены после того, как сцена была нарисована.

Текстура генерируется следующим образом:

 if (context_ == nullptr)
{
  QSurfaceFormat format;

  format.setDepthBufferSize( 16 );
  format.setStencilBufferSize( 8 );
  format.setMajorVersion(3);
  format.setMinorVersion(3);

  native_context_ = new QOpenGLContext;
  native_context_->setNativeHandle( QVariant::fromValue(
    QGLXNativeContext( native_context_information_->context, native_context_information_->display )));

  if ( !native_context_->create())
  {
    ROS_ERROR( "OverlayManager: Fatal! Failed to create context!" );
  }

  context_ = new QOpenGLContext;
  context_->setFormat( format );
  context_->setShareContext( native_context_ );

  if ( !context_->create())
  {
    ROS_ERROR( "OverlayManager: Fatal! Failed to create context!" );
  }

  surface_ = new QOffscreenSurface;
  surface_->setFormat( format );
  surface_->create();
  if ( !surface_->isValid()) ROS_ERROR( "Surface invalid!" );

  context_->makeCurrent( surface_ );

  paint_device_ = new QOpenGLPaintDevice( 1920, 1080 );

  {
    QOpenGLFramebufferObjectFormat format;
    format.setSamples(16);
    format.setAttachment( QOpenGLFramebufferObject::CombinedDepthStencil );
    fbo_ = new QOpenGLFramebufferObject( 1920, 1080, format );
    texture_fbo_ = new QOpenGLFramebufferObject( 1920, 1080 );
  }
  fbo_->bind();
}
else
{
  context_->makeCurrent( surface_ );
  fbo_->bind();
}
context_->functions()->glClear(GL_COLOR_BUFFER_BIT);

QPainter painter(paint_device_);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
painter.setBrush(QBrush(Qt::green));
painter.drawRect(0, 0, 400, 300);
//  painter.setPen(Qt::red);
painter.setPen(QPen(QBrush(Qt::red), 4));
painter.setFont(QFont("Arial", 20));
painter.drawText(100, 120, "Hello");
painter.drawText( 10, 80, QString( "Rendertime (ms): %1" ).arg( timer_average_ / 15.0 ));
painter.end();
fbo_->release();
QOpenGLFramebufferObject::blitFramebuffer(texture_fbo_, fbo_);
context_->functions()->glFinish();
// Texture looks fine
context_->doneCurrent();
glXMakeCurrent( native_context_information_->display, native_context_information_->drawable, native_context_information_->context );
// Now it is messed up
  

Вероятно, более интересной частью является рисование текстуры:

 glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glOrtho(0, 1920, 0, 1080, -1, 1);

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_fbo_->texture());

glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(0, 1); glVertex2f(0, 1080);
glTexCoord2f(1, 1); glVertex2f(1920, 1080);
glTexCoord2f(1, 0); glVertex2f(1920, 0);
// glClear(GL_DEPTH_BUFFER_BIT); // Wrong but not the issue, see second edit
glEnd();

glPopMatrix();
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glMatrixMode(GL_MODELVIEW);
  

В основном я нашел этот метод рисования текстур вместе с некоторыми комментариями, в которых говорилось, что он устарел, но на самом деле не смог найти много о наложенных текстурах в режиме полного просмотра, используя более поздние методы. Если у вас есть какие-либо краткие рекомендации по этому вопросу, я был бы признателен, но поскольку это далеко от моей области знаний, я действительно не хочу тратить на это больше пары часов, просто чтобы избежать использования устаревшего кода.

Я надеюсь, у вас сложилось несколько четкое представление о том, чего я пытаюсь достичь.
Это действительно хорошо работает на моем рабочем столе с использованием NVidia Geforce GTX 1080 с использованием Ubuntu 16.04, Qt 5.5.1, OGRE 1.9.0 и OpenGL 4.6 (GLSL 4.6) и виртуальной машины на моем рабочем столе с использованием Ubuntu 18.04, Qt 5.9.5, OGRE 1.9.0 и OpenGL 2.1 (GLSL 1.2). Однако на моем ноутбуке, использующем Ubuntu 16.04, Qt 5.5.1, OGRE 1.9.0 и OpenGL 3 (GLSL 1.3), это вообще не работает.
Теперь возникает очевидный вопрос: почему это так и как я могу это исправить?

Вот как это выглядит на моем рабочем столе и виртуальной машине: Рабочий пример

Вот как это выглядит на моем ноутбуке: Неработающий пример

Весь исходный код можно найти здесь.

Редактировать: На случай, если это важно, если я перемещаю камеру в нижнем примере, белые области также изменяются. Из-за этого я думаю, что они могут быть остатками рендеринга сцены.

Второе редактирование: я провел дополнительную отладку, и ошибка не в чертеже, как я изначально думал, а в переключении контекста. Я сохранил текстуру в файл до переключения и после него, и текстура выглядит так, как предполагалось раньше, и испорчена после переключения. Теперь мне просто нужно выяснить, почему.

Комментарии:

1. Возможно, это может быть как-то связано с графическими драйверами, поскольку мой ноутбук оснащен встроенной видеокартой (i7 8550U)?

2. Я воспроизвел проблему на другом ноутбуке со встроенной видеокартой. Я думаю, что это может иметь какое-то отношение к драйверам mesa.

Ответ №1:

Вызов glClear внутри glBegin glEnd блока недопустим. Также я не совсем уверен, каковы ваши намерения по этому поводу. Если вы хотите запретить запись в буфер глубины, вы бы использовали glDepthMask для этого. Также отключение тестирования глубины отключает запись в глубину.

Комментарии:

1. Спасибо за информацию! Я удалил строку. На самом деле не было намерения, это был просто артефакт из некоторых примеров кода, который я забыл удалить. К сожалению, это не решает проблему и не меняет того, что происходит. Судя по тому, как это выглядит, похоже, что текстурная память не такая, какой она должна быть. Возможно, совместное использование контекста не работает, и дескриптор текстуры недействителен?

2. Я выполнил еще некоторую отладку, сохранив текстуру в файл перед переключением контекста и перед попыткой рисования текстуры, и, похоже, совместное использование не работает. Текстура выглядит нормально до переключения и испорчена после него.

Ответ №2:

На данный момент я решил это с помощью обходного пути.
При инициализации я проверяю, работает ли совместное использование контекста, создавая текстуру в одном контексте, переключая контекст, считывая содержимое обратно и сравнивая их.
Если это не так, я извлекаю содержимое текстуры после рендеринга с помощью glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data_ ); , переключаю контекст и загружаю его снова с помощью glTexImage2D .
Не очень красиво, но это работает.