服务端基于libMesa实现离屏渲染


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的使用也很简单,首先安装依赖:

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

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

#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

Category