HLSL
:)
The High Level Shading Language (HLSL) is a shading language used in Direct3D and DirectX12. It's a C/C++ style language. On these pages the focus on shader model 5.1 (SM5.1) that are used in DX 12.
HLSL source code use the .hlsl extension. The code can then be compiled at buildtime with the FXC compiler or at runtime using D3DCompileFromFile() or D3DCompile() . When compiled by directx they are in a format called DXBC or bytecode. Compiled shaders are given the .cso (compiled shader object) extension. To the compiler one give the type of shader to build, known as the Shader profile and also the name of the function to use. That way it is possible to have multiple shaders in the same .hlsl file.
When using Create*Shader (DX11) or CreateGraphicsPipelineState (DX12) the graphic driver compile the DXBC bytecode to GPU shader code. This is a operation that takes time so it but the driver might have a disk cache that help. The PSO depends on the pso description, the hardware and the driver.
Functions
The built-in functions in HLSL is called the Intrinsic Functions. They have been optimized and tested by the best minds at Microsoft so it is better to use them then to write custom ones that do the same thing.
Variables
Similar to variables in the C programming language. The syntax for a variable is in the form below.
[Storage_Class] [Type_Modifier] Type Name[Index] [= Initial_Value]
Storage_Class
extern:
uniform:
Type
Scalar: bool, int, uint, dword, half, float and double.
Vector: A vector type name is made up of a scalar name with the number of components (1-4) at the end. Ex, int3 or float2.
Matrix: A matrix type name is made up of a scalar name with the number of row of columns after separated by an x. Ex int3x2 or float2x2.
Buffer: Buffers are in the form Buffer<type> where type is a HLSL scalar, vector or matrix type. The matrix must fit in 4*32 bit's.
Sampler: sampler1D, sampler2D, sampler3D, samplerCUBE, sampler_state and SamplerState.
Texture: Texture1D, Texture1DArray, Texture2D, Texture2DArray, Texture3D and TextureCube.
Control Flow
HLSL use the standard c++ style of statements.
Jump: break, continue and discard.
Exit: discard, Can only be used in a pixel shader. It will discard and not output the result of the current pixel. Using this disables early-z so it should only be used when really needed.
Semantics
As data moves along the shaders in the graphic pipeline there need to be a way to know how the output of one shader arrives as the input of another. In HLSL Semantics are used for that purpose. A Semantics is a string used on a variable. The HLSL compiler connects the same semantics string in the output of a shader with the input of the next shaders. So if the vertex shaders write something to a variable with the TEXCOORD0 semantic it will find the variable in the fragment shader with the same TEXCOORD0 semantic and put the value into it. Semantics can only be used on on global variables or on parameters passed into the shader. Semantics are tags so what matter is that the sting is the same. Even if it possible to make up any tag it's a good idea to keep them logical so it is easy to know what they contain. No one is helped by a color being passed on with the semantic IDrinkYourMilkshake.
There are some special system Semantics and they all start with the SV_ prefix. Some of them can only be used in specific shaders and it's a best to avoid making custom semantic that use the SV_ prefix.
Start
The vertex shader is the first shader stage and it links it's semantics with the semantic name in the Input Layout.
Middle
End
At the end of the pipeline is the pixel shader and there are two semantics one can write to, SV_Target[n] and SV_Depth. SV_Target selects the render target to write to and n can be 0-7. SV_Depth is the depth buffer data.
Resource Binding
In DX12 one sets the value of resources using root signature slot number. The root signature bound to the pipeline map these slot numbers to virtual registers within logical register spaces. In HLSL the register keyword is then used ti tell the compiler what register and space a variable should use. Each register is describe by a single letter and a number. The letter is given by the type of resource in the register so there are four of them, one for each resource that can be used from a shader.
t - Shader resource views (SRV)
b - Constant buffer views (CBV)
u - Unordered access views (UAV)
s - Samplers
FXC
Fxc.exe is the tool to compile HLSL shaders offline.
fxc SwitchOptions Filenames
Reference
Tutorials
Links
HLSL Viewport Clamping trick - 2020
HLSLexplorer 1.01 - UI improvements and D3D12 rendering backend - 2019
Half The Precision, Twice The Fun: Working With FP16 In HLSL - 2019
Few words about HLSLexplorer - 2018
Signing DXIL Post-Compile - 2018
Next power of two in HLSL - 2017
Introducing HLSL Tools for Visual Studio - 2015
Parsing Direct3D shader bytecode - 2015
Diving into the Tessellation Stages of Direct3D 11 - 2013
Introduction to DirectX Shader - 2010
Implementing Lighting Models With HLSL - 2003
Working Around Constructors in HLSL (or lack thereof)
https://colinbarrebrisebois.com/2021/11/01/working-around-constructors-in-hlsl-or-lack-thereof/
HLSL shaders compilation pipeline in BG3
https://youtu.be/0zCxpMS7ul0?t=3723