Work Graphs & Newer Shader Model Features
Work graphs let shaders launch other shaders on the GPU — a graph of nodes, each consuming records produced by upstream nodes — without CPU round trips or worst-case-sized intermediate buffers.
34.1 Work graphs (SM 6.8)
Work graphs let shaders launch other shaders on the GPU — a graph of nodes, each consuming records produced by upstream nodes — without CPU round trips or worst-case-sized intermediate buffers. Use cases: GPU-driven culling and binning, material classification, procedural generation, tree traversal.
one record launches a full dispatch grid ([NodeDispatchGrid] fixed or [NodeMaxDispatchGrid] + SV_DispatchGrid in the record) a thread group processes up to N records together (GroupNodeInputRecords) one thread per record (ThreadNodeInputRecord), the system packs threads into waves
Compile as a library: dxc -T lib_6_8 workgraph.hlsl -Fo workgraph.cso. On the host, create a state object (D3D12_STATE_OBJECT_TYPE_EXECUTABLE) with a work-graph subobject, allocate backing memory (size from GetWorkGraphMemoryRequirements), and launch with ID3D12GraphicsCommandList10::DispatchGraph. The output-node name matches the downstream node's function name by default (or use [NodeId("Name")]). Graphics mesh nodes extend work graphs to drive mesh shaders (introduced as a preview; check current Agility SDK support).
struct EntryRecord { uint3 gridSize : SV_DispatchGrid; uint baseTile; };
struct TileRecord { uint2 tile; uint materialId; };
RWTexture2D<float4> gTarget : register(u0);
[Shader("node")]
[NodeLaunch("broadcasting")]
[NodeIsProgramEntry]
[NodeMaxDispatchGrid(1024, 1, 1)]
[NumThreads(64, 1, 1)]
void ClassifyTiles(
DispatchNodeInputRecord<EntryRecord> input,
[MaxRecords(64)] NodeOutput<TileRecord> ShadeTile,
uint dtid : SV_DispatchThreadID)
{
uint tileIndex = input.Get().baseTile + dtid;
bool needsShading = (tileIndex % 3) != 0; // stand-in for real classification
ThreadNodeOutputRecords<TileRecord> rec = ShadeTile.GetThreadNodeOutputRecords(needsShading ? 1 : 0);
if (needsShading)
{
rec.Get().tile = uint2(tileIndex % 128, tileIndex / 128);
rec.Get().materialId = tileIndex & 7;
}
rec.OutputComplete(); // must be called uniformly
}
[Shader("node")]
[NodeLaunch("thread")]
void ShadeTile(ThreadNodeInputRecord<TileRecord> input)
{
TileRecord r = input.Get();
for (uint y = 0; y < 8; ++y)
for (uint x = 0; x < 8; ++x)
gTarget[r.tile * 8 + uint2(x, y)] = floa
…34.2 Feature highlights by shader model
Barycentrics, view instancing float3 b: SV_Barycentrics, uint v: SV_ViewID float16_t3 c = (float16_t3)color; Packed integer dot products dot4add_u8packed(a, b, acc)
feedback.WriteSamplerFeedback(tex, samp, uv); Sample() and ddx() in CS/AS/MS with quad-arranged threads (numthreads X, Y multiples of 2)
if (IsHelperLane()) return; (inside wave logic only) Pack/unpack 8-bit
uint8_t4_packed p = pack_clamp_u8(int32_t4(v)); uint32_t4 u = unpack_u8u32(p);
InterlockedMax(gU64Buffer[i], value64); Integer sampling, raw gather
Texture2D<uint> with Sample on point samplers; GatherRaw RWTexture2DMS<float4, 4> gMSAA;
shadow.SampleCmpLevel(cmp, uv, ref, lod) uint baseVertex: SV_StartVertexLocation Comparison bias/gradient SampleCmpBias, SampleCmpGrad Wave size ranges [WaveSize(32, 64)]
vector<float, 64> v; (beyond 4 components, for ML-style code in buffers) SER, opacity micromaps
Always check device support: CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, ...) for the highest supported SM and the relevant D3D12_FEATURE_DATA_D3D12_OPTIONSn fields. Newer features often require the Agility SDK and sometimes experimental features / developer mode during preview.