When developing graphics applications such as OpenGL or Vulkan apps, we typically using hardware acceleration need a graphics card (Graphics Processing Unit, aka. GPU) to render graphics for better performance and visual quality.
However, in some cases, we may not have access to a GPU, such as headless cloud server or in a CI/CD environment.
In this blog post, I will show you how to develop OpenGL applications inside a Linux server environment which is running in a GPU-less Docker container (in my case, a MacBook Pro with Apple Silicon M3).
On a headless Linux server without a GPU, we can use the software implementation of OpenGL provided by Mesa.
About Mesa
Mesa is an open-source implementation of OpenGL that provides software rasterizers inside its Gallium driver, such as softpipe and LLVMpipe, for CPU-based rendering. The Gallium LLVMpipe driver uses LLVM to do runtime code generation with LLVM IR, is multithreaded and offers better performance than softpipe. Read more about Mesa's llvmpipe.
On Linux, EGL is commonly used as the integration layer between OpenGL and the native windowing system, such as X window system and Wayland.
EGL also supports off-screen rendering by creating an headless surface called Pbuffer (pixel buffer), which enables rendering without any real display or window.
RTT (Render To Texture) with EGL + OpenGL Image made by author
苹果系统的链接器/usr/lib/dyld 提供了一个叫dyld-interposing的功能(从 Mac OS X 10.4 开始),可以在程序启动时替换掉某个函数的实现。这个功能可以用来实现代码注入(详见:《Mac OS X Internals: A Systems Approach》- Amit Singh - 第二章 2.6.3.4 dyld interposing)
Frame graphs are a design pattern for handling complex rendering pipelines, which are currently used in industry. Their usage is motivated by handling barriers, queue synchronization and memory aliasing in the background by abstracting the rendering pipeline of a frame on a higher level. —— https://github.com/gfx-rs/gfx/wiki/Frame-graphs
解决什么问题?
在传统的渲染管线中,渲染过程通常被划分为多个阶段,如下图所示:
这些阶段之间存在着输入和输出的依赖关系,其中一个阶段的输出作为下一个阶段的输入。
Render Graph 的主要思想是将渲染过程表示为一个有向无环图(DAG),其中节点表示渲染通道(Render pass),边表示依赖关系。每个渲染通道执行特定的渲染操作,可具有输入和输出资源,例如Texture、Frame Buffer和执行的 Shader/Program。例如,假设节点 A 的输出Texture是节点 B 的输入Texture,那么节点 B 就依赖于节点 A。