Compile shader source to SPIR-V and render it with Vulkan.
shaderlab takes a small project directory containing shader source, compiles it
to SPIR-V using the Slang compiler (slangc), and
renders a fullscreen quad through Vulkan with the compiled program. It is a
minimal, self-contained scaffolding project written in C++20 and organized the
way a small C++ project under LLVM-style conventions would be.
project directory ──► discovery ──► compile (slangc) ──► render (Vulkan/SDL3)
- discovery — finds the shader source files in the project directory.
- compile — invokes the external
slangcbinary to produce SPIR-V. shaderlab does not implement a shader compiler itself; the compile module is the single boundary a new frontend (GLSL, HLSL, ...) would plug into. - render — creates a Vulkan device, builds a pipeline from the compiled stages, and presents a fullscreen quad in a window (SDL3) or fullscreen.
- CMake 3.25 or newer
- A C++20 compiler (developed and tested with MSVC on Windows)
- The Vulkan SDK — supplies
slangc, theVulkanpackage, and the bundled SDL3 for Windows.- Set
VULKAN_SDK(or let CMake findC:/VulkanSDK/*on Windows). SDL3_DIRdefaults to the SDK'scmakedirectory on Windows.
- Set
cmake -S . -B build -G Ninja -DSHADERLAB_ENABLE_TESTS=ON
cmake --build buildSHADERLAB_ENABLE_TESTS defaults to OFF; enable it to build the unit tests.
shaderlab --run [options] [project directory]
Options:
| Option | Description |
|---|---|
--windowed |
present in a window (default) |
--fullscreen |
present fullscreen |
--watch |
recompile and reload shaders when the source files change |
--slangc PATH |
path to the slangc executable |
--help, -h |
show help |
Example:
build/tools/shaderlab/shaderlab.exe --run my-projectWithout --slangc, the executable is found on the PATH, then in the Vulkan
SDK installation.
project/
├── vertex.slang optional; a default fullscreen-quad vertex shader is
│ supplied when absent
└── fragment.slang required
Stage files are matched in a fixed language-preference order: slang, glsl,
hlsl, then conventional stage suffixes (vert/vsh, frag/fsh). An error
is reported when the directory does not exist or no fragment shader is found.
The fragment shader receives the environment through a constant buffer at set 0, binding 0. Declare it in your shader as:
struct ShaderlabEnvironment {
float2 resolution;
float time;
uint frame;
};
ConstantBuffer<ShaderlabEnvironment> shaderlab;The block is 16 bytes in std140 layout: resolution at offset 0, time at
offset 8, frame at offset 12. time is the elapsed seconds since the runtime
clock started and frame is the frame counter; both begin at 0 and increase
monotonically.
With --watch, shaderlab polls the discovered shader sources each frame and
recompiles them through slangc when a file is saved. On success the graphics
pipeline is swapped live — time and frame continue uninterrupted. When a
compile fails, the error is reported on the terminal and the last-good program
keeps rendering, so a broken save never blanks the window. The sources are
re-discovered after each change, so adding or removing a vertex.slang mid-run
is picked up as well.
Unit tests cover the CLI, source discovery, shader compilation, and process
utilities. Build with -DSHADERLAB_ENABLE_TESTS=ON, then:
ctest --test-dir build --output-on-failurecmake/ CMake helper modules
include/shaderlab/ public headers
cli/ command-line parsing
compile/ shader compilation (slangc boundary)
discovery/ project shader source discovery
interface/ SPIR-V interface inference (vertex input, bindings)
render/ Vulkan rendering
runtime/ application runtime (window/clock)
Support/ generic support (error handling, processes)
watch/ file-change detection (--watch hot reload)
window/ windowing (SDL3)
lib/ library implementations (one subdirectory per module)
tools/shaderlab/ the shaderlab executable
shaders/ sample shader sources
test/ unit tests