Android,OpenGL ES 2.0,ndk - glCheckFramebufferStatus返回GL_FRAMEBUFFER_UNSUPPORTED

时间:2015-05-16 18:42:36

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

我正在将用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上进行测试。

提前致谢!

1 个答案:

答案 0 :(得分:1)

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

4.1每片段操作 除遮挡查询,逻辑运算,alpha测试外,支持所有OpenGL 2.0每片段操作 和颜色索引相关的操作。支持深度和模板操作,但不支持选定的配置 需要包含深度或模板缓冲区,以及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_COMPONENT16 {1}}和GL_STENCIL_INDEX8组合,因为该驱动程序肯定支持它。使用此格式创建的渲染缓冲区应同时绑定到GL_DEPTH_ATTACHMENTGL_STENCIL_ATTACHMENT(同时)。此扩展在GLES 3.0中成为标准,这意味着每个支持GLES 3.0的设备都应该具有它。

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