본문 바로가기

GPU

Ep 2.4 : Engine and API best practices

https://youtu.be/5FV-jYKBRsM

위 영상을 요약한 글입니다. Mali를 포함한 mobile GPU에서 API 또는 컨텐츠 별 최적화 방안을 제시합니다.

 

  • Graphics API는 복잡하다 - Arm Mali GPU Best developer’s guide 에 자세한 권장사항을 적어두었으니, 참고할 것을 권함
  • 가장 많이 맞닥뜨리는 상황은, 어떤 목표한 퍼포먼스 타겟을 만족하나, 때때로 프레임을 드랍시키는 frame hitching 상황이다. 이것은 거의 대부분 비싼 리소스 업로드 - 또는 critical path의 비싼 리소스 동기화 때문이다.
    • 큰 텍스처를 업로드하거나, 큰 버퍼를 업로드하거나, 셰이더 프로그램을 컴파일하거나 링크하는 동작들이 완료되는 데 상당한 양의 CPU time을 소비한다.
    → 가능한 한 레벨 로드 시에 리소스를 메모리에 로드해 둔다. 이렇게 해서 그것들이 필요할 때 메모리에 이미 존재하도록 해 둔다.
  • 게임플레이 중 스트리밍 로드를 수행할 경우, 리소스가 Critical path 에 부담을 주지 않도록 백그라운드 스레드를 사용하자. 이렇게 하면 메인 렌더 스레드가 계속 프레임을 렌더링 할 수 있다..
  • 원래 존재하던 buffer나 텍스처를 수정할 경우, 리소스의 그 전 값을 사용하는 모든 드로우콜이 완료되었는지 확실히 하자. 아직 참조되고 있는 리소스를 수정하려고 시도하는 것은 비싼 메모리 할당을 일으킬 수 있고, 파이프라인을 stall시키지 않기 위해 원본 리소스에서 드라이버가 생성한 새로운 복사본을 만들 수 있다.
  • 반면, buffer의 경우에서는 glMapBuffer() 을 GL_MAP_UNSYNCHRONIZED 로 사용해서 어플리케이션에서 리소스 동기화를 수동으로 제어하고 있다는 것을 명시할 수 있다.

CPU Load

극단적인 경우, 렌더링 과정에서 1개 또는 그 이상의 CPU Core가 critical path가 되면서 어플리케이션이 cpu 병목이 된다.

하지만, 만약 cpu에 제한이 없더라도, thermal budget과 전원 효율을 향상시키기 위해 CPU 부담을 줄일 가치가 있다. 가장 흔한 CPU 병목의 어플리케이션은 프레임 당 드로우콜 갯수가 너무 많은 경우이다. 드로우콜은 드라이버가 보통의 프레임 렌더링에서 수행할 수 있는 가장 비싼 동작이다. 왜냐하면, 드라이버가 command stream으로 render state 묶음을 보내야 하기 때문이다.

 

  • 권장사항은 프레임당 500 드로우콜 이하를 유지하는 것이다. 특히 보급형 기기들을 타겟팅 할 때에 그렇다.
  • 같은 render state를 가진 여러 개의 오브젝트를 1개의 드로우콜로 batching 하는 것이 드로우 카운트를 낮추는 가장 좋은 테크닉이다.
  • 모든 드로우콜에 같은 비용이 드는 것은 아니다. 드로우 콜 간의 state 또는 resource binding을 변경하는 것은, command stream에 드로우콜을 보낼 때, 여러 개의 descripter를 재빌드해야 하는 것을 의미한다.
    → 드로우 당 비용을 줄이려면 드로우콜 간의 state 변경 횟수를 최소화하도록 한다.
  • state의 갯수를 줄이는 것의 한 가지 이점은 여러 개의 오브젝트를 1개의 커다란 드로우 콜로 배칭하기 쉽도록 만든다는 것이다.
  • 마지막으로, 어플리케이션에서 렌더링을 병렬로 수행할 수 있는지 살펴본다. low frequency 의 코어를 여러 개 돌리는 것이 high frequency 코어 하나를 돌리는 것보다 더 에너지 효율이 좋기 때문에, 멀티스레딩이 CPU 온도 budget을 아끼는 데 강력한 테크닉이 된다.
  • Vulkan API에서는 CPU 부담을 줄이는 것이 주 디자인 목적 중 하나이다. 명시적인 state contruction 이 드로우콜 비용을 줄여주고, 명시적인 context model이 렌더링 코드를 멀티스레딩 하기 좋게끔 해 준다.
  • 보통 서로 상충하는 최적화 목표들 중에서는 1개의 정답이 없다. 드로우콜을 Batching 하는 것은 드로우 콜 개수를 줄이는 가장 효율적인 방법이지만, 배치 사이즈가 커진다는 것은 CPU 쪽의 frustum culling, occlusion culling, depth sorting 모두 덜 효율적이 된다는 것을 의미한다. 당신의 컨텐츠에 알맞는 스윗스팟을 찾아가는 실험을 하라.

 

Rendering

일단 적당한 숫자의 드로우콜을 찾았다면, 이제 가장 최선의 방법으로 기기로 dispatch하는 것이 중요해진다. Early ZS Test unit에서 가장 최선의 결과를 얻으려면, 세 가지 pass를 통한 접근으로 렌더링을 해 볼 것을 추천한다.

먼저, 앞에서부터 뒤 순서로 모든 fixed coverage인 불투명 오브젝트를 그린다. 이렇게 하면 depth buffer가 카메라 기준으로 가장 가까운 값으로 채워지도록 보장한다 - depth testing에서 fail 하는 fragment가 최대가 된다. 그 다음은, 셰이더 기반의 알파 테스팅 또는 Alpha-to-coverage 를 사용하는, 여러 종류의 coverage 의 불투명한 오브젝트들을 앞에서부터 뒤 순서로 그린다 이렇게 앞에서부터 뒤 순서대로 그리는 것은 dependent layer들을 최소화하고, 셰이더 코어에서의 fragment 스레드 스케쥴링을 향상시킨다. 마지막으로, blending을 사용하는 모든 투명한 오브젝트들을 뒤에서부터 앞 순서대로 그린다. 이렇게 해야 블렌딩이 올바르게 보이도록 보장이 되면서, 불투명한 오브젝트들의 depth value에 대한 작업을 가능한 한 줄이게 된다.

 

일반적으로 많이 하는 질문 중 하나는, 이런 종류의 depth sorting이, 대부분의 GPU - Mali를 포함해서 - 들이 어떤 형태의 hidden surface removal 을 수행함애도 불구하고, 여전히 할 가치가 있는지이다. 여기에 대한 답은 그렇다 - 여전히 할 가치가 있다 이다. hidden surface removal 은 완벽하지 않고, Early-ZS만큼 효율적으로 특정 상황에 대응할 수 없다. 저비용의 싼 sorting을 수행하는 것은 거의 항상 좋다. 완벽할 필요가 없고, Early ZS test를 최대한 활용하기 위한 것이다.

이 시점에서, 퍼포먼스에 영향을 줄 수 있는 또다른 셋팉들을 살펴보는 것도 좋다. 닫힌 메시 오브젝트 전부가 facing test 가 허용되어 있는지 확인하자 - 모델에서 뒤를 향하고 있는 부분들이 cull 될 수 있도록 말이다. 투명할 필요가 없는 메시들에서 blending 과 alpha-to-coverage가 비활성화 되어 있는지도 확인하자.

 

Prepass

콘솔과 데스크탑 렌더링에서 depth-only prepass는 보편적인 테크닉이다. 이 패스들은 불투명한 지오메트리를 두 번 렌더한다 - 첫 번째는 depth buffer 내용을 채우고, 두 번째는 저장된 depth 값과 일치하는 픽셀들에 대해 color shading 을 수행한다. 이 테크닉을 퍼포먼스 최적화를 사용하는 것은 모바일 기기에서는 대체로 별로 알맞지 않다. depth prepass를 사용하면 드로우콜 갯수가 두 배가 되고, 장면의 triangle count를 증가시킨다. 이 두 가지는 모두 에너지 효율 측면에서 좋지 않거니와, prepass에서 얻을 수 있을 이득의 대부분을 하드웨어에서 수행되는 backed hidden surface removal 에서 취할 수 있다.

 

Depth prepass는 폴리지 같은 몇몇 컨텐츠에서는 유용할 수 있는데, 폴리지는 alpha-to-coverate 또는 alpha-testing 같은 것들을 사용하는 다양한 coverage mask를 가지기 때문이다. 이것들은 coverage mask mutability 때문에 hidden surface occluder가 될 수 없다. 따라서, 일반적인 불투명한 오브젝트들을 prepass 없이 먼저 그리고, 폴리지 같은 것들만 depth prepass에 앞에서 뒤 순서로 렌더링하면, 상당한 양의 overdraw가 있을 경우에 도움이 될 수 있다.

'GPU' 카테고리의 다른 글

Ep 2.5 Content best practices  (0) 2024.05.26
Ep 2.2 : Best practice principles  (1) 2024.04.08
Unreal에서의 GPU Crash Debugging  (1) 2023.12.17
Shader Programs 최적화  (0) 2023.09.02