Qt是如何在幕后共享OpenGL上下文的?

3

我正在编写一个应用程序,其功能如下:

  • 在具有私有OpenGL上下文和私有线程的管道中持续呈现屏幕外内容
  • 在小部件中绘制一些以前呈现的纹理

为了实现这一目的,我需要在管道和小部件上下文之间共享这些纹理:

方法1:共享所有上下文

int main (int argc, char *argv[])
{
     QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
     QApplication a(argc, argv);

     // [...] Create and initialize the pipeline (private context)
     // [...] Create a window with a widget that can display a texture (Qt creates a private context itself)
     // [...] Set the texture to display in the widget with one created and rendered in the pipeline
}

当我想在 paintGL() 回调函数中绘制纹理时,glBindTexture 会产生一个 GL_INVALID_OPERATION 的错误。

图形调试器显示的是奇怪的纹理,而不是我的纹理:上下文共享似乎没有起作用。

方法二:小部件拥有自己创建的上下文,该上下文共享了管线和 Qt 上下文。

// [...] Create and initialize the pipeline (private context)
// [...] Create a window with a widget that can display a texture (Qt creates a private context itself)
// widget's initializeGL() callback gets called
void initializeGL()
{
     initializeOpenGLFunctions();
     m_secondContext.setShareContext(QOpenGLContext::currentContext());
     m_secondContext.setShareContext(pipelineContext);
     m_secondContext.create();
}
// use the second context during paintEvents
void paintGL()
{
     auto contextBackup(QOpenGLContext::currentContext());
     auto surfaceBackup(contextBackup->surface());
     assert(m_secondContext->makeCurrent(surfaceBackup));

     // [...] draw texture

     contextBackup->makeCurrent(surfaceBackup);
}

这个方法也无法工作,会产生与方法1相同的错误以及我还没有找到的其他错误。

方法3:管道共享小部件上下文

// [...] Create a window with a widget that can display a texture (Qt creates a private context itself)
// [...] Create and initialize the pipeline with the widgets context set as shared 
//       before calling create on the new pipeline context
void initializePipeline()
{
     m_pipelineContext.setShareContext(widgetContext);
     m_pipelineContext.create();
}

这确实可以解决问题,但是这不是一个理想的解决方案,因为它不允许在管道初始化后创建此类小部件

我的问题:

  • 这三种情况应该得到相同的结果,发生了什么事,我错过了什么?
  • 在共享上下文中是否需要添加特定指令来分配共享资源?
  • 上下文共享是线程安全的吗?例如,我可以使用共享资源而不关心互斥吗? (编辑:使用一个并没有解决任何问题)

1
既然在使用CodeXL时可以工作,那么在渲染到纹理后,您是否运行了 glFlushglFinish 来“提交”上下文命令队列?因为您应该这样做。 - Andreas
我错了,它在CodeXL上不起作用(它执行了程序的另一个版本)。然而,glFlush并不能解决这个问题。 - Adrien Grosjean
1个回答

1

回答您的问题:

在共享上下文中,是否需要添加特定指令来分配共享资源?

不需要。

上下文共享是否线程安全?例如,我可以在不关心互斥的情况下使用共享资源吗?

上下文共享不是线程安全的。共享是OpenGL对象命名空间的巩固。

但我怀疑这些答案对您没有帮助。我会继续观察。您的错误很奇怪,因为glBindTexture只会在一个场景下生成GL_INVALID_OPERATION

如果texture以前是用与target不匹配的目标创建的,则会生成GL_INVALID_OPERATION。

这表明存在名称为textureHandle的纹理,但目标不是GL_TEXTURE_2D。也许纹理目标实际上是GL_TEXTURE_2D_MULTISAMPLE

当然,有可能由于某些原因共享无法正常工作。可以使用几乎任何图形调试器列出每个上下文中的对象来轻松找到问题;在一个上下文中创建对象,然后查看它是否出现在另一个上下文中。

谢谢 :) 我使用Renderdoc,但我找不到如何在上下文中列出对象。对我来说,这似乎确实是一个共享问题,因为在调试器中,显示的纹理是一些ASCII字符纹理(奇怪),而目标在创建和使用时都是GL_TEXTURE_2D。我在所有三个initializeGL() paintGL()resizeGL()中添加了互斥锁以确保,但问题仍然存在。 - Adrien Grosjean
@AdrienGrosjean CodeXL 是我喜欢的用于分析 GL 状态的调试器。建议:尝试在 QOpenGLContext 类实例上的 create() 之前使用 setShareContext(),而不是使用全局的 QCoreApplication::setAttribute(...) - Andreas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接