3

问题的简短形式:如何使用我的 FBO 作为纹理在我的 QGLWidget 中绘制,而不仅仅是获得一个空白的白色图像?

并且,一些背景和细节......我正在使用 Qt 5.1 作为在 GPU 上进行一些图像处理的应用程序。有一个“合成器”类,它使用一个 QOffscreenSurface、一个 QOpenGLContext 和一个 QOpenGLFramebufferObject。它向 FBO 渲染了一些东西。如果应用程序在仅渲染模式下运行,则结果将写入文件。以交互方式运行,它会显示在我的 QGLWidget 子类中,即“查看器”。</p>

如果我从 FBO 制作 QImage 并将其绘制给查看器,它就可以工作。但是,这需要从 GPU-> QImage-> 作为纹理返回到 GPU 的往返行程。理论上,我应该可以直接将FBO作为纹理使用,这正是我想要的。

我试图在我的 QOpenGLContext 和 QGLWidget 的 QGLContext 之间共享,如下所示:

查看器 = 新 tl::ui::glViewer(this); 合成器 = 新 tl::playback::glCompositor(1280, 720, this); 查看器->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。画的时候,我只是绑定 glBindTexture(GL_TEXTURE_2D, frameBuffer->texture());

我正在标记我得到正确的答案,即使它没有直接解决我的问题。这是非常有用的。

4

1 回答 1

2

我相信您的问题与 FBO 本身不能跨上下文共享这一事实有关。但是,您可以做的是共享附加的数据存储(渲染缓冲区、纹理等)。

这真的归结为这样一个事实,即 FBO 只不过是管理读取/绘制缓冲区集合的漂亮前端,FBO 本身实际上并不是一个可共享的资源。事实上,尽管有这个名字,但就 API 的其余部分而言,它们甚至都不是缓冲区对象。你有没有想过为什么你不使用glBufferData (...),等等?:)

至关重要的一点:

FrameBuffer 对象不是缓冲区对象;它们不包含数据存储;它们只管理连接点的状态,并为验证和绑定语义提供接口。

这就是它们不能共享的原因,就像顶点数组对象不能共享一样,但它们的组成顶点缓冲区对象可以。

这里的外卖信息是:

  • 如果它不存储数据,它通常不是可共享的资源。

您必须寻求的解决方案将涉及使用附加到您的 FBO 的渲染缓冲区和纹理。如果你不做任何疯狂的事情,比如同时在两种上下文中尝试和渲染,共享这些资源应该不会带来太多麻烦。如果您开始尝试从渲染缓冲区或纹理中读取而其他上下文正在绘制它,它可能会变得非常难看,所以不要这样做:P


由于 OpenGL 规范中的以下语言,您可能必须先分离纹理,然后才能在其他上下文中使用它:

OpenGL 3.2(核心配置文件) - 4.4.3 纹理和帧缓冲区之间的反馈循环 - 第 230 页:

当纹理对象同时用作 GL 操作的源和目标时,可能存在反馈循环。当存在反馈循环时,会产生未定义的行为。本节更详细地描述了渲染反馈循环(参见第 3.8.9 节)和纹理复制反馈循环(参见第 3.8.2 节)。

坦率地说,您的白色纹理可能是反馈循环的结果(OpenGL 在 3.1 之前的规范版本中没有给这种情况命名,因此仅在 3.1+ 文献中可以找到关于“反馈循环”的正确讨论)。因为这会调用未定义的行为,所以供应商之间的行为会有所不同。分离将消除未定义行为的根源,您应该一切顺利。

于 2013-10-12T03:00:30.280 回答