# SPIR-V Toolchain

The LunarG Vulkan SDK includes tools and files for shader generation, inspection and compression improvement.

SPIR-V is a new binary intermediate representation for graphical shaders and compute kernels. This new intermediate representation has many advantages. The advantages and a high-level description of the representation are detailed in the SPIR-V white paper included in the SDK. The SPIR-V provisional specification for the version supported by the SDK is also included. These documents are located in `$VULKAN_SDK/doc/khronos/spirv/` (Linux) and `$VK_SDK_PATH\Doc` (Windows).

The Vulkan graphics API requires that all shaders be presented in SPIR-V format. As a binary format, it cannot easily be manually created. SPIR-V shaders can be automatically created from equivalent GLSL shaders using the `glslangValidator` tool. The SPIR-V code can be read from the file into an application's memory and directly passed to the Vulkan API call `vkCreateShader()`.

The SDK includes a SPIR-V disassembler named `spirv` for debugging Vulkan applications. This disassembler can create a human-readable text from a SPIR-V file. This text represents the SPIR-V program in terms of SPIR-V objects. Note that the text is not an assembly language, and that the Vulkan SDK does not contain a program which can re-assemble the text into a binary SPIR-V program.

Some Vulkan application publishers will wish to include many SPIR-V files in their distribution package. The Vulkan SDK also includes `spirv-remap`, a tool to improve the compressibility of collections 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, depending on the nature of the modules.

## GLSL Validator (SPIR-V Generator)

`glslangValidator` is the tool used to compile GLSL shaders into SPIR-V, Vulkan's shader format.

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 Disassembler and Assembler

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.

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.

## SPIR-V Remapper

The SPIR-V Remapper 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`.

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

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

3. 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 Optimization

spirv-opt is a SPIR-V to SPIR-V optimizer. It is a work in progress. Its current capabilities primarily center around setting and optimizing specialization constants. `spirv-opt --help` prints the following:

    ./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.
      -h, --help   Print this help.
      --version    Display optimizer version information.

## SPIR-V Validation

spirv-val is a SPIR-V validation program. It is a work in progress. `spirv-val --help` prints the following:

    ./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.
      --version    Display validator version information.
      --target-env {vulkan1.0|spv1.0|spv1.1}
                   Use Vulkan1.0/SPIR-V1.0/SPIR-V1.1 validation rules.

## 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.

### Windows

On Windows, 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.

### Linux

On Linux, shaderc is provided as source code only. The easiest way to build shaderc is to run the `build_tools` script located in the root of the SDK. Alternatively, the library can also be build using:

    cd <Version>/source/shaderc
    python update_shaderc_sources.py
    cd src
    cmake -H. -Bbuild -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
    make -Cbuild

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