PicoGineSC
This project is a small shader compiler made in conjunction with PicoGine3. The main goal of this shader compiler is to interpret some Json-style metadata to generate all the required shader targets and compile them with the DirectXCompiler (DXC for short).Â
The project is available on GitHub! Link below.
This project will evolve with the progress of PicoGine3 as it will bring other more complex shaders to compile and might reveal some cases that aren't handled properly at the moment.
Invoking the PicoGineSC
When building the Release target of the project, the path to the output executable is set to an environment variable to make it accessible for any other projects. In my case, I added a custom build step in the project settings of PicoGine3 to always invoke PicoGineSC to check for new/modified shader files, even when no changes were made to the project's files.
The command to call PicoGineSC will look like this: "%PGSC_PATH%PicoGineSC.exe" -vk "$(SolutionDir)Shaders" "$(OutDir)Shaders" (example from PicoGine3). The first argument determines the output file format: -vk generates .spirv for Vulkan and -dx generates .cso for DirectX 12. The second argument is the input folder that will be parsed to compile all .hlsl files in it. Finally, the third argument is the output directory where all compiled targets will be stored, as well as a log file from the compilation process.
Shader metadata and compilation process
The first step is to parse the input directory to find all .hlsl files, other files and sub-folders being ignored. Therefore, include-only files should use the .hlsli extension in order not to cause unnecessary errors or warnings. The processing of all these files is then spread across multiple threads.
The metadata is a Json-style comment at the top of the shader file. It has two mandatory fields and an optional one, as described in the screenshot on the left. This allows to choose a per-file shader model, compile multiple entry points within the same .hlsl file (for different stages for example), and define keywords to make different variants of the same logic (added as preprocessor #define). If the metadata is missing or doesn't follow the the correct model, the file is ignored with a corresponding error being output to the invoking program's console output and the log file in the output directory. PicoGineSC also searches the file for the given entry point, ensuring it exists in the file, and outputs an error before starting the compilation if it is missing.
Once all targets have been identified, PicoGineSC checks for already up-to-date outputs (by comparing the last write time of the output shader and the source .hlsl file. ToDo: handle included files.) and skips unchanged files. All those target filenames are stored for a final cleanup pass. One all targets have been compiled, PicoGineSC parses the output directory to delete all shader outputs (both .cso and .spirv) to delete old output that are not required anymore (i.e. deleted source files or keywords or a change in the targeted API).