-
Notifications
You must be signed in to change notification settings - Fork 847
HLSL FAQ
This document will describe the usage of HLSL in glslang, including basic invocation, creating SPIR-V modules, binding and linkage, and reflection queries. It is not meant to describe the HLSL language.
Currently the HLSL FE is complete enough to run many types of complex real world workloads. A few incomplete areas will be described in "Limitations" below. It can accept shaders for any shader stage, and will handle common language constructs for functions, control flow, variable and type declarations, registers and pack offsets, most DX10 and later texture methods, most intrinsic functions, most preprocessor functionality, most built in semantics, attributes where they effect stage functionality, and more.
Please note that the HLSL FE is not currently a validator. It accepts well formed shaders, but may not reject invalid shaders. Behavior in the latter case is undefined except where explicitly noted.
Obtaining and building glslang is outside the scope of this document. The github source is here. Please see the README.md file included with the project for details.
This document will assume that glslangValidator is somewhere in your search path, or that you have given a path to it explicitly. "glslangValidator -?" will print a usage message including the options below.
Here is an example of a simple compilation of an HLSL shader:
glslangValidator -e main -o test.spv -V -D myshader.frag
This will compile the HLSL shader given in "myshader.frag", with an entry point named "main", and produce a SPIR-V binary module as output in "test.spv".
The options above are as follows:
The "-D" option indicates that the input is an HLSL shader. The shader stage can be automatically determined from the file suffix if the suffix is in the following list:
vert for a vertex shader
tesc for a hull (tessellation control) shader
tese for a domain (tessellation evaluation) shader
geom for a geometry shader
frag for a pixel (fragment) shader
comp for a compute shader
The "-e name" option specifies the shader entry point function name.
The -V option creates a SPIR-V binary.
The "-o name" option provides the filename for the SPIR-V binary - in this case "test.spv"
If the file to be compiled does not have a suffix as above, the stage can be explicitly provided using the -S option. For example:
glslangValidator -S frag -e main -o test.spv -V -D myshader.frag
The "-q" option can be used to print the reflection database:
glslangValidator -q -S frag -e main -o test.spv -V -D myshader.frag
There are other options related to binding mappings that will be described later.
--keep-uncalled This will preserve uncalled functions. Normally they are eliminated from the output.
--shift-sampler-binding These are described in the binding section of this document below.
--shift-texture-binding
--shift-cbuffer-binding
--shift-uav-binding
--auto-map-bindings
--hlsl-iomap
--hlsl-offsets *TODO...*
The following features are unimplemented or mostly unimplemented. This may be an incomplete list.
- DX9 texturing
- Some preprocessor features
- Some mixtures of object types, e.g, structured buffers as members in classes or structures.
- mapping of "half" type to float
- inout parameter bidirectional conversions
- #include support
- immediate sampler modes
- most Shader model 6 features
- Command line specification of preprocessor symbols
- Texture2D etc templatized on user structures (as opposed to float4, int4, etc)
- Implicit matrix truncations
- GatherCmp* methods except for *Red.
The following have partial support:
- classes (no inheritance from interfaces yet)
- namespaces
- some unusual intrinsic functions are unimplemented. E.g, printf.
- GetSamplePosition returns fixed positions, and only for 1, 2, 4, 8 and 16 cases. Others produce (0,0).
IO variables can adopt bindings from ": register()" specifications in the shader, or be automatically assigned bindings. Offsets can be provided per HLSL register space, and these bindings can be queried with the reflection interface described below.
Binding numbers are can be assigned in the shader text using the register() syntax. For example, this will create a tbuffer named "tbufName" with a binding number of 8:
tbuffer tbufName : register(b8) { ...
The same applies for other resource classes, for example, samplers.
Binding numbers can also be assigned through attributes in front of declarations:
[[vk::binding(binding, set)]]
Some examples can be found [here].(https://github.com/KhronosGroup/glslang/blob/046bae0babd17ecc19fc7cbe40c35aa13ac2ee65/Test/hlsl.attributeC11.frag)
IO variables without explicit bindings can be auto-assigned bindings using the --auto-map-bindings
command line option. HLSL shaders should also include --hlsl-iomap
to perform the mapping in HLSL register class space. For example:
glslangValidator -D -e main -q --hlsl-iomap --auto-map-bindings test.frag
The mapping of HLSL types to register spaces is as follows:
t – for shader resource views (SRV)
TEXTURE1D
TEXTURE1DARRAY
TEXTURE2D
TEXTURE2DARRAY
TEXTURE3D
TEXTURECUBE
TEXTURECUBEARRAY
TEXTURE2DMS
TEXTURE2DMSARRAY
STRUCTUREDBUFFER
BYTEADDRESSBUFFER
BUFFER
TBUFFER
s – for samplers
SAMPLER
SAMPLER1D
SAMPLER2D
SAMPLER3D
SAMPLERCUBE
SAMPLERSTATE
SAMPLERCOMPARISONSTATE
u – for unordered access views (UAV)
RWBYTEADDRESSBUFFER
RWSTRUCTUREDBUFFER
APPENDSTRUCTUREDBUFFER
CONSUMESTRUCTUREDBUFFER
RWBUFFER
RWTEXTURE1D
RWTEXTURE1DARRAY
RWTEXTURE2D
RWTEXTURE2DARRAY
RWTEXTURE3D
b – for constant buffer views (CBV)
CBUFFER
CONSTANTBUFFER
These flags can also be set through the TShader API:
void TShader::setAutoMapBindings(bool map);
void TShader::setHlslIoMapping(bool hlslIoMap);
IO objects can have offsets applied in the HLSL register class namespace class as described above. These command line options provide an offset which will be added to the binding number provided by either register() or --auto-map-bindings:
--shift-sampler-binding s#
--shift-texture-binding t#
--shift-cbuffer-binding b#
--shift-uav-binding u#
These have shortcuts: for example, --ssb is a synonym for --shift-sampler-binding. See the help message for the entire set.
Here is an example which uses the above options (in shortcut form) along with binding automapping, in HLSL register space:
glslangValidator --amb --hlsl-offsets --sbb 20 --suavb 30 -q -e main -i -V -D test.frag
These values can also be set through the TShader API:
void TShader::setShiftSamplerBinding(unsigned int base);
void TShader::setShiftTextureBinding(unsigned int base);
void TShader::setShiftUavBinding(unsigned int base);
void TShader::setShiftCbufferBinding(unsigned int base);
Custom mappings can be created by overriding the TIoMapResolver class.
There are two groups of uniform reflection data, both with type information attached which can be queried through a TProgram class API. The first group is uniform variables, and the second is for uniform blocks. The number of each can be queried via:
int TProgram::getNumLiveUniformVariables() const;
int TProgram::getNumLiveUniformBlocks() const;
A variable name can be mapped to a uniform index via:
int TProgram::getUniformIndex(const char* name) const;
The uniform block index associated with a uniform variable index can be obtained via:
int TProgram::getUniformBlockIndex(int index) const;
The reflection API is also defined in the TProgram class. Type information for uniforms, or uniform blocks, can be obtained via:
const TType* TProgram::getUniformTType(int index) const;
const TType* TProgram::getUniformBlockTType(int index) const;
Some StructuredBuffer types have associated counter buffers. These types are:
AppendStructuredBuffer
ConsumeStructuredBuffer
RWStructuredBuffer
The counter buffer is a separate buffer object. Its index can be queried with the following API:
int TProgram::getUniformBlockCounterIndex(int index) const;
The index argument is an index in the Uniform Block Reflection list for the structured buffer. The return value is another index in the Uniform Block Reflection list for the associated counter. If there is no associated counter, the query returns -1.
- Currently, hull shader patch constant functions with control point frequency inputs are emulated by invoking the hull shader entry point once for each control point.
The SPIRV-tools project contains a number of tools that are useful in conjunction with SPIR-V modules created through glslang:
- spirv-opt is a module optimizer.
- spirv-val is a module validator.
- spirv-dis is a module disassembler.
- spirv-stats prints statistics for a module.
See the project's README for more details.