2015-03-02 6 views
2

Я очень смущен на поверхности egl pbuffer. По-моему, поверхность pbuffer является независимой от платформы поверхностью, как поверхность окна или поверхность pixmap. Вещи, нарисованные на этой поверхности, хотя и не видны, должны быть в состоянии прочитать.pbuffer vs fbo в egl на экране рендеринга

ответ на этот вопрос, кажется, подтверждает мое понимание:

Difference from eglCreatePbufferSurface and eglCreatePixmapSurface with OpenGL ES(EGL)

однако, мой опыт показывает, что мне нужно, чтобы создать буфер FBO в дополнении к использованию поверхности пиксельного буфера.

Этот код работает для меня, он создает поверхность pbuffer, а затем fbo.

#include <GLES2/gl2.h> 
#include <EGL/egl.h> 

int main(int argc, char *argv[]) 
{ 
    EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, 
                EGL_NONE }; 
    // Step 1 - Get the default display. 
    EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0); 
    // Step 2 - Initialize EGL. 
    eglInitialize(eglDisplay, 0, 0); 
    // Step 3 - Make OpenGL ES the current API. 
    eglBindAPI(EGL_OPENGL_ES_API); 
    // Step 4 - Specify the required configuration attributes. 
    EGLint pi32ConfigAttribs[5]; 
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE; 
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT; 
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE; 
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT; 
    pi32ConfigAttribs[4] = EGL_NONE; 
    // Step 5 - Find a config that matches all requirements. 
    int iConfigs; 
    EGLConfig eglConfig; 
    eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs); 

    if (iConfigs != 1) 
    { 
     printf("Error: eglChooseConfig(): config not found.\n"); 
     exit(-1); 
    } 

    // Step 6 - Create a surface to draw to. 
    EGLSurface eglSurface; 
    eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, NULL); 

    // Step 7 - Create a context. 
    EGLContext eglContext; 
    eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs); 

    // Step 8 - Bind the context to the current thread 
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); 

    GLuint fboId = 0; 
    GLuint renderBufferWidth = 1920; 
    GLuint renderBufferHeight = 1080; 

    // Step 9 - create a framebuffer object 
    glGenFramebuffers(1, &fboId); 
    glBindFramebuffer(GL_FRAMEBUFFER, fboId); 

    GLuint renderBuffer; 
    glGenRenderbuffers(1, &renderBuffer); 
    glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer); 

    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, renderBufferWidth, renderBufferHeight); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBuffer); 

    GLuint depthRenderbuffer; 
    glGenRenderbuffers(1, &depthRenderbuffer); 
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, renderBufferWidth, renderBufferHeight); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); 

    // Step 10 - check FBO status 
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
    if(status != GL_FRAMEBUFFER_COMPLETE) 
    { 
     printf("Problem with OpenGL framebuffer after specifying color render buffer: \n%x\n", status); 
    } 
    else 
    { 
     printf("FBO creation succedded\n"); 
    } 

    int size = 4 * renderBufferHeight * renderBufferWidth; 
    unsigned char *data2 = new unsigned char[size]; 
    // Step 11 - clear the screen in Red and read it back 
    glClearColor(1.0,0.0,0.0,1.0); 
    glClear(GL_COLOR_BUFFER_BIT); 
    eglSwapBuffers(eglDisplay, eglSurface); 
    glReadPixels(0,0,renderBufferWidth,renderBufferHeight,GL_RGBA, GL_UNSIGNED_BYTE, data2); 

    ... save data2 to image ... 
} 

Однако, если я удалить FBO, и попытаться привлечь к себе пиксельный буфер напрямую, я вижу ошибку сегментации сразу после вызова функции() glClear:

#include <GLES2/gl2.h> 
#include <EGL/egl.h> 

int main(int argc, char *argv[]) 
{ 
    EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, 
                EGL_NONE }; 
    // Step 1 - Get the default display. 
    EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0); 
    // Step 2 - Initialize EGL. 
    eglInitialize(eglDisplay, 0, 0); 
    // Step 3 - Make OpenGL ES the current API. 
    eglBindAPI(EGL_OPENGL_ES_API); 
    // Step 4 - Specify the required configuration attributes. 
    EGLint pi32ConfigAttribs[5]; 
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE; 
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT; 
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE; 
    pi32ConfigAttribs[3] = EGL_OPENGL_ES2_BIT; 
    pi32ConfigAttribs[4] = EGL_NONE; 
    // Step 5 - Find a config that matches all requirements. 
    int iConfigs; 
    EGLConfig eglConfig; 
    eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs); 

    if (iConfigs != 1) 
    { 
     printf("Error: eglChooseConfig(): config not found.\n"); 
     exit(-1); 
    } 

    // Step 6 - Create a surface to draw to. 
    EGLSurface eglSurface; 
    eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, NULL); 

    // Step 7 - Create a context. 
    EGLContext eglContext; 
    eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs); 

    // Step 8 - Bind the context to the current thread 
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); 

    int size = 4 * renderBufferHeight * renderBufferWidth; 
    unsigned char *data2 = new unsigned char[size]; 
    // Step 11 - clear the screen in Red and read it back 
    glClearColor(1.0,0.0,0.0,1.0); 
    glClear(GL_COLOR_BUFFER_BIT); 
    eglSwapBuffers( eglDisplay, eglSurface); 
    glReadPixels(0,0,renderBufferWidth,renderBufferHeight,GL_RGBA, GL_UNSIGNED_BYTE, data2); 

    ... save data2 to image ... 
} 

Моя среда убунту 14 с intel graphics/mesa.

Знаете ли вы, почему я увидел ошибку сегментации? (Я проверил eglcontext, который, кажется, был создан успешно.) Можете ли вы подтвердить, что fbo требуется с поверхностью pbuffer?

EDIT: как указано Reto, моя проблема связана с отсутствующими атрибутами.

после установки этих атрибутов я смог заставить все работать с контекстом opengl es 2. Однако у меня все еще есть проблемы с контекстом opengl для настольных компьютеров.

Вместо того, чтобы читать красное изображение, с контекстом opengl рабочего стола, я мог получить только прозрачное изображение. вот мой текущий код:

#include <QCoreApplication> 
#include <QDebug> 
#include <QImage> 
#include <GL/gl.h> 
#include <EGL/egl.h> 
#include <QElapsedTimer> 

int main(int argc, char *argv[]) 
{ 
    // Step 1 - Get the default display. 
    EGLDisplay eglDisplay = eglGetDisplay((EGLNativeDisplayType)0); 

    // Step 2 - Initialize EGL. 
    eglInitialize(eglDisplay, 0, 0); 

    // Step 3 - Make OpenGL ES the current API. 
    eglBindAPI(EGL_OPENGL_API); 

    // Step 4 - Specify the required configuration attributes. 
    EGLint pi32ConfigAttribs[5]; 
    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE; 
    pi32ConfigAttribs[1] = EGL_PBUFFER_BIT; 
    pi32ConfigAttribs[2] = EGL_RENDERABLE_TYPE; 
    pi32ConfigAttribs[3] = EGL_OPENGL_BIT; 
    pi32ConfigAttribs[4] = EGL_CONFORMANT; 
    pi32ConfigAttribs[5] = EGL_OPENGL_BIT; 
    pi32ConfigAttribs[6] = EGL_COLOR_BUFFER_TYPE; 
    pi32ConfigAttribs[7] = EGL_RGB_BUFFER; 
    pi32ConfigAttribs[8] = EGL_LUMINANCE_SIZE; 
    pi32ConfigAttribs[9] = 0; 
    pi32ConfigAttribs[10] = EGL_RED_SIZE; 
    pi32ConfigAttribs[11] = 8; 
    pi32ConfigAttribs[12] = EGL_GREEN_SIZE; 
    pi32ConfigAttribs[13] = 8; 
    pi32ConfigAttribs[14] = EGL_BLUE_SIZE; 
    pi32ConfigAttribs[15] = 8; 
    pi32ConfigAttribs[16] = EGL_ALPHA_SIZE; 
    pi32ConfigAttribs[17] = 8; 
    pi32ConfigAttribs[18] = EGL_DEPTH_SIZE; 
    pi32ConfigAttribs[19] = 8; 
    pi32ConfigAttribs[20] = EGL_LEVEL; 
    pi32ConfigAttribs[21] = 0; 
    pi32ConfigAttribs[22] = EGL_BUFFER_SIZE; 
    pi32ConfigAttribs[23] = 24; 
    pi32ConfigAttribs[24] = EGL_NONE; 
    // Step 5 - Find a config that matches all requirements. 
    int iConfigs; 
    EGLConfig eglConfig; 
    eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs); 
    qDebug() << "egl error" << eglGetError(); 

    if (iConfigs != 1) 
    { 
     printf("Error: eglChooseConfig(): config not found.\n"); 
     exit(-1); 
    } 

    EGLint pbufferAttribs[5]; 
    pbufferAttribs[0] = EGL_WIDTH; 
    pbufferAttribs[1] = 1920; 
    pbufferAttribs[2] = EGL_HEIGHT; 
    pbufferAttribs[3] = 1080; 
    pbufferAttribs[4] = EGL_NONE; 

    // Step 6 - Create a surface to draw to. 
    EGLSurface eglSurface; 
    eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, pbufferAttribs); 
    qDebug() << "egl error" << eglGetError(); 

    if (eglSurface == EGL_NO_SURFACE) 
    { 
     qDebug() << "surface issue"; 
    } 

    // Step 7 - Create a context. 
    EGLContext eglContext; 
    eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, NULL); 
    qDebug() << "egl error" << eglGetError(); 

    if (eglContext == EGL_NO_CONTEXT) 
    { 
     qDebug() << "context issue"; 
    } 

    // Step 8 - Bind the context to the current thread 
    bool result = eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); 

    if (!result) 
    { 
     qDebug() << "make current error" << eglGetError(); 
    } 
    qDebug() << "egl error" << eglGetError(); 

    GLuint renderBufferWidth = 1920; 
    GLuint renderBufferHeight = 1080; 

    QElapsedTimer benchmarkTimer; 
    int size = 4 * renderBufferHeight * renderBufferWidth; 
    unsigned char *data2 = new unsigned char[size]; 
    int i = 0; 
    benchmarkTimer.start(); 
    while(i<1000) 
    { 
     glClearColor(1.0,0.0,0.0,1.0); 
     glClear(GL_COLOR_BUFFER_BIT); 
     eglSwapBuffers(eglDisplay, eglSurface); 
     glReadPixels(0,0,renderBufferWidth,renderBufferHeight,GL_RGBA, GL_UNSIGNED_BYTE, data2); 
     ++i; 
    } 
    qDebug() << "fps" << 1000.0*1000.0/benchmarkTimer.elapsed(); 

    QImage saveImage(data2, renderBufferWidth, renderBufferHeight, QImage::Format_RGBA8888_Premultiplied); 
    saveImage.save("haha.png"); 
    QCoreApplication a(argc, argv); 
    qDebug() << "done"; 
    return a.exec(); 
} 
+0

Почему вы не проверяете 'eglMakeCurrent (например,) 'возвращаемое значение? – genpfault

+0

Я проверил, а также проверил eglGetError(), все выглядит нормально. Я не вставлял их здесь для краткости. –

ответ

2

Есть несколько проблем в этом коде:

  1. EGL_SURFACE_TYPE, указанный в конфигурации атрибутов является неправильным:

    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE; 
    pi32ConfigAttribs[1] = EGL_WINDOW_BIT; 
    

    Чтобы оказать a PBuffer, необходимо использовать соответствующее значение:

    pi32ConfigAttribs[0] = EGL_SURFACE_TYPE; 
    pi32ConfigAttribs[1] = EGL_PBUFFER_BIT; 
    
  2. Для PBufer не указан размер. В то время как man page предполагает, что законно создавать PBuffer без указания размера, значения по умолчанию для ширины и высоты равны 0. Я не могу себе представить, что при попытке визуализации на поверхность размером 0 раз 0 произойдет что-либо хорошее. Чтобы указать размер:

    EGLint pbufferAttribs[5]; 
    pbufferAttribs[0] = EGL_WIDTH; 
    pbufferAttribs[1] = DesiredWidthOfPBuffer; 
    pbufferAttribs[2] = EGL_HEIGHT; 
    pbufferAttribs[3] = DesiredHeightOfPBuffer; 
    pbufferAttribs[4] = EGL_NONE; 
    eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, pbufferAttribs); 
    

Мой ответ на этот вопрос имеет полный код, чтобы создать контекст и поверхность пиксельный буфер для двух разных версий EGL: GLES10.glGetIntegerv returns 0 in Lollipop only. В коде используются привязки Java, но его легко адаптировать.

+0

Большое спасибо, после редактирования моего кода на основе вашего предложения, мне удалось заставить его работать с opengl es 2 context. изображение, которое я читаю, действительно красное. Однако, как только я меняю opengl es на настольный opengl, у меня все еще есть проблемы. изображение, которое я читаю, теперь полностью прозрачно. Я попытался установить размер буфера, размер глубины и все, что мне кажется нужным, но я все еще не могу исправить проблему. :(мой код обновляется в вопросе. –

0

Почему вы делаете eglSwapBuffers перед glReadPixels? Предположительно eglSwapBuffers не влияет на PBufferSurface (поскольку это не поверхность с двойным буфером), но если это вы попытаетесь прочитать пиксели из неопределенного буфера, с неопределенным результатом.