QOpenGLContext 和本机 OpenGL 上下文之间的纹理共享不适用于 Mesa 驱动程序

Texture sharing between QOpenGLContext and native OpenGL context does not work with Mesa drivers

我正在尝试将 UI 作为插件添加到使用 OpenGL 的现有应用程序。 为此,我将 UI 渲染到纹理中,并在绘制场景后在 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) 的笔记本上,它根本不起作用。
现在,显而易见的问题是:为什么会这样,我该如何解决?

这就是它在我的桌面和 VM 上的样子:

我的笔记本上是这样的:

可以找到完整的源代码here

编辑: 如果重要的话,如果我在底部示例中移动相机,白色区域也会发生变化。因此,我认为它们可能是场景渲染的残留物。

第二次编辑: 我做了更多的调试,这不是我最初认为的错误的绘图,而是上下文切换。 我已经在切换之前和之后将纹理保存到一个文件中,并且纹理看起来像之前预期的那样,并且在切换之后搞砸了。 现在,我只需要弄清楚为什么。

glBeginglEnd 块中调用 glClear 无效。另外我不完全确定,你的意图是什么。如果你想阻止它写入深度缓冲区,你可以使用 glDepthMask 。禁用深度测试也会禁用深度写入。

我现在已经用变通方法解决了它。
初始化时,我通过在一个上下文中创建纹理、切换上下文、读回内容并比较它们来检查上下文共享是否有效。
如果没有,我会在渲染后使用 glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data_ ); 抓取纹理内容,切换上下文并使用 glTexImage2D.
再次上传 不漂亮,但它有效。