我正在尝试创建一个framebuffer对象,然后将其blit到主显示器。这样做的目的是缓存一个屏幕截图,我可以随时blit到显示器,而无需重新渲染对象。我正在使用Open GLES 3.0和Android NDK。
我以正常方式创建了一个帧缓冲区。
GLuint framebuffer = NULL;
glGenFramebuffers( 1, &framebuffer );
glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
GLuint colorRenderBuffer = NULL;
glGenRenderbuffers( 1, &colorRenderbuffer );
glBindRenderbuffer( GL_RENDERBUFFER, colorRenderbuffer );
glRenderbufferStorage( GL_RENDERBUFFER, GL_RGBA8, engine->width, engine->height );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer );
GLuint depthRenderbuffer = NULL;
glGenRenderbuffers( 1, &depthRenderbuffer );
glBindRenderbuffer( GL_RENDERBUFFER, depthRenderbuffer );
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, engine->width, engine->height );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer );
GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if (status != GL_FRAMEBUFFER_COMPLETE) {
LOGI( "failed to make complete framebuffer object %d", status );
}
else {
LOGI( "Frame buffer is complete." );
}
这没有错误。然后,我能够成功编辑帧缓冲区。
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, framebuffer );
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebuffer );
// Just fill the screen with a color.
glClearColor( red, green, blue, 255 );
glClear( GL_COLOR_BUFFER_BIT );
read_pixels( ); //wrapper for glReadPixels. Shows that all pixels in the frame buffer object have the desired color.
然而,尝试将其blit到主绘制缓冲区失败。
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebuffer );
glReadBuffer( GL_COLOR_ATTACHMENT0 );
glBlitFramebuffer( 0, 0, engine->width, engine->height, 0, 0, engine->width, engine->height, GL_COLOR_BUFFER_BIT, GL_LINEAR );
LOGI("GL error after blit: %d", glGetError()); //no error reported
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
read_pixels( engine ); //gives zero'd buffer (wrong result)
eglSwapBuffers( engine->display, engine->surface ); //shows a black screen, unless I use glClearColor directly on the primary display buffer.
答案 0 :(得分:0)
我能够通过使用纹理(而不是渲染缓冲区)帧缓冲区对象,绘制到该帧缓冲区,然后将该帧缓冲区纹理绘制到默认缓冲区来解决问题。这不是一个真正的答案,而是一个解决方案,所以如果有人对原始问题有答案,我仍然很感激。
作为参考,我在下面提供了关键代码:
GLuint LoadFrameBufferTexture( ESContext *context, int width, int height ) {
glGenFramebuffers( 1, &(context->framebuffer) );
glBindFramebuffer( GL_FRAMEBUFFER, context->framebuffer );
// create the texture
GLuint texture;
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0 );
GLuint depthRenderbuffer;
glGenRenderbuffers( 1, &depthRenderbuffer );
glBindRenderbuffer( GL_RENDERBUFFER, depthRenderbuffer );
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height );
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer );
GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if (status != GL_FRAMEBUFFER_COMPLETE) {
LOGI("failed to make complete framebuffer object ");
} else {
LOGI("Frame buffer is complete.");
}
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
return texture;
}
void draw_frame(int red, int green, int blue) {
glBindFramebuffer( GL_FRAMEBUFFER, esContext->framebuffer );
glClearColor( red, green, blue, 255 );
glClear( GL_COLOR_BUFFER_BIT );
glBindFramebuffer(GL_FRAMEBUFFER, 0 );
DrawFrame( esContext );
eglSwapBuffers( engine->display, engine->surface );
}
void DrawFrame( ESContext *esContext ) {
UserData *userData = (UserData *)esContext->userData;
GLfloat vVertices[] = {-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f };
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
glViewport( 0, 0, esContext->width, esContext->height );
glUseProgram( userData->programObject );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof( GLfloat ), vVertices );
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof( GLfloat ), &vVertices[3] );
glEnableVertexAttribArray( 0 );
glEnableVertexAttribArray( 1 );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, userData->frameTexId );
glUniform1i( userData->baseMapLoc, 0 );
glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
}