绘制到framebuffer对象,然后blit到主显示(GLES 3.0)

时间:2015-06-02 21:59:52

标签: android opengl-es android-ndk opengl-es-3.0

我正在尝试创建一个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.

1 个答案:

答案 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 );
}