SPIR-V Toolchain

The Vulkan graphics API requires that all shaders be presented in SPIR-V format. SPIR-V is a binary intermediate representation for graphical shaders and compute kernels. The advantages and a high-level description of the representation are given in the SPIR-V White Paper. A more detailed description of the SPIR-V supported by this SDK can be found in The SPIR-V Specification v1.2.

The LunarG Vulkan SDK includes tools for SPIR-V shader generation, inspection, editing, validation, optimization, constant manipulation and compression improvement.

Chief member of the SPIR-V toolchain is glslangValidator, which can be used to create SPIR-V shaders from equivalent GLSL or HLSL shaders.

The SDK also includes spirv-opt which can be used (along with spirv-remap, described below) to reduce the size of SPIR-V code by more than 60% through classic optimization tranformations. spirv-opt can also be used to set and optimize a SPIR-V file's specialization constants.

The SPIR-V disassembler spirv-dis converts SPIR-V binary into a special text format for reading and editing. The SPIR-V assembler spirv-as converts such text back into SPIR-V binary format. The SPIR-V validator spirv-val can be used to assure that the resulting SPIR-V binary code is valid.

The SDK also includes spirv-remap, a tool to improve the compressibility of a collection of SPIR-V modules. This can result in up to a 50% reduction in the size of a compressed collection relative to the compressed originals. spirv-remap also has options (--dce all) to remove dead functions and types exposed by spirv-opt size reduction passes. It also can strip debug instructions from SPIR-V (--strip all) if not needed.

Finally, the SDK also provides a tool for viewing a SPIR-V file's control flow with spirv-cfg, a tool for generating high-level language representation and reflection data for a SPIR-V file with spirv-cross, and a standard compilation command line with shaderc.

glslangValidator (SPIR-V Generator)

glslangValidator is the tool used to compile GLSL and HLSL shaders into SPIR-V, Vulkan's shader format. Additional information on compiling HLSL can be found in the HLSL FAQ.

Executed without any options, glslangValidator returns the message:

Usage: glslangValidator [option]... [file]...

Where: each 'file' ends in .<stage>, where <stage> is one of
    .conf   to provide an optional config file that replaces the default configuration
            (see -c option below for generating a template)
    .vert   for a vertex shader
    .tesc   for a tessellation control shader
    .tese   for a tessellation evaluation shader
    .geom   for a geometry shader
    .frag   for a fragment shader
    .comp   for a compute shader

Compilation warnings and errors will be printed to stdout.

To get other information, use one of the following options:
Each option must be specified separately.
  -V          create SPIR-V binary, under Vulkan semantics; turns on -l;
              default file name is <stage>.spv (-o overrides this)
  -G          create SPIR-V binary, under OpenGL semantics; turns on -l;
              default file name is <stage>.spv (-o overrides this)
  -H          print human readable form of SPIR-V; turns on -V
  -E          print pre-processed GLSL; cannot be used with -l;
              errors will appear on stderr.
  -S <stage>  uses explicit stage specified, rather then the file extension.
              valid choices are vert, tesc, tese, geom, frag, or comp
  -c          configuration dump;
              creates the default configuration file (redirect to a .conf file)
  -C          cascading errors; risks crashes from accumulation of error recoveries
  -d          default to desktop (#version 110) when there is no shader #version
              (default is ES version 100)
  -D          input is HLSL
  -e          specify entry-point name
  -h          print this usage message
  -i          intermediate tree (glslang AST) is printed out
  -l          link all input files together to form a single module
  -m          memory leak mode
  -o  <file>  save binary to <file>, requires a binary option (e.g., -V)
  -q          dump reflection query database
  -r          relaxed semantic error-checking mode
  -s          silent mode
  -t          multi-threaded mode
  -v          print version strings
  -w          suppress warnings (except as required by #extension : warn)
  -x          save 32-bit hexadecimal numbers as text, requires a binary option (e.g., -V)

  --shift-sampler-binding [stage] num     set base binding number for samplers
  --ssb [stage] num                       synonym for --shift-sampler-binding

  --shift-texture-binding [stage] num     set base binding number for textures
  --stb [stage] num                       synonym for --shift-texture-binding

  --shift-UBO-binding [stage] num         set base binding number for UBOs
  --sub [stage] num                       synonym for --shift-UBO-binding

  --auto-map-bindings                     automatically bind uniform variables without
                                          explicit bindings.
  --amb                                   synonym for --auto-map-bindings

  --flatten-uniform-arrays                flatten uniform texture & sampler arrays to scalars
  --fua                                   synonym for --flatten-uniform-arrays

SPIR-V Optimizer

A programmer may wish to reduce the size of a SPIR-V file, especially as it is initially generated by the glslangValidator frontend. The SPIR-V optimizer spirv-opt can be used to apply classic optimization transformations to SPIR-V to reduce its size without changing its functionality. The following "recipe" of spirv-opt options can be effective at reducing SPIR-V size:

--inline-entry-points-exhaustive
--convert-local-access-chains
--eliminate-local-single-block
--eliminate-local-single-store
--eliminate-insert-extract
--eliminate-dead-code-aggressive
--eliminate-dead-branches
--merge-blocks
--eliminate-local-single-block
--eliminate-local-single-store
--eliminate-local-multi-store
--eliminate-insert-extract
--eliminate-dead-code-aggressive
--eliminate-common-uniform

The transformations are applied in the order specified on the command line. Note some options are applied more than once. More detailed information can be found in the file SpirvOptSizeReduction.pdf in the SDK documentation folder.

spirv-opt can also be used to manipulate the SPIR-V file's specialization constants.

spirv-opt -h returns the message:

spirv-opt - Optimize a SPIR-V binary file.

USAGE: spirv-opt [options] [<input>] -o <output>

The SPIR-V binary is read from <input>. If no file is specified,
or if <input> is "-", then the binary is read from standard input.
if <output> is "-", then the optimized output is written to
standard output.

NOTE: The optimizer is a work in progress.

Options:
  --strip-debug
               Remove all debug instructions.
  --freeze-spec-const
               Freeze the values of specialization constants to their default
               values.
  --eliminate-dead-const
               Eliminate dead constants.
  --fold-spec-const-op-composite
               Fold the spec constants defined by OpSpecConstantOp or
               OpSpecConstantComposite instructions to front-end constants
               when possible.
  --set-spec-const-default-value "<spec id>:<default value> ..."
               Set the default values of the specialization constants with
               <spec id>:<default value> pairs specified in a double-quoted
               string. <spec id>:<default value> pairs must be separated by
               blank spaces, and in each pair, spec id and default value must
               be separated with colon ':' without any blank spaces in between.
               e.g.: --set-spec-const-default-value "1:100 2:400"
  --unify-const
               Remove the duplicated constants.
  --flatten-decorations
               Replace decoration groups with repeated OpDecorate and
               OpMemberDecorate instructions.
  --compact-ids
               Remap result ids to a compact range starting from %1 and without
               any gaps.
  --inline-entry-points-exhaustive
               Exhaustively inline all function calls in entry point functions.
               Currently does not inline calls to functions with early return
               in a loop.
  --convert-local-access-chains
               Convert constant index access chain loads/stores into
               equivalent load/stores with inserts and extracts. Performed
               on function scope variables referenced only with load, store,
               and constant index access chains.
  --eliminate-common-uniform
               Perform load/load elimination for duplicate uniform values.
               Converts any constant index access chain uniform loads into
               its equivalent load and extract. Some loads will be moved
               to facilitate sharing. Performed only on entry point
               functions.
  --eliminate-local-single-block
               Perform single-block store/load and load/load elimination.
               Performed only on function scope variables in entry point
               functions.
  --eliminate-local-single-store
               Replace stores and loads of function scope variables that are
               only stored once. Performed on variables referenceed only with
               loads and stores. Performed only on entry point functions.
  --eliminate-local-multi-store
               Replace stores and loads of function scope variables that are
               stored multiple times. Performed on variables referenceed only
               with loads and stores. Performed only on entry point functions.
  --eliminate-insert-extract
               Replace extract from a sequence of inserts with the
               corresponding value. Performed only on entry point functions.
  --eliminate-dead-code-aggressive
               Delete instructions which do not contribute to a function's
               output. Performed only on entry point functions.
  --eliminate-dead-branches
               Convert conditional branches with constant condition to the
               indicated unconditional brranch. Delete all resulting dead
               code. Performed only on entry point functions.
  --merge-blocks
               Join two blocks into a single block if the second has the
               first as its only predecessor. Performed only on entry point
               functions.
  -h, --help   
               Print this help.
  --version    
               Display optimizer version information.

SPIR-V Disassembler, Assembler and Validator

A programmer may wish to view or change the contents of a shader while debugging a Vulkan application. Since Vulkan accepts shaders only in SPIR-V, a binary format, the SDK provides spirv-dis, a standalone program which prints a SPIR-V shader in human-readable and parsable form, and spirv-as, which can assemble the possibly edited output of spirv-dis. Finally, spirv-val can be used to verify that the resulting SPIR-V code is valid.

spirv-dis -h returns the message:

./spirv-dis - Disassemble a SPIR-V binary module

Usage: ./spirv-dis [options] [<filename>]

The SPIR-V binary is read from <filename>. If no file is specified,
or if the filename is "-", then the binary is read from standard input.

Options:

  -h, --help      Print this help.
  --version       Display disassembler version information.

  -o <filename>   Set the output filename.
                  Output goes to standard output if this option is
                  not specified, or if the filename is "-".

  --no-color      Don't print in color.
                  The default when output goes to a file.

  --no-indent     Don't indent instructions.

  --offsets       Show byte offsets for each instruction.

spirv-as -h returns the message:

./spirv-as - Create a SPIR-V binary module from SPIR-V assembly text

Usage: ./spirv-as [options] <filename>

The SPIR-V assembly text is read from <filename>.  The SPIR-V binary
module is written to file "out.spv", unless the -o option is used.

Options:

  -h              Print this help.

  -o <filename>   Set the output filename.
  --version       Display assembler version information.

spirv-val -h returns the message:

spirv-val - Validate a SPIR-V binary file.

USAGE: spirv-val [options] [<filename>]

The SPIR-V binary is read from <filename>. If no file is specified,
or if the filename is "-", then the binary is read from standard input.

NOTE: The validator is a work in progress.

Options:
  -h, --help                       Print this help.
  --max-struct-members             <maximum number of structure members allowed>
  --max-struct-depth               <maximum allowed nesting depth of structures>
  --max-local-variables            <maximum number of local variables allowed>
  --max-global-variables           <maximum number of global variables allowed>
  --max-switch-branches            <maximum number of branches allowed in switch statements>
  --max-function-args              <maximum number arguments allowed per function>
  --max-control-flow-nesting-depth <maximum Control Flow nesting depth allowed>
  --max-access-chain-indexes       <maximum number of indexes allowed to use for Access Chain instructions>
  --version                        Display validator version information.
  --target-env                     {vulkan1.0|spv1.0|spv1.1|spv1.2}
                                   Use Vulkan1.0/SPIR-V1.0/SPIR-V1.1/SPIR-V1.2 validation rules.

SPIR-V Remapper

The SPIR-V remapping tool, spirv-remap, enhances compression of SPIR-V binary files via entropy reduction, including optional stripping of debug information and dead functions. spirv-remap transforms SPIR-V to SPIR-V, remapping IDs to reduce the size of a compressed image containing multiple SPIR-V modules. This works with compression procedures that can find dictionary entries across multiple files.

The SPIR-V Remapper supports two modes of use: command line and a C++11 API.

Remapping is accomplished via ID canonicalization. In this scheme, IDs become larger and are no longer tightly packed near zero, but should compress better when multiple modules are compressed together. The command line tool operates serially on multiple modules. The API accepts only a single module at a time.

Note: The spirv-remap tool is in early stages of development and should be considered alpha quality.

Command Line

spirv-remap supports multiple levels of verbosity, specified with -v, -vv, -vvv, etc or by providing an integer parameter to the --verbose option. Note that higher levels of verbosity provide a considerable quantity of stdout messages. With no verbosity, spirv-remap is silent, returning 0 on success and a positive integer error status on error.

The SPIR-V remapper provides basic ID remapping, ID remapping with debug symbol and line number stripping, and ID remapping with those features plus dead function and type elimination.

Executed without any options, spirv-remap returns a message similar to:

Usage: 
  spirv-remap [-v[v[...]] | --verbose [int]] [--map (all|types|names|funcs)] [--dce (all|types|funcs)] [--opt (all|loadstore)] [--strip-all | --strip all | -s] [--do-everything] --input | -i file1 [file2...] --output|-o DESTDIR
  spirv-remap [--version | -V]
  spirv-remap [--help | -?]

Options supported by spirv-remap are identified in the table below. Options can appear anywhere on the command line.

Option Description
--dce dead code elimination mode; eliminates dead functions and types
-i, --input *.spv shader input files
--map remap types, names, functions, or all
-o, --output write remapped shader files to this directory
-s, --strip-all strip debug symbol information and line numbers

Examples:

  1. Basic ID remapping example:

    spirv-remap --map all --input *.spv --output /tmp/out_dir
    

Performs ID remapping on all shaders in the current directory, writing new files with the same basenames to /tmp/out_dir.

  1. ID remapping with debug symbol and line number stripping:

    spirv-remap --map all --strip-all --input *.spv --output /tmp/out_dir
    
  2. ID remapping with debug symbol and line number stripping plus dead function and type elimination:

    spirv-remap --map all --dce all --strip-all --input *.spv --output /tmp/out_dir
    

API

API access to the SPIR-V Remapper may be provided in future SDKs.

SPIR-V Control Flow Visualization

spirv-cfg shows the SPIR-V control flow in GraphiViz "dot" form. It is experimental. spirv-cfg --help prints the following:

./spirv-cfg - Show the control flow graph in GraphiViz "dot" form. EXPERIMENTAL

Usage: ./spirv-cfg [options] [<filename>]

The SPIR-V binary is read from <filename>. If no file is specified,
or if the filename is "-", then the binary is read from standard input.

Options:

  -h, --help      Print this help.
  --version       Display version information.

  -o <filename>   Set the output filename.
                  Output goes to standard output if this option is
                  not specified, or if the filename is "-".

SPIR-V Cross-Compilation and Reflection

spirv-cross translates SPIR-V files into readable shader languages including GLSL, MSL (experimental) and C++ (experimental). It can also generate reflection information for a SPIR-V shader. spirv-cross --help shows the latest command line options. Additional information for using this tool can be found at the spirv-cross github page.

Shaderc - SPIR-V Compilation Wrapper

Shaderc wraps around core functionality in glslang and SPIRV-Tools. Shaderc aims to to provide: a command line compiler with GCC and Clang-like usage for better integration with build systems, an API where functionality can be added without breaking existing clients, an API supporting standard concurrency patterns across multiple operating systems, and increased functionality such as file #include support.

Shaderc consists of two components: a command line compiler and a static library. The command line compiler (glslc) is provided by the SDK and is put in the user's path so that it can be used from the command prompt. glslc --help shows the latest command line options.

The static library is provided only as a release build. As such, to link a debuggable program to the shaderc included in the SDK, it is necessary to build the library from the source provided in the SDK. To build a 64-bit debuggable library from the SDK, use the folloing commands (you will need msbuild and cmake to be available from the command prompt):

cd %VULKAN_SDK%\shaderc
cmake -H. -Bbuild -G "Visual Studio 14 Win64"
cmake --build ./build --config Debug

Note that you may have to adjust the Visual Studio version, depending on which version you are using.

Additional information for using shaderc can be found at the shaderc github page.