모바일 렌더링에서 Vulkan의 대역폭과 동기화를 이해하기 위한 기사

1. 모바일 GPU 아키텍처

즉시 모드 렌더링 아키텍처(IMR)

6f938a9e9872d4fff6621d3d266812fa.png

대부분의 초기 PC 측 GPU는 IMR 아키텍처를 사용했습니다. IMR 아키텍처의 일반적인 흐름은 그림에 나와 있습니다. 각 픽셀에 대해 몇 번의 색상/깊이 읽기 및 쓰기 후 최종적으로 프레임 버퍼로 그려지는 점은 주목할 가치가 있습니다. 이러한 각 읽기 및 쓰기는 메모리와 직접 상호 작용합니다. 따라서 빈번한 메모리 읽기 및 쓰기는 많은 대역폭을 소비하며 이 프로세스는 많은 열을 발생시킵니다. PC의 경우 더 높은 화질과 프레임 속도를 위해 더 나은 팬과 방열 장치를 사용하여 외부에서 발열 문제를 해결할 수 있지만 공간이 매우 제한된 휴대폰의 경우 방열 장치를 설치하는 것은 확실히 불가능합니다.

타일 ​​기반 렌더링 아키텍처(TBR)

따라서 대역폭으로 인한 열 문제를 해결하기 위해 휴대폰 GPU는 일반적으로 타일 기반 아키텍처를 사용합니다.Adreno/Mali/PowerVR GPU는 이를 기반으로 고유한 최적화를 가지고 있습니다.예를 들어 PowerVR의 TBDR 아키텍처의 HSR은 완전히 제거할 수 있습니다. 불투명 객체를 렌더링할 때 오버드로가 발생하므로 여기서는 다루지 않습니다.

그러나 핵심 아이디어는 동일하며 모두 GPU를 위한 온칩 메모리를 개방합니다.이 온칩 메모리의 특징은 메모리와의 상호 작용에 비해 GPU는 매우 작습니다.

타일 ​​기반 렌더링은 전체 프레임 버퍼를 여러 개의 타일로 분할합니다. 각 타일의 내용이 완전히 그려지기 전에 GPU는 온칩 메모리만 읽고 씁니다. 타일이 완전히 렌더링된 후 온칩 메모리의 내용은 렌더링 메모리에 일회성 쓰기, 다음 그림은 전체 그리기 프로세스를 설명합니다.

5bf3a7812e7d2638066fa9176afb7a5f.png

이와 같이 원래 각 픽셀을 그리기 위해서는 메모리의 직접 읽기 및 쓰기가 필요하지만 지금은 읽기 및 쓰기 오버헤드가 매우 낮은 온칩 메모리로 변경되어 대역폭을 절약하고 전력 소비를 줄입니다.

2. Vulkan을 사용하는 이유는 무엇입니까?

이것은 또한 모바일 렌더링 개발에서 고려해야 하는 문제로, 엔진 기술 팀은 프로젝트 요구 사항, Vulkan API 및 관련 휴대폰 하드웨어 기능을 매우 명확하게 이해해야 합니다. Vulkan API에는 다음과 같은 특별한 이점이 있습니다.

1) 드라이버가 더 얇아졌습니다. Vulkan은 최하위 계층에 가깝고 드라이버는 GLES와 같이 많은 추측과 판단을 하지 않기 때문에 잘 사용하면 CPU 부하를 크게 줄일 수 있습니다.

2) Vulkan은 명시적인 동기화 및 대역폭 제어 명령을 제공하며 이러한 명령을 효과적이고 올바르게 사용하면 GPU 작동 효율성을 높이고 GPU 전력 소비를 줄일 수 있습니다.

3) Vulkan은 다중 스레드 렌더링을 더 잘 지원하는 명령 버퍼 아키텍처를 굽고 제출합니다. 예를 들어 Unity PC 끝은 보조 명령 버퍼 멀티스레딩을 사용하여 동일한 장면에서 동시에 개체를 렌더링하고 UE는 Vulkan의 특성을 사용하여 렌더링 스레드에서 RHI 스레드를 분리하고 멀티 코어 로드를 평균화하며 멀티 코어 효율성.

4) Vulkan 표준은 상대적으로 새롭고 가치가 높기 때문에 Vulkan 표준을 사용자 정의할 때 최신 하드웨어 기능을 사용하는 많은 방법을 직접 포함합니다.

따라서 합리적인 스케줄링의 경우 Vulkan은 드라이버 얇음과 멀티 스레딩으로 인한 CPU 이점을 누릴 수 있습니다. GPU 측면에서 하드웨어 아키텍처와 각 드라이버의 특성을 완전히 이해하고 동기화 및 대역폭을 수동으로 제어하면 게임 성능을 효과적으로 향상시킬 수 있습니다. 그러나 일부 프로젝트는 종종 렌더링 알고리즘을 최적화하거나 렌더링 프로세스를 개선하거나 사용자 지정 렌더링 파이프라인을 추가하는 데 많은 시간과 에너지를 소비하지만 특정 하드웨어 기능을 이해하지 못하거나 특정 API를 잘못 사용하기 때문에 성능 저하가 매우 심각하거나 최적화된 알고리즘이 부정적으로 개선되며, 이 영역에서 다소 부족한 초기 Unity 및 Unreal 기본 모바일 렌더링 파이프라인을 포함합니다.

3. 게임의 대역폭과 소비전력

아주 간단한 예부터 시작하겠습니다.

e584aafce9a41f61ebb36c862fdbf464.png

위의 그림은 Unity의 렌더링 커맨드 버퍼로 구현된 커스텀 후처리 렌더링 프로세스입니다. 렌더 타겟을 전환할 때 기본 인터페이스를 사용하여 RT를 설정하고 하단 레이어로 전달하면 Vulkan 렌더패스의 로드 동작이 로드, 즉 이전 렌더링 결과가 유지되는 것을 볼 수 있습니다.

그리고 다음 인터페이스를 사용하여 Vulkan의 로드 동작을 dontcare로 변경하기 위해 rendertarget의 loadaction을 명시적으로 설정하면 GPU가 바인딩되었을 때 프레임 속도가 1프레임 이상 증가한 것을 확인할 수 있습니다.

5390811b127e895ed4d919878b879ee2.png

이는 타일 기반 아키텍처에서 이 렌더 타겟을 로드할 때 렌더 타겟이 메모리에서 온칩 메모리로 로드되기 때문에 추가 오버헤드가 발생하기 때문입니다. 그리고 dontcare를 명시적으로 설정하면 로딩 시간과 대역폭이 줄어들고 GPU bound의 경우 성능 향상이 프레임 속도에 직접 반영됩니다.

지연 렌더링에서 타일 기반 렌더링 적용

c1f2f86541d54d9e445d3c78ec7fe39e.png

기존의 디퍼드 렌더링 방식에서는 Gbuffer를 렌더링한 후 메모리에 기록한 다음 조명 단계에서 gbuffer를 샘플링합니다. 그리고 조명 단계에서 각 픽셀은 자체 픽셀 위치에서 gbuffer 정보가 필요하기 때문에 subpass를 사용하여 gbuffer를 온칩 메모리에 저장하고 후속 조명에서 온칩 메모리에서 직접 읽을 수 있습니다. 단계. 먼저 메모리를 저장한 다음 두 번 샘플링하는 대역폭 소비를 절약합니다.

다음은 지연 렌더링의 데모이며, 왼쪽은 샘플 방식, 오른쪽은 서브패스 방식입니다.

6b54979cdf412eedca4633e9c71a1a26.png

두 경우 모두 조명 알고리즘, 해상도, 조명 수, GPU 주파수를 포함한 fps가 모두 고정되어 있습니다. 유일한 차이점은 메모리와 상호 작용하는지 여부인데 왼쪽은 샘플링 메모리에 저장된 Gbuffer이고 오른쪽은 메모리와 전혀 상호 작용하지 않고 직접 온칩 메모리를 쓰고 읽습니다.

a2aca24ea48832cbad9e59de2fa585eb.png

쉐이더의 계산량은 동일하나 서브패스 솔루션에 의해 메모리 주파수와 대역폭이 크게 향상됨을 테스트 결과에서 확인할 수 있으며, 여기서 읽기 및 쓰기 대역폭은 총 4.9Gb/s 감소하였고, 메모리 주파수도 감소합니다.

69fcd0fbd1abb0b5f9aa59c2b380eb11.png

프레임 속도, GPU 사용량, 주파수 차이가 없는 경우 순전히 대역폭 감소로 인해 567mW의 전력 차이가 발생했으며 GPU의 평균 온도도 5도 감소했습니다.

96ae4476eb3d7f9e58edc777a2431445.png

일반적인 참고사항입니다.메모리 대역폭에서 발생하는 전력 소비량은 GPU의 전력 소비량과 거의 동일합니다.메모리 대역폭 1GB를 소비할 때마다 약 120mW의 전력 소비량을 생성하며 이는 이전과도 일치합니다. 5GB, 567mW 테스트 결과.

지연된 렌더링뿐만 아니라 렌더링 프로세스에서 현재 픽셀 위치의 역사적 색상과 깊이를 읽으려는 한 하위 패스를 사용할 수 있습니다. 예를 들어 일부 입자 효과의 데칼, 반투명 렌더링, MSAA 안티앨리어싱 등은 서브패스를 합리적으로 사용하면 대역폭 측면에서 상당한 이점을 얻을 수 있습니다.

물론 타일 기반 아키텍처에는 여전히 몇 가지 단점이 있습니다.

예를 들어 타일링 단계에서는 모든 VS 계산이 완료되어야 하고 모든 가변은 메모리에 저장되어야 하므로 IMR에 비해 기하학 데이터를 가져오는 일반적인 오버헤드 외에도 타일링 단계에는 추가 지연이 있습니다. 및 대역폭 소비.

204a28b56521687892bfa278e08a8bb5.png

따라서 정점 데이터의 구성도 매우 중요합니다. 예를 들어 아래 그림에 표시된 사용자 지정 정점 데이터에서 aColor는 사용자 지정 렌더링을 위해 조각 셰이더로 전달됩니다.

ffd0a2a840634b3ca0ca0ca6ddf58524.png

각 데이터는 유효 숫자가 1개뿐인 정수이지만 32비트 형식으로 저장됩니다. 모델이 복잡하고 정점이 많은 경우에도 상당한 오버헤드가 발생합니다. 실제로 16비트 또는 8비트 형식으로도 충분합니다. 따라서 프로젝트에서 각 정점 데이터의 용도를 아는 경우에는 가능한 가장 작은 형식을 사용해야 합니다.

인덱스 기반 버텍스 쉐이딩(IDVS)

아래 그림은 지오메트리 데이터 가져오기 대역폭을 줄이기 위해 ARM에서 수행한 최적화를 보여줍니다.엄밀히 말하면 TBR 아키텍처를 위해 특별히 설계된 최적화라고 볼 수는 없지만 그 이점은 매우 큽니다.

7f3663e61a35e712e6902ba8bd37b132.png

IDVS의 아이디어는 VS에서 위치 관련 계산만 먼저 하고 제거가 완료된 후 다른 속성 데이터를 가져오고 가변 관련 계산을 수행한다는 것입니다. 그러나 이 최적화를 위해서는 개발자가 위치 및 기타 속성을 별도의 버퍼에 저장해야 GPU가 이를 개별적으로 가져올 수 있습니다.

시장에 나와있는 대부분의 모바일 게임은 왼쪽에 있고 모든 정점 데이터는 동일한 vkbuffer에 저장됩니다. vs가 무거운 경우에 따라 둘 사이의 전력 소비 격차가 30%를 초과합니다. 따라서 정점 데이터가 복잡한 경우 정점 데이터를 분할할 가치가 있습니다.

4. Vulkan의 동기화

Vulkan 동기화에서 매우 중요한 요소는 파이프라인 장벽입니다.프로젝트가 엔진의 기본 파이프라인을 수정하는 한 분명히 파이프라인 장벽의 수정이 포함됩니다.실제로 거의 모든 프로젝트에는 일부 부적절한 용도가 있습니다. 또한 프로젝트 개발 주기가 상대적으로 길고 이전 버전의 Unity 및 Unreal 엔진을 사용하는 경우 네이티브 코드가 다소 부적절하게 사용될 수 있습니다.

다음 세 가지 사항은 Vulkan 사양에서 위에서 언급한 파이프라인 배리어의 역할입니다.

첫째, 실행 순서를 제어할 수 있습니다.GPU가 실제로 명령어를 실행할 때 반드시 우리가 명령어를 제출한 순서대로 실행할 필요는 없습니다.따라서 명령어 사이에 파이프라인 장벽을 추가하면 장벽 이전의 명령어가 장벽 뒤의 명령 전입니다. 명령이 실행됩니다.

명령어가 시작되는 순서만 보장되며 병렬의 경우 명령어가 끝나는 순서를 제어할 수 없으며 메모리 수정이 포함되면 문제가 발생합니다.

둘째, 파이프라인 장벽은 나중에 자세히 설명할 명령 간의 메모리 종속성도 보장합니다.

세 번째 포인트는 이미지의 레이아웃 변환이 실제로 똑같이 중요하다는 것입니다 관심 있는 독자는 관련 정보를 참조할 수 있습니다.

위험

실제 상황은 훨씬 더 복잡하기 때문에 여기서는 읽기-쓰기 모델을 GPU 코어-캐시-메모리의 세 부분으로 단순화합니다.

a7e72c511b390a8ebf64e6e1aa5ad35b.png

데이터를 쓸 때 GPU 코어는 캐시를 수정한 후 캐시를 플러시하고 그 안의 데이터를 메모리에 복사해야 하는데, 이 과정을 메모리 사용 가능 상태라고 합니다.

GPU 코어가 데이터를 읽을 때 먼저 캐시를 무효화하고 메모리에 있는 데이터를 캐시에 로드해야 하는데, 이 과정을 메모리 가시화라고 합니다.

이 단순화된 모델을 이해한 후 메모리 읽기 및 쓰기의 세 가지 위험인 쓰기 후 읽기, 쓰기 후 쓰기 및 읽기 후 쓰기를 살펴보겠습니다.

쓰기 후 읽기와 같은 동기화가 없으면 읽기 명령이 실행될 때 이전 쓰기 명령이 메모리를 수정할 시간이 없어 렌더링 오류가 발생할 수 있습니다. 동기화 명령.

WAR, RAW, WAW를 처리하는 Pipline Barrier의 특정 프로세스

세 가지 문제 중 가장 좋은 해결책은 읽은 후 쓰는 것으로, 파이프라인 배리어를 통해 명령어 실행 순서를 제한하는 한 데이터 읽기의 정확성을 보장할 수 있다. 읽기 명령이 먼저 실행되기 때문에 데이터는 이미 캐시에 로드되었으며 최악의 경우에도 후속 쓰기 작업이 즉시 완료되고 메모리의 내용만 수정되며 읽고 있는 내용에는 영향을 미치지 않습니다. 캐시에 로드된 데이터입니다.

다음으로 약간 더 복잡한 다른 두 가지 동기화를 살펴보겠습니다.

파이프라인 단계 마스크 및 액세스 마스크는 파이프라인 장벽이 적용되는 메모리 세그먼트를 결정합니다. 그런 다음 동일한 메모리 세그먼트를 먼저 쓴 다음 읽는 경우 모든 데이터를 메모리에 쓴 후에 읽기 작업을 수행해야 합니다.

1c73fad21b6e000f49550026875aab57.png

따라서 파이프라인 장벽의 보호 아래 오른쪽 상단에 전체 동기화 프로세스가 표시됩니다.

먼저 읽기 명령이 차단되고 쓰기 명령이 실행되기를 기다립니다. srcAccessMask는 데이터가 메모리에 기록되도록 이 메모리를 사용 가능하게 만드는 것을 의미합니다. dstAccessMask는 이 메모리를 표시하는 것, 즉 방금 메모리에 쓴 데이터가 캐시에 성공적으로 로드되었는지 확인하는 것을 의미합니다.

마지막으로 읽기 명령을 실행합니다. 이 방법으로 전체 메모리 동기화가 완료됩니다.

쓰기 후 쓰기의 원리는 비슷합니다.먼저 두 번째 쓰기 작업을 차단하고 첫 번째 쓰기 작업이 완료될 때까지 기다렸다가 데이터가 메모리에 플러시된 후 다음 쓰기 작업을 수행합니다.

0cf97896fd57f3332e6d3e4e408a9517.png

위는 read-after-write의 전형적인 동기식 예입니다. 이것은 Gbuffer를 읽기 위해 샘플링을 사용하는 지연된 렌더링 데모입니다. 시뮬레이션은 게임에서 가장 일반적인 프로세스입니다. RT를 먼저 렌더링한 다음 조각을 나중에 렌더링하는 것입니다. 셰이더는 이 RT의 결과를 샘플링합니다. 지연된 렌더링 외에도 그림자 맵, sss, 일부 실시간 바람 필드, 발자국 전처리 등이 일반적입니다.

오른쪽은 완전히 맞습니다.먼저 조명 단계에서 fs를 차단한 다음 이전 Gbuffer 단계에서 색상 출력 단계의 색상 부착으로 쓰여진 메모리를 사용 가능하게 한 다음 동일한 메모리를 가시화하여 조명 단계의 fs가 Gbuffer를 올바르게 읽을 수 있도록 fs 차단을 해제합니다.

왼쪽의 유일한 차이점은 대기해야 하는 프래그먼트 단계가 정점으로 변경되어 정점 쉐이딩 단계에서 GPU가 미리 파이프라인을 차단하게 한다는 것입니다.

이 문제는 매우 숨겨져 있습니다.우선 Vulkan의 유효성 검사 계층은 오류가 아니라 비효율적이기 때문에 오류를 보고하지 않습니다. ALU, 읽기 및 쓰기 대역폭, 렌더링 시간을 대략적으로 테스트해보면 그래프에서 이들 데이터의 테스트 결과에서 거의 차이가 없음을 알 수 있습니다. 따라서 이 질문은 쉽게 간과됩니다.

테스트 분석 도구 사용

각 Soc 제조업체는 Mali 칩용 Mali Streamline, PowerVR 칩용 PVRTune, Qualcomm용 Snapdragon 프로파일러와 같은 자체 GPU 분석 및 테스트 도구를 제공합니다. 이 예에서 사용하는 휴대폰은 Mali GPU이므로 분석을 위해 Mali의 테스트 도구를 사용합니다.

82f09ea26655360ef0f14535d38a7464.png

위의 그림과 같이 계산량과 읽기 및 쓰기 대역폭에는 차이가 없으며 변경되는 것은 External Bus Read Latency와 External Bus Stall뿐입니다.

354802fb6a954a4782f0135403639621.png

특히, 메모리 버스에서 데이터를 읽는 차단 주기에는 6배의 간격이 있는데, 이는 우리의 동기화 명령이 대기 단계가 정점 음영 단계에 더 일찍 도달하도록 하기 때문입니다. 그러나 GPU 주파수가 충분히 높고 장면이 GPU 경계에 도달할 만큼 복잡하지 않기 때문에 이러한 지연은 프레임 속도에 영향을 미칠 만큼 충분히 높지 않습니다.

이제 인위적으로 GPU 주파수를 제한하고 GPU 바운드 상황을 시뮬레이트하면 메모리 버스 읽기 및 쓰기 지연을 커버할 수 없으며 문제가 노출됩니다.

b613f50af44fc2652eff8d0668496bfc.png

Bus Stall이 프레임 속도에 미치는 영향은 여전히 ​​명백함을 알 수 있습니다.프레임 시간 차이는 3밀리초, 즉 8개 프레임을 깊이 테스트하지 않으면 이 문제를 무시하기 쉽습니다.렌더링 압력이 점차 증가하고 문제가 노출되면 원래 원인을 찾지 못할 수도 있습니다.

요약하면 동기화 문제는 매우 중요합니다.코어-캐시-메모리 모델을 완전히 이해하고 파이프라인이 어떤 위험에 직면하는지 명확하게 알고 파이프라인 장벽을 올바르게 사용하여 수동 제어로 인한 성능 이점을 최대한 활용해야 합니다. 동기화.

기타 동기화 지침

물론 Vulkan에는 barrier와 거의 동일한 subpass dependency와 같은 다른 많은 동기화 명령이 있지만 renderpass에서 첨부 파일과 관련된 메모리만 동기화할 수 있습니다. Queue 간의 동기화는 Semaphore, GPU와 CPU의 동기화는 Fence를 사용 이벤트는 모바일 게임에서는 거의 사용하지 않음 현재 엔진을 수정한 게임 한두 개를 제외하고는 최신 언리얼 버전만 모바일에서 사용 가능 셰이딩 렌더러 오클루전 쿼리 부분에서 사용합니다.

5. 요약

이 글은 먼저 모바일 렌더링 아키텍처와 그 특징을 소개하고, Vulkan API의 장점을 설명하고, 실제 테스트 결과를 바탕으로 Tile 기반 렌더링의 장단점을 분석하고, 마지막으로 Vulkan의 명시적 동기화 제어에 초점을 맞추고, 구체적인 시나리오와 측정된 데이터를 기반으로 최적화 방안을 제시하고 근본 원인을 분석합니다.

독자들이 이 기사를 통해 Vulkan API 및 모바일 렌더링 아키텍처에 대해 더 깊이 이해하고 특정 개발 시나리오를 결합하고 테스트 분석 도구를 합리적으로 사용하여 모바일 렌더링에서 전력 소비, 대역폭 및 동기화 문제를 개선할 수 있기를 바랍니다.

참조

PowerVR의 장점(imgtec.com)

https://docs.imgtec.com/Architecture_Guides/PowerVR_Architecture/topics/powervr_architecture_the_powervr_advantage.html

동기화 예 · KhronosGroup/Vulkan-Docs Wiki · GitHub

https://github.com/KhronosGroup/Vulkan-Docs/wiki/Synchronization-Examples

모바일 개발자를 위한 ARM 소프트웨어/Vulkan 모범 사례

https://github.com/ARM-software/vulkan_best_practice_for_mobile_developers

SaschaWillems/Vulkan: 새로운 Vulkan API의 예 및 데모

https://github.com/SaschaWillems/Vulkan

Vulkan 사용 권장 사항 | 삼성 개발자

https://developer.samsung.com/galaxy-gamedev/resources/articles/usage.html

발두크/렌더독

https://github.com/baldurk/renderdoc

Snapdragon 프로파일러 - Qualcomm 개발자 네트워크

https://developer.qualcomm.com/software/snapdragon-profiler

과거

예상하다

푸시

추천하다

2023년 Arm의 최신 프로세서 아키텍처 분석 - X4, A720 및 A520

실시간 미리보기 | Linux 커널 페이지에서 Folio로의 변경 사항

좋은 이름의 중요성: Linux 커널 페이지에서 Folio로 변경

44d3228a1699b67ff4cd5e5adef79f14.gif

Kernel Craftsman WeChat을 팔로우하려면 길게 누르세요.

Linux 커널 블랙 기술 | 기술 문서 | 주요 자습서

추천

출처blog.csdn.net/feelabclihu/article/details/131989994