[KOR][100]Managing-Unbounded-Growth--A-Story-of-Sh

https://www.youtube.com/watch?v=FQVOYNczPpw

Frame at 0.00s
# 언리얼 엔진 셰이더 시스템 개선: 요약 ## 발표자 소개 * **이름:** Dan Oxnidis * **소속:** 언리얼 엔진 렌더링 아키텍처 팀 * **주요 업무:** 셰이더 시스템, 재질 시스템 등 ## 발표 개요 이번 발표는 언리얼 엔진 셰이더 시스템의 주요 변경 사항, 셰이더 수 증가의 원인, 프로젝트에서 셰이더 수를 줄이는 전략, 그리고 엔진 업데이트를 통해 이루어진 시스템 개선 사항을 다룹니다. ## 1. 동기 (Motivation) * **핵심 문제:** * 수년간 지속된 방대한 셰이더 수와 긴 컴파일 시간 * 프로젝트 빌드 시 셰이더 재컴파일 문제 발생 * 빌드 타임아웃으로 인한 QA 빌드 지연 및 워크플로우 방해 * **근본 원인:** * 잦은 셰이더 코드 변경으로 인한 DDC(Data Driven Caching) 메커니즘 과부하 * 단순한 코드 변경(공백, 주석 수정 등)으로 인한 전체 셰이더 재컴파일 발생 * **임시 해결책 (비효율적):** * 주말 셰이더 제출 제한 * 셰이더 개발팀 분리 및 별도 CI 프로세스 (결과 반영 지연) ## 2. 셰이더 시스템 기본 정보 * **셰이더 유형:** * **글로벌 셰이더:** * HLSL 코드로 직접 작성 (프로그래머 작성) * 특정 패스, 컴퓨트 작업 등에 사용 * 씬 오브젝트와 직접적으로 연결되지 않음 * 콘텐츠 비의존적 * **재질 셰이더:** * HLSL 코드와 재질 그래프 결합으로 자동 생성 * 씬 오브젝트에 적용 * 콘텐츠 의존적 (대규모 프로젝트에서 컴파일/쿡 시간 대부분 차지) * **기타 셰이더:** Niagara, 컴퓨트 프레임워크 등 (영향 적음) * **셰이더 타입 (Shader Types):** C++ 및 HLSL 코드 결합으로 셰이더 생성 * 각 구현은 렌더링 패스와 매핑 * **재질 셰이더:** 베이스 패스, 섀도우 패스, 뎁스 패스 등 * **글로벌 셰이더:** 포스트 이펙트, 라이팅 패스, 컴퓨트 관련 등 * **버텍스 팩토리 (Vertex Factories):** * 메시, 파티클, 헤어, 워터 등 다양한 버텍스 데이터 언패킹 처리 * 동일 재질도 사용 플래그에 따라 다른 버텍스 팩토리로 셰이더 생성 가능 * **셰이더 포맷 (Shader Formats):** * 단일 런타임 타겟을 위한 셰이더 코드 및 데이터 타입 * PC는 SM5, SM6, Vulkan, 모바일 등 다중 타겟 지원 * 각 포맷별 C++ 컴파일러 구현 (외부 컴파일러 호출 및 UE 특화 전/후처리) * **셰이더 컴파일 단계:** * **에디터:** * **시작 시:** 글로벌 셰이더, 기본 셰이더 컴파일 (에디터 실행 전 필수) * **맵 로딩 시:** 해당 맵 렌더링에 필요한 셰이더 컴파일 * **PIE (Play In Editor):** 게임 로직 실행 및 추가 에셋 로딩에 필요한 셰이더 컴파일 * **쿡 (Cook):** * 에디터 시작 단계와 동일 (타겟 플랫폼 수만큼) * 패키지 로딩/저장 중 해당 패키지에 필요한 셰이더 컴파일 (패키지 저장 블록) * **셰이더 무효화 (Shader Invalidation):** * 코드 또는 콘텐츠 변경으로 인한 셰이더 재컴파일 트리거 * **전체 무효화:** 모든 셰이더 재컴파일 요구 (GUID 변경 등) ## 3. 셰이더 수 증가의 주요 원인 * **간소화된 공식:** `총 재질 셰이더 수 ∝ 재질 수 × 버텍스 팩토리 수 × 셰이더 타입 수 × 셰이더 포맷 수` * `재질 수` 및 `버텍스 팩토리 수`는 콘텐츠 의존적 (예술가/기획자 영향) * `셰이더 타입 수`는 엔지니어링 영향 (새로운 기능 추가) * `셰이더 포맷 수`는 타겟 플랫폼 구성에 따라 결정 (엔지니어링 영향) * **핵심 문제:** 위의 변수 중 최소 두 가지 이상이 꾸준히 증가 * **콘텐츠 측면 추가 요인:** * 새로운 재질 및 재질 인스턴스 생성 * 재질/재질 함수 내 `Static Switch` 추가 * 품질 수준별 재질/재질 함수 변형 * 재질 인스턴스 내 재질 속성 오버라이드 * **Static Switch의 함정:** * Boolean Switch 하나당 셰이더 수 2배 증가 가능성 * 현대 GPU에서 동적 분기(Dynamic Branching) 비용 감소에도 불구하고 여전히 Static Switch 사용 습관 존재 * **권장:** 정말 필요한 경우가 아니라면 Static Switch 사용 자제, 성능 프로파일링 필수 ## 4. 셰이더 컴파일 및 캐싱 메커니즘 * **셰이더 맵 캐싱:** * 동일한 재질 매개변수를 가진 여러 재질 인스턴스는 동일한 셰이더 맵 공유 (메모리 절약) * 셰이더 컴파일 작업 제출 시, 코드 및 설정이 완전히 일치하면 컴파일 1회만 수행 후 결과 캐싱 * **셰이더 바이트코드 중복 제거:** * 컴파일된 셰이더의 최종 바이트코드는 1회만 저장 (런타임 메모리 및 PSO 컴파일 비용 절감) * **문제점:** 이 중복 제거는 컴파일 후 작동하므로, 불필요한 컴파일 작업을 이미 수행한 후 인식 가능 * **UE5 온디맨드 셰이더 컴파일 (ODSC):** * **기능:** 에디터 실행 시 불완전한 셰이더 맵으로 시작, 가시적인 씬에 필요한 셰이더만 필요 시 컴파일 * **효과:** 맵 로딩 및 PIE 시 셰이더 컴파일 부담 대폭 감소 (UE4 대비) * **한계:** 에디터 워크플로우 개선에 집중, 쿡 프로세스에는 영향 없음 * **중요한 파생 효과:** 셰이더 캐시 메커니즘 도입 (ODSC 요청 결과 DDC 캐싱) ## 5. 셰이더 수 감소 전략 (엔진 변경 없이) 1. **재질 관리:** * 프로젝트 내 재질 수 최소화 * 재질 인스턴스 활용 권장 (중복 제거 가능성 높음) 2. **Static Switch 지양:** * 가능하면 `Uniform Parameters` 활용 (성능 측정 필수) * **예외:** * 재질 변환기(Material Translator)의 동적 분기 지원 미흡 시 (신규 재질 변환기 개발 중) * 텍스처 샘플링 회피 또는 샘플러 제한 초과 방지 목적 3. **사용하지 않는 셰이더 분석 및 제거:** * 컴파일되었으나 사용되지 않는 셰이더 식별 * 불필요한 재질 사용 플래그 비활성화 * 사용하지 않는 렌더링 기능 비활성화 (CVar, 설정 등) * **UE 5.6 신규 기능:** * `ListShaders` 런타임 명령어: 런타임 시 로드된 셰이더 목록 확인 * `Shader Type Stats` 쿡 결과: 쿡 시 컴파일 및 패키징된 셰이더 목록 확인 * **팁:** 불일치 항목 발견 시 엔진 팀에 제보 ## 6. UE 5.2 ~ 현재 셰이더 시스템 개선 사항 * **셰이더 미니파이어 (Shader Minifier):** * **문제점:** DXC(DirectX Shader Compiler) 전처리 단계에서 과도한 시간 소요 (큰 셰이더 파일, 불필요한 함수 파싱) * **해결책:** 사전 데드 스트립핑(Dead Stripping) 기법 도입 * **작동 방식:** 셰이더 소스 파일을 함수, cbuffer 등으로 분할 후, 엔트리 포인트에 관련 있는 청크만 추출하여 새로운 소스 파일 생성 * **효과:** * 전처리 단계 컴파일 비용 대폭 감소 * 전체 컴파일 시간 현저히 개선 (특히 코드 비중이 큰 셰이더) * **적용:** UE 5.1/5.2 (실험적), UE 5.3 (기본 활성화, Metal/OpenGL 제외), UE 5.4 (모든 플랫폼 기본 활성화) * **전처리 라이브러리 재구축:** * **기존:** MCPP (느리고 유지보수 어려운 C++ 라이브러리) * **대안:** DXC (코드 출력 방식 비유연) → **Rad Game Tools의 Pure C Preprocessor (사용)** * **개선 작업:** 파일 로딩 가상화, 안정성/메모리/성능 최적화 * **적용:** UE 5.2 (실험적), UE 5.3 (기본 활성화, MCPP 대체) * **개별 셰이더 DDC 캐싱 (Per-Shader DDC Caching):** * **핵심 아이디어:** 전처리 및 미니파이된 셰이더 소스를 기반으로 개별 셰이더 캐싱 활성화 및 공유 캐시 지원 * **작동 방식:** 1. 셰이더 맵 캐시 미스 발생 시, 개별 셰이더 전처리 및 미니파이 2. 개별 셰이더별 캐시 키 생성 및 쿼리 (인메모리 캐시 → DDC) 3. 컴파일이 필요한 셰이더만 컴파일 4. 캐시 히트된 셰이더 결과와 컴파일된 셰이더 결과를 결합하여 새 셰이더 맵 생성 및 캐싱 * **주요 작업:** * 셰이더 포맷 리팩토링 (전처리/컴파일 분리) * 셰이더 작업 생성/제출 최적화 및 병렬화 * ODSC의 에디터/로컬 전용 제한 해제 (공유 캐시 활용) * **DDC 병목 현상 해결:** Zen Server 도입 (파일 시스템 DDC 대체) * **효과:** * 이전보다 훨씬 적은 셰이더 컴파일 발생 * 대규모 셰이더 무효화 빈도 현저히 감소 * 코드 변경(주석, 공백 등)으로 인한 무효화 제거 * 플랫폼 간 셰이더 무효화 오류 감소 (예: Xbox 헤더 변경 시 PS5 셰이더 컴파일 문제 해결) * 평균 셰이더 컴파일 수 감소 (공유 캐싱으로 인한) * **바이트코드 중복 제거 최적화:** * **문제점:** 셰이더 맵 레코드 구조로 인한 DDC 내 셰이더 데이터 중복 발생 (쿡 메모리 및 DDC 오버헤드 증가) * **해결책:** 바이트코드 배열을 DDC의 값 첨부(Value Attachments)로 분리 → 해시가 동일하면 DDC가 자동으로 중복 제거 * **효과:** DDC 저장 공간 및 쿡 메모리 사용량 대폭 감소 * **DXC 저수준 최적화:** * 인라이닝(Inlining) 및 디버그 정보 내보내기 성능 개선 * 특정 셰이더 컴파일 시간 개선 및 심볼 포함/미포함 컴파일 시간 격차 해소 * **한계:** D3DSM6에만 적용, Vulkan은 별도 문제 존재 * **재질 번역 결과 캐싱:** * 대규모 재질 번역 시간 단축 * **Unreal Build Accelerator (UBA) 활용:** * 분산 빌드 시스템을 이용한 셰이더 컴파일 분산 * 가상 입력/출력 파일 메커니즘 활용 (디스크 I/O 감소) * 셰이더 컴파일 작업 배치 시각화 및 분석 기능 * **기타 개선 사항:** * 유사 버텍스 팩토리 병합 (셰이더 수 감소, 런타임 성능 영향 미미) * 심볼 버퍼 최적화 (디버그 심볼 중복 저장 감소) * 메모리 사용량 최적화 (공유 버퍼 사용) ## 7. 결과 (Results) * **CitySample 프로젝트 쿡 시간 비교 (UE 5.1 vs 5.7):** * **전체 무효화:** 37분 → 14분 * **전체 무효화 (심볼 포함):** 1시간 15분 → 15분 * **부분 무효화 (common.ush 함수 변경):** 37분 (거의 전체 재컴파일) → 12분 (21개 셰이더만 컴파일) * **주요 개선 사항:** * 요청 셰이더 및 컴파일 셰이더 수 감소 (셰이더 감소 및 중복 제거) * 전체 쿡 시간 대폭 단축 * 심볼 포함/미포함 컴파일 시간 격차 해소 * 평균 전처리 시간 개선 (미니파이어, 정규화 추가에도 불구하고) * 평균 컴파일 시간 개선 (미니파이어 + DXC 최적화) * 캐시 히트율 증가 (CitySample은 예외적으로 높은 편, 일반 프로젝트는 더 큰 향상) * **메모리 사용량:** UE 5.7에서 UE 5.1 대비 피크 메모리 사용량 약 20GB 감소 * **DDC 저장 공간:** UE 5.7에서 UE 5.1 대비 약 20% 증가 (심볼 비활성화 시) ## 8. 향후 계획 (Future Work) * **콘텐츠 생성자 대상 개선:** * 변경 사항이 셰이더 생성에 미치는 영향 시각화 도구 제공 * **버텍스 팩토리 폐지 고려:** * 동적 분기 기반 버텍스 페치 코드 작성 (GPU 성능 영향 검증 필요) * 유사한 버텍스 팩토리 병합 (성능 저하 없는 범위 내) * **신규 재질 변환기 (Material Translator):** * 적절한 동적 분기 지원 → Static Switch 필요성 감소 * Bindless와 결합하여 텍스처 샘플링 관련 Static Switch를 동적 분기로 전환 (퍼뮤테이션 수 대폭 감소) * **코드 생성 분리:** 재질 변환/컴파일 단계를 분리하여 필요한 코드만 생성, 셰이더 중복 제거율 향상 목표 (1:1에 근접) * **셰이더 모듈 개념 도입:** * 전처리 코드 공유 라이브러리 구축 → 각 셰이더별 전처리 비용 절감 * **UBA 가상 파일 확장:** * 셰이더 파라미터 메타데이터, 컴파일러 환경 설정 등 공유 데이터 관리 * 작업 배치 제거 및 부하 분산 개선 * **글로벌 셰이더에 대한 ODSC 적용:** * 전체 글로벌 셰이더 컴파일을 비동기적으로 제출하고 필요 시 블록킹 * **커뮤니티 피드백 요청** ## 9. 감사합니다. * 본 발표 내용은 많은 사람들의 노력으로 이루어졌습니다. * 질문 받습니다.