使用opengl绘制和映射纹理到系统RAM



我想在我的树莓派上使用OpenGL ES 2.0来绘制一个矩形,其RGB像素值将存储在内存中的缓冲区中,稍后通过CPU进行进一步处理。

换句话说,这是路径:RAM中的RGB缓冲区->GPU上的纹理->画→回到RAM。最后,通过阅读下面的简单程序,我想要做的事情应该是清楚的。

我试图通过eglCreateImageKHR()创建一个EGLImage上下文来实现这一点,但是程序失败了错误0x501(来自GLCHK宏的断言):

#include <bcm_host.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <iostream>
#include <stdexcept>
#include <cassert>
#include <system_error>
#include <memory>
/* Uncomment to enable extra GL error checking */
#define CHECK_GL_ERRORS
#if defined(CHECK_GL_ERRORS)
#define GLCHK(X) 
do { 
    GLenum err = GL_NO_ERROR; 
    X; 
   while ((err = glGetError())) 
   { 
      std::cout << "GL error " << err << " in file " << __FILE__<< ", line " << __LINE__ << ' '; 
      assert(err == GL_NO_ERROR); 
      exit(err); 
   } 
} 
while(0)
#else
#define GLCHK(X) X
#endif /* CHECK_GL_ERRORS */
void demo() {
    EGLDisplay eglDisplay = 0;
    EGLConfig eglConfigWindow = 0;
    EGLSurface eglSurfacePbuffer = 0;
    EGLContext eglContext = 0;
    const EGLint attribListWindow[] = {
                                       EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
                                       EGL_RED_SIZE, 8,
                                       EGL_GREEN_SIZE, 8,
                                       EGL_BLUE_SIZE, 8,
                                       EGL_ALPHA_SIZE, 8,
                                       EGL_DEPTH_SIZE, 16,
                                       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
                                       EGL_NONE                                       
    };
    const EGLint srfPbufferAttr[] = {
                                     EGL_WIDTH, 640,
                                     EGL_HEIGHT, 480,
                                     EGL_NONE
    };
   const EGLint context_attribs[] = {
      EGL_CONTEXT_CLIENT_VERSION, 1,
      EGL_NONE
   };
    EGLint iMajorVersion, iMinorVersion;
    int iConfigs;
    eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (eglDisplay == EGL_NO_DISPLAY)
        throw std::runtime_error {"error eglGetDisaply()"};
    auto result = eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion);
    if (result == EGL_FALSE)
        throw std::runtime_error {"error eglInitialize()"};
    //result = eglChooseConfig(eglDisplay, attribListPbuffer, &eglConfigWindow, 1, &iConfigs);
    result = eglChooseConfig(eglDisplay, attribListWindow, &eglConfigWindow, 1, &iConfigs);
    if (result == EGL_FALSE)
        throw std::system_error(result, std::generic_category(), "Error setting configuration for the given display: check your settings");
    auto context = eglContext = eglCreateContext(eglDisplay, eglConfigWindow, EGL_NO_CONTEXT, context_attribs);
    if (context == EGL_NO_CONTEXT)
        throw std::runtime_error{"error eglCreateContext()"};                
    eglSurfacePbuffer = eglCreatePbufferSurface(eglDisplay, eglConfigWindow, srfPbufferAttr);
    if (eglSurfacePbuffer == EGL_NO_SURFACE)
        throw std::runtime_error{"error CreatePbufferSurface(). " + std::to_string(eglGetError())};                
    eglMakeCurrent(eglDisplay, eglSurfacePbuffer, eglSurfacePbuffer, eglContext);
    GLuint texture;                          // Name for the preview texture
    EGLImageKHR egl_image = EGL_NO_IMAGE_KHR; // The current preview EGL image
    glClearColor(0x11, 0x22, 0x33, 0); // random color
    glClearDepthf(1);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    const int bytes_per_pixel = 4;
    unsigned char buffer[640 * 480 * bytes_per_pixel] = {}; // 0x77 to see if it will be changed somehow
    GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture));
    egl_image = eglCreateImageKHR(eglDisplay, EGL_NO_CONTEXT, EGL_IMAGE_BRCM_MULTIMEDIA, (EGLClientBuffer) buffer, NULL);
    GLCHK(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, &egl_image));
    glReadPixels(0, 0, 640, 480, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    if (glGetError() != GL_NO_ERROR)
        throw std::runtime_error{"error glReadPixels():" + std::to_string(eglGetError())};
    eglSwapBuffers(eglDisplay, eglSurfacePbuffer);
    // print the buffer pixel values, should be different from 0x00
    for (auto x : buffer)
        std::cout << std::hex << int(x) << ' ';
   // Terminate
   /* Delete OES textures */
   glDeleteTextures(1, &texture);
   eglDestroyImageKHR(eglDisplay, egl_image);
   egl_image = EGL_NO_IMAGE_KHR;
    
   /* Terminate EGL */
   eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   eglDestroyContext(eglDisplay, context);
   eglDestroySurface(eglDisplay, eglSurfacePbuffer);
   eglTerminate(eglDisplay);
}
int main() {
    atexit(bcm_host_deinit);
    bcm_host_init();
    demo();
}

代码中的几个问题。您正在请求ES 1.0上下文,而代码中的其他内容和您的问题表明您计划使用ES 2.0:

const EGLint context_attribs[] = {
   EGL_CONTEXT_CLIENT_VERSION, 1,
   EGL_NONE
};

ES 2.0需要客户端版本2

最直接的问题是你使用的texture变量未初始化:
GLuint texture;                          // Name for the preview texture
...
GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture));

texture在这两个语句之间没有设置。你需要一个glGenTextures(1, &texture)来创建一个有效的纹理id。

最新更新