Control Flow, Attributes & Functions

These are *hints*; DXC (LLVM) often makes its own decisions, but [unroll] and [loop] are generally honored.

11.1 Statements

if (x > 0) { ... } else if (x < 0) { ... } else { ... }

for (int i = 0; i < 8; ++i) { if (i == 3) continue; if (i == 6) break; }

while (n > 1) { n >>= 1; }
do { k++; } while (k < 4);

switch (mode)
{
    case 0:  color = float3(1, 0, 0); break;
    case 1:  color = float3(0, 1, 0); break;
    default: color = 0;               break;
}

clip(alpha - 0.5);       // PS: discard pixel if any component < 0
if (alpha < 0.5) discard; // PS: explicit discard

11.2 Flow-control attributes

[unroll] / [unroll(n)] fully unroll (or by factor n); requires a compile-time trip count for full unroll keep as a real loop (no unrolling) reduce compile time; less optimization (FXC) allow loop condition that depends on a UAV read (FXC) emit a real (dynamic) branch evaluate both sides and select (no branch) [forcecase], [call] jump table / subroutine (FXC)

These are *hints*; DXC (LLVM) often makes its own decisions, but [unroll] and [loop] are generally honored.

[unroll]
for (int i = 0; i < 9; ++i) sum += tex.Sample(s, uv + offsets[i]) * weights[i];

[branch]
if (shadowEnabled)            // uniform across the draw: a cheap, coherent branch
    lit *= ComputeShadow(posLS);

[flatten]
if (x > 0.5) y = a; else y = b;   // tiny bodies: select is cheaper than a branch

11.3 Divergence

Branches are free when all lanes in a wave take the same path (uniform/coherent). When lanes diverge, the wave executes both paths with masking. Gradient operations (Sample, ddx) inside divergent flow are undefined in pixel shaders — use SampleLevel/SampleGrad there, or compute derivatives before the branch.

11.4 Functions

Out parameters are copy-out, not references. inout copies in then out (no aliasing). HLSL 2021 adds member functions in structs and templates (Chapter 35).

// Parameters: in (default, by value), out (write-only), inout (copy in/out)
void ComputeLight(in float3 N, in float3 L, out float diffuse, inout float3 accum)
{
    diffuse = saturate(dot(N, L));
    accum  += diffuse;
}

// Overloading by parameter types
float  Square(float x)  { return x * x; }
float3 Square(float3 x) { return x * x; }

// Default parameter values
float4 Tint(float4 c, float amount = 0.5) { return lerp(c, float4(1, 0.8, 0.6, 1), amount); }

// 'inline' is implied — all functions are inlined; recursion is not allowed