GBM for EGL (Linux)

Mesa GBM (Generic Buffer Manager) basically provides a EGL native window type (just like Wayland and X11), so one could obtain a real EGL surface and create render target buffers. With that then, GL can be used to render into these buffers, which will be shown to the display by queuing a page flip via KMS/DRM API.

用户应用程序直接对内存进行管理,通过 EGL 可以获取真实的 EGL 表面并创建渲染目标缓冲区

gbm(通用缓冲区管理),它提供了一种为 Mesa 绑定的图形渲染分配缓冲区的机制。GBM 旨在被当做一个本地平台为了工作在 DRM 上的 EGL 或者 openwfd。它创建的句柄可用于初始化 EGL 和创建渲染目标缓冲区。

MESA_platform_gbm

This extension defines how to create EGL resources from native GBM resources using the functions defined by EGL_EXT_platform_base. (GBM is a Generic Buffer Manager for Linux).

离屏渲染–简单示例

https://github.com/elima/gpu-playground/tree/master/render-nodes-minimal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl31.h>
#include <assert.h>
#include <fcntl.h>
#include <gbm.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

/* a dummy compute shader that does nothing */
#define COMPUTE_SHADER_SRC " \
#version 310 es\n \
\
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in; \
\
void main(void) { \
/* awesome compute code here */ \
} \
"

int32_t
main (int32_t argc, char* argv[])
{
bool res;

int32_t fd = open ("/dev/dri/renderD128", O_RDWR);
assert (fd > 0);

struct gbm_device *gbm = gbm_create_device (fd);
assert (gbm != NULL);

/* setup EGL from the GBM device */
EGLDisplay egl_dpy = eglGetPlatformDisplay (EGL_PLATFORM_GBM_MESA, gbm, NULL);
assert (egl_dpy != NULL);

res = eglInitialize (egl_dpy, NULL, NULL);
assert (res);

const char *egl_extension_st = eglQueryString (egl_dpy, EGL_EXTENSIONS);
assert (strstr (egl_extension_st, "EGL_KHR_create_context") != NULL);
assert (strstr (egl_extension_st, "EGL_KHR_surfaceless_context") != NULL);

static const EGLint config_attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
EGL_NONE
};
EGLConfig cfg;
EGLint count;

res = eglChooseConfig (egl_dpy, config_attribs, &cfg, 1, &count);
assert (res);

res = eglBindAPI (EGL_OPENGL_ES_API);
assert (res);

static const EGLint attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE
};
EGLContext core_ctx = eglCreateContext (egl_dpy,
cfg,
EGL_NO_CONTEXT,
attribs);
assert (core_ctx != EGL_NO_CONTEXT);

res = eglMakeCurrent (egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, core_ctx);
assert (res);

/* print some compute limits (not strictly necessary) */
GLint work_group_count[3] = {0};
for (unsigned i = 0; i < 3; i++)
glGetIntegeri_v (GL_MAX_COMPUTE_WORK_GROUP_COUNT,
i,
&work_group_count[i]);
printf ("GL_MAX_COMPUTE_WORK_GROUP_COUNT: %d, %d, %d\n",
work_group_count[0],
work_group_count[1],
work_group_count[2]);

GLint work_group_size[3] = {0};
for (unsigned i = 0; i < 3; i++)
glGetIntegeri_v (GL_MAX_COMPUTE_WORK_GROUP_SIZE, i, &work_group_size[i]);
printf ("GL_MAX_COMPUTE_WORK_GROUP_SIZE: %d, %d, %d\n",
work_group_size[0],
work_group_size[1],
work_group_size[2]);

GLint max_invocations;
glGetIntegerv (GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &max_invocations);
printf ("GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS: %d\n", max_invocations);

GLint mem_size;
glGetIntegerv (GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &mem_size);
printf ("GL_MAX_COMPUTE_SHARED_MEMORY_SIZE: %d\n", mem_size);

/* setup a compute shader */
GLuint compute_shader = glCreateShader (GL_COMPUTE_SHADER);

assert (glGetError () == GL_NO_ERROR);
const char *shader_source = COMPUTE_SHADER_SRC;

glShaderSource (compute_shader, 1, &shader_source, NULL);
assert (glGetError () == GL_NO_ERROR);

glCompileShader (compute_shader);
assert (glGetError () == GL_NO_ERROR);

GLuint shader_program = glCreateProgram ();

glAttachShader (shader_program, compute_shader);
assert (glGetError () == GL_NO_ERROR);

glLinkProgram (shader_program);
assert (glGetError () == GL_NO_ERROR);

glDeleteShader (compute_shader);

glUseProgram (shader_program);
assert (glGetError () == GL_NO_ERROR);

/* dispatch computation */
glDispatchCompute (1, 1, 1);
assert (glGetError () == GL_NO_ERROR);

printf ("Compute shader dispatched and finished successfully\n");

/* free stuff */
glDeleteProgram (shader_program);
eglDestroyContext (egl_dpy, core_ctx);
eglTerminate (egl_dpy);
gbm_device_destroy (gbm);
close (fd);

return 0;
}
1
gcc main.c `pkg-config --libs --cflags egl gbm gl`

主要分 4 部分:

  • 从渲染节点创建 GBM 设备
  • 设置(无表面的)EGL / OpenGL-ES 上下文
  • 创建一个计算着色器程序
  • 调度计算着色器

GBM+EGL+OPENGL+render

利用 GBM 进行图像的离屏渲染

https://raw.githubusercontent.com/Winddoing/CodeWheel/master/egl/egl_gbm_render.c

参考