OpenGL是一种跨平台的图形渲染API,主要用于2D和3D图形的渲染。OpenGL实现通常由GPU厂商提供,使得程序可以不关心硬件实现直接与GPU做交互。一般情况下图形渲染在客户端进行,因为大部分渲染目标都是屏幕窗口。而不同操作系统的图形窗口系统实现千差万别,所以又有了EGL(Embedded-System Graphics Library) 接口,用于管理图形上下文、Surface,作为OpenGL与原始窗口系统之间的桥梁。

服务端渲染是相对小众的需求,主要场景有云渲染、媒体处理等。服务端渲染有一个问题是我们的服务通常部署在ECS或K8s上,不会配置GPU,也没有GUI界面,软硬件环境都不具备。要解决这个问题,我们可以借助开源的图形库libMesa。

OSMesa软件渲染

OSMesa (Off-Screen Mesa) 是libMesa的一部分。可以用于在没有窗口系统支持的情况下进衣赖于GPU进行渲染。OSMesa的使用也很简单,首先安装依赖:

1
yum install -y mesa-libOSMesa-devel mesa-libGL-devel mesa-libEGL-devel

接下来是常规的创建GL上下文,这里需要引入<GL/osmesa.h>头文件,使用其提供系列函数实现GL上下文管理,示例代码如下:

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
#include <stdio.h>
#include <stdlib.h>
#include <GL/osmesa.h>
#include <GL/gl. h>

int main()
{
// 定义窗口宽度和高度
const int width = 800;
const int height = 600;
// 创建OSMesa上下文
OSMesaContext ctx = 0SMesaCreateContextExt(OSMESA_RGBA, 16, 0, 0, NULL);
if (!ctx)
{
fprintf(stderr, "OSMesaCreateContext failed\n");
return 1;
}
// 创建一个缓冲区
void *buffer = malloc(width * height * 4);
if (!buffer)
{
printf(stderr, "Buffer allocation failed\n");
OSMesaDestroyContext(ctx);
return 1;
}

// 创建一个缓冲区
void *buffer = malloc(width * height * 4);
if (!buffer)
{
fprintf(stderr, "Buffer allocation failed\n");
OSMesaDestroyContext(ctx);
return 1;
}

// 绑定上下文并将缓冲区绑定到上下文
OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, width, height);

// 清除颜色缓冲区为红色
glClearColor(1.0, 0.0, 0.0, 1.0);
gLClear(GL_COLOR_BUFFER_BIT);

// 将绘制结果保存到文件
FILE *f = fopen("output. rgba", "wb");
if (f)
{
fwrite(buffer, width * height * 4, 1, f);
fclose(f);
printf("Image saved to output.rgba\n");
}
else
{
fprintf(stderr, "Failed to open file for writing\n");
}

// 清理
OSMesaMakeCurrent((OSMesaContext) nullptr, nullptr, GL_UNSIGNED_BYTE, 0, 0);
free(buffer);
OSMesaDestroyContext(ctx);
return 0;
}

这里我们创建了一块内存作为渲染缓冲区,渲染结果直接可以通过内存获取。当然,使用glReadPixels 读取结果也是一样的。

DRM硬件加速

如果你的服务部署在本地物理机并配置有显卡,或是配置了带GPU的ECS机器,那可以用DRM做硬件加速。DRM(Direct Rendering Manager)是Linux内核的一部分,用于管理图形显示的硬件加速以及图形上下文的切换。它的优点是可以不依赖图形窗口系统,直接与GPU通信,提高渲染性能。
这个方案我们项目里没有实际应用,相关实现可以参考libMesa提供的demo:
https://gitlab.freedesktop.org/mesa/demos/-/blob/main/src/egl/opengl/eglkms.c