역자의 말.
몇 년전 회사에서 경품으로 받은 PS5 를 최근에서야 설치하고 호라이즌 포비든 웨스트를 플레이하고 있습니다. 전작에 비해서 더 밀도 높은 식생처리와 지형의 이끼등을 포함하여 매우 인상적인 비주얼을 보여주고 있더군요. 그럼에도 PS5 4K에서 부드럽게 동작하는 포비든웨스트를 플레이 하면서 이것과 관련 된 여러가지 기술들에 무엇이 적용됬을까 무척 궁금한 차에 일부분이 이미 공개되어있어 소개해 봅니다. ( 감기 기운도 아직 가시지 않아서 파트 1 과 2로 나눴습니다. )
약력
제임스 맥라렌은 게릴라에서 근무하는 수석 테크니컬 프로그래머입니다. 그는 10살에 ZX 스펙트럼으로 프로그래밍을 시작하여 25년 넘게 3개 대륙에서 비디오 게임 업계에 종사해 왔습니다.
2018년 암스테르담으로 이주한 후 지금까지 데시마를 더 빠르게 만들기 위해 열심히 일하고 있습니다.
요약
호라이즌 포비든 웨스트는 폴리지 및 알파 테스트를 거친 지오메트리를 가속화하기 위해 새로운 루스 타일 디퍼드 텍스처링 시스템( loosely tiled deferred texturing system )을 구현했습니다. 가시성 버퍼는 프리패스로 그려진 다음 전적으로 컴퓨트 셰이더에서 실행되는 분석 및 셰이딩 단계로 이어집니다. 또한 컴퓨팅 셰이더를 사용하면 소프트웨어 가변 비율 셰이딩 솔루션을 구현할 수 있는 추가적인 유연성이 제공됩니다. PS4와 PS5의 컴퓨트 파이프에서 실행할 수 있기 때문에 G-버퍼 렌더링과 캐스케이드 섀도 맵 렌더링을 모두 겹칠 수 있어 일반적으로 분석과 셰이딩의 오버헤드가 거의 발생하지 않습니다. 이 프레젠테이션에서는 시스템의 세부 사항과 이를 데시마 엔진에 통합하기 위해 수행한 최적화 및 설계 선택에 대해 설명합니다.
파트 1.
"진정한 발견의 항해는 새로운 풍경을 찾는 것이 아니라 새로운 눈을 갖는 데 있습니다."
— Marcel Proust
호라이즌 포비든 웨스트에서 알로이는 머나먼 땅에서 새로운 풍경과 함께 멋진 모험을 떠나는데, 그중 일부를 구현하기 위해 렌더링 파이프라인을 새롭게 살펴봐야 했고, 오늘 그 이야기를 해보려고 합니다.
안녕하세요, 와주셔서 감사합니다.
저는 게릴라의 수석 테크니컬 프로그래머인 제임스 맥라렌입니다.
이번 강연에서는 주로 호라이즌 포비든 웨스트의 폴리지 속도를 높이기 위해 만든 디퍼드 텍스처링 시스템의 세부 사항을 살펴보려고 합니다.
먼저 폴리지 렌더링의 문제점에 대해 이야기하고 이전 시스템을 검토한 다음, 디퍼드 텍스처링이 실제로 무엇인지에 대해 잠시 이야기하겠습니다. 그런 다음 시스템에 대한 개괄적인 개요를 설명한 다음 세부적인 내용을 살펴보고 가변 비율 셰이딩 구현에 대해 조금 이야기하고 마지막으로 몇 가지 성능 수치로 마무리하겠습니다.
하지만 그 전에 호라이즌 포비든 웨스트에 대해 전혀 모르시는 분들을 위해 소개해드리겠습니다. 호라이즌 포비든 웨스트는 PS4 및 PS5용 오픈 월드 어드벤처 게임으로, 올해 2월에 출시된 후속작입니다.
이 게임에서 플레이어는 노라족의 용감한 알로이가 되어 수많은 위험한 기계와 싸우며 세상을 구해야 합니다.
자세한 내용은 트레일러를 통해 확인하실 수 있습니다.
호라이즌의 세계에는 숲과 울창한 정글 등 다양한 환경이 존재합니다.이러한 환경은 일반적으로 효율적으로 렌더링하기 어렵습니다. 대부분의 식물은 알파 테스트를 거친 지오메트리로 구성되어 있으며, 오버드로가 매우 많을 수 있습니다.
또한 지오메트리에 애니메이션이 적용되어 있어 TAA와 모션 블러에 적용하려면 정확한 모션 벡터를 생성해야 하므로 쉽게 잘라낼 수 있는 부분이 없습니다.
호라이즌 제로 던에서는 이미 고도로 최적화된 폴리지 시스템을 갖추고 있었습니다,하지만 호라이즌 포비든 웨스트의 아트 부서에서는 더 높은 밀도의 에셋을 원했고, 이로 인해 발생하는 추가 밀리초를 어떻게 확보할지 고민했습니다.
특히 PS4를 타깃으로 해야 했기 때문에 프로젝트에서 원하는 모든 것을 충족하기란 정말 빡빡한 일이었습니다.아트 부서에서 더 많은 것을 요구했을 때 저희를 어떻게 보았는지 궁금하신가요?게임에서 극적으로 재연된 장면을 소개합니다.
그래서 저희는 무엇을 할 수 있는지 알아보고 싶었습니다.
폴리지 렌더링은 비용이 많이 들 수 있습니다. 오버드로가 많고 알파 테스트를 거치는 경우가 많기 때문에 하드웨어의 early Z 최적화를 일부 비활성화할 수 있기 때문에 비용이 추가될 수 있습니다.
호라이즌 제로 던에서는 뎁스 프리패스를 사용하여 알파 테스트를 수행한 다음 지오메트리 패스에서 알파 테스트 없이 폴리지를 다시 렌더링하되 depth equals test를 사용하여 보이는 픽셀에만 셰이딩을 적용하는 방식으로 이 문제를 해결했습니다.
이 방법은 G-버퍼의 폴리지 픽셀에 두 번 이상 쓰지 않아도 되므로 꽤 좋은 해결책입니다.
하지만 이 방식에는 몇 가지 문제가 있습니다.모든 지오메트리는 GPU에 의해 두 번 변환 되어야 합니다. 이 때문에 모든 지오메트리를 다시 렌더링할 때 GPU가 모든 지오메트리를 꽉 채우기가 어렵고, 두 번째 패스에서는 정점이 변환되지만 픽셀 작업이 생성되지 않는 간격이 많이 생깁니다.또한 폴리지 특유의 섬세한 디테일로 인해 이 방식은 많은 양의 쿼드 오버드로로 인해 어려움을 겪을 수 있습니다.
쿼드 오버드로에 대해 잘 모르시는 분들을 위해 간략하게 설명해 드리겠습니다.GPU의 픽셀 셰이딩 하드웨어는 올바른 밉맵을 선택하고 텍스처가 샘플링될 때 올바르게 필터링할 수 있도록 파생물을 자동으로 계산할 수 있어야 합니다.
이를 위해 항상 2x2 쿼드로 셰이딩합니다.이렇게 하면 유한 차분을 사용하여 한 레인(Lane)의 UV 좌표를 다른 레인에서 빼고 텍스처 샘플링에 필요한 도함수를 계산할 수 있습니다.
잠시 시간을 내어 이를 시각화해 보겠습니다. 다음은 래스터라이즈하는 것으로 가정할 삼각형입니다.
노란색 픽셀은 래스터화 결과를 나타냅니다.
안타깝게도 HW는 음영 처리할 픽셀을 스케줄링하지 않고 쿼드를 스케줄링합니다.
따라서 여기에서도 모든 파란색 픽셀에 대한 음영 작업을 수행합니다.
작은 삼각형으로 내려갈수록 이 문제는 더욱 심각해집니다. 여기 오른쪽의 삼각형이 특히 문제입니다.
4픽셀을 출력하지만, 도함수를 계산하기 위해 16픽셀에 대한 음영 작업을 수행해야 했습니다.
이것이 바로 쿼드 오버드로에 대해 이야기할 때 언급하는 것입니다.
폴리지에서는 때때로 큰 트라이앵글을 사용할 수 있지만, 세밀한 디테일을 모방하기 위해 보통 알파 테스트가 수반됩니다.
그런데 지오메트리 패스에서 뎁스 이퀄라이저 테스트를 할 때 기존 시스템에서 정확히 동일한 쿼드 오버드로 문제가 발생했습니다.
이제 이러한 지식을 바탕으로 더 나은 솔루션을 찾기 위한 새로운 모험을 떠날 준비가 되었습니다.
모험을 떠날 준비가 된 알로이입니다.
저희는 디퍼드 텍스처링을 구현하기로 결정하고 큰 모험을 시작했습니다.기본 아이디어는 불투명 지오메트리를 렌더링하기 전에 씬에 프리패스를 수행하여 가시성 버퍼를 생성하는 것입니다.이는 뎁스 프리패스와 매우 유사하지만 추가 렌더 타깃에 프리미티브 ID를 쓴다는 점이 다릅니다.완료되면 비저빌리티 버퍼에는 각 픽셀에 대한 최상위 트라이앵글의 프리미티브 ID가 포함됩니다. 그런 다음 이 버퍼를 분석하고 프리미티브 ID를 사용하여 픽셀을 셰이딩할 수 있습니다.
이 아이디어는 원래 인텔의 논문에 설명되어 있습니다: 비저빌리티 버퍼: 디퍼드 셰이딩에 대한 캐시 친화적인 접근 방식.이 방법은 포워드 렌더러와 디퍼드 렌더러 모두에 적용할 수 있습니다.
호라이즌 포비든 웨스트에는 디퍼드 렌더러가 있으므로 픽셀을 셰이딩하는 패스가 G버퍼를 생성합니다.
그리고 이것은 가시성 버퍼에 넣을 모든 프리미티브 ID를 보여주는 동일한 장면을 색상으로 구분한 시각화입니다.
보시다시피 일부 픽셀만 실제로 유효한 프리미티브 ID를 가지고 있으며, 노란색 픽셀은 가시성 버퍼에 포함되지 않는 픽셀입니다.
그렇다면 왜 이렇게 해야 할까요?우선, 보이는 픽셀만 음영 처리하여 오버드로가 발생하지 않도록 할 수 있습니다.
이론적으로는 처리 방법에 따라 쿼드 오버드로 문제에서 벗어날 수도 있습니다.
또한 모든 지오메트리를 다시 변환하는 과정을 거치지 않아도 되고, 구현 방식에 따라 화면에 보이는 것만 변환할 수도 있고 아예 변환하지 않을 수도 있습니다.
또한 순진한 지연 솔루션에 비해 최소한 대역폭을 절약하는 데 도움이 됩니다.
하지만 모든 것이 햇살과 장미빛인 것은 아닙니다.
하드웨어가 쿼드를 생성하지 않기 때문에 더 이상 유한 미분을 사용하여 도함수를 생성할 수 없으며 직접 계산해야 합니다.
또한 이제 머티리얼을 해결하기 위해 비저빌리티 버퍼에 있는 모든 픽셀을 효율적으로 배치하거나 그리는 방법을 알아내야 하는 중요한 과제를 안게 되었습니다.다른 좋은 기술과 마찬가지로 이 기술도 이미 다양한 형태로 등장하기 시작했습니다.
원본 논문에서는 단일 32비트 정수로 인코딩된 트라이앵글 ID와 인스턴스 ID가 포함된 간단한 가시성 버퍼를 작성합니다.
그런 다음 이를 분석하고 각각의 고유한 머티리얼을 포함하는 화면 공간 타일 세트를 구축합니다.
그런 다음 간접 디스패치를 사용하여 컴퓨팅 셰이더를 실행하여 각 머티리얼에 대해 기록된 타일 세트를 처리합니다,
기본 ID를 읽고 정점 정보를 읽는 데 사용하고, 이심률을 계산하고, 픽셀 작업과 함께 모든 정점 변환 작업을 수행하므로 각 픽셀에 대해 반복됩니다.
모든 속성에 대한 미분도 필요한 경우 탄젠트 프레임과 함께 타일을 처리하는 계산 셰이더에서 수동으로 계산됩니다.마지막에는 음영 및 조명 결과가 중간 G버퍼 없이 기록되므로 대역폭이 매우 낮습니다.
스펙트럼의 반대쪽 끝에는 Dawn 엔진과 같은 것이 있습니다.여기에서도 비슷한 접근 방식을 취하지만, 백엔드에서 미분, 바이센트릭 및 탄젠트 프레임을 계산하는 대신 머티리얼을 해결할 때 해당 작업을 프론트 엔드에 로드하는 대신 UV, 도함수, 머티리얼 ID 및 탄젠트 스페이스가 레이다운 중에 매우 큰 가시성 버퍼에 패킹됩니다.
그런 다음 가시성 버퍼를 분석하고 머티리얼 ID를 16비트 깊이 버퍼에 복사합니다. 그런 후 "뎁스 버퍼의 창의적인 남용"이라고 부르는 방법을 사용하여 각 머티리얼을 음영 처리합니다,
다음 단계에서 머티리얼 ID당 깊이 동일성 테스트를 사용하여 적절한 픽셀을 선택하고 픽셀 셰이더로 음영 처리합니다.
해당 머티리얼을 사용하는 모든 오브젝트를 경계로 하는 화면 공간 쿼드를 그리고 쿼드의 깊이를 머티리얼 ID와 동일하게 설정합니다.
그리고 이 둘의 중간쯤에 있는 다른 변형도 있습니다.토마슈 스타초비악(Tomasz Stachowiak)의 디퍼드 머티리얼 시스템은 머티리얼당 픽셀 목록을 생성하여 기본 ID와 함께 2원심과 음영을 계산 음영에 기록합니다.
최근에는 나나이트와 액티비전의 지오메트리 파이프라인이 있습니다.
나나이트는 압축된 소프트웨어 래스터화된 지오메트리 클러스터와 함께 작동하며, 클러스터와 트라이앵글 정보가 64비트 UINT에 깊이와 함께 패킹된 비교적 얇은 비저빌리티 버퍼를 생성합니다.
그런 다음 머티리얼을 리졸브할 때 픽셀 셰이더를 통해 GBuffer를 작성하여 "창의적인 뎁스 버퍼 남용" 트릭의 변형을 사용합니다.
지오메트리 클러스터와 함께 작동하는 Activision의 지오메트리 파이프라인은 대부분의 지오메트리에 대해 얇은 가시성 버퍼를 기록하지만, 폴리지의 경우 두 렌더 타깃에 걸쳐 64비트 정보를 기록하여 노멀, 텍스처 LOD 및 UV를 인코딩하므로 머티리얼 복잡도를 제한하여 머티리얼 리졸브 단계에서 필요한 작업을 최소한으로 유지할 수 있습니다.
이 주제에 대해 더 자세히 알고 싶으시다면 John Hable의 블로그 게시물 '머티리얼 그래프를 사용한 가시성 버퍼 렌더링'을 확인해 보시길 진심으로 추천합니다.
디퍼드 텍스처링 시스템을 설정할 수 있는 다양한 가능성을 고려할 때, 저희는 필요한 기능을 살펴보고 요구사항에 맞는 것이 무엇인지 파악하기 시작했습니다.
모든 폴리지는 애니메이션이 적용되므로 동적 지오메트리를 지원하는 것이 필수적이었습니다.또한 다양한 유형의 폴리지에 대해 여러 가지 머티리얼을 사용하므로 머티리얼 간 전환을 효율적으로 지원해야 했습니다.
또한 PS4와 PS5에 모두 출시할 예정이었기 때문에 이 접근 방식은 PS4와 PS5 모두에서 작동해야 했습니다.PS4에서 실행할 것이기 때문에 어떤 작업을 하든 메모리 사용량이 매우 적어야 했습니다.
100메가바이트가 아니라 10메가바이트 정도면 충분했습니다.또한 폴리지에는 일반적으로 오버드로가 많기 때문에 비저빌리티 버퍼의 레이다운을 매우 저렴하게, 가급적이면 32비트 익스포트 하나만 사용해야 했습니다.
또한 다른 비디퍼드 텍스처 지오메트리와 잘 통합되기를 바랐기 때문에 G-버퍼로 출력하기를 원했습니다.
고민하는 동안 이 모든 작업이 어디에 어울릴지 프레임도 살펴보기 시작했습니다.초기 프로토타입은 픽셀 셰이더를 사용했습니다.
저는 디퍼드 텍스처링을 사용할 경우 어떤 일이 일어날지 파악하기 위해 생성된 셰이더 중 일부를 직접 수정하는 것으로 이 프로세스를 시작했습니다.
유망해 보였지만 이 방법이 옳은 방법인지 완전히 확신하지는 못했습니다.
어쨌든 프레임을 살펴보기 시작했을 때 제가 본 것은 다음과 같았습니다.
따라서 계단식 그림자가 렌더링되는 멋진 지점이 있는데, 일반적으로 픽셀 작업은 많지 않고 버텍스 작업으로 채워져 있음을 알 수 있습니다.
그래서 이 틈새에 폴리지 머티리얼을 셰이딩할 수 없을까 고민하기 시작했습니다.
하지만 이렇게 하려면 비동기 컴퓨트 파이프를 사용하여 셰이딩을 하고 컴퓨팅 셰이더를 사용하여 G-버퍼를 채워야 했습니다.
그래서 이 점을 염두에 두고 픽셀 셰이딩을 컴퓨팅으로 어떻게 처리할지 생각하기 시작했습니다.
이것은 생각보다 간단하지 않습니다. 단순하고 순진한 접근 방식은 적어도 부분적으로 같은 재질을 덮고 있는 작은 타일을 식별하고 타일 목록을 음영 처리하는 일련의 디스패치 인디렉트를 수행하는 것입니다.이것이 원래의 가시성 버퍼가 했던 일입니다. 그러나 동일한 재질의 쿼드를 식별하고 이를 웨이브로 묶어주는 HW가 없으면 각 타일의 많은 양의 레인이 아무 작업도 하지 않게 될 것이 분명합니다.이는 픽셀 셰이더가 작은 트라이앵글에서 발생할 수 있는 채워지지 않은 쿼드 문제와 비슷하지만 실제로는 훨씬 더 심각합니다!
다른 간단한 옵션은 동일한 재질의 픽셀을 식별하고 음영 처리할 픽셀 목록을 작성하는 것입니다.
이 방법이 훨씬 더 나은 옵션이지만 이 방법에는 여전히 몇 가지 문제가 있습니다.머티리얼을 사실상 무작위 순서로 처리하기 때문에 화면 공간에서 많이 튀어나올 수 있습니다.
동일한 머티리얼과 배치를 가진 큰 픽셀 그룹을 처리하는 경우에는 큰 문제가 되지 않지만, 폴리지의 경우 동일한 화면 공간 영역에 많은 배치가 섞여 있기 쉽습니다.
즉, 셰이딩을 할 때 잠재적으로 동일한 메모리를 L2에 반복해서 넣었다 뺐다 할 수 있다는 뜻입니다.
또 다른 문제는 각각 고유한 셰이더, 유니폼, 텍스처 조합이 있는 배치가 여러 개 있는 경우 각각 별도의 디스패치가 필요하다는 것입니다(물론 웨이브에서 발산을 허용하고 싶지 않다면).
또한 컴퓨팅 파이프를 사용하는 경우 각 디스패치를 처리하는 데 걸리는 시간이 GFX 파이프보다 훨씬 더 오래 걸리기 때문에 비용이 엄청나게 많이 들 수 있으며, 이로 인해 CP에 상당히 종속될 수 있습니다.
모험의 정신으로...우리는 두 가지 접근 방식을 결합하기로 결정했습니다.타일의 우수한 공간적 위치성과 픽셀 목록의 패킹 유연성을 모두 원했습니다.
그래서 생각해낸 것이 "루스 타일링" 접근 방식입니다.기본 아이디어는 128x128픽셀의 대형 타일로 작업하는 것입니다.타일 내에서 동일한 셰이더를 사용하지만 반드시 동일한 상수와 텍스처를 사용하지 않는 픽셀을 식별합니다.
즉, 서로 다른 배치에서 가져올 수 있습니다.그런 다음 이러한 픽셀을 가져와서 동일한 상수와 텍스처를 가진 완전한 웨이브로 정렬할 수 있습니다.
각 픽셀에 대한 명령 외에도 각 웨이브에 대해 처리 중인 타일, 처리 중인 배치 및 픽셀 명령이 시작되는 위치를 알려주는 "웨이브 명령"을 저장합니다.
화면의 모든 타일에 대해 이 작업을 수행하면 각 셰이더에 대해 여러 배치를 한 번에 처리하는 단일 dispatchIndirect() 호출로 끝낼 수 있습니다.
또한 각 타일에 대한 픽셀 명령이 함께 저장되도록 하기 때문에 서로 가까운 시간적 위치에서 처리될 가능성이 높으므로 G버퍼를 채우기 위해 메모리 요청을 할 때 메모리가 여전히 L2에 있을 가능성이 훨씬 더 높습니다.
또한 동일한 상수와 텍스처로 완전한 웨이브를 처리하기 때문에 발산에 대해 걱정할 필요가 없습니다.여기에는 특정 타일에 맞추기 위해 픽셀 명령을 반올림해야 하므로 "채워지지 않은 웨이브"가 발생할 수 있다는 약간의 주의가 있습니다.
그러나 실제로 이것은 매우 사소한 문제가 되는 경향이 있습니다.
다음은 이러한 루스 타일링의 개념을 실제로 보여주는 간단한 예시입니다.렌더링 중인 씬의 타일이라고 가정해 보겠습니다. 128x128이 아닌 16x16에 불과하지만 제 역할을 할 수 있습니다.모든 컬러 픽셀은 동일한 셰이더를 사용합니다.서로 다른 색상은 서로 다른 배치 그룹이라고 부르는 픽셀을 나타냅니다.여기서 배치 그룹은 동일한 셰이더, 텍스처, 상수 및 지오메트리를 가진 배치의 집합이지만 해당 그룹의 배치에는 서로 다른 인스턴스 집합이 있습니다.......이 예제에서는 웨이브의 크기가 8개의 스레드에 불과한 GPU를 사용한다고 가정해 보겠습니다.우리가 할 일은 동일한 배치 그룹에 속한 픽셀을 웨이브로 그룹화하는 것입니다.
또한 음영 처리할 픽셀을 설명하는 픽셀 명령 목록을 작성합니다.
그런 다음 웨이브가 작동할 배치 그룹을 정의하고 해당 픽셀 명령 집합을 가리키는 웨이브 명령 집합을 생성합니다.
웨이브 명령에 대해 자세히 살펴봅시다. 웨이브 명령은 해당 명령이 어느 타일에 있는지와 웨이브가 처리해야 하는 픽셀 명령의 수를 기록합니다.따라서 이 타일에서 특정 셰이더에 대한 모든 웨이브 및 픽셀 명령을 생성한 후에는 다음 타일에 대한 명령을 추가할 수 있습니다.이렇게 하면 단일 셰이더에 대해 여러 배치를 음영 처리하는 웨이브 및 픽셀 명령 세트를 구축하는 동시에 발산을 피하고 공간적 로컬리티를 보존하여 우수한 L2 캐시 성능을 얻을 수 있습니다.이 방식에서 한 가지 좋은 점은 128x128 타일로 작업하기 때문에 픽셀 명령을 저장하는 버퍼는 16비트만 있으면 된다는 점입니다.또한 128x128 타일 크기를 신중하게 선택했기 때문에 원할 경우 16비트 중 12비트를 픽셀 쿼드를 인코딩하는 데 사용하고 4비트를 해당 쿼드 내에 설정된 픽셀을 인코딩하는 데 사용할 수 있으며, 이는 나중에 가변 비율 셰이딩에 대해 이야기할 때 중요하게 사용될 것입니다.
이제 컴퓨팅에서 픽셀을 처리하는 방법을 대략적으로 알았습니다. 정점은 어떨까요?이론적으로는 원래 인텔 논문에서처럼 픽셀을 음영 처리하면서 변환할 수 있습니다.하지만 상대적으로 큰 삼각형을 처리하는 PS4에서는 각 픽셀이 3개의 정점을 셰이딩해야 하므로 많은 양의 중복 작업이 발생할 수 있습니다.호라이즌 제로 던에서는 오브젝트 스페이스 버텍스 위치에 대한 캐싱 시스템을 도입하여 뎁스 이퀄 패스에서 많은 중복 변환 작업을 피할 수 있었고, 모션 벡터의 마지막 프레임에서 버텍스 위치에 쉽게 액세스할 수 있었습니다. 이를 기반으로 구축할 수도 있었지만, 크기가 제한적이고 오버플로가 발생할 수 있으며 캐시 공간이 부족해지는 상황을 우아하게 처리할 수 있어야 했습니다.
따라서 버텍스 캐시를 계속 사용하면서 별도의 컴퓨팅 파이프에서 버텍스를 링 버퍼로 변환합니다.
이 접근 방식이 작동하려면 동일한 셰이더를 가진 패스로 배치를 정렬하고 패스에 대한 버텍스를 한 번에 변환해야 합니다.
이를 구동하고 셰이딩할 버텍스에 대한 정보를 전달하려면 셰이딩해야 할 버텍스 청크를 알려주는 버텍스 웨이브 명령도 생성해야 합니다.
이 작업을 수행하는 동안 픽셀 계산 셰이더는 이전 패스의 버텍스를 사용할 수 있습니다.이런 식으로 항상 겹쳐지는 것을 원하기 때문에 한 패스에서 처리하는 최대 버텍스 수를 링 버퍼 크기의 ½로 제한합니다.
이 링 버퍼는 PS4에서는 12MB, PS5에서는 24MB입니다.
이제 시스템이 어떻게 작동하는지 간단히 살펴보겠습니다.
먼저, 배치를 머티리얼별 패스로 정렬하는 데 필요한 몇 가지 CPU 작업이 있습니다.
그런 다음 얇은 32비트 가시성 버퍼를 채우고 음영 처리하려는 트라이앵글에 대한 정보를 인코딩합니다.
그런 다음 가시성 버퍼를 분석하고 몇 가지 분류를 수행하여 픽셀 측에서 셰이딩을 구동할 픽셀 및 픽셀 웨이브 명령을 생성합니다.
버텍스 웨이브 명령과 함께 픽셀 작업에 사용되기 전에 링 버퍼를 사용하여 메모리에서 튕겨져 나가는 별도의 컴퓨팅 파이프에서 버텍스의 변환을 구동하는 버텍스 웨이브 명령을 생성합니다.
마지막으로 가변 비율 셰이딩 마법을 추가하여 더 많은 것을 끌어낼 수 있습니다.
더 자세히 설명하기 전에 데시마 엔진의 입력에 대해 간략하게 설명하겠습니다.데시마에서는 고도로 최적화된 씬 그래프를 쿼리하여 매 프레임마다 무엇을 그려야 하는지 결정합니다.씬 그래프는 현재 프레임에 대해 오클루전 컬링을 수행하여 보이는 오브젝트의 인스턴스를 배치로 묶은 가시성 목록을 출력하며, 각 배치에는 1개 이상의 인스턴스가 포함됩니다.씬 그래프의 배치는 일반적으로 단일 드로콜로 렌더링되므로 배치에 포함된 모든 인스턴스는 동일한 셰이더, 지오메트리 및 텍스처를 공유하지만 일부 인스턴스별 매개변수는 다를 수 있습니다.다른 인스턴스가 컬링될 수도 있고, 씬 그래프 쿼리 내부에서 배치가 병합될 수도 있기 때문에 프레임을 이동하면서 프레임마다 배치가 반드시 일관되지 않을 수 있습니다.간단하고 당연한 내용처럼 보일 수 있지만, 나중에 다시 일괄 처리에 대해 이야기할 것이므로 혼란을 피하기 위해 어떤 작업을 했는지 자세히 설명하기 전에 여기서 언급할 가치가 있다고 생각합니다.
따라서 GPU에서 렌더링을 시작하기 전에 셰이더의 해시, 배치별 데이터 및 해당 위치의 양자화된 모튼 코드를 기반으로 CPU에서 배치를 정렬하고 패스로 나눕니다.하지만 이 접근 방식에는 몇 가지 문제가 있었습니다. 가장 큰 문제는 월드에 있는 대부분의 폴리지를 배치하는 절차적 폴리지 배치 시스템을 사용한다는 점입니다.이로 인해 종종 100개의 인스턴스가 포함된 배치가 생성될 수 있습니다.이러한 인스턴스 각각이 많은 수의 버텍스를 사용하는 경우 링 버퍼에 절반은 커녕 모든 버텍스를 넣을 수 없는 경우가 많기 때문에 문제가 발생합니다!
이를 방지하기 위해 먼저 지오메트리의 모든 개별 비트가 16비트 인덱스와 최대 64k 프리미티브를 사용하도록 하여 지오메트리의 크기에 적절한 한계를 설정했습니다.이렇게 하면 지오메트리의 개별 비트가 너무 많은 링 버퍼 공간을 필요로 하지 않게 됩니다.그런 다음 배치 시스템에서 가져온 배치를 마이크로 배치라고 하는 관리 가능한 조각으로 분할해야 합니다.각 마이크로 배치에는 최대 6만 4천 개의 트라이앵글이 있으며 1~6만 4천 개의 인스턴스가 포함됩니다.그런 다음 배치가 아닌 마이크로 배치로 패스를 만듭니다.따라서 배치에 너무 많은 버텍스가 포함되어 있으면 여러 개의 마이크로 배치로 나뉩니다.즉, 주어진 원본 배치는 결국 여러 패스에 걸쳐 처리될 수 있습니다.
생성하는 각 마이크로 배치에 대해 MicroBatchInfoTable 테이블에 항목을 입력합니다.여기에는 지오메트리가 사용하는 버트 수, 배치의 어느 인스턴스에서 시작되는지, 어느 패스에 속하는지 등 마이크로 배치에 대한 정보가 포함됩니다.이 정보는 GPU 액세스 가능 버퍼에 저장되며, 셰이딩 중에 셰이딩 중인 마이크로 배치에 대한 정보를 복구하는 데 사용할 수 있습니다.<계속하기 전에 보너스 슬라이드 108을 살펴보세요...>
여기에서 배치의 대략적인 흐름을 볼 수 있습니다.
셰이더에서 정렬됩니다, 그런 다음 마이크로 배치로 분할하여 패스를 형성합니다.
그런 다음 마이크로 배치는 버텍스 컴퓨트 셰이더에 의해 링 버퍼로 변환됩니다.
그리고 이렇게 변환된 버텍스는 각 패스와 연결된 픽셀 계산 셰이더에 의해 소비됩니다.
이제 CPU에 대한 설정 작업을 대략적으로 이해하셨을 것입니다. 가시성 버퍼를 배치하는 방법을 자세히 살펴보겠습니다.
데시마에는 이미 뎁스 프리패스가 있었기 때문에 뎁스 버퍼뿐만 아니라 비저빌리티 버퍼에 기록하는 추가 뎁스 및 비저빌리티 패스로 이를 보강했습니다.
이 패스는 각 픽셀에 대해 트라이앵글, 인스턴스 및 배치에 대한 정보를 32비트 프리미티브 ID로 기록해야 합니다.
이론적으로는 PS4 Pro와 PS5에 있는 전용 하드웨어를 사용할 수 있지만, 안타깝게도 지오메트리 셰이더를 사용하지 않고는 프리미티브 ID를 얻을 수 있는 적절한 방법이 없기 때문에 PS4 베이스는 이 작업을 수행할 수 없습니다.
초기 계획은 트라이앵글 인덱스의 상위 16비트에 프리미티브 ID를 인코딩하고 픽셀 셰이더에서 자극하는 버텍스를 읽어 버텍스 셰이더에서 프리미티브 ID를 통과시키는 것이었지만, 개발 초기에는 하드웨어가 버텍스를 회전하는 데 문제가 있었습니다.지금은 이 문제를 해결할 수 있는 방법이 있다고 생각하지만, 결국 이 문제를 완전히 피할 수 있는 솔루션을 사용하게 되었습니다.XOR을 사용하면 3개의 버텍스 각각에 인코딩한 3개의 값에서 원시 ID를 고유하게 재구성할 수 있습니다.이 방식을 사용하면 정점의 순서는 신경 쓰지 않고 페이로드의 조합만 신경 쓰면 됩니다.*이 경우에도 추가 인덱스를 도입해야 하지만, 프로비저닝 버텍스 스키마를 사용할 때보다 더 많은 인덱스가 필요하지는 않습니다.이제 메시를 전처리할 때 인코딩하려는 프리미티브 ID와 다른 인덱스에 이미 인코딩한 데이터를 기반으로 프로비저닝 버텍스 인덱스에 어떤 데이터를 저장할지 결정합니다.모든 인덱스에 이미 데이터가 결정되어 있는 경우 새 인덱스를 추가해야 합니다.
그런 다음 픽셀 셰이더에서 재구성한 프리미티브 ID를 마이크로 배치 ID 및 인스턴스 ID와 결합하여 가시성 버퍼를 생성할 수 있습니다.
상위 16비트는 마이크로 배치 ID를 인코딩합니다.
렌더링하는 지오메트리에 있는 프리미티브의 수에 따라 가변 비트 수를 사용하여 프리미티브 ID를 인코딩합니다.
나머지 비트는 인스턴스 ID에 사용됩니다.
자, 이제 가시성 버퍼를 배치했습니다.
다음으로, 어떤 버텍스와 픽셀을 음영 처리해야 하는지 파악하기 위해 몇 가지 분류 작업을 수행해야 합니다.
우리는 분류를 3단계로 나누었습니다.레이아웃 마무리, 중간 분류, 출력물 분류 단계
먼저, 레이다운 최종화라고 부르는 작업이 있습니다.
이 작업은 가시성 버퍼를 읽은 다음 패스당 각 타일에 어떤 배치 그룹이 사용되는지 마스크를 씁니다.
여기서 한 가지 주의할 점은 모든 것이 비저빌리티 버퍼에 기록되는 것은 아니라는 점입니다. 나중에 실행되는 지오메트리 패스는 일반 디퍼드 지오메트리로 G버퍼를 채웁니다.
모든 셰이더에 비저빌리티 버퍼를 쓰기 위해 또 다른 익스포트를 추가하고 싶지 않습니다.그래서 스텐실 버퍼의 비트를 사용하여 가시성 버퍼의 콘텐츠가 유효한지 여부를 나타냅니다.
비저빌리티 버퍼를 내려놓을 때 이 스텐실 비트를 쓰면 오버드로 양으로 인해 적지 않은 비용이 발생합니다.따라서 대신 레이다운 마무리 셰이더를 실행할 때 UAV를 통해 작성합니다.
그런 다음 지오메트리 패스의 배치가 이 스텐실 비트를 덮어씁니다.지오메트리 패스가 완료되면 스텐실 비트가 설정된 픽셀에만 유효한 가시성 버퍼 정보가 포함됩니다.
대신 레이다운 마무리 셰이더를 실행할 때 UAV를 통해 이를 작성합니다.
그러면 지오메트리 패스의 배치가 이 스텐실 비트를 덮어씁니다.
지오메트리 패스가 완료되면 스텐실 비트가 설정된 픽셀에만 유효한 가시성 버퍼 정보가 포함됩니다.
<참고: 패스당 32개의 배치 그룹 제한을 이해하려면 이 슬라이드 전에 보너스 슬라이드 108을 읽어보는 것이 좋습니다.
그런 다음 중간 분류 단계가 있습니다.
이 단계는 지오메트리 패스와 함께 실행할 수 있습니다.
이미 배치 그룹에 사용된 마스크가 있고 레이아웃 마무리에서 스텐실 버퍼를 채웠습니다.
다음으로 사용된 마스크를 가져와 팝카운트를 사용하여 비트를 합산하여 각 패스에서 각 타일에 사용된 배치 그룹 수를 계산합니다.
그리고 카운터의 오프셋을 얻기 위해 접두사 합계를 수행합니다.
이는 각 패스의 타일마다 32개의 배치 그룹 카운터를 모두 사용할 필요가 없도록 하기 위한 것으로, 현재 지원하는 최대치인 4K에서 256개의 패스를 사용하려면 카운터를 위한 16MB의 공간이 필요합니다.
하지만 대부분의 배치 그룹이 모든 타일에서 사용되는 것은 아니므로 실제로 사용될 카운터 세트를 계산하고 글로벌 카운터 버퍼에 오프셋을 저장하면 이보다 훨씬 적은 공간을 확보할 수 있습니다.
이 모든 작업이 진행되는 동안 지오메트리 패스는 계속 실행 중이며 스텐실 버퍼를 업데이트합니다.
그런 다음 스텐실 버퍼, 가시성 버퍼 및 타일 배치 그룹 카운터 오프셋을 읽고 각 패스의 각 타일에서 각 배치 그룹에 있는 픽셀 수를 계산합니다.
동시에 프리미티브 ID를 사용하여 사용된 버텍스를 디코딩하고 이를 버텍스 컬 버퍼에 기록합니다.
상황에 따라 한 씬에 수천만 개의 버텍스가 있을 수 있으므로 작업을 단순화하고 공간을 절약하기 위해 현재는 64개의 버텍스 청크 단위로만 이 작업을 수행합니다.
그런 다음 타일 배치 그룹 픽셀 수를 가져와 접두사 합계를 수행한 다음 패스당 타일당 각 배치 그룹에 대한 픽셀 명령을 기록하기 시작할 위치에 대한 오프셋 집합을 출력합니다.
지오메트리 패스가 아직 실행 중일 때 이 모든 작업을 실행할 수 있으므로 각 배치 그룹에 필요한 픽셀 명령의 수를 과도하게 추정할 수 있지만, 지오메트리 패스의 후반부로 갈수록 유효한 가시성 픽셀 수가 줄어들기 때문에 문제가 되지 않습니다.
이 모든 작업은 지오메트리 패스가 아직 진행 중일 때 실행할 수 있으므로 각 배치 그룹에 필요한 픽셀 명령의 수를 과도하게 추정할 수 있지만, 지오메트리 패스의 후반부로 갈수록 유효한 비저빌리티 픽셀 수가 줄어들기 때문에 문제가 되지 않는다는 점을 기억하세요.
이제 이 중간 분류 단계에서 각 패스에서 수행해야 할 버텍스 작업을 알려주는 버텍스 웨이브 명령을 생성하는 작업도 처리해야 합니다.이 계산의 주요 입력은 이전에 생성한 버텍스 컬 버퍼입니다.여기에는 버텍스 청크당 바이트가 설정되어 표시 여부를 나타냅니다.시간 관계상 이 프레젠테이션에서 버텍스 명령이 어떻게 생성되는지는 다루지 않겠지만, 관심이 있으시다면 이 프레젠테이션의 마지막에 있는 보너스 슬라이드에서 관련 슬라이드를 찾아보실 수 있습니다.
따라서 중간 분류가 완료되면 지오메트리 패스가 완료된 후 가시성 버퍼에서 실행되는 분류 출력 단계가 있습니다.
지오메트리 패스에서 업데이트되는 스텐실 버퍼는 가시성 버퍼의 어떤 항목이 실제로 유효한지 알려주는 데 사용됩니다.
그런 다음 이를 사용하여 다양한 명령을 작성할 수 있습니다.
픽셀 명령은 타일 내의 픽셀 X와 Y를 포함하는 픽셀 명령입니다.
또한 타일 좌표, 배치 그룹 ID, 픽셀 명령의 오프셋과 개수를 인코딩하는 픽셀 웨이브 명령도 작성합니다.
이 단계를 좀 더 자세히 살펴보겠습니다.여기서는 앞서 계산한 가시성 버퍼, 스텐실 버퍼 및 타일 배치 그룹 픽셀 출력 오프셋을 가져와 분류 출력 셰이더로 각 픽셀을 처리하는 것을 볼 수 있습니다.이렇게 하면 픽셀 명령과 함께 각 배치 그룹에서 각 패스의 각 타일에 사용된 픽셀 수에 대한 최종 카운트가 출력됩니다.그런 다음 이 카운트를 반올림하여 웨이브 정렬에 사용하고 이를 사용하여 패스당 타일당 각 배치 그룹에 필요한 웨이브 수를 계산할 수 있습니다.그런 다음 접두사 합계를 수행하여 픽셀 웨이브 명령을 출력해야 하는 위치를 파악할 수 있습니다.마지막으로 모든 패스와 타일에 대해 디스패치를 수행하여 픽셀 패스에 사용할 웨이브 명령과 디스패치 버퍼를 모두 출력할 수 있습니다.
이 모든 것이 GPU 타임라인에 어떻게 들어맞는지 살펴봅시다.
보시다시피 뎁스 및 가시성 패스 직후에 레이다운 마무리 작업을 시작합니다.
운이 좋으면 이 작업을 워터 큐브 맵의 면 렌더링과 동시에 실행할 수 있습니다.
그 후 지오메트리 패스가 시작되고 중간 분류 단계를 시작할 수 있습니다.
이를 통해 최종 분류 출력 단계를 준비할 수 있을 뿐만 아니라 정점을 컬링하고 정점 웨이브 명령을 출력할 수 있습니다.
지오메트리 패스가 그래픽스 파이프에서 실행되는 동안 중간 분류가 이루어지기 때문에 일부 결과는 보수적일 수 있습니다.
따라서 오클루드될 수 있는 일부 버텍스가 변형될 수 있습니다.
하지만 대부분의 주요 오클루더가 뎁스 프라임 패스에 있기 때문에 일반적으로 지오메트리 패스 이후에 정확한 결과를 기다리는 것보다 지오메트리 패스와 병렬로 실행하는 것이 더 낫다는 것을 알게 되었습니다.
또한 지오메트리 패스가 완료되기 전에 디퍼드 텍스처링 패스에 대한 버텍스 트랜스폼을 시작할 수 있습니다.
지오메트리 패스가 완료되면 최종 분류를 수행하고, 픽셀 및 웨이브 명령을 출력하고, 그림자를 렌더링하면서 픽셀 셰이딩을 시작합니다.
그런 다음 이미 작성된 G버퍼 값을 수정할 수 있는 데칼 등에 사용되는 커스텀 디퍼드 패스로 G버퍼 레이다운을 마무리합니다.
중간 분류를 지오메트리 패스의 끝으로 이동하는 대체 모드로 시스템을 실행할 수도 있습니다.이렇게 하면 지오메트리 패스와 병렬로 처리하는 작업이 줄어드는 대신 버텍스 컬링률이 높아지며, 지오메트리 밀도가 훨씬 높은 PS5에서 이 모드를 실험하고 있습니다.
파트 2에서 계속...
'TECH.ART.FLOW.IO' 카테고리의 다른 글
[주석번역,해석]수백만 개의 자산을 위한 확장 도구 (2) | 2024.01.02 |
---|---|
[주석번역]ADVENTURES WITH DEFERRED TEXTURING IN HORIZON FORBIDDEN WEST 파트-2 (1) | 2023.12.27 |
[주석번역/PPT한글화]horizon forbidden west 공간 효율적 패키징 (1) | 2023.12.21 |
[번역]FASTBuild로 UE4 및 UE5 컴파일하기 (0) | 2023.12.18 |
바이트덴스 조석광년 SGR 테크아트팀 구조. (0) | 2023.12.14 |