Отрисовка объекта фреймбуфера, затем перенос на основной дисплей (GLES 3.0)

Я пытаюсь создать объект фреймбуфера, а затем вывести его на основной дисплей. Целью этого является кэширование снимка экрана, который я могу вывести на дисплей, когда захочу, без повторного рендеринга объекта. Я использую 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.

Однако попытка перенести это в основной буфер отрисовки не удалась.

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.

person Matthew Grivich    schedule 02.06.2015    source источник
comment
То есть ошибок нет, но нет установленных пикселей? Какую версию Android вы используете? (У меня были некоторые проблемы с glBlitFramebuffer() из-за ошибок драйвера на Android 4.x, но я считаю, что проблема, которая у меня была, была исправлена ​​в 5.0. github.com/google/grafika/blob/master/src/com/android/grafika/ )   -  person fadden    schedule 03.06.2015
comment
Да, никаких ошибок и установленных пикселей. Я видел проблему с Android версии 4.4.2 и 5.0.1.   -  person Matthew Grivich    schedule 03.06.2015


Ответы (1)


Мне удалось обойти эту проблему, используя объект кадрового буфера текстуры (вместо буфера рендеринга), рисуя в этот буфер кадра, а затем рисуя эту текстуру буфера кадра в буфер по умолчанию. На самом деле это не ответ, а обходной путь, поэтому я все равно буду признателен, если у кого-нибудь есть ответ на исходный вопрос.

Для справки я включаю код ключа ниже:

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 );
}
person Matthew Grivich    schedule 04.06.2015