如何在共享上下文中呈现给FBO?

时间:2013-05-28 00:41:58

标签: macos opengl core-graphics fbo render-to-texture

我有一个应用程序需要执行以下操作:

  1. 将纹理从磁盘加载到GL纹理
  2. 在其上运行图像过滤器(通过FBO将其渲染到另一个纹理上)
  3. 在屏幕上显示生成的纹理
  4. 我有那么多工作。

    接下来,我希望能够将步骤#2移动到单独的共享GL上下文中。

    在初始化时,我创建了一个共享上下文:

    rootContext = CGLGetCurrentContext();
    CGLPixelFormatObj pf = CGLGetPixelFormat(rootContext);
    CGLCreateContext(pf, rootContext, &childContext);
    

    ...然后将其设置为当前并在其上设置帧缓冲...

    CGLSetCurrentContext(childContext);
    glGenTextures(1, &childTexture);
    glBindTexture(GL_TEXTURE_2D, childTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glGenFramebuffers(1, &childFramebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, childFramebuffer);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, childTexture, 0);
    

    然后,当渲染每一帧时,我将childContext设为当前并呈现给它:

    CGLSetCurrentContext(childContext);
    glBindFramebuffer(GL_FRAMEBUFFER, childFramebuffer);
    glUseProgram(childProgram);
    
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, inputTexture);
    glUniform1i(childTextureUniform, 0);
    
    glBindBuffer(GL_ARRAY_BUFFER, childQuadPositionBuffer);
    glVertexAttribPointer(childPositionAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*2, (void*)0);
    glEnableVertexAttribArray(childPositionAttribute);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, childQuadElementBuffer);
    glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void*)0);
    glDisableVertexAttribArray(childPositionAttribute);
    
    glUseProgram(0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    

    ...然后我将rootContext设为当前并将FBO的纹理渲染到屏幕:

    CGLSetCurrentContext(rootContext);
    glUseProgram(rootProgram);
    
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, childTexture);  // This texture was created and populated on childContext.
    glUniform1i(rootTextureUniform, 0);
    
    glBindBuffer(GL_ARRAY_BUFFER, rootQuadPositionBuffer);
    glVertexAttribPointer(rootPositionAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*2, (void*)0);
    glEnableVertexAttribArray(rootPositionAttribute);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, rootQuadElementBuffer);
    glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void*)0);
    glDisableVertexAttribArray(rootPositionAttribute);
    
    glUseProgram(0);
    

    如果我发表CGLSetCurrentContext(childContext);次来电,则完全

    但是,如果我切换到共享上下文渲染到FBO,我会看到屏幕上呈现出毛刺的垃圾,好像什么都没有渲染到childTexture上一样:

    glitchy garbage rendered onscreen when using shared contexts

    ......这真的很酷,但我想在这里找到更多的现实主义美学。

    关于在使用共享上下文时如何使其工作的任何想法?


    我已经尝试过了

    1. 创建共享上下文时检查CGLError - 没有错误;它已成功创建。
    2. 检查glGetError() - 没有错误。
    3. 正在检查glCheckFramebufferStatus() - 它是GL_FRAMEBUFFER_COMPLETE
    4. 按照@datenwolf的建议,在每次glBindTexture(GL_TEXTURE_2D, 0);通话后拨打glDisableVertexAttribArray()。没有变化。
    5. 完整的源代码

      我创建了2个简单的测试应用程序,它们都表现出同样的问题:

2 个答案:

答案 0 :(得分:7)

无法在上下文之间共享帧缓冲区对象(FBO)。 Only data carrying objects (textures, buffer objects, etc) are shared。抽象对象,即仅绑定其他对象和管理状态的对象(帧缓冲对象,顶点数组对象)不是。

因此,绑定您在其他上下文中创建的FBO不起作用。 BUT 你可以在辅助上下文中创建一个FBO,并将纹理对象从主要上下文绑定为颜色附件就好了。

更新

如果FBO目标纹理在主要上下文中作为纹理源绑定,则可能会出现另一个问题,同时它也应该用作渲染目标。我实际上并不确定OpenGL规范对这种情况所说的^ 1(我必须深入研究规格大概是我们左右的一半),但我猜驱动程序可能会认为这是一种情况,纹理不能被FBO瞄准。因此,我建议您使用互斥锁或信号量来同步主线程中纹理的绑定/解绑定与辅助线程中FBO的绑定。


1 EDIT OpenGL规范说,可以在光栅化操作中获取片段的纹理层不能同时用作FBO渲染目标;但OpenGL规范中的措辞并未明确考虑共享上下文。但我很确定,受共享上下文约束并且可以随时获取,可以满足此约束条件。在我自己的项目中,如果我在这种情况下实现这样的事情,我会自动实现双缓冲或三缓冲方案,并在从缓冲区(n+1)%M获取数据时渲染缓冲区n%M

答案 1 :(得分:3)

我完成了它,对上面的示例代码进行了2次更改:

  • 创建后,在childContext上调用glViewport()
  • 在每帧渲染到FBO后调用glFlushRenderAPPLE();