Shaders
Shaders are authored once in HLSL and compiled at build time into per-stage SPIR-V (.spv) and MSL (.msl) artifacts by cmake/SafiShaders.cmake (via glslangValidator + spirv-cross). At runtime, safi_shader_load inspects SDL_GetGPUShaderFormats() and picks the artifact matching the active backend — the caller only knows the logical shader name.
Functions
safi_shader_load
Loads <shader_dir>/<name>.<vert|frag>.<spv|msl> based on the device's supported formats. Returns a ready-to-bind SDL_GPUShader * or NULL on failure.
The four trailing counts tell SDL_gpu how many of each resource the shader will bind at draw time — they must match the register() declarations in your HLSL.
safi_shader_create_blob
Low-level: creates a GPU shader directly from a pre-compiled byte blob of a known format. Prefer safi_shader_load unless you are shipping embedded bytecode.
Stages
Compute shaders aren't wrapped yet — call SDL_CreateGPUComputePipeline directly if you need them.
HLSL binding layout (SDL_gpu rules)
SDL_gpu maps HLSL register spaces to resource slots:
For the engine's unlit material (1 vertex uniform, 1 fragment texture + sampler):
Build pipeline
The CMake helper safi_compile_shader() (in cmake/SafiShaders.cmake) runs two steps per stage:
- HLSL → SPIR-V via
glslangValidator -V -D -S <stage> -e <entry> - SPIR-V → MSL via
spirv-cross --msl --msl-version 20000
Generated artifacts land in ${CMAKE_BINARY_DIR}/shaders/. See examples/gltf_viewer/assets/shaders/unlit.hlsl and engine/src/ui/shaders/microui.hlsl for working examples.
Example
See also
SafiMaterial— builds a graphics pipeline from avs_main+fs_mainpair- Render overview — frame lifecycle and coordinate conventions