如何在不需要任何窗口系统库的情况下使用 OpenGL 渲染到内存?

How can I use OpenGL to render to memory without requiring any windowing system library?

我想使用 OpenGL(1.5 版)将图像渲染到内存中,而不在屏幕上显示它们(例如,我可以将它们保存为图像文件或在终端中将它们渲染为 ASCII)。我不想要任何 I/O。我在 SO 上发现了类似的问题,但是 none 解决了我将要遵循的具体进一步要求。

现在我想我可以使用像 glx 这样的库并告诉它不要打开任何 window,但是我也不希望我的代码依赖于任何 windowing 系统库,例如X11,因为我的程序根本不对任何 windows 或 I/O 做任何事情,我不明白为什么我的程序应该因依赖 X window 而负担重担(因为某些系统根本就没有 X window,他们甚至可能根本就没有图形界面)。我的程序应该只依赖于 OpenGL 驱动程序。

我明白为此我需要创建一个 OpenGL 上下文,它不是 OpenGL 的一部分并且是平台相关的东西,所以实际上我可能需要一些库来理想地创建 OpenGL 渲染到内存上下文以多平台的方式(即抽象出平台相关的东西)。有这样的东西存在吗? (我对任何专有的、特定于 GPU 或特定于驱动程序的软件不感兴趣,该程序应该 运行 在支持给定 OpenGL 版本的任何 GPU 上。)还有什么我应该考虑的吗?

基本上我希望我的程序非常精简,不要被不需要的东西所累,因为它所需要的只是使用通用的 OpenGL 驱动程序将图像渲染到内存中,并且应该可以在任何系统上运行有这样的OpenGL驱动。

谢谢。

根据您使用的操作系统和驱动程序的可用性,您可以使用 EGL 进行纯粹的、无头的、GPU 加速的 OpenGL 渲染。 Nvidia 在 https://developer.nvidia.com/blog/egl-eye-opengl-visualization-without-x-server/

上有一个很好的开发者博客,介绍如何做到这一点

要点是,在显示设备上创建 EGL 上下文而不将其与输出相关联。来源(直接从链接文章复制):

#include <EGL/egl.h>
static const EGLint configAttribs[] = {
          EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
          EGL_BLUE_SIZE, 8,
          EGL_GREEN_SIZE, 8,
          EGL_RED_SIZE, 8,
          EGL_DEPTH_SIZE, 8,
          EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
          EGL_NONE
};    

static const int pbufferWidth = …;
static const int pbufferHeight = …;

static const EGLint pbattr[] = {
        EGL_WIDTH, pbufferWidth,
        EGL_HEIGHT, pbufferHeight,
        EGL_NONE,
};

int main(int argc, char *argv[])
{
  EGLDisplay eglDpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  EGLint major, minor;
  eglInitialize(eglDpy, &major, &minor);
  EGLint numConfigs;
  EGLConfig eglCfg;

  eglChooseConfig(eglDpy, configAttribs, &eglCfg, 1, &numConfigs);
  EGLSurface eglSurf = eglCreatePbufferSurface(eglDpy, eglCfg, pbattr);
  eglBindAPI(EGL_OPENGL_API);
  EGLContext eglCtx = eglCreateContext(eglDpy, eglCfg, EGL_NO_CONTEXT, NULL);    
  eglMakeCurrent(eglDpy, eglSurf, eglSurf, eglCtx);

  do_opengl_stuff();

  eglTerminate(eglDpy);
  return 0;
}

如果您无法访问 EGL,但您的 OS 和您的 GPU 受 Linux DRM/DRI 支持,您可以选择 KMS/GBM 路线并值得通过扩展机制获得的帧缓冲区对象(好吧,对于 Mesa,您可以像使用它们一样使用它们,就好像它们是非扩展,即使使用 OpenGL-1.x)。 kmscube 演示有一个“无表面”模式,它演示了这样做。

简而言之:EGL 是处理它的“干净”方法。 KMS 是实现它的“hacky”方式。

另一个可能完全超出您现在范围的选择是使用 Vulkan,严格来说,无头渲染是“默认”,并且将内容显示在屏幕上的方法是对规范的实际扩展:

    VK_KHR_wayland_surface
    VK_KHR_xcb_surface
    VK_KHR_xlib_surface
    VK_KHR_win32_surface