[week2] Texture Rendering
# DirectX 11 렌더링 파이프라인 (함수 호출 기반 정리)
## CPU 준비 단계 (함수 단위)
1. **디바이스 및 스왑 체인 생성**
- `D3D11CreateDeviceAndSwapChain()`
2. **렌더 타겟 및 뎁스 스텐실 준비**
- `SwapChain->GetBuffer()`
- `Device->CreateRenderTargetView()`
- `Device->CreateDepthStencilView()`
3. **자원(Resource) 준비**
- 정점 버퍼: `Device->CreateBuffer()`
- 인덱스 버퍼: `Device->CreateBuffer()`
- 셰이더 컴파일: `D3DCompileFromFile()`
- 셰이더 생성: `Device->CreateVertexShader()`, `Device->CreatePixelShader()`
- 인풋 레이아웃 생성: `Device->CreateInputLayout()`
- 상수 버퍼 생성: `Device->CreateBuffer()` (D3D11_BIND_CONSTANT_BUFFER)
- 텍스처 및 샘플러: `Device->CreateTexture2D()`, `Device->CreateSamplerState()`
## 한 프레임 렌더링 함수 호출 순서
1. Context->ClearRenderTargetView()
2. Context->ClearDepthStencilView()
3. Context->OMSetRenderTargets()
4. Context->IASetVertexBuffers()
5. Context->IASetIndexBuffer()
6. Context->IASetInputLayout()
7. Context->VSSetShader(), PSSetShader(), (필요 시 GS/HS/DS)
8. Context->VSSetConstantBuffers(), PSSetConstantBuffers()
9. Context->RSSetViewports()
10. Context->PSSetSamplers(), PSSetShaderResources()
11. Context->Draw() 또는 DrawIndexed()
12. SwapChain->Present()
자원(메모리/성능) 소모가 큰 순서
1️⃣ | 텍스처 생성 / 로드 | 고해상도 텍스처는 VRAM 메모리를 대량 사용하며 압축 및 비압축 처리 비용도 큼 |
2️⃣ | 셰이더 컴파일 (D3DCompileFromFile) | 실시간 컴파일은 CPU 부하가 매우 큼 (실제 게임은 보통 미리 컴파일한 *.cso 파일 사용) |
3️⃣ | 버퍼 생성 (CreateBuffer) | 대규모 Vertex / Index / ConstantBuffer 생성 시 메모리 할당 비용 발생 |
4️⃣ | InputLayout 생성 | 내부 구조 분석과 파싱으로 약간의 자원 소비 (한 번만 생성 후 캐싱 가능) |
5️⃣ | PSSetShaderResources (텍스처 바인딩) | 너무 자주 바인딩하면 드라이버 state change 비용 발생 |
6️⃣ | Draw() / DrawIndexed() 호출 | GPU 실행 명령이긴 하지만, 이미 준비된 자원 위에서 실행되므로 상대적으로 비용은 낮음 |
7️⃣ | OMSetRenderTargets / Clear 호출 | 렌더타겟 & 뎁스 초기화는 GPU 메모리 클리어 작업, 비용 있지만 짧은 편 |
8️⃣ | VSSetShader / PSSetShader 호출 | 상태 설정 변경 정도이므로 자원 소모는 낮음 |
자원 소모 최적화 팁
✅ 1️⃣ 텍스처 최적화
DDS(DXT 압축) 텍스처 사용 | 압축된 텍스처 포맷으로 VRAM 사용량 최소화, 로딩 속도 증가, GPU-Friendly |
Mipmap 포함 저장 | 멀리 있는 물체는 낮은 해상도로 자동 렌더링 → 성능 최적화 |
필요한 해상도만 사용 | 8K 텍스처 불필요하면 4K / 2K 로 줄여서 메모리 절약 |
다중 텍스처 통합(Atlas) | 여러 작은 텍스처를 한 장으로 묶어 Draw Call & state change 최소화 |
✅ 2️⃣ 셰이더 최적화
런타임 컴파일 금지 | D3DCompileFromFile() 대신 미리 컴파일된 cso 파일 로드 사용 |
셰이더 캐싱 시스템 구축 | 동일한 셰이더 재사용 시 재컴파일/재로드 하지 않음, 메모리 절약 |
불필요한 if / 분기 최소화 | GPU 분기 처리는 비싼 연산 → 브랜치 대신 조건 mask 처리 추천 |
✅ 3️⃣ 버퍼 관리 최적화
큰 정적 버퍼는 한 번 생성 후 재사용 | 매 프레임 CreateBuffer() 호출하지 말고 초기화 시 생성해서 계속 유지 |
동적 버퍼는 D3D11_USAGE_DYNAMIC + Map() 사용 | CPU 가 자주 업데이트하는 경우 Map/Unmap 으로 효율적 쓰기 가능 |
Stream Output 또는 Instancing 사용 | 반복되는 데이터 전송을 줄이고 GPU 내부 인스턴싱으로 성능 향상 |
✅ 4️⃣ 상태 변화(State Change) 최적화
PSSetShaderResources / VSSetShader / Sampler 최소 변경 | 매 Draw Call 마다 텍스처, 쉐이더 바꾸면 드라이버 오버헤드 증가 — 유사 상태 묶어 그리기 (Batch) 추천 |
DrawCall 정리 (Batching) | 유사한 메터리얼, 동일 텍스처를 사용하는 객체들을 한 번에 처리해서 상태 전환 비용 최소화 |
렌더링 순서 정리 (Material sorting) | 텍스처나 셰이더 교체가 적은 순서대로 렌더링을 정리하면 GPU 스테이트 변경 비용 절약 |
✅ 5️⃣ Present & VSync 주의
VSync 끄기(개발 중) | 성능 측정 시 GPU 제한 없이 성능 체크 가능 |
VSync 켜기(출시) | 화면 찢어짐 방지, 그러나 GPU 대기 시간이 추가되므로 FPS 제한 확인 필요 |
✅ 전체 최적화 흐름 추천
- 초기화 시 정적 리소스 전부 로드 & 캐싱
- 렌더링 시 텍스처 & 셰이더 상태 변경 최소화 → 비슷한 메터리얼끼리 묶어서 그리기
- 자주 변경되는 정점 데이터는 동적 버퍼 사용 (Map/Unmap)
- draw 호출 개수 최소화 (인스턴싱 또는 배치)
- 텍스처는 압축 포맷과 mipmap 필수 적용
- Shader 컴파일은 무조건 사전 컴파일 후 cso 파일 로딩
✅ 3️⃣ 정적 버퍼 vs 동적 버퍼 비교 정리
항목 | 정적 버퍼 (D3D11_USAGE_DEFAULT) | 동적 버퍼 (D3D11_USAGE_DYNAMIC) |
용도 | 변경 거의 없는 데이터 (지형, 모델 메쉬 등) | 프레임마다 업데이트되는 데이터 (UI, 파티클, 애니메이션 변형 등) |
CPU 접근 | ❌ 없음 (GPU 전용) | ✅ CPU 쓰기 가능 (Map/Unmap 사용) |
업데이트 방법 | 변경 시 리소스를 다시 생성해야 함 | Map(DISCARD) & memcpy & Unmap |
장점 | GPU 최적화 / 빠른 렌더링 | CPU가 자주 바꾸는 데이터 처리에 최적화 |
단점 | 변경 어려움 (매번 리소스 새로 생성 필요) | 잘못 설계하면 빈번한 복사 및 GPU Sync 문제가 발생할 수 있음 |
✅ 배치 렌더링(Batching) vs 인스턴싱(Instancing) 비교
항목 | 배치 렌더링 (Batching) | 인스턴싱 (Instancing) |
방식 | CPU 에서 여러 오브젝트 정점 데이터를 월드 변환 후 큰 버퍼로 묶어서 전송 | 정점 버퍼는 1개, 인스턴스 데이터(월드행렬 등)를 추가로 보내 GPU에서 변환 처리 |
움직임/변화 | 불가능 또는 버퍼 재생성 필요 | 실시간 가능 (인스턴스 버퍼만 매 프레임 업데이트) |
DrawCall 개수 | 1회 Draw() 호출 (묶어서 처리) | 1회 DrawIndexedInstanced() 호출로 여러 인스턴스 렌더링 |
CPU 부하 | 큼 (큰 정점 버퍼 합치고 계산 필요) | 적음 (인스턴스 버퍼 갱신만 하면 됨) |
GPU 효율 | 중간 (큰 정점량이면 오히려 부담) | 높음 (병렬 처리 최적화 가능) |
주로 사용하는 상황 | 고정 지형, 타일맵, 변경 안 되는 배경 | 나무, 풀, 파티클, 반복되는 작은 오브젝트 대량 렌더링 |
2주차 배운 것
1. Actor와 ActorComponent
2. 대략적인 생명주기
3. 텍스쳐 렌더링
4. 인덱스 버퍼 사용방법
5. SubUV