将多个渲染目标(MRT)与多重采样相结合在iOS设备上失败,而不是在模拟器

时间:2016-08-18 11:48:49

标签: ios swift opengl-es

我正在尝试在iOS(> = 8.0)上编写一个使用多个渲染目标(MRT)的OpenGLES-3.0 Swift应用程序。为了获得适当的抗锯齿功能,我启用了多重采样。

详细说明,我的渲染架构如下所示:

  • 显示帧缓冲区附加了一个渲染缓冲区:

    • 显示渲染缓冲区:由iOS通过 EAGLContext.renderbufferStorage()控制,附加为GL_COLOR_ATTACHMENT0
  • Sample framebuffer 附加了两个渲染缓冲区:

    • Color renderbuffer I :GL_RGBA8,多重采样,附加为GL_COLOR_ATTACHMENT0
    • Color renderbuffer II :GL_RGBA8,多重采样,附加为GL_COLOR_ATTACHMENT1

每当我的图层更改其边界时,我会调整所有渲染缓冲区的大小,就像Apple在GLPaint示例中所做的那样。

我为你创建了一个最小的例子。渲染本身如下所示:

//Set the GL context, bind the sample framebuffer and specify the viewport:
EAGLContext.setCurrentContext(context)
glBindFramebuffer(GLenum(GL_FRAMEBUFFER), self.sampleFramebuffer)
glViewport(0, 0, self.layerWidth, self.layerHeight)

//Clear both render targets:
glClearBufferfv(GLenum(GL_COLOR), 0, self.colorRenderbufferIClearColor)
glClearBufferfv(GLenum(GL_COLOR), 1, self.colorRenderbufferIIClearColor)

//Specify the vertex attribute (only position, 6 floats for a triangle):
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 2, GLenum(GL_FLOAT), GLboolean(GL_FALSE), GLsizei(2 * sizeof(GLfloat)), nil)

//Use the shader program and render a single triangle:
glUseProgram(self.program)
glDrawArrays(GLenum(GL_TRIANGLES), 0, 3)

//Prepare both framebuffers as source and destination to do multisampling:
glBindFramebuffer(GLenum(GL_READ_FRAMEBUFFER), self.sampleFramebuffer)
glBindFramebuffer(GLenum(GL_DRAW_FRAMEBUFFER), self.displayFramebuffer)

//Specify from which of the attachments we do the multisampling.
//This is GL_COLOR_ATTACHMENT0 or GL_COLOR_ATTACHMENT1.
glReadBuffer(self.blitAttachment)

//Transfer data between framebuffers and do multisampling:
glBlitFramebuffer(0, 0, self.layerWidth, self.layerHeight, 0, 0, self.layerWidth, self.layerHeight, GLbitfield(GL_COLOR_BUFFER_BIT), GLenum(GL_LINEAR))

//Invalidate the sample framebuffer for this pass:
glInvalidateFramebuffer(GLenum(GL_READ_FRAMEBUFFER), 2, [GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_COLOR_ATTACHMENT1)])

//Bind the display renderbuffer and present it:
glBindRenderbuffer(GLenum(GL_RENDERBUFFER), self.displayRenderbuffer)
self.eaglContext.presentRenderbuffer(Int(GL_RENDERBUFFER))

现在问题:我的示例项目在红色背景上绘制一个蓝色三角形到第一个渲染目标(颜色渲染缓冲区I)和绿色背景上的紫色三角形到第二个渲染目标(颜色渲染缓冲区II)。通过在代码中设置 blitAttachment ,您可以选择将两个附件中的哪一个解析为显示帧缓冲区。

  • 一切都在iOS模拟器(所有设备,所有iOS版本)上按预期工作。
  • 目前我只能访问iPad Air(型号A1475,iOS 9.3.4)。但在设备上,存在以下问题:
    • 如果我禁用多重采样(glRenderbufferStorageMultisample()中的level = 0),一切正常。
    • 如果启用多重采样(级别= 4),我只能从GL_COLOR_ATTACHMENT0(颜色渲染缓冲区I)中进行blit。
    • 来自GL_COLOR_ATTACHMENT1的Blitting产生相同的结果(红色的蓝色三角形),但应该导致另一个(绿色的紫色三角形)。

您可以使用我附加的sample code (DropBox)重现该问题。 所以有两个问题:

  1. 有人可以确认这可以在模拟器上运行,但不能在真实设备上运行吗?
  2. 有人对我的代码中的错误有所了解吗?或者这是一个已知的错误?
  3. 提前致谢!

1 个答案:

答案 0 :(得分:0)

此API中似乎有一些奇怪的行为。您链接的代码确实可以在模拟器上运行,但模拟器与实际设备完全不同,所以我建议您永远不要将它用作参考。

所以似乎发生的事情是渲染缓冲区被丢弃的速度太快了。为什么以及如何发生这种情况我不知道。您将缓冲区blit然后使它们无效,因此只需删除缓冲区失效就可以解决问题。但是不建议删除缓冲区失效,而是确保GPU在使它们无效之前执行了所有任务。这意味着只需拨打flush

在致电glInvalidateFramebuffer(GLenum(GL_READ_FRAMEBUFFER), 2, [GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_COLOR_ATTACHMENT1)])之前,只需致电glFlush()

//Resolve from source to destination while applying multisampling:
glBlitFramebuffer(0, 0, self.layerWidth, self.layerHeight, 0, 0, self.layerWidth, self.layerHeight, GLbitfield(GL_COLOR_BUFFER_BIT), GLenum(GL_LINEAR))
OpenGLESView.checkError(dbgDomain, andDbgText: "Failed to blit between framebuffers")

glFlush()

//Invalidate the whole sample framebuffer:
glInvalidateFramebuffer(GLenum(GL_READ_FRAMEBUFFER), 2, [GLenum(GL_COLOR_ATTACHMENT0), GLenum(GL_COLOR_ATTACHMENT1)])
OpenGLESView.checkError(dbgDomain, andDbgText: "Failed to invalidate sample framebuffer")