핵심 정리
| 항목 | 의미 |
|---|---|
| Resource state | resource가 현재 어떤 용도로 접근되는지 나타내는 상태 |
| Transition barrier | render target에서 shader resource처럼 사용 목적을 바꿀 때 필요 |
| UAV / storage barrier | 순서가 중요한 read/write 접근을 정렬 |
| Aliasing barrier | 같은 메모리 영역을 다른 resource로 재사용할 때 필요 |
| Image layout | Vulkan 계열에서 image 사용 방식과 memory layout을 함께 표현 |
offscreen render target write
-> barrier / layout transition
-> shader resource read in post-process구조
현대 explicit graphics API에서는 resource 상태 추적 책임이 드라이버에서 애플리케이션 쪽으로 많이 이동했습니다. texture 하나가 어느 pass에서는 render target으로 쓰이고, 다음 pass에서는 shader resource로 읽히며, 또 다른 pass에서는 copy source가 될 수 있습니다. 이 역할 변경을 명시하지 않으면 GPU가 이전 write를 언제 끝냈는지, 다음 read가 어떤 layout과 cache 상태를 기대하는지 알기 어렵습니다.
Direct3D 12의 resource barrier는 이런 상태 변화를 드라이버에 알리는 API입니다. transition barrier는 subresource가 다른 usage로 넘어갈 때 쓰고, UAV barrier는 unordered access read/write 순서가 중요할 때 쓰며, aliasing barrier는 같은 heap 영역을 겹쳐 쓰는 resource 사이를 구분할 때 씁니다.
G-buffer pass
normal texture: RENDER_TARGET
lighting pass
normal texture: PIXEL_SHADER_RESOURCEVulkan에서는 pipeline barrier와 image layout transition이 실행 순서, 메모리 가시성, image layout을 함께 다룹니다. 표현은 API마다 다르지만 핵심은 같습니다. "누가 썼고, 누가 읽으며, 그 사이에 어떤 순서 보장이 필요한가"를 명확히 해야 합니다.
barrier는 정합성과 성능 비용을 함께 만든다
Barrier가 없으면 결과가 매번 깨지지 않을 수도 있습니다. GPU 스케줄링, 캐시 상태, 프레임 타이밍에 따라 가끔만 깜빡이거나 특정 하드웨어에서만 재현될 수 있습니다. 반대로 barrier를 너무 넓게 잡으면 필요 없는 대기와 cache flush가 생겨 GPU 병렬성이 줄어듭니다.
선택 기준
| 상황 | 필요한 판단 |
|---|---|
| render target을 다음 pass에서 sampling | write 이후 read barrier |
| compute shader가 buffer를 쓰고 draw가 읽음 | compute write 완료와 shader read 가시성 |
| copy로 texture를 채운 뒤 sampling | copy destination에서 shader resource로 전환 |
| 같은 texture의 일부 mip만 바뀜 | subresource 범위 정확히 지정 |
| temporary resource memory를 재사용 | aliasing barrier 또는 lifetime 관리 |
| barrier가 너무 많음 | pass merge, state 유지, render graph 검토 |
좋은 barrier 설계는 "항상 전체 resource를 모든 단계에서 막기"가 아닙니다. 실제로 충돌하는 access 범위와 다음 사용 목적을 좁게 표현해야 합니다.
주의할 점
Barrier는 correctness 장치이면서 성능 장치입니다. 누락하면 간헐적 깨짐이 생기고, 과하면 GPU가 불필요하게 멈춥니다. validation layer나 graphics debugger가 경고하지 않는다고 해서 모든 동기화가 최적이라는 뜻은 아닙니다.
실패 예시
- compute pass가 light list buffer를 갱신함
- 바로 lighting pass에서 읽지만 barrier를 넣지 않음
- 결과: 특정 프레임에서 이전 데이터가 섞이거나 하드웨어별로만 깨짐
- 대응: write stage/access와 read stage/access 사이의 barrier를 명시한다참고 링크
2 sources