병렬 렌더링 개요

언리얼 엔진 4 의 병렬 렌더링에 대한 일반적 수준의 개요서입니다.

Windows
MacOS
Linux

스레드 개요

원래 렌더러는 렌더 스레드(Render Thread)에서 실행되었고, 그 스레드에 대한 명령은 나중 프레임에 실행되도록 게임 스레드(Game Thread)가 큐에 등록시켰습니다. 이러한 명령은 렌더 하드웨어 인터페이스(Render Hardware Interface, RHI) 층으로 호출하는데, 이 RHI 는 지원하는 플랫폼의 다양한 그래픽 API 에 대한 크로스 플랫폼 인터페이스 역할을 합니다.

이 프로세스의 효율을 높이고 지원 플랫폼의 성능을 활용하기 위해, 렌더 스레드는 이제 플랫폼 무관 그래픽 명령을 렌더러의 명령 목록(Command List) 속에 큐 등록(enque)시키는 프론트엔드 역할을 합니다. 그러면 새로운 RHI 스레드는 백엔드에서 적합한 그래픽 API 를 통해 변환(실행)합니다. 이러한 분리 덕에 게임 콘솔, DX12, Vulkan 과 같은 지원 플랫폼에서 독립적인 백엔드 병렬화가 가능합니다. 일반적으로, 프론트엔드에서 병렬 생성되는 것은 무엇이든 백엔드에서 병렬 변환(translate)됩니다.

명령 목록 시스템을 사용하지 않고 실행되는 명령이 몇 가지 있습니다. 예를 들면 Lock, Unlock 작업입니다. 이 명령은 렌더 스레드가 바로 내립니다. 그 경우, 엔진은 RHI 스레드가 플러싱되어 작업이 끝날 때까지 기다리거나, 데이터를 복사하여 큐 등록시켜야 합니다. 이에 대한 구현은 작업과 플랫폼에 따라 달라집니다.

그래픽 명령과 명령 목록

렌더 스레드가 큐 등록하는 명령은 FRHICommand 템플릿에서 파생된 구조체 인스턴스입니다. Execute 함수를 호출하는데, 이 함수는 변환 과정에서 호출되며, 필요한 데이터가 있으면 저장합니다. 명령을 GPU 에 제출할 때는 플랫폼의 최적 퍼포먼스 휴리스틱에 따라 플랫폼 별로 (프레임 당 여러 번 제출할지, 프레임 끝에 한꺼번에 제출할지 식으로) 다르게 제출할 수도 있고, FRHISubmitCommandsHint 명령으로 제출할 수도 있습니다.

변환에 사용되는 메인 인터페이스는 IRHICommandContext 입니다. 각 플랫폼 및 API 마다 파생된 RHICommandContext 가 있습니다. 변환 도중 RHICommandList 에는 작업의 컨텍스트가 되는 RHICommandContext 가 주어지며, 각 명령의 Execute 함수는 RHICommandContext API 속으로 호출합니다. 명령의 컨텍스트는 스테이트-섀도잉, 유효성 검사, 지정된 작업을 하는 데 필요한 API 전용 디테일을 담당합니다.

동기화

게임 스레드, 렌더 스레드, RHI 스레드, GPU 사이 렌더러 동기화는 복잡한 주제입니다. 최상위 레벨에서 언리얼 엔진 4 는 보통 "한 프레임 뒤쳐지는" 렌더러로 구성됩니다. 즉 렌더 스레드가 N 프레임을 처리하는 동안 게임 스레드는 N+1 프레임을 처리한다는 뜻으로, 렌더 스레드가 게임 스레드보다 실행 속도가 빠를 경우는 예외입니다. 여기에 RHI 스레드가 추가되면 살짝 복잡해지는데, RHI 스레드가 N 프레임을 처리하는 도중 N+1 프레임의 가시성 계산을 마치는 식으로 렌더 스레드를 RHI 스레드 앞으로 옮길 수 있기 때문입니다. 최종 결과는, 게임 스레드가 N+1 프레임을 처리하는 도중 렌더 스레드가 N 프레임 또는 N+1 프레임의 명령을 처리하고 있을 수 있으며, RHI 스레드 역시 실행 시간에 따라 N 프레임 또는 N+1 프레임의 명령을 전환하고 있을 수 있습니다. 이러한 보장은 FFrameEndSyncRHIThreadFence 라고 불리는 FRHICommandListImmediate 함수에 의해 중재됩니다. 또한 병렬화가 어떻게 구성되었는지에 관계없이, GPU 에 명령을 제출하는 순서는 싱글 스레드 렌더러에서 명령을 제출하는 순서와 동일합니다. 이는 일관성 보장을 위해 필수이며, 렌더링 코드가 변경되면 반드시 유지해야 합니다.

디버깅

이 동작을 제어하는 콘솔 변수가 여럿 있습니다. 이 단계들 중 많은 부분이 직교성을 띠(서로 무관하)므로 독립적으로 비활성화시켜 테스트할 수 있으며, 시간이 되면 새로운 플랫폼이 도입될 수 있습니다. 예:

명령

설명

r.rhicmdusedeferredcontexts

RHI 명령 디퍼드 컨텍스트 사용 - 0 으로 설정하면, 백엔드의 병렬화를 비활성화시킵니다. 기본값은 1입니다.

r.rhicmduseparallelalgorithms

RHI 명령 병렬 알고리즘 사용 - 0 으로 설정하면, 프론트엔드의 병렬화를 비활성화시킵니다. 기본값은 1입니다.

r.rhithread.enable

RHI 스레드.활성화 - 0 으로 설정하면, RHI 스레드를 완전 비활성화합니다. 명령 목록이 계속 생성될 수는 있지만, 일정 시점에 렌더 스레드에서 바로 전환될 것입니다.

r.rhicmdbypass

RHI 명령 바이패스 - 1 로 설정하면, 명령 목록 생성을 완전 비활성화시키고 렌더러가 원래 그랬던 것처럼 명령 목록 없이 렌더 스레드에서 바로 RHI 명령을 호출하도록 만듭니다. 참고로 RHI 스레드가 비활성화 되어있지 않으면 이 값은 무시됩니다.

Parallel_Rendering_00.png

UE4 에서의 병렬 명령 목록 생성 방식을 보여줍니다.

Tags
Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback