게임 산업 트렌드

Work Graphs가 컴퓨트 셰이더를 대체한다는 말, 2026년에 진짜로 시작됐다 (GDC 2026 정리)

kr-gamedev 2026. 5. 23. 09:02

GDC 2026 의 그래픽스 트랙에서 가장 많이 들린 단어는 단연 Work Graphs 였다. 2024년 D3D12 에 처음 들어왔을 때만 해도 "재미있는 실험" 정도로 보는 분위기였는데, 올해 분위기가 완전히 달라졌다. AMD RDNA4 와 NVIDIA Blackwell 모두 production 수준의 드라이버를 내놓았고, Unreal Engine 5.6 의 Nanite 일부 패스가 이미 Work Graphs 기반으로 다시 짜여졌다는 발표가 나왔다.

문제 의식 자체는 단순하다. 멀티 패스 GPU 파이프라인을 컴퓨트 셰이더로 짤 때마다 우리는 indirect dispatch → scan → compaction → indirect dispatch 의 끝없는 ping-pong 을 만들어야 했다. CPU 가 dispatch graph 의 모양을 전부 미리 결정해야 한다는 D3D12 의 근본 제약 때문이다. Work Graphs 는 이걸 뒤집는다. 셰이더가 직접 다음 노드를 enqueue 할 수 있다. GPU 가 GPU 에게 일을 던지는 셈이다.

이번 글은 GDC 2026 세션과 Unreal Fest 2026 의 Nanite 후속 발표를 종합해서, Work Graphs 가 실제 무엇을 해결하는지 그리고 raw D3D12 와 Unreal 5.6 양쪽에서 어떻게 쓰이는지를 정리한다.

1. 컴퓨트 셰이더 파이프라인의 근본 한계

GPU-driven rendering 을 한 번이라도 구현해봤다면 다음 패턴이 익숙할 것이다.

// 전형적인 GPU-driven culling 의 한 사이클
cmdList->Dispatch(numInstances / 64, 1, 1);          // 1단계: frustum cull
cmdList->ResourceBarrier(...);                        // UAV barrier
cmdList->Dispatch(...);                               // 2단계: prefix scan
cmdList->ResourceBarrier(...);
cmdList->ExecuteIndirect(cmdSig, maxDraws, ...);     // 3단계: indirect draw

각 단계 사이에 barrier 가 필수다. 게다가 "다음에 몇 개를 dispatch 할지" 를 GPU 가 결정한 결과를 CPU 가 다시 받지 못하므로, 항상 worst-case 워크로드를 가정하고 buffer 를 잡아야 했다. Nanite 처럼 cluster 단위 적응형 LOD 를 하는 시스템은 이런 한계 때문에 readback latency 와 메모리 낭비를 동시에 떠안아 왔다.

2. Work Graphs 의 작동 원리

Work Graphs 는 셰이더 노드 사이의 producer-consumer 관계를 GPU 가 직접 스케줄링한다. HLSL 측 예시는 다음과 같다.

struct CullRecord { uint instanceId; };
struct DrawRecord { uint meshletId; uint instanceId; };

[Shader("node")]
[NodeLaunch("broadcasting")]
[NumThreads(64, 1, 1)]
void CullNode(
    DispatchNodeInputRecord<CullRecord> input,
    [MaxRecords(64)] NodeOutput<DrawRecord> DrawNode)
{
    if (FrustumTest(input.Get().instanceId))
    {
        ThreadNodeOutputRecords<DrawRecord> rec =
            DrawNode.GetThreadNodeOutputRecords(1);
        rec.Get().instanceId = input.Get().instanceId;
        rec.Get().meshletId  = SelectLOD(input.Get().instanceId);
        rec.OutputComplete();
    }
}

핵심은 NodeOutput 이다. 셰이더가 동적으로 다음 노드로 record 를 흘려보낸다. CPU 는 그래프의 모양만 한 번 등록하고, 실제 dispatch 수와 record 수는 GPU 가 알아서 처리한다. AMD 의 GDC 2026 측정치에 따르면 동일한 GPU-driven culling 파이프라인이 RDNA4 기준 약 22~38% 단축 됐다.

3. Unreal Engine 5.6 의 도입 사례

언리얼 5.6 는 Nanite 의 cluster culling 단계 일부를 Work Graphs 로 옮겼다. 사용자 코드에서 직접 노드를 짤 일은 아직 없지만, 다음과 같이 새로 들어온 RHI 인터페이스로 커스텀 패스를 시도해볼 수 있다.

// Unreal 5.6 RHI 신규 API (실험적)
FRHIWorkGraphPipelineStateInitializer Init;
Init.AddNode(TEXT("CullNode"),  CullShader);
Init.AddNode(TEXT("DrawNode"),  DrawShader);
Init.AddEdge(TEXT("CullNode"), TEXT("DrawNode"));

FWorkGraphPipelineStateRef PSO =
    RHICreateWorkGraphPipelineState(Init);

RHICmdList.DispatchWorkGraph(PSO, EntryRecord, RecordCount);

r.Nanite.UseWorkGraphs 1 콘솔 변수로 엔진 자체 적용도 켜고 끌 수 있다. 5.6 에서는 기본값 off, 5.7 부터 on 이 될 예정이라고 발표됐다.

4. 도입을 고려해야 할 상황

모든 컴퓨트 패스를 Work Graphs 로 바꿔야 하는 건 절대 아니다. 다음 조건이 두 개 이상 겹치면 도입을 검토할 가치가 있다.

  • 패스 사이에 GPU readback 없이 dispatch 크기를 결정해야 한다
  • 워크로드가 극단적으로 가변적이다 (예: cluster culling, particle subdivision, BVH refit)
  • worst-case buffer 크기 때문에 VRAM 압박이 있다
  • 패스 수가 3개 이상이고 사이마다 UAV barrier 가 강제된다

반대로 픽셀 패스 후처리, 정적인 post-process chain 같은 경우엔 기존 컴퓨트 셰이더가 더 단순하고 빠르다. Work Graphs 는 만능이 아니라 "동적 그래프" 에 특화된 도구다.

결론

2026년은 Work Graphs 가 실험 단계에서 production 단계로 넘어가는 분기점이 됐다. RDNA4 와 Blackwell 의 보급, Unreal 5.6 의 공식 RHI 지원, GDC 의 사례 발표 3박자가 맞아떨어졌다. 당장 모든 프로젝트에 도입할 필요는 없지만, GPU-driven rendering 을 진지하게 다루는 팀이라면 PoC 한 번은 해볼 시점이다.

다음 글에서는 같은 GDC 2026 트랙에서 같이 화제가 된 Neural Texture Compression (NTC) 의 실전 적용기를 정리할 예정이다. 한 텍스처를 1/8 크기로 줄이면서 품질을 유지하는 NVIDIA 의 새 압축 포맷이 게임 빌드 크기 문제를 어떻게 풀어내는지 다룬다.