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

时间:2019-03-12 23:02:06

标签: c++ opengl textures mesa qopenglfunctions

我正在尝试使用OpenGL将UI作为插件添加到现有应用程序中。 为此,我将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);

我主要发现了这种绘制纹理的方法,并有一些评论说此方法已被弃用,但使用较新的方法在全视角覆盖纹理上并不能真正找到很多东西。如果您对此有任何简短的资源/方法,我将不胜感激,但是由于这与我的专业领域相去甚远,因此我真的不想在此上花费超过几个小时的时间,只是为了避免使用不推荐使用的代码。 / p>

我希望您对我要实现的目标有所了解。
这实际上在使用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的台式机上的VM上均可正常运行.0和OpenGL 2.1(GLSL 1.2)。 但是,在使用Ubuntu 16.04,Qt 5.5.1,OGRE 1.9.0和OpenGL 3(GLSL 1.3)的笔记本上,它根本不起作用。
现在,一个明显的问题是:为什么会这样,我该如何解决?

在我的桌面和VM上是这样的: Working example

这就是我笔记本上的样子: Broken example

可以找到整个源代码here

修改: 如果很重要,如果我在下面的示例中移动相机,白色区域也会改变。因此,我认为它们可能是场景渲染的剩余部分。

第二次修改: 我做了更多的调试,不是我最初想到的是错误的图形,而是上下文切换。 我已经将纹理保存到切换之前和之后的文件中,并且该纹理看起来像之前一样,并且在切换之后被弄乱了。 现在,我只需要弄清楚为什么。

2 个答案:

答案 0 :(得分:2)

glClearglBegin块内调用glEnd无效。另外我也不是很确定。如果要防止它写入深度缓冲区,则可以使用glDepthMask。另外,禁用深度测试也会禁用深度写入。

答案 1 :(得分:0)

我已经通过一种解决方法解决了它。
初始化时,我通过在一个上下文中创建纹理,切换上下文,读回内容并进行比较来检查上下文共享是否起作用。
如果没有,我将在使用glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel_data_ );渲染后获取纹理内容,切换上下文并使用glTexImage2D重新上传。
不漂亮,但是可以。