所以这就是 FBO 的初始化方式:
/**
* Initializes Renderbuffer.
*/
static GLuint init_renderbuffer(GLuint width, GLuint height, GLenum format) {
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
checkGlError("init_renderbuffer: glGenRenderbuffers");
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
checkGlError("init_renderbuffer: glBindRenderbuffer");
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
checkGlError("init_renderbuffer: glRenderbufferStorage");
glBindRenderbuffer(GL_RENDERBUFFER, 0);
checkGlError("init_renderbuffer: glBindRenderbuffer");
return renderbuffer;
}
/**
* Initializes FBO.
*/
static void engine_init_fbo(struct engine* engine, GLuint width, GLuint height) {
// create renderable texture
glGenTextures(1, &engine->renderableTexture);
checkGlError("engine_init_fbo: glGenTextures");
glBindTexture(GL_TEXTURE_2D, engine->renderableTexture);
checkGlError("engine_init_fbo: glBindTexture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
checkGlError("engine_init_fbo: glTexImage2D");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
checkGlError("engine_init_fbo: glTexParameteri");
// create render buffers
engine->depthRenderBuffer = init_renderbuffer(width, height, GL_DEPTH_COMPONENT16);
engine->stencilRenderBuffer = init_renderbuffer(width, height, GL_STENCIL_INDEX8);
LOGI("****************************** FBO: T: %d, D: %d, S: %d", engine->renderableTexture,
engine->depthRenderBuffer, engine->stencilRenderBuffer);
// create framebuffer object
glGenFramebuffers(1, &engine->framebufferObject);
checkGlError("engine_init_fbo: glGenFramebuffers");
glBindFramebuffer(GL_FRAMEBUFFER, engine->framebufferObject);
checkGlError("engine_init_fbo: glBindFramebuffer");
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, engine->renderableTexture, 0);
checkGlError("engine_init_fbo: glFramebufferTexture2D");
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, engine->depthRenderBuffer);
checkGlError("engine_init_fbo: glFramebufferRenderbuffer");
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, engine->stencilRenderBuffer);
checkGlError("engine_init_fbo: glFramebufferRenderbuffer");
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
checkGlError("engine_init_fbo: glCheckFramebufferStatus");
if(status != GL_FRAMEBUFFER_COMPLETE) {
switch(status) {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
LOGI("****************************** engine_init_fbo: FBO error: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
LOGI("****************************** engine_init_fbo: FBO error: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
LOGI("****************************** engine_init_fbo: FBO error: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
LOGI("****************************** engine_init_fbo: FBO error: FRAMEBUFFER_UNSUPPORTED");
break;
default:
LOGI("****************************** engine_init_fbo: Unknown FBO error");
}
}
else {
LOGI("****************************** engine_init_fbo: FBO has been successfully initialized");
}
glBindTexture(GL_TEXTURE_2D, 0);
checkGlError("engine_init_fbo: glBindTexture");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkGlError("engine_init_fbo: glBindFramebuffer");
}
可以看到,这里的一切都是按照 OpenGL ES 标准来完成的:使用 RGB565 内部格式的 2D 纹理作为颜色;2 个渲染缓冲区用作深度和模板表面;尺寸为 32x32。
它在真实设备上运行良好(Alcatel OT 918D,在 adb logcat 中打印“FBO 已成功初始化”),但在虚拟设备上因 FRAMEBUFFER_UNSUPPORTED 而失败。
我的虚拟设备的 CPU 是 atom,启用了 GPU 仿真,OpenGL ES 2.0 工作正常 - 与其他应用程序(不使用 FBO)检查。
可以使用 ndk-build 编译的整个项目(基于 NDK 的本机活动示例)在这里: https ://docs.google.com/file/d/0Byy41LxMuTKUZVJxSUtBZDVDXzA/edit?usp=sharing
我的问题是:这是 android-sdk 模拟器中的错误吗?因为一切似乎都满足 OpenGL ES 2.0 实现的最低要求。
谢谢!
编辑:找到解决方案。看来,AVD 不支持附加对象的这种配置。我必须移除模板附件才能使其正常工作。
EDIT2:这似乎是上下文创建问题。我不需要模板位,所以可能 AVD 在没有模板支持的情况下创建了上下文,而阿尔卡特手机 - 使用了模板。
无论如何,这不是错误,而是我的错误。