Shader Development Overview¶
Available shader types¶
As the reference libretro frontend, RetroArch supports three shader languages:
|Shader Language||Video Context Drivers|
|Slang||Vulkan, GL 2.x (legacy desktop), GL 3.x+ (modern desktop), GLES2 (legacy mobile), GLES3 (modern mobile), HLSL (Planned), Metal (Planned)|
|GLSL||GL Shading Language, OpenGL, OpenGL ES, and EGL contexts including KMS mode in Linux)|
|Cg (deprecated)||HLSL/GLSL, nVidia|
When possible, it is recommended to use Slang shaders for supporting the widest variety of modern systems.
RetroArch is able to stack these shaders to create a combined effect. These complex effects are saved with a special extension:
Common Shaders Repository¶
The Libretro organization hosts a repository on Github that contains a compilation of shaders. Users can contribute their own shaders to this repository by doing a Pull Request.
Shader development: The rendering pipeline¶
With shaders you are able to take control over a large chunk of the GPUs inner workings by writing your own programs that are uploaded and run on the GPU. In the old days, GPUs were a big black box that was highly configurable using endless amount of API calls. In more modern times, rather than giving you endless amounts of buttons, you are expected to implement the few
«buttons» you actually need, and have a streamlined API.
The rendering pipeline is somewhat complex, but we can in general simplify
- Vertex processing
- Fragment processing
- Framebuffer blend
Shader developers can take control of what happens during vertex processing, and fragment processing.
Frontend development: Rendering the shader chain¶
With all these options, the rendering pipeline can become somewhat complex. The meta-shader format greatly utilizes the possibility of off-screen rendering to achieve its effects.
In OpenGL usually this is referred to as frame-buffer objects, and in HLSL as render targets. This feature will be referred to as FBO from here. FBO texture is assumed to be a texture bound to the FBO. As long as the visual result is approximately identical, the implementation does not have to employ FBO.
With multiple passes our chain looks like this conceptually:
|Source image| ---> |Shader 0| ---> |FBO 0| ---> |Shader 1| ---> |FBO 1| ---> |Shader 2| ---> (Back buffer)
In the case that Shader 2 has set some scaling params, we need to first render to an FBO before stretching it to the back buffer.
|Source image| ---> ... |Shader 2| ---> |FBO 2| ---> (Back buffer)
Scaling parameters determine the sizes of the FBOs. For visual fidelity it is recommended that power-of-two sized textures are bound to them. This is due to floating point inaccuracies that become far more apparent when not using power-of-two textures. If the absolute maximum size of the source image is known, then it is possible to preallocate the FBOs.
Do note that the size of FBOn is determined by dimensions of
FBOn-1 when "source" scale is used, not the source image size! Of course, FBO0 would use source image size, as there is no
For example, with SNES there is a maximum width of
512 and height of
478. If a source relative scale of
3.0x is desired for first pass, it is thus safe to allocate a FBO with size of
2048x2048. However, most frames will just use a tiny fraction of this texture.
With "viewport" scale it might be necessary to reallocate the FBO in run-time if the user resizes the window.
Shader compatibility with RetroArch video drivers¶
In RetroArch, the following table specifies which shader types work with what video contexts:
Attempting to load unsupported shader types may result in segmentation faults because the context drivers currently do not have the behavior to declare which types of shaders it supports.