Performance Optimization
39.1 Where time goes
ALU-bound: too much math per pixel/thread.
Memory/bandwidth-bound: texture fetches, cache misses, uncompressed or oversized resources, large render targets.
Occupancy-limited: too many registers (VGPRs) or too much groupshared memory → fewer waves in flight to hide latency.
Fixed-function: overdraw, ROP blending, rasterization of tiny triangles, vertex attribute export.
CPU/API-bound: too many draws, state changes, root signature changes, PSO compilation hitches.
39.2 Shader optimization techniques
Move work to the coarsest frequency: CPU → VS → PS per-object math once, not per pixel
Use half/min16float/float16_t where precision allows 2× ALU rate and fewer registers on many GPUs
Use mad, rsqrt, rcp, saturate, dot map to fast instructions; saturate is often free
Avoid pow with constant integer exponents x*x*x*x is cheaper than pow(x, 4)
Normalize only when necessary; avoid redundant normalize each costs a rsqrt + multiplies
Keep branches uniform (per draw/wave) divergent branches execute both paths
Reduce register pressure: shorter live ranges, fewer large arrays Avoid dynamically indexed local arrays spilled to slow memory (scratch)
Pack data: channel-pack textures (ORM), R11G11B10, BC compression, octahedral normals
Use Load/operator[] instead of Sample when no filtering is needed Use [unroll] for small constant loops removes loop overhead, enables scheduling
Prefer StructuredBuffer/ByteAddressBuffer reads that are coalesced (adjacent threads → adjacent addresses)
Use wave intrinsics to replace groupshared + barriers fewer syncs, fewer atomics
Avoid discard and SV_Depth on opaque geometry keeps early-Z / hierarchical-Z
Render half-res for blurs, SSAO, volumetrics; upsample bilaterally
Use compute for full-screen passes when you can exploit groupshared memory fewer redundant fetches
Prefer branching on constants via permutations or specialization over runtime uniforms (when it reduces registers)
39.3 Measuring
Use GPU timestamps (EndQuery with D3D12_QUERY_TYPE_TIMESTAMP) around passes; use PIX timing captures and vendor counters (occupancy, cache hit rate, VGPR count).
Inspect generated code: dxc -Fc (DXIL), Radeon GPU Analyzer (RDNA ISA, VGPR/SGPR counts), Nsight's shader profiler, Shader Playground.
Change one thing at a time; test on multiple vendors and on low-end hardware.