ShaderMake is a front-end tool for batch multi-threaded shader compilation developed by NVIDIA DevTech. It is compatible with Microsoft FXC and DXC compilers by calling them via API functions or executing them through command line, with Slang through command line only, and with the Metal compiler from Xcode (via xcrun) on macOS or from Metal Developer Tools for Windows on Windows.
Features:
- Generates DXBC, DXIL and SPIR-V using FXC, DXC or Slang where supported, and Metal libraries from Metal Shading Language sources or, via Metal Shader Converter, from HLSL (as Metal converter bundles);
- Output formats: a native binary, a header file, and a binary or header blob (containing all permutations for a given input shader file);
- Minimizes the number of re-compilation tasks by tracking file modification times, include trees, compiler executables and recognized runtime libraries, and global code-generation settings.
CMake options:
SHADERMAKE_FIND_FXC- find FXC in installed Windows SDK and populateSHADERMAKE_FXC_PATHSHADERMAKE_FIND_DXC- download DXC from GitHub and populateSHADERMAKE_DXC_PATHSHADERMAKE_FIND_DXC_VK- find DXC in installed Vulkan SDK and populateSHADERMAKE_DXC_VK_PATH(this is the only way to get DXC on macOS currently)SHADERMAKE_FIND_SLANG- download Slang from GitHub and populateSHADERMAKE_SLANG_PATHSHADERMAKE_FIND_COMPILERS- master switchSHADERMAKE_DXC_VERSION- DXC to download from GitHub/DirectXShaderCompiler releasesSHADERMAKE_DXC_DATE- DXC release date (unfortunately present in the download links)SHADERMAKE_SLANG_VERSION- Slang to download from GitHub/Shader-slang/slang releasesSHADERMAKE_BIN_OUTPUT_PATH- output directory for the ShaderMake executableSHADERMAKE_TOOL- use ShaderMake as an external tool and hide the executable from the parent project IDE; this avoids shader recompilation when switching build configurations
If either SHADERMAKE_DXC_PATH or SHADERMAKE_DXC_VK_PATH is empty during deployment, it is set to the available path because both compilers support DXIL and SPIR-V generation. After deployment, the SHADERMAKE_PATH CMake variable stores the path to the ShaderMake executable.
Usage:
ShaderMake.exe -p {DXBC|DXIL|SPIRV|METAL} [-b] [-h] [-B] [-H] -c "path/to/config"
-o "path/to/output" --compiler "path/to/compiler" [--compilerAlias "NAME=path"] [other options]
-D DEF1 -D DEF2=1 ... -I "path1" -I "path2" ...
-h, --help show this help message and exit
Required inputs and output selection:
-p, --platform(string) - DXBC, DXIL, SPIRV or METAL (macOS and Windows only)-c, --config(string) - Configuration file with the list of shaders to compile-o, --out(string) - Output directory-b, --binary- Output binary files-h, --header- Output header files-B, --binaryBlob- Output binary blob files-H, --headerBlob- Output header blob files--compiler(string) - Path to an FXC/DXC/Slang compiler. An executable namedslangcis detected automatically. For METAL, path toxcrunon macOS (optional, default =/usr/bin/xcrun), tometal.exeon Windows (optional, see below) or to DXC with--metalFromDXIL
Compiler settings:
--compilerAlias(string) - RegisterDXCorSLANGasNAME=pathfor selection by config-local--compilerDXILand--compilerSPIRV; names are case-insensitive and each alias may be registered once-m, --shaderModel(string) - Shader model for DXIL/SPIRV (always SM 5.0 for DXBC) in 'X_Y' format-O, --optimization(int) - Optimization level 0-3 (default = 3, disabled = 0)-X, --compilerOptions(string) - Custom command line options for the compiler, separated by spaces--WX- Treat warnings as errors (-WXfor DXC/FXC,-warnings-as-errors allfor Slang,-Werrorfor Metal)--allResourcesBound- Maps to-all_resources_boundDXC/FXC option: all resources bound--PDB- Output PDB files inout/PDB/; ShaderMake does not currently support separate PDB output with Slang, so debug information remains in the shader binary. For METAL, debug information and sources are written into a.metallibsymfile next to the output--embedPDB- Embed PDB with the shader binary (for METAL, debug information and sources are embedded into the library)--stripReflection- Maps to-Qstrip_reflectDXC/FXC option: strip reflection information from a shader binary--matrixRowMajor- Maps to-ZprDXC/FXC option: pack matrices in row-major order--hlsl2021- Maps to-HV 2021DXC option: enable HLSL 2021 standard--slang- Explicitly select Slang for wrappers or non-standard executable names--slangHLSL- Use HLSL compatibility mode when compiler is Slang
Defines & include directories:
-I, --include(string) - Include directory(s)-D, --define(string) - Macro definition(s) in forms 'M=value' or 'M'
Other options:
-f, --force- Treat all source files as modified--project(string) - Project name used in informational output--sourceDir(string) - Source code directory--relaxedInclude(string) - Include file(s) not invoking re-compilation--outputExt(string) - Extension for output files, default is one of.dxbc,.dxil,.spirv,.metallib(.metalbundlewith--metalFromDXIL)--serial- Disable multi-threading-j, --jobs(int) - Maximum number of parallel compilation tasks;0uses the number of logical processors (default =0)--flatten- Flatten source directory structure in the output directory--continue- Continue compilation if an error occurred--colorize- Colorize console output--verbose- Print commands before they are executed--retryCount(int) - Retry count for compilation task subprocess failures (default = 10)--ignoreConfigDir- Use 'current dir' instead of 'config dir' as parent path for relative dirs--compactProgress- Compact compilation progress reporting
SPIR-V options:
--vulkanMemoryLayout(string) - Vulkan memory layout: dx, gl or scalar--vulkanVersion(string) - Vulkan environment version; maps to-fspv-target-envfor DXC. For Slang,1.0,1.1,1.1spirv1.4,1.2,1.3and1.4map tospirv_1_0,spirv_1_3,spirv_1_4,spirv_1_5,spirv_1_6andspirv_1_6, respectively (default =1.3). Slang HLSL profiles impose minimum SPIR-V versions: SM 5.x requires 1.0, SM 6.0-6.2 requires 1.3, SM 6.3-6.7 requires 1.4, SM 6.8 and later SM 6.x require 1.5, and newer major models conservatively require 1.6; incompatible combinations are rejected--spirvExt(string) - Add a permitted SPIR-V extension (-fspv-extensionfor DXC,-capabilityfor Slang); the legacyKHRwildcard is DXC-only and is omitted for Slang--sRegShift(int) - register shift for sampler (s#) resources--tRegShift(int) - register shift for texture (t#) resources--bRegShift(int) - register shift for constant (b#) resources--uRegShift(int) - register shift for UAV (u#) resources--noRegShifts- Don't specify any register shifts for the compiler
METAL options:
-
--metalSdk(string) - Target SDK:macosx,iphoneosoriphonesimulator(default =macosx) -
--metalStd(string) - Metal language standard (default =metal4.0) -
--metalMinOS(string) - Minimum OS version for the selected SDK (default =26.0, required bymetal4.0) -
--metalFromDXIL- Compile HLSL with DXC and convert DXIL withmetal-shaderconverterinto Metal converter bundles (see below) -
--metalShaderConverter(string) - Path tometal-shaderconverter(default = found inPATHor/usr/local/bin, on Windows see below) -
--metalShaderConverterOptions(string) - Custom command line options formetal-shaderconverter, separated by spaces
METAL compiles each shader into a .metallib using xcrun -sdk <sdk> metal, which may contain any number of functions. Defines, include directories, optimization level (-O0..3), --WX and custom compiler options are passed to the compiler. -T is optional, -E and -m don't affect compilation, HLSL-specific options are ignored. Unresolved <metal_*> and <simd/...> includes are treated as toolchain headers and are not tracked; other includes must be found through -I like on other platforms (or listed with --relaxedInclude).
METAL with --metalFromDXIL compiles HLSL exactly as DXIL (--compiler is DXC, config-local --compilerDXIL and --compilerOptionsDXIL apply) and converts the result with metal-shaderconverter using the entry point, the deployment OS and version from --metalSdk and --metalMinOS, and global and config-local --metalShaderConverterOptions (passed as is, in this order, relative paths are relative to the current directory). The converter decides which profiles and options are supported. The metallib and the reflection JSON are written as a Metal converter bundle. Contents of files referenced by --root-signature, --local-root-signature and --vertex-input-layout-file converter options are tracked for re-compilation.
METAL on Windows uses Apple's Metal Developer Tools for Windows and Metal Shader Converter for Windows (default installation paths), targeting macOS, iOS and iOS Simulator as on macOS:
metal.exeis taken from--compiler,%PROGRAMFILES%\Metal Developer Tools\bin, the per-target%PROGRAMFILES%\Metal Developer Tools\macos\bin(--metalSdk macosx) or...\ios\bin(iphoneos,iphonesimulator), orPATH. There are no SDKs on Windows,--metalSdkonly selects the deployment target (-mmacosx-version-min,-mios-version-minor-mios-simulator-version-min). The tools version should match the targeted SDKs (e.g. 6.2 for Xcode 26.2)metal-shaderconverter.exeis taken from--metalShaderConverter,%PROGRAMFILES%\Metal Shader Converter\binorPATH- Per Apple's license, the Windows tools must not be used on Apple devices
ShaderMake makes implicit definitions available in config files and shader sources, matching real compiler definitions:
__SLANG__matches the definition exposed by Slang and is added when that compiler is selected__spirv__matches the DXC SPIR-V target definition and is added for every SPIR-V compiler__METAL__matches the Metal compiler definition and is available in config files for METAL
When Slang is selected, ShaderMake translates these known DXC SPIR-V options to their Slang equivalents:
-fspv-extension=SPV_EXT_mesh_shaderis omitted because the mesh-shader profile enables the extension automatically-fspv-extension=SPV_*maps to-capability SPV_*-fspv-use-descriptor-heapmaps to-capability spvDescriptorHeapEXT -spirv-unified-descriptor-heap-stride-fspv-use-unknown-image-formatmaps to-default-image-format-unknown
Options without a known mapping are passed through unchanged.
For DXC, -fspv-use-descriptor-heap also permits SPV_EXT_descriptor_heap if it was not specified explicitly.
A config file consists of several lines, where each line has the following structure:
path/to/shader -T profile [-O3] [-o "output/subdirectory"] [-E entry] [--compilerDXIL NAME] [--compilerSPIRV NAME] [-D DEF1={0,1}] [-D DEF2={0,1,2}] [-D DEF3]
where:
path/to/shader(string) - shader source file-T, --profile(string) - shader profile (optional for METAL without--metalFromDXIL), can be:vs- vertexps- pixelgs- geometryhs- hullds- domaincs- computems- meshas- amplificationlib- library
-E, --entryPoint(string, optional) - Entry point (mainby default)-D, --define(string, optional) - Adds a macro definition to the list, optional range of possible values can be provided in{}-O, --optimization(int, optional) - Optimization level (global setting used by default)-o, --output(string, optional) - Output directory override-s, --outputSuffix(string, optional) - Suffix inserted before the first.in the filename (Shader.cs.hlsl -s TestproducesShaderTest.cs.hlsl)-m, --shaderModel(string, optional) - Shader model for DXIL/SPIRV (always SM 5.0 for DXBC) in 'X_Y' format--compilerDXIL(string, optional) - Select a compiler registered with the global--compilerAlias NAME=pathoption when compiling DXIL; ignored for other platforms--compilerSPIRV(string, optional) - Select a compiler registered with the global--compilerAlias NAME=pathoption when compiling SPIR-V; ignored for other platforms-X, --compilerOptions(string, optional) - Custom compiler options for this shader--compilerOptionsDXIL(string, optional) - Custom compiler options used only for DXIL--compilerOptionsSPIRV(string, optional) - Custom compiler options used only for SPIR-V--noRegShifts(optional) - Don't specify SPIR-V register shifts for this shader--metalShaderConverterOptions(string, optional) - Custommetal-shaderconverteroptions for this shader (METAL with--metalFromDXIL)
Additionally, the config file parser supports:
- One line comments starting with
// #ifdef D, whereDis a global or implicit macro definition name#if 1and#if 0#else#endif
Config preprocessing uses the default compiler selected by the global --compiler option. Consequently, #ifdef __SLANG__ reflects only the default compiler; config-local --compilerDXIL and --compilerSPIRV overrides define __SLANG__ for the shader source but do not affect config preprocessing.
Every active shader permutation must produce a unique output path. ShaderMake rejects duplicate outputs because compiling them concurrently would be unsafe.
ShaderMake inserts every generated filename suffix before the first extension that remains after removing the source extension. This applies to the explicit --outputSuffix, a non-main entry point, and the permutation hash. The platform extension is appended afterward.
For example, compiling Shader.cs.hlsl for DXIL with -s _Test -E CSMain and permutation defines produces names in this form:
Shader_Test_CSMain_0123ABCD.cs.dxil
Header output adds .h after the platform extension, while blob output follows the same suffix placement for its base filename.
When the --binaryBlob or --headerBlob command line arguments are specified, ShaderMake will package multiple permutations for the same shader into a single "blob" file with a custom format. ShaderMake provides a small library with parsing functions to use these blob files. This library can be statically linked with an application by including ShaderMake into the project and linking ShaderMakeBlob target to your application. Then include <ShaderMake/ShaderBlob.h> and use the ShaderMake::FindPermutationInBlob() to locate a specific shader permutation in a blob. If that is unsuccessful, ShaderMake::EnumeratePermutationsInBlob() and/or ShaderMake::FormatShaderNotFoundMessage() functions can help to provide a meaningful error message to the user.
With --metalFromDXIL, ShaderMake writes metal-shaderconverter output as a bundle (default extension .metalbundle), which allows using converted shaders without the converter at runtime (e.g. on iOS). All values are little-endian uint32_t, offsets are from the bundle start:
| Field | Value |
|---|---|
magic |
SMMB (0x424D4D53) |
version |
1 |
metallibOffset |
8-byte aligned, after the header |
metallibSize |
|
reflectionOffset |
reflection JSON (--output-reflection-file) after the metallib, followed by a zero terminator |
reflectionSize |
without the terminator |
ShaderMake::MetalConverterBundleHeader and ShaderMake::ParseMetalConverterBundle() from <ShaderMake/ShaderBlob.h> (ShaderMakeBlob target) describe and validate the bundle.