핵심 정리
| 셰이더 | 역할 |
|---|---|
| Vertex shader | 정점 변환과 vertex output 생성 |
| Fragment shader | fragment 색과 material output 계산 |
| Compute shader | 그래픽스 파이프라인 밖의 범용 병렬 계산 |
| Geometry/Tessellation | API에 따라 제공되는 추가 기하 단계 |
구조
셰이더는 GPU에서 대량의 데이터를 병렬 처리하는 작은 프로그램입니다. vertex shader는 정점마다 실행되고, fragment shader는 rasterization 이후 fragment마다 실행됩니다.
vertex count -> vertex shader invocation
covered samples -> fragment shader invocation
workgroup/thread -> compute shader invocationGPU는 많은 스레드를 동시에 실행해 처리량을 얻습니다. 하지만 모든 계산이 빠른 것은 아닙니다. 메모리 접근 패턴, 분기, texture sampling, register pressure, bandwidth가 성능에 큰 영향을 줍니다.
geometry shader나 tessellation shader는 API와 플랫폼에 따라 제공되는 추가 기하 단계입니다. tessellation은 patch를 더 작은 primitive로 세분화하고, geometry shader는 primitive 단위로 새 geometry를 만들거나 버릴 수 있지만 현대 실시간 파이프라인에서는 비용과 지원 범위를 먼저 확인해야 합니다.
fragment shader는 화면 sample 수에 비용이 묶입니다. 같은 shader라도 작은 물체에 쓰면 가볍고, 전체 화면 후처리에 쓰면 모든 픽셀을 훑기 때문에 texture read/write와 bandwidth가 병목이 될 수 있습니다.
Compute shader
compute shader는 화면에 직접 그리는 파이프라인과 분리된 범용 병렬 계산 단계입니다. particle simulation, culling, image processing, prefix sum, tiled lighting 같은 작업에 쓰입니다.
병목 기준
| 증상 | 의심할 축 |
|---|---|
| shader 명령이 많음 | ALU 비용 |
| texture sample이 많음 | texture unit, cache |
| 큰 render target | bandwidth |
| 분기가 심함 | warp/wavefront divergence |
| 임시 값이 많음 | register pressure |
| CPU는 한가하고 GPU가 바쁨 | GPU-bound |
성능을 볼 때 셰이더 코드 줄 수보다 실제 instruction, sample 수, 메모리 접근, 화면 점유율을 봐야 합니다.
주의할 점
GPU는 병렬 처리에 강하지만 순차 의존성이 강한 작업에는 맞지 않을 수 있습니다. 이전 결과가 다음 결과에 계속 필요하면 병렬화 이점이 줄어듭니다.
또 fragment shader의 비용은 화면에서 얼마나 많이 실행되는지에 따라 달라집니다. 같은 shader라도 작은 물체와 전체 화면 후처리에서는 비용이 완전히 다릅니다.
참고 링크
1 sources