OpenGL 离屏渲染

OpenGL 离屏渲染(Off-screen Rendering),短答案:

  • eglCreatePbufferSurface()
  • glReadPixels()

TLDR

EGL 1.5 的 2 个扩展

定义了一个独立于具体窗口系统(如:X11, Wayland, Windows)的抽象设备类别 EGLDeviceEXT。大致而言,一个 EGLDeviceEXT object 代表一个 GPU 设备。各个具体的窗口系统(X11, Wayland...)及 EGLDeviceEXT 在 EGL 规范中统称"platform"。指定 platform,调用 eglGetPlatformDisplay() 函数可创建针对此 platform 的 EGLDisplay object,进一步创建 EGLSurfaceEGLContext object,供 OpenGL 渲染。

基于 EGLDeviceEXT 的应用程序,不依赖于平台的窗口系统 API,例如,不需要在 X11 或 Wayland 图形环境下运行,适合 headless 系统下的图像渲染,且利用了 OpenGL 提供的硬件加速。

下面按先后顺序介绍用到的 API。

首先需检查 EGL 实现是否支持前述扩展。调用 EGL 函数 eglQueryString() 并提供 EGL_NO_DISPLAY 参数可查询 EGL 支持的全部扩展。如下:

C 复制代码
const char *s = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (NULL == strstr(s, "EGL_EXT_platform_device") || NULL == strstr(s, "EGL_EXT_device_base"))
{
    printf("EGL extension EXT_platform_device not supported\n");
    exit(-1);
}

要使用 EGL 扩展,程序需包含 <EGL/eglext.h> 头文件,并调用 eglGetProcAddress() 函数获取扩展函数的函数指针/地址。EGL_EXT_device_base 扩展中定义了一个 eglQueryDevicesEXT() 函数是后面需要用到的,必须先获取其函数地址,如下:

C 复制代码
#include <EGL/egl.h>
#include <EGL/eglext.h>

PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;

...

eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");

接下来可调用此函数获取支持的 EGLDeviceEXT object:

C 复制代码
EGLDeviceEXT egl_device;
{
    EGLint num;
    eglQueryDevicesEXT(0, NULL, &num);
        
    if (0 == num)
    {
        ...
    }

    eglQueryDevicesEXT(1, &egl_device, &num);
}

然后通过 EGLDeviceEXT object 创建 EGLDisplay object,并初始化:

C 复制代码
EGLDisplay egl_disp = eglGetPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, egl_device, NULL);
if (EGL_NO_DISPLAY == egl_disp)
{
    ...
}

if (!eglInitialize(egl_disp, NULL, NULL))
{
    ...
}

接下来创建 pbuffer surface。Pbuffer surface 不同于 window surface,用于 off screen 渲染。通常 pbuffer 用作 OpenGL texture object,但也可以直接将其复制到应用程序地址空间,例如,保存为图片文件。创建 pbuffer surface 代码如下:

C 复制代码
#define WINDOW_WIDTH 480
#define WINDOW_HEIGHT 480

...

EGLConfig egl_config;
{

    const EGLint attr_list[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //
        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,       //
        EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,   //
        EGL_RED_SIZE, 5,                         //
        EGL_GREEN_SIZE, 6,                       //
        EGL_BLUE_SIZE, 5,                        //
        EGL_DEPTH_SIZE, 8,                       //
        EGL_NONE,                                //
    };

    EGLint num;
    if (!eglChooseConfig(egl_disp, attr_list, &egl_config, 1, &num) || 1 != num)
    {
        ...
    }
}

EGLSurface egl_surf;
{
    EGLint attr_list[] = {
        EGL_WIDTH, WINDOW_WIDTH,   //
        EGL_HEIGHT, WINDOW_HEIGHT, //
        EGL_NONE,                  //
    };
    egl_surf = eglCreatePbufferSurface(egl_disp, egl_config, attr_list);
    if (EGL_NO_SURFACE == egl_surf)
    {
        ...
    }
}

特别留意上面代码第 10, 11 行。

最后,创建 EGLContext object,并将其设为当前:

C 复制代码
EGLContext egl_context;
{
    EGLint attr_list[] = {
        EGL_CONTEXT_CLIENT_VERSION, 2, //
        EGL_NONE,                      //
    };
    egl_context = eglCreateContext(egl_disp, egl_config, EGL_NO_CONTEXT, attr_list);
    if (EGL_NO_CONTEXT == egl_context)
    {
        ...
    }
}

eglMakeCurrent(egl_disp, egl_surf, egl_surf, egl_context);

至此,EGL 初始化完毕,可以进行 OpenGL 渲染,并调用 OpenGL glReadPixels() 函数从 pbuffer 中将图像/像素数据复制到 CPU 地址空间:

C 复制代码
GLubyte buf[3 * WINDOW_WIDTH * WINDOW_HEIGHT];
glReadPixels(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, buf);

完整的示例程序代码在 gitlab.com/sihokk/lear...

相关推荐
雪弯了眉梢10 天前
OpenGL(八)摄像机(Camera)
算法·图形渲染·opengl
爱看书的小沐14 天前
【小沐学WebGIS】基于Three.JS绘制二三维地图地球晨昏效果(WebGL / vue / react )
javascript·vue.js·gis·webgl·three.js·opengl·晨昏线
唯道行15 天前
计算机图形学·25 消隐2 区域子分算法-光线投射算法
人工智能·算法·计算机视觉·计算机图形学·opengl
唯道行17 天前
计算机图形学·23 Weiler-Athenton多边形裁剪算法
算法·计算机视觉·几何学·计算机图形学·opengl
落樱弥城17 天前
Compute Shader概论
ai·图形学·opengl
唯道行18 天前
计算机图形学·22 绘制(Implementation)2
人工智能·算法·计算机视觉·计算机图形学·opengl
深海潜水员20 天前
OpenGL 学习笔记 第一章:绘制一个窗口
c++·笔记·学习·图形渲染·opengl
唯道行23 天前
计算机图形学·21 梁友栋-Barsky直线裁剪算法与三维直线裁剪
人工智能·算法·机器学习·计算机视觉·计算机图形学·opengl
唯道行23 天前
计算机图形学·20 绘制(Implementation)1与Cohen-Sutherland算法
人工智能·算法·计算机视觉·计算机图形学·opengl
四维碎片1 个月前
【Qt】OpenGL渲染框架
qt·opengl