Best Practices & Common Pitfalls

43.1 Code style

Prefix convention: g for globals/resources (gAlbedo), s for groupshared, k for constants; suffix spaces (posW, posV, posH, nTS).

Put all shared structs in .hlsli files; give every resource an explicit register(xN, spaceM).

Use ConstantBuffer<T> and structs mirrored in C++ with static_assert on sizes.

Pick one matrix convention (mul(M, v) or mul(v, M)) and one packing (column/row-major) for the entire codebase.

Compile with -WX in CI for every target (DXIL, SPIR-V) and every shipped permutation.

Format with clang-format; HLSL Tools for VS Code / Visual Studio gives IntelliSense.

43.2 Common pitfalls

Using * for matrix multiplication Row/column-major mismatch mesh invisible or distorted transpose on upload, or row_major / -Zpr, consistently cbuffer packing mismatch (float3 + 16-byte rules, float arrays) values shifted/corrupted pad C++ structs, use float4 arrays, check -Fc offsets CBV not 256-byte aligned (D3D12) align buffer offsets/sizes to 256 Missing NonUniformResourceIndex flickering/wrong textures on some GPUs wrap divergent descriptor indices

Sample in divergent control flow / compute mip artifacts, compile errors

SampleLevel/SampleGrad, hoist derivatives Sampling sRGB data as linear (or vice versa) washed-out or too dark

_SRGB formats for color, linear for data Not normalizing interpolated normals faceted, wrong highlights normalize in the PS Barrier inside divergent if hang/undefined behavior barriers must be reached by all threads Out-of-bounds compute threads writes past edges guard with if (any(id.xy >= size)) return; Race conditions on UAVs flicker, nondeterminism atomics, barriers, separate passes VS output/PS input struct mismatch PSO creation failure share one struct Assuming wave size 32 wrong results on AMD/Intel use WaveGetLaneCount() or [WaveSize]

Forgetting D3D's [0,1] depth and flipped texture V shadows/projections off uv = ndc.xy * float2(0.5, -0.5) + 0.5

NaNs from normalize(0), pow(neg, x), sqrt(neg), acos(>1) black/white pixels spreading through bloom/TAA clamp inputs, max(eps,...), NaN checks huge build times, PSO hitches prune variants, uniform branches, PSO caches

43.3 Performance checklist

Profile before optimizing; know whether you're ALU, bandwidth, occupancy, fixed-function, or CPU bound.

Minimize overdraw (depth prepass, front-to-back sorting) and full-resolution passes.

Compress and mip all textures; pack channels; use 16-bit math where safe.

Batch, instance, and go GPU-driven (indirect, bindless, mesh shaders) for large scenes.

Pre-compile shaders and PSOs; never compile in the middle of gameplay.