【问题标题】:Android, OpenGL ES 2.0, ndk - glCheckFramebufferStatus returning GL_FRAMEBUFFER_UNSUPPORTEDAndroid,OpenGL ES 2.0,ndk - glCheckFramebufferStatus 返回 GL_FRAMEBUFFER_UNSUPPORTED
【发布时间】:2015-05-16 18:42:36
【问题描述】:

我正在将一款用 C++(使用 SDL)编写的游戏移植到 Android。我之前在机翼和祈祷上使用了一个较旧的项目(之前有一些来自 stackoverflow 的帮助!),但尽管结果有点草率,但它几乎可以在我扔给它的所有 Android 设备上运行。

当时我太累了,无法重构和简化我拥有的东西。这一次,我正在创建一个 理论上 我不必再接触的引擎,并且我正在使用我的旧代码。虽然我已经编译并运行了所有东西,但它没有渲染任何东西。

具体来说,OpenGL ES 2.0 正在抛出 GL_FRAMEBUFFER_UNSUPPORTED 消息。我将所有内容绘制到纹理上(它 320x240 - 最终会改变),然后绘制该纹理以使其覆盖屏幕。它拒绝绘制到该纹理 - 我可以直接绘制到屏幕上(这至少让我希望着色器很好),但这不是很有帮助。

我的帧缓冲代码看起来有点像这样:

_superDuperFrameBuffer = 0;
_depthRenderBuffer = 0;

glGenFramebuffers(1, &_superDuperFrameBuffer);

//-----

glGenTextures(1, &_screenTexture);
glBindTexture(GL_TEXTURE_2D, _screenTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREENWIDTH2, SCREENHEIGHT2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); //float?

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

if(_currentWidth < SCREENWIDTH2*2 || _currentHeight < SCREENHEIGHT2*2) {
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else {
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


glBindTexture(GL_TEXTURE_2D, 0);

//-----

glGenRenderbuffers(1, &_depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, SCREENWIDTH2, SCREENHEIGHT2);

glGenRenderbuffers(1, &_stencilRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _stencilRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, SCREENWIDTH2, SCREENHEIGHT2);


glBindFramebuffer(GL_FRAMEBUFFER, _superDuperFrameBuffer);

glFramebufferTexture2D(GL_FRAMEBUFFER,      GL_COLOR_ATTACHMENT0,   GL_TEXTURE_2D,      _screenTexture, 0); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER,   GL_DEPTH_ATTACHMENT,    GL_RENDERBUFFER,    _depthRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,   GL_STENCIL_ATTACHMENT,  GL_RENDERBUFFER,    _stencilRenderBuffer);


GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE) {
    __android_log_print(ANDROID_LOG_VERBOSE, "LOG", "FRAMEBUFFER BORK %x", status);
}

这里有什么明显的我做错了吗?这是一个简单的 2D 游戏 - 没有什么花哨的,而且之前似乎都可以正常工作。我不知道 Android 的最佳设置是什么 - 没有任何东西可以解释如何正确地做事。

根据我所阅读的内容,GL_FRAMEBUFFER_UNSUPPORTED 应该在其中一个设置与另一个设置不一致时出现,或者如果设备不支持帧缓冲区(我知道它支持,因为我的上一个游戏运行得很好!)

另外担心代码可能没有被正确清理 - 一两次早期版本显示出生命迹象,但重新启动游戏后,他们没有。我不排除有外部影响搞砸了事情的想法,但我想我会先检查一下上面的代码是否正确。

在 2013 Nexus 7 上进行测试。

提前致谢!

【问题讨论】:

  • 只附加颜色缓冲是否通过测试?
  • 我的直觉是你需要一个组合的 DEPTH_STENCIL 格式而不是单独的格式。
  • 只通过了颜色缓冲区,但缺少深度和模板缓冲区会导致问题吗?
  • 那只是为了诊断。顺便说一句,您可以使用@username 符号在您回复他们的 cmets 时通知人们。直到现在我才看到附加信息。

标签: android c++ opengl opengl-es android-ndk


【解决方案1】:

正如评论中所述,帧缓冲区可以在没有深度和模板渲染缓冲区的情况下工作。这是 GL[ES] 的常见问题,因为没有查询支持的组合和/或格式的方法。您只需尝试一下,看看它是否有效——如果无效,实际问题并不总是很清楚。来自GLES 2.0 spec

4.1 分片操作 支持所有 OpenGL 2.0 每个片段的操作,除了遮挡查询、逻辑操作、alpha 测试 和颜色索引相关的操作。支持深度和模板操作,但不支持选定的配置 需要包含深度或模板缓冲区,并注意 OpenGL ES 2.0 实现必须 支持至少一种深度位深度为 16 或更高且模板位深度为 8 或更高的配置。

但是,它不需要任何特定的深度和/或模板格式或其组合。 glCheckFramebufferStatus manpage 声明:

GL_DEPTH_COMPONENT16 是唯一可深度渲染的格式。 GL_STENCIL_INDEX8 是唯一可模板渲染的格式。

这个语句可以(并且是)被扩展修改。它也没有明确说明这两者的组合必然形成一个有效的组合,这将导致glCheckFramebufferStatus 报告成功,而在某些驱动程序中,它们不会(Adreno 320 可能是其中之一)。

事实上,许多(大多数)Android GPU 支持GL_OES_packed_depth_stencil 扩展,它提供DEPTH24_STENCIL8_OES 格式,所以如果此扩展可用,DEPTH24_STENCIL8_OES 应该优先于GL_DEPTH_COMPONENT16GL_STENCIL_INDEX8组合,因为该驱动程序绝对支持它。使用这种格式创建的渲染缓冲区应该绑定到GL_DEPTH_ATTACHMENTGL_STENCIL_ATTACHMENT(同时)。此扩展在 GLES 3.0 中成为标准,这意味着每个支持 GLES 3.0 的设备都应该拥有它。

当然,如果您不需要深度/模板附件,那么它们只是浪费内存,您不应该使用它们。不过,如果您只是移植任意渲染代码,绑定它们可能更安全。

【讨论】:

    猜你喜欢
    • 2016-08-26
    • 2011-09-14
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多