Quick Reference
| 구분 | 고정하거나 연결하는 값 | 보통 바꾸는 단위 |
|---|---|---|
| Pipeline state | shader, vertex layout, primitive, raster/depth/blend, render target format, sample count | material / pass |
| Dynamic state | viewport, scissor, blend constant, stencil reference처럼 API가 허용하는 값 | draw 또는 pass |
| Resource binding | texture, buffer, sampler, uniform 또는 push constant | material / object |
| Pipeline layout / root signature | shader binding slot과 resource type의 약속 | shader interface가 바뀔 때 |
| Resource view | texture의 mip, layer, format, buffer 범위를 해석한 view | resource 사용 범위가 바뀔 때 |
pipeline state
-> 어떤 shader와 고정 기능 상태로 그릴지
resource binding
-> 그 shader가 어떤 texture/buffer/sampler를 읽을지바인딩 계약
Pipeline state는 GPU가 geometry를 어떻게 해석하고 화면에 합성할지를 결정하는 큰 상태 묶음입니다. Direct3D 12 기준 PSO에는 shader bytecode, input vertex format, primitive topology type, blend state, rasterizer state, depth stencil state, render target format, multisampling 정보, root signature 같은 값이 들어갑니다. API별 이름은 달라도 shader interface, attachment format, 고정 기능 상태가 서로 맞아야 한다는 점은 같습니다.
Resource binding은 별도 축입니다. shader가 읽을 texture, constant buffer, storage buffer, sampler를 descriptor, descriptor table, descriptor heap, root signature 같은 구조를 통해 연결합니다. 즉 같은 pipeline state라도 다른 material texture와 per-object constant를 바인딩하면 다른 물체를 그릴 수 있습니다.
같은 PSO:
- same vertex shader
- same pixel shader
- same blend/depth/raster state
draw마다 변경:
- vertex/index buffer
- material texture descriptor
- per-object constant
- render target 또는 viewportshader가 Texture2D albedo와 SamplerState linearSampler를 서로 다른 binding으로 선언했다면, texture만 넣고 sampler를 생략할 수 없습니다. storage buffer를 읽기 전용으로 선언했는데 쓰기 view를 연결하거나, RGBA16F attachment를 전제로 만든 pipeline에 다른 format target을 붙이는 것도 계약 불일치입니다. validation error가 없더라도 view의 mip/layer가 다르면 예상과 다른 데이터가 읽힙니다.
자주 바뀌는 상태와 비싼 상태를 분리한다
PSO 전환은 shader와 고정 기능 상태를 함께 바꾸는 큰 전환입니다. 반면 descriptor나 small constant 변경은 draw마다 자주 일어나는 쪽입니다. 렌더러는 보통 material, shader, render target 기준으로 draw를 정렬해 PSO와 큰 binding 전환을 줄이고, object transform이나 색상 같은 작은 값만 자주 바꿉니다.
갱신 기준
| 상황 | 먼저 볼 것 |
|---|---|
| draw마다 shader가 바뀜 | material 정렬, PSO 캐시 |
| 같은 shader인데 texture만 바뀜 | descriptor/bind group 재사용 |
| viewport나 scissor만 바뀜 | dynamic state로 처리 가능한지 확인 |
| material variant가 많음 | shader permutation과 PSO 수 제한 |
| per-object 값이 작음 | constant/root constant/주기적 buffer upload |
| binding 비용이 큼 | descriptor table, bind group, material batching |
좋은 렌더러는 "무엇을 그릴지"와 "어떤 상태로 그릴지"를 분리합니다. mesh와 material 데이터가 바뀌더라도 pipeline state가 계속 바뀌지 않도록 batch 기준을 잡는 것이 핵심입니다. 반대로 depth write, blend mode, render target, sample count가 다른 draw는 같은 PSO로 억지로 묶을 수 없습니다.
pass 시작: render target, viewport, PSO를 정한다
material: texture / sampler / material constant를 연결한다
object: transform, skinning offset, instance index를 연결한다
draw: vertex/index buffer와 draw 범위를 지정한다descriptor와 bind group은 resource 자체가 아니라 resource를 shader에 노출하는 방법입니다. frame마다 새 texture를 만들지 않더라도 per-frame uniform buffer의 offset, dynamic uniform range, descriptor heap 또는 bind group의 lifetime을 맞춰야 합니다. GPU가 아직 읽는 descriptor 또는 upload buffer 영역을 CPU가 덮어쓰면 프레임마다 흔들리는 데이터 오류가 생깁니다.
자주 틀리는 계약
Pipeline state와 resource binding을 같은 비용으로 보면 최적화 방향이 흐려집니다. PSO를 draw 중 계속 만들거나 material마다 shader variant를 과도하게 늘리면 CPU submission과 driver validation 비용이 커집니다. PSO는 초기화 또는 명시적인 cache miss에서 만들고, frame 중에는 이미 만든 항목만 고르는 편이 안전합니다.
| 증상 | 먼저 비교할 값 |
|---|---|
| material이 검게 나오거나 흰색만 보임 | shader slot, descriptor type, texture view의 mip/layer, sampler |
| 특정 MSAA 설정에서만 pipeline 생성 실패 | color/depth target format과 sample count |
| depth가 전혀 기록되지 않음 | PSO의 depth write/compare, depth attachment 존재 여부 |
| 투명 material 순서가 이상함 | blend state, depth write, draw order |
| frame마다 uniform 값이 흔들림 | dynamic offset alignment, in-flight frame 수, upload buffer 재사용 시점 |
참고 링크
2 sources