当前位置: 代码迷 >> 综合 >> imx6 GPU 后台离屏绘制3D图
  详细解决方案

imx6 GPU 后台离屏绘制3D图

热度:91   发布时间:2023-12-22 12:00:50.0

fsl的官方资料可以作为参考:https://download.csdn.net/download/ruhailiu126/10864713

官方并未提供offscreen离屏渲染例子

以下采用c++操作,后台离屏将3D图存储为图片。关键代码记录笔记如下:

初始化:

  static const EGLint s_configAttribs[] =
    {
        EGL_SURFACE_TYPE,  EGL_PBUFFER_BIT,
        EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
        EGL_RED_SIZE,  8,
        EGL_GREEN_SIZE,  8,
        EGL_BLUE_SIZE,  8,
        EGL_ALPHA_SIZE,  8,
   //   #  EGL_SAMPLES,  0,
        EGL_NONE
    };

 

    EGLint numconfigs;

 


    eglNativeDisplayType = fsl_getNativeDisplay();
    egldisplay = eglGetDisplay(eglNativeDisplayType);
    eglInitialize(egldisplay, NULL, NULL);
    assert(eglGetError() == EGL_SUCCESS);
    eglBindAPI(EGL_OPENGL_ES_API);

 

    eglChooseConfig(egldisplay, s_configAttribs, &eglconfig, 1, &numconfigs);
    assert(eglGetError() == EGL_SUCCESS);
    assert(numconfigs == 1);

 

    eglNativeWindow = fsl_createwindow(egldisplay, eglNativeDisplayType);
    assert(eglNativeWindow);

 

#if 0
    eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, eglNativeWindow, NULL);
#else
    EGLint attribListPbuffer[] = {
            // The NDK code would never draw to Pbuffer, so it's not neccessary to
            // match anything.
            EGL_WIDTH, width,
            EGL_HEIGHT, height,
            EGL_NONE };
    eglsurface = eglCreatePbufferSurface(egldisplay,eglconfig,attribListPbuffer);
#endif

 

    assert(eglGetError() == EGL_SUCCESS);
    EGLint ContextAttribList[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };

 

    eglcontext = eglCreateContext( egldisplay, eglconfig, EGL_NO_CONTEXT, ContextAttribList );
    assert(eglGetError() == EGL_SUCCESS);
    eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext);
    assert(eglGetError() == EGL_SUCCESS);

 

   GLuint texture,renderBuffer,frameBuffer;
   glActiveTexture(GL_TEXTURE0);
   glGenTextures(1,&texture);
   glBindTexture(GL_TEXTURE_2D,texture);
   glPixelStorei(GL_UNPACK_ALIGNMENT,1);
   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,pImageData);

 

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

 

   glGenFramebuffers(1, &frameBuffer);
   glGenRenderbuffers(1, &renderBuffer);
   glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
   glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
   glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, width,height);
   glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
          GL_RENDERBUFFER, renderBuffer);

 

   if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
   {
          qDebug()<<"Image Handler initImageFBO failed!\n";
          return -1;
   }

 

    {
       glViewport(0,0,width,height);

 

        // Compile the shaders
        GLuint hVertexShader = glCreateShader( GL_VERTEX_SHADER );
        glShaderSource( hVertexShader, 1, &g_strVertexShader, NULL );
        glCompileShader( hVertexShader );

 

        // Check for compile success
        GLint nCompileResult = 0;
        glGetShaderiv( hVertexShader, GL_COMPILE_STATUS, &nCompileResult );
        if( 0 == nCompileResult )
        {
            char  strLog[1024];
            GLint nLength;
            glGetShaderInfoLog( hVertexShader, 1024, &nLength, strLog );
            return FALSE;
        }

 

        GLuint hFragmentShader = glCreateShader( GL_FRAGMENT_SHADER );
        glShaderSource( hFragmentShader, 1, &g_strFragmentShader, NULL );
        glCompileShader( hFragmentShader );

 

        // Check for compile success
        glGetShaderiv( hFragmentShader, GL_COMPILE_STATUS, &nCompileResult );
        if( 0 == nCompileResult )
        {
            char  strLog[1024];
            GLint nLength;
            glGetShaderInfoLog( hFragmentShader, 1024, &nLength, strLog );
            return FALSE;
        }

 

        // Attach the individual shaders to the common shader program
        g_hShaderProgram = glCreateProgram();
        glAttachShader( g_hShaderProgram, hVertexShader );
        glAttachShader( g_hShaderProgram, hFragmentShader );

 

        // Init attributes BEFORE linking
        glBindAttribLocation( g_hShaderProgram, g_hVertexLoc,   "g_vPosition" );
        glBindAttribLocation( g_hShaderProgram, g_hColorLoc,    "g_vColor" );

 

        // Link the vertex shader and fragment shader together
        glLinkProgram( g_hShaderProgram );

 

        // Check for link success
        GLint nLinkResult = 0;
        glGetProgramiv( g_hShaderProgram, GL_LINK_STATUS, &nLinkResult );
        if( 0 == nLinkResult )
        {
            char strLog[1024];
            GLint nLength;
            glGetProgramInfoLog( g_hShaderProgram, 1024, &nLength, strLog );
            return FALSE;
        }

 

        // Get uniform locations
        g_hModelViewMatrixLoc = glGetUniformLocation( g_hShaderProgram, "g_matModelView" );
        g_hProjMatrixLoc      = glGetUniformLocation( g_hShaderProgram, "g_matProj" );

 

        glDeleteShader( hVertexShader );
        glDeleteShader( hFragmentShader );

 


        //gen textures

    }

 

绘制:

 static float fAngle = 0.0f;
    fAngle += 0.01f;

 

 

 

    // Rotate and translate the model view matrix
    float matModelView[16] = {0};
    matModelView[ 0] = +cosf( fAngle );
    matModelView[ 2] = +sinf( fAngle );
    matModelView[ 5] = 1.0f;
    matModelView[ 8] = -sinf( fAngle );
    matModelView[10] = +cosf( fAngle );
    matModelView[12] = 1.5f;
    matModelView[14] = -6.0f;
    matModelView[15] = 1.0f;

 


    // Build a perspective projection matrix
    float matProj[16] = {0};
    matProj[ 0] = cosf( 0.5f ) / sinf( 0.5f );
    matProj[ 5] = matProj[0] * (w/h) ;
    matProj[10] = -( 10.0f ) / ( 9.0f );
    matProj[11] = -1.0f;
    matProj[14] = -( 10.0f ) / ( 9.0f );

 


    // Clear the colorbuffer and depth-buffer
    glClearColor( 0.0f, 0.0f, 0.5f, 1.0f );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

 

    // Set some state
    glEnable( GL_DEPTH_TEST );
    glEnable( GL_CULL_FACE );
    glCullFace( GL_BACK );

 

    // Set the shader program
    glUseProgram( g_hShaderProgram );
    glUniformMatrix4fv( g_hModelViewMatrixLoc, 1, 0, matModelView );
    glUniformMatrix4fv( g_hProjMatrixLoc,      1, 0, matProj );

 

    // Bind the vertex attributes
    glVertexAttribPointer( g_hVertexLoc, 3, GL_FLOAT, 0, 0, VertexPositions );
    glEnableVertexAttribArray( g_hVertexLoc );

 

    glVertexAttribPointer( g_hColorLoc, 4, GL_FLOAT, 0, 0, VertexColors );
    glEnableVertexAttribArray( g_hColorLoc );

 


    glDrawArrays( GL_TRIANGLES, 0, 12 );

 

 

 

 

 

    matModelView[12] = -1.5f;
    // Set the shader program

 

    glUniformMatrix4fv( g_hModelViewMatrixLoc, 1, 0, matModelView );

 


    // Bind the vertex attributes
    glVertexAttribPointer( g_hVertexLoc, 3, GL_FLOAT, 0, 0, VertexPositions2 );

 


    glVertexAttribPointer( g_hColorLoc, 4, GL_FLOAT, 0, 0, VertexColors2 );

 

 

 

    /* Drawing Using Triangle strips, draw triangle strips using 4 vertices */
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
    glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
    glDrawArrays(GL_TRIANGLE_STRIP, 12, 4);
    glDrawArrays(GL_TRIANGLE_STRIP, 16, 4);
    glDrawArrays(GL_TRIANGLE_STRIP, 20, 4);

 

    //!wait
    glFinish();

 

    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glReadPixels(0,0,w,h,GL_RGBA,GL_UNSIGNED_BYTE,pImageData);

 

    QFile file("openesRaw.bat");
    if(!file.open(QIODevice::WriteOnly))
    {
        qDebug()<<"open file err"<<endl;
        return;
    }

 

    int writebyte =file.write((const char*)pImageData,4*800*600);
    qDebug()<<writebyte<<endl;
    file.flush();
    file.close();

 

  // QImage saveImage(pImageData, w, h, QImage::Format_RGB888);
    QImage saveImage(800,600,QImage::Format_RGB888);
    for(int ih=0;ih<600;ih++)
    {
        for(int iw=0;iw<800;iw++)
        {
            UN_RGBA rgba;
            rgba.m_rgba=pImageData[800*ih+iw];
            int r= (int)rgba.m_rgbaArray[0];
            int g=(int)rgba.m_rgbaArray[1];
            int b=(int)rgba.m_rgbaArray[2];

 

            saveImage.setPixel(iw,ih,qRgb(r,g,b));
        }
    }

   saveImage.save("opengs.png");

 

附录:

    1. OpenGL ES

OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。OpenGL ES 是从 OpenGL 裁剪的定制而来的,去除了四边形、多边形等复杂图元等许多非绝对必要的特性。OpenGL ES 1.x 针对固定pipeline硬件,OpenGL ES 2.x 针对可编程pipeline硬件。

    1. EGL

OpenGL是一个操作GPU的API,它通过驱动向GPU发送相关指令,控制pipeline状态机的运行状态。但OpenGL需要与本地视窗系统进行交互,这就需要一个中间控制层,最好与平台无关,EGL因此被独立的设计出来,它作为OpenGL ES和本地窗口的桥梁。

EGL API 是独立于OpenGL ES各版本标准的独立API ,其主要作用是为OpenGL指令创建 Context 、绘制目标Surface 、配置Framebuffer属性、Swap提交绘制结果等。此外,EGL为GPU厂商和OS窗口系统之间提供了一个标准配置接口。一般来说,OpenGL ES中pipeline的状态被存储于EGL管理的一个Context中。而Frame Buffers 和其他绘制Surfaces 通过EGL API进行创建、管理和销毁。 EGL 同时也控制和提供了对设备显示和可能的设备渲染配置的访问。

图 1为一个典型的EGL系统布局。应用程序通过调用EGL API进行window、surface、context的初始化,接着通过调用OpenGL ES的API进行设置context等,最后调用GPU渲染API进行渲染。

 

 

图 1 典型EGL系统布局

    1. Vivante GPU软件框架

图 2表示的是Vivante GPU的软件框架。GAL Driver是为了降低跨平台(操作系统,硬件平台)移植的难度而设计的一套API,包括用户层驱动:主要提供GAL API给开发者使用;内核层驱动:主要负责管理对GPU硬件的操作。

在实际使用中,图中的EGL、OpenGL ES等图形库以动态库形式被使用,用户层的GAL Driver也以动态库形式被使用,内核层的GAL Driver以内核模块驱动形式被使用。

https://img-blog.csdn.net/20170615185713121

 

    1. EGL要做什么?

EGL既然做平台和OpenGL ES的中间件那EGL做的就肯定是和平台息息相关的事:

创建绘图窗口也就是所谓的FrameBuffer,FrameBuffer可以显示到屏幕上(SurfaceView)

创建渲染环境(Context上下文)渲染环境指OpenGL ES的所有项目运行需要的数据结构。如顶点、片段着色器、顶点数据矩阵。

https://img-blog.csdnimg.cn/2018122016163530

 

1. 获取Display。
Display代表显示器,在有些系统上可以有多个显示器,也就会有多个Display。获得Display要调用EGLboolean eglGetDisplay(NativeDisplay dpy),参数一般为 EGL_DEFAULT_DISPLAY 。该参数实际的意义是平台实现相关的,在X-Window下是XDisplay ID,在MS Windows下是Window DC。

2. 初始化egl。
调用 EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor),该函数会进行一些内部初始化工作,并传回EGL版本号(major.minor)。

3. 选择Config。
所为Config实际指的是FrameBuffer的参数,在MS Windows下对应于PixelFormat,在X-Window下对应Visual。一般用EGLboolean eglChooseConfig(EGLDisplay dpy, const EGLint * attr_list, EGLConfig * config, EGLint config_size, EGLint *num_config),其中attr_list是以EGL_NONE结束的参数数组,通常以id,value依次存放,对于个别标识性的属性可以只有 id,没有value。另一个办法是用EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config) 来获得所有config。这两个函数都会返回不多于config_size个Config,结果保存在config[]中,系统的总Config个数保存在num_config中。可以利用eglGetConfig()中间两个参数为0来查询系统支持的Config总个数。Config有众多的Attribute,这些Attribute决定FrameBuffer的格式和能力,通过eglGetConfigAttrib ()来读取,但不能修改。

4. 构造Surface。

Surface实际上就是一个FrameBuffer,通过 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr) 来创建一个可实际显示的Surface。系统通常还支持另外两种Surface:PixmapSurface和PBufferSurface,这两种都不是可显示的Surface,PixmapSurface是保存在系统内存中的位图,PBuffer则是保存在显存中的帧。Surface也有一些attribute,基本上都可以故名思意, EGL_HEIGHT EGL_WIDTH EGL_LARGEST_PBUFFER EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET EGL_MIPMAP_TEXTURE EGL_MIPMAP_LEVEL,通过eglSurfaceAttrib()设置、eglQuerySurface()读取。

5. 创建Context。
OpenGL的pipeline从程序的角度看就是一个状态机,有当前的颜色、纹理坐标、变换矩阵、绚染模式等一大堆状态,这些状态作用于程序提交的顶点坐标等图元从而形成帧缓冲内的像素。在OpenGL的编程接口中,Context就代表这个状态机,程序的主要工作就是向Context提供图元、设置状态,偶尔也从Context里获取一些信息。用EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface read, EGLContext * share_list)来创建一个Context。

6. 绘制。
应用程序通过OpenGL API进行绘制,一帧完成之后,调用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示。

 

颜色缓冲区

  颜色缓冲区(COLOR_BUFFER)就是帧缓冲区(FRAME_BUFFER,你需要渲染的场景最终每一个像素都要写入该缓冲区,然后由它在渲染到屏幕上显示.

深度缓冲区

  深度缓冲区(DEPTH_BUFFER)与帧缓冲区对应,用于记录上面每个像素的深度值,通过深度缓冲区,我们可以进行深度测试,从而确定像素的遮挡关系,保证渲染正确.

模板缓冲区

  模版缓冲(STENCIL_BUFFER)与深度缓冲大小相同,通过设置模版缓冲每个像素的值,我们可以指定在渲染的时候只渲染某些像素,从而可以达到一些特殊的效果.