HLSL 2021 Language Features

HLSL 2021 is the default language version in DXC since release 1.7 (2022).

HLSL 2021 is the default language version in DXC since release 1.7 (2022). Select with -HV 2021 (or -HV 2018 for legacy behavior).

35.1 Templates

Function templates, struct templates, template specialization and non-type parameters are supported. Built-in types were already templates (vector<T, N>, matrix<T, R, C>, Texture2D<T>, StructuredBuffer<T>).

template<typename T>
T Remap(T x, T inMin, T inMax, T outMin, T outMax)
{
    return (x - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
}

template<typename T, uint N>
struct FixedStack
{
    T    items[N];
    uint count;
    void Push(T v) { if (count < N) items[count++] = v; }
    T    Pop()     { return items[--count]; }
    bool Empty()   { return count == 0; }
};

float4 TemplateDemo(float2 uv : TEXCOORD0) : SV_Target
{
    float  a = Remap(uv.x, 0.0, 1.0, -1.0, 1.0);
    float3 b = Remap(float3(uv, 0), (float3)0, (float3)1, (float3)0.2, (float3)0.8);
    FixedStack<uint, 8> stack = (FixedStack<uint, 8>)0;
    stack.Push(3); stack.Push(5);
    uint top = stack.Pop();
    return float4(b, a * top);
}

35.2 Operator overloading

Only member operator overloads are supported; logical &&, ||, the ternary operator and a few others cannot be overloaded.

struct Complex
{
    float re, im;
    Complex operator+(Complex o) { Complex r; r.re = re + o.re; r.im = im + o.im; return r; }
    Complex operator*(Complex o)
    {
        Complex r;
        r.re = re * o.re - im * o.im;
        r.im = re * o.im + im * o.re;
        return r;
    }
    float LengthSq() { return re * re + im * im; }
};

// Mandelbrot iteration with overloaded operators
float Mandelbrot(float2 c2)
{
    Complex z = { 0, 0 }, c = { c2.x, c2.y };
    [loop] for (uint i = 0; i < 256; ++i)
    {
        z = z * z + c;
        if (z.LengthSq() > 4.0) return i / 256.0;
    }
    return 0;
}

35.3 Bitfields

struct PackedVertexInfo
{
    uint materialId : 10;
    uint lodLevel   : 4;
    uint flags      : 8;
    uint reserved   : 10;
};
StructuredBuffer<PackedVertexInfo> gInfo : register(t0);
uint GetMaterial(uint i) { return gInfo[i].materialId; }   // compiler emits shifts/masks

35.4 Behavior changes to know

HLSL 2018 and earlier &&, || on vectors component-wise, no short-circuit scalar only, short-circuits; use and(), or() ?: with vector condition scalar condition; use select() for loop variable scope leaks out of the loop (i usable afterwards) C++ scoping (loop-local) Struct member functions & inheritance partial (inheritance existed) member functions, operators, templates

Implicit struct casts between identical layouts