问题的简短形式:如何使用 FBO 作为纹理在 QGLWidget 中进行绘制,而不只是获得空白的白色图像?
还有一些背景和细节...我正在使用 Qt 5.1 作为在 GPU 上进行一些图像处理的应用程序。有一个“合成器”类,它使用 QOffscreenSurface、QOpenGLContext 和 QOpenGLFramebufferObject。它向 FBO 呈现一些内容。如果应用程序在仅渲染模式下运行,结果将写入文件。以交互方式运行,它显示在我的 QGLWidget 子类“查看器”上。
如果我从 FBO 制作 QImage 并将其绘制到查看器,它就可以工作。然而,这需要从 GPU-> QImage-> 返回 GPU 作为纹理进行往返。理论上,我应该可以直接使用FBO作为纹理,这就是我想要的。
我试图在我的 QOpenGLContext 和 QGLWidget 的 QGLContext 之间共享,如下所示:
viewer = new tl::ui::glViewer(this); 合成器 = 新 tl::playback::glCompositor(1280, 720, 这个); 查看器->context()->contextHandle()->setShareContext(compositor->context);
是否可以在两种类型的上下文之间共享?这是这样做的方法吗?我是否需要做其他事情来使用合成器中的 FBO 在查看器中进行绘制?当我直接绘制 FBO 而不是 QImage 时,我只是得到纯白色,所以我显然做错了什么。
<小时/>所以我已经解决了我的问题。我误解了 setShareContext() 的文档,其中指出它“在调用 create() 之前不会生效”,我错误地认为这意味着您必须在创建上下文后共享上下文。相反,共享必须在以下之前建立:
viewer = new tl::ui::glViewer(this);
compositor = new tl::playback::glCompositor(512, 512, viewer->context()->contextHandle(), this);
以及我的 glCompositor 的新构造函数:
offscreenSurface = new QOffscreenSurface();
QSurfaceFormat format;
format.setMajorVersion(4);
format.setMinorVersion(0);
format.setProfile(QSurfaceFormat::CompatibilityProfile);
format.setSamples(0);
offscreenSurface->setFormat(format);
offscreenSurface->create();
context = new QOpenGLContext();
context->setShareContext(srcCtx);
context->setFormat(format);
context->create();
context->makeCurrent(offscreenSurface);
QOpenGLFramebufferObjectFormat f;
f.setSamples(0);
f.setInternalTextureFormat(GL_RGBA32F);
frameBuffer = new QOpenGLFramebufferObject(w, h, f);
将在与查看者上下文共享的新上下文中创建新的 FBO。当需要绘制时,我只需绑定(bind) glBindTexture(GL_TEXTURE_2D, frameBuffer->texture());
我正在标记我得到的正确答案,即使它没有直接解决我的问题。内容非常丰富。
最佳答案
我认为您的问题与 FBO 本身无法跨上下文共享这一事实有关。但是,您可以做的是共享附加的数据存储(渲染缓冲区、纹理等)。
归根结底,FBO 只不过是一个管理读取/绘制缓冲区集合的漂亮前端,FBO 本身实际上并不是可共享的资源。事实上,尽管有这个名字,但就 API 的其余部分而言,它们甚至不是缓冲区对象;您有没有想过为什么不使用 glBufferData (...)
等等? :)
Critically Important Point:
FrameBuffer Objects are not Buffer Objects; they contain no data stores; they only manage state for attachment points and provide an interface for validation and binding semantics.
block 引用> block 引用>This is why they cannot be shared, the same way that Vertex Array Objects cannot be shared, but their constituent Vertex Buffer Objects can.
这里的要点是:
- 如果不存储数据,则通常不是可共享资源。
您必须寻求的解决方案将涉及使用附加到 FBO 的渲染缓冲区和纹理。如果您不做任何疯狂的事情,例如尝试同时在两个上下文中渲染,那么共享这些资源应该不会带来太多麻烦。如果您开始尝试从渲染缓冲区或纹理中读取数据,而其他上下文正在绘制其中,那么它可能会变得非常难看,所以不要这样做:P
<小时/> 由于 OpenGL 规范中使用以下语言,您可能必须先分离纹理,然后才能在其他上下文中使用它:OpenGL 3.2 (Core Profile) - 4.4.3 纹理和帧缓冲区之间的反馈循环 - 第 230 页:
A feedback loop may exist when a texture object is used as both the source and destination of a GL operation. When a feedback loop exists, undefined behavior results. This section describes rendering feedback loops (see section 3.8.9) and texture copying feedback loops (see section 3.8.2) in more detail.
坦率地说,你的白色纹理可能是反馈循环的结果(OpenGL在3.1之前的规范版本中没有给这种情况命名,所以对“反馈循环”的正确讨论将在3.1中找到) + 仅文献)。因为这会调用未定义的行为,所以供应商之间的行为会有所不同。分离将消除未定义行为的根源,您应该可以开始了。
关于opengl - QOpenGLContext 和 QGLWidget 之间的共享,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19329888/