Skip to main content

Metal과 함께한 3년

7월

23, 2020

by coberst


테크

지금으로부터 3년 전, Roblox는 렌더러를 Metal로 포팅하는 작업을 수행했습니다. 시간도 많이 걸리지 않았고, 획기적이었으며 iOS에서 매우 잘 작동했죠. 그래서 그 과정에서 있었던 결정 과정에 대해, 그리고 그 결과(결론: 매우 훌륭!)에 대한 글을 쓰기도 했습니다. 그때의 기록은 여전히 대부분 ​​유효하지만, 현재의 Metal은 그 어느 때보다도 개선된 성능을 자랑합니다. 이에 우리는 지난 3년 간의 업데이트를 기록한 글을 다시 작성하기로 했습니다.

그럼 시간을 거슬러 올라가 지금이 2016년 12월이고, 당시 iOS용으로 자체 개발한 Metal 렌더러를 막 적용했다고 가정해 봅시다.

왜 Metal이어야 하는가?

지난 2014년 WWDC에서 Apple이 Metal을 처음 소개했을 때 저는 별다른 감흥을 느끼지 못했습니다. 일단 우리 사용자 대다수가 가지고 있지 않은 최신 하드웨어에서만 이용할 수 있는 API였고, Metal이 CPU 성능 문제를 해결했다고는 하지만 작은 규모의 시장을 겨냥하기 위해 이를 최적화한다는 건 가장 빠른 기기와 가장 느린 기기 간의 격차를 더욱 확대하는 결과를 낳는 것이기 때문이었습니다. 당시 Roblox에서는 Apple 전용으로 OpenGL ES2를 사용하고 있었고, Android로 포팅을 시작하던 차였습니다.

그렇게 2년 반이라는 시간이 흘렀습니다. 이제 사용자 관점에서 Metal의 시장 점유율을 살펴보겠습니다.

일단 이전보다 훨씬 매력적인 면모를 지니고 있습니다. 사실 Metal의 구현은 여전히 구형 기기에는 별 도움이 되지 않습니다. 하지만 iOS에서의 GL 시장이 점점 위축되고 있고 구형 기기에서 작동하는 콘텐츠는 최신 기기에서 작동하는 콘텐츠와 다른 경우가 많습니다. 따라서 속도를 향상시키는 데 주력해야 합니다. 이제 iOS Metal 코드를 작성하면 별다른 변경 없이 Mac에서 실행됩니다. 그러면 모바일 위주의 사업이라도 이 코드는 Mac에서 사용하는 것이 합리적일 수도 있습니다. (현재 Roblox에서는 iOS용 Metal 빌드만 제공합니다.)

이제 시장 점유율을 보다 면밀히 분석해 볼 필요가 있습니다. 현재 iOS에서는 iOS 8.3 이상용 Metal을 지원하고 있습니다. 따라서 버전 제한으로 인해 Metal을 사용할 수 없는 일부 사용자들이 있습니다. 현재 GL을 사용 중인 25%의 사용자는 대개 SGX 하드웨어를 갖춘 구형 기기를 이용하고 있는데, 이 기기들은 OpenGL ES 3의 기능을 전혀 갖추고 있지 않습니다. 따라서 우리는 사양이 더 낮은 로우엔드 렌더링 경로를 사용하는 정도에 만족하고 있습니다. (물론 모든 기기에서 Metal을 사용하면 좋을 것입니다. 다행히 GL와 Metal의 양분화는 완화될 전망입니다.) Mac에서는 보다 최신 버전의 Metal API를 사용하고, 운영체제가 중요한 요소입니다. Metal을 사용하려면 최소 사양이 OSX 10.11은 되어야 하는데, 사용자의 절반은 그보다 더 구형의 운영체제를 사용하고 있습니다. 즉 이는 하드웨어보다는 소프트웨어 문제입니다. (Mac 사용자의 95%는 OpenGL 3.2 이상을 사용합니다.)

따라서 이러한 시장 점유율을 감안하면 Metal로 포팅을 하지 않고 적용 가능한 대안들이 아직 있습니다. 그중 하나는 MoltenGL을 사용하는 것입니다. MoltenGL은 기존에 이미 지원 중인 OpenGL 코드를 이용하며 보다 빠른 속도로 작동합니다. 또 다른 대안은 PC에서의 성능을 개선하고 궁극적으로 Android로 포팅하기 위해 Vulkan으로 포팅한 후 MoltenVK를 사용하는 것입니다. 이에 간단히 MoltenGL을 테스트해 봤는데, 결과가 썩 마음에 들지는 않았습니다. 코드를 실행시키는 데 시간이 꽤 걸렸고, 스톡 OpenGL에 비해 성능은 아주 조금 더 나은 정도에 불과했기 때문입니다. MoltenVK의 경우, 하나의 로우레벨 API를 다른 API 위에 쌓을 레이어로 구현하는 것은 잘못된 판단이라고 생각합니다. 임피던스 불일치가 발생하여 최적의 성능을 이끌어내지 못합니다. 이전에 사용하던 하이레벨 API보다는 나을 수 있지만, 속도를 극대화하기 어렵습니다. 그러므로 처음부터 로우레벨 API를 사용해야 합니다. 또한 Metal을 구현하는 작업이 Vulkan보다 훨씬 간단하다는 점도 중요합니다. (자세한 내용은 아래에서 다루고 있습니다.) 결론적으로, Vulkan -> Metal 보다는 Metal -> Vulkan 래퍼의 작업이 더 바람직해 보입니다.

최신 아이폰의 iOS 10에는 GL 드라이버가 없다는 점도 염두에 두어야 합니다. GL은 Metal 위에 구현됩니다. 즉 OpenGL을 사용해야 개발 비용을 조금이라도 절감할 수 있습니다. ‘한 번 작성하면 어디에서든 작동한다’는 OpenGL의 특징은 모바일 기기에서는 유효하지 않기 때문에 아주 많은 비용을 절감하기는 어렵습니다.

포팅

Metal로 포팅하는 작업은 전반적으로 매우 수월했습니다. 우리는 Direct3D 9/11 같은 하이레벨 API부터 PS4 GNM 같은 로우레벨 API까지 다양한 그래픽스 API를 다룬 폭넓은 경험을 가지고 있습니다. 따라서 Metal처럼 적당히 하이레벨인 API를 편하게 다룰 수 있다는 독보적인 장점이 있지만, CPU-GPU 동기화 등 앱 개발자로서 수행해야 하는 몇 가지 작업이 있었습니다.

우선 최대 난제는 셰이더 컴파일 작업이었습니다. 이 작업을 끝낸 후에야 코드를 작성할 수 있었습니다. Metal은 매우 간단하고 부연 설명이 필요 없는 API이므로 코드가 자동으로 작성되는 것이나 다름없었습니다. 그리하여 하루 10시간 이내에 최적화하지 않은 상태에서 대부분의 요소를 렌더링한 포트를 작동시킬 수 있었습니다. 그리고 나서 2주 동안 코드 클린업, 검증 문제 해결, 프로파일링, 최적화 등 마무리 작업을 진행했습니다. 이 기간 동안 API 구현을 할 수 있었다는 결과 자체가 그 API와 툴셋의 품질이 얼마나 좋은지를 증명합니다. 이 결과에 기여한 요인들은 아래와 같습니다.

  • 개발자는 매 단계마다 좋은 피드백을 얻어가면서 코드를 점진적으로 개발할 수 있습니다. 우리는 CPU-GPU 동기화를 모두 무시하고, 상태 설정의 일부분은 최적화하지 않으면서, 각종 리소스에 대한 빌트인 참조 추적을 이용하고, 모든 문제를 미연에 방지하기 위해 CPU와 GPU를 절대로 함께 사용하지 않는 상태에서 코드를 개발했습니다. 결론적으로, 렌더링 능력을 훼손하지 않고 최적화 및 마무리 단계에서 제공할 수 있는 완성품을 만들어낼 수 있었습니다.
  • 필요한 툴은 이미 준비되어 있고 모든 툴이 효과적으로 작동합니다. Direct3D 11에 익숙한 사용자에게는 그리 놀라운 일이 아닐지도 모릅니다. 하지만 CPU 프로파일러, GPU 프로파일러, GPU 디버거, GPU API 검증 레이어가 다같이 제대로 작동한 모바일 사례는 처음이었습니다. 덕분에 개발 단계에서 대부분의 문제를 방지할 수 있었고, 코드를 최적화하는 데 도움이 되었습니다.
  • Metal은 Direct3D 11보다 다소 로우레벨이고, 개발자는 렌더링 패스 설정이나 동기화 등 여러 가지 로우레벨 의사결정을 진행해야 합니다. 그러나 Metal은 각 리소스가 ‘사용량 플래그’를 포함하되 파이프라인 배리어나 레이아웃 전환이 필요하지 않은 전형적인 리소스 모델을 이용합니다. 또한 각 셰이더 스테이지에 여러 개의 슬롯이 있어 리소스를 자유롭게 할당할 수 있는 전형적인 바인딩 모델을 이용합니다. 이 두 모델은 개발자가 이해하기 쉽고 익숙한 모델이며, 매우 제한적인 양의 코드만 있어도 빠르게 작동할 수 있습니다.

또 다른 기여 요인은 Metal 같은 API에 대응할 수 있는 자체적인 API 인터페이스를 가지고 있었다는 점입니다. 매우 간소화된 인터페이스지만 충분한 양의 디테일(렌더링 패스 등)을 노출시켜 적당히 우수한 성능의 API를 쉽게 구현할 수 있습니다. 우리는 구현 과정에서 어떠한 상태 저장이나 복원도 할 필요가 없었습니다. (다른 API 인터페이스의 경우, 렌더링 타깃을 설정하면서 상태를 변경하거나 리소스 또는 상태 바인딩이 지속되어 문제가 발생합니다.) 또는 리소스 수명이나 동기화에 대해 복잡한 결정을 할 필요도 없었습니다. 렌더링에 필요한 ‘복잡한’ 코드가 있다면, 바로 코드를 생성하는 데 필요한 비트를 해싱하여 렌더링 파이프라인 상태를 생성하는 코드뿐입니다. 파이프라인 상태 객체들은 우리가 개발한 API 추상화의 일부가 아닙니다. 심지어 이 코드마저도 매우 간단하고 빠릅니다. 우리가 개발한 API 인터페이스에 대해서는 별도의 글을 통해 소개하겠습니다.

셰이더 컴파일에 1주, 최적화된 구현1에 2주가 걸렸는데 그 결과는 어땠을까요? 매우 우수했습니다. Metal은 완벽하게 우리가 예상한 수준의 성능을 보였습니다. 일단 싱글 스레드 디스패치 성능의 경우, OpenGL에 비해 현저히 우월합니다. (작업량에 따라 다르지만, 우리가 보유한 렌더링 프레임의 드로잉 디스패치 부분은 2~3배 정도 축소했습니다.) 이는 이중화 상태 설정을 줄이고 빠른 경로를 이용해서 드라이버를 제대로 활용했다는 점에서 우리의 OpenGL 구현 작업이 꽤 성공적임을 나타냅니다. 하지만 이것이 전부가 아닙니다. 렌더링 코드만 제대로 준비되어 있다면, Metal에서 멀티 스레드 작업을 수행하는 것은 매우 쉽습니다. 아직 스레드 드로잉 디스패치로 전환하지 않았지만, 렌더링 스레드 밖에서 리소스를 생성하는 다른 파트들을 이미 변환하기 시작했습니다. OpenGL과는 달리 Metal에서는 매우 쉽게 할 수 있는 작업입니다.

게다가 Metal에서는 쉽게 접근 가능하고 믿을 수 있는 툴을 이용할 수 있어 다른 성능 문제들도 개선할 수 있습니다. 우리가 개발한 렌더링 코드의 핵심적인 특징 중 하나는 월드 공간에 있는 CPU의 라이팅 데이터를 연산하여 3D 텍스처의 일부 영역들로 업로드하는 시스템입니다. (3D 텍스처의 해당 영역들은 우리가 OpenGL ES 2 하드웨어에서 에뮬레이션해야 합니다.) 업데이트는 부분적으로 이루어지므로 전체 텍스처를 복제할 수 없습니다. 드라이버가 glTexSubImage3D를 어떻게 구현하느냐에 달려 있습니다. 우리는 업데이트 성능을 개선하려고 PBO를 사용하기도 했지만 Android든 iOS든 전반적으로 안정성이 현저히 저하되는 문제가 발생했습니다. Metal에서는 영역(region)을 업로드할 수 있는 두 가지 기본적인 내장 옵션이 있습니다. GPU가 해당 텍스처를 읽지 못하는 경우 사용할 수 있는 MTLTexture.replaceRegion과, GPU가 이 텍스처를 이용할 수 있도록 적시에 해당 영역을 비동기적으로 업로드할 수 있는 MTLBlitCommandEncoder(copyFromBufferToTexture 또는 copyFromTextureToTexture)가 있습니다.

두 방법 모두 기대보다는 속도가 느렸습니다. 첫 번째는 효율적인 부분 업데이트를 지원하기 위해 이용할 수 없는 옵션이었습니다. 매우 느린 어드레스 번역 구현으로 CPU에서만 작동하는 옵션입니다. 두 번째는 이용할 수 있는 옵션이지만 3D 텍스처를 채우기 위해 일련의 2D 블리트를 이용해야 합니다. 2D 블리트는 CPU에서 명령어를 설정하기에는 비용이 많이 들고, 이유가 무엇이든지 간에 GPU 오버헤드가 매우 높았습니다. OpenGL이었다면 엄두도 내지 못했을 것입니다. 위의 두 방법을 사용하여 이끌어내는 성능이 OpenGL에서 이러한 업데이트를 진행하는 데 드는 예상 비용에 상응했습니다. 다행히 Metal에서는 쉬운 접근으로 셰이더를 연산할 수 있습니다. 매우 간소화된 연산 셰이더를 통해 버퍼에서 3D 텍스처로 업로드할 수 있습니다.> CPU와 GPU에서는 매우 빠르게 수행할 수 있으므로 코드 개발 시 성능 문제를 근본적으로 해결합니다2.

요약하자면, Metal 코드를 유지하는 것은 매우 쉽습니다. 지금까지 우리가 추가한 부가 기능들은 우리가 지원하는 그 어떠한 API보다도 추가하기가 쉬웠습니다. 이 트렌드는 꾸준히 지속될 것으로 예상합니다. 한 가지 이상 API를 추가하면 지속적인 유지보수가 필요한데, OpenGL에 비해 그다지 많은 노력을 기울이지 않아도 됩니다. OpenGL ES 3을 iOS에서 지원할 필요가 없으므로, 우리가 가지고 있는 일부 OpenGL 코드를 간소화할 수 있습니다.

안정성

현재 Metal은 iOS에서 매우 안정적으로 작동합니다. 2014년 론칭 당시 상황이 어떠했는지, 현재 Mac에서는 어떻게 작동할지 모르지만, iOS에서는 드라이버와 툴이 모두 제대로 작동합니다.

iOS 10의 경우, Xcode 7으로 컴파일한 셰이더를 로딩하면서 드라이버 문제가 발생했습니다(Xcode 8을 사용하여 이 문제를 해결했습니다). 알고 보니 nextDrawable API를 잘못 사용하는 바람에 iOS 9에서 드라이버 하나가 크래시(충돌)된 것이었습니다. 그 외의 행동 버그나 크래시 문제는 발생하지 않았습니다. 비교적 최신 버전의 API Metal은 전반적으로 매우 잘 작동합니다.

또한 Metal에서는 다양한 툴을 이용할 수 있습니다. 구체적으로 나열하면 아래와 같습니다.

  • Metal API 이용 시 흔히 발생하는 문제들을 파악하는 포괄적인 검증 레이어. Direct3D 디버그와 유사합니다. Direct3D 사용자라면 익숙하지만 OpenGl 사용자에게는 낯선 개념일 것입니다. (이론적으로 ARB_debug_callback으로 이 문제를 해결할 수 있지만, 실제로는 이용할 수 없고 유용하지도 않습니다.)
  • 명령어 상태, 타깃 콘텐츠, 텍스처 콘텐츠 등과 함께 디스패치한 모든 명령어를 표시하는 GPU 디버거. 셰이더 디버거를 사용해 본 적이 없어서 이 디버거를 포함하는지는 알 수 없습니다. 버퍼 검사도 수월할 수 있지만, GPU 디버거로도 대체로 충분합니다.
  • 패스당 성능 통계자료(시간, 대역폭 등), 셰이더당 실행시간을 표시하는 GPU 프로파일러. GPU는 타일러이기 때문에 드로우콜당 타이밍을 예측할 수는 없습니다. iOS에서 사용하는 그래픽 API 인터페이스에서 GPU 타이밍 정보를 완전히 구할 수 없다는 점을 감안하면, 이 정도의 가시성도 매우 훌륭한 수준입니다.
  • GPUView처럼 CPU와 GPU 렌더링 작업량의 일정을 표시하는 CPU/GPU 타임라인 기록장치(즉 Metal System Trace). 사용하기 쉽고 UI의 일부 특징들을 모듈로 연산합니다.
  • 셰이더 신택스(문법)를 검증하고, 유용한 경고를 표시하며, 셰이더를 실행시간에 빠르게 로딩하는 로딩 바이너리 라지 오브젝트(이진 데이터 모임)로 변환하고, 적당히 최적화가 가능하며, 드라이버 컴파일러가 빠르게 작동하므로 로딩 타임을 줄일 수 있는 오프라인 셰이더 컴파일러.

Direct3D나 콘솔 사용자의 경우 이 모든 기능을 사용할 수 있다는 사실을 당연시할 수도 있습니다. 하지만 OpenGL에서는 그렇지 않기 때문에 사용자들 사이에서 열렬한 반응을 불러일으켰습니다. 특히 종종 고장이 발생하는 드라이버, 검증 기능 부재, GPU 디버거나 유용한 GPU 프로파일러의 부재, GPU 스케줄링 데이터를 수집할 능력의 부재, 벤더가 별도의 파서를 이용하여 텍스트 기반 셰이더 언어를 다루어야 하는 문제 등을 맞닥뜨리는 모바일 환경에서는 더욱 그러합니다.

Metal은 코드를 작성하기에도 훌륭한 API고 애플리케이션을 함께 제공하기에도 뛰어난 API입니다. 사용하기도 쉽고 성능 수준도 예측할 수 있습니다. 견고한 드라이버와 우수한 툴셋을 갖추고 있습니다. 휴대성 측면만 제외하면 모든 면에서 OpenGL보다 우수합니다. iOS, Android, Mac 플랫폼에서 모두 OpenGL을 사용해야 했다면, 이제 이 플랫폼들 중에서 두 가지는 Metal을 지원하고 있습니다. 또한 OpenGL의 휴대성도 완벽하지는 않습니다. 한 가지 플랫폼에서 작성하는 코드가 모종의 이유로 다른 플랫폼에서는 작동하지 않는 경우도 있기 때문입니다.

Unity나 UE4 등 독립적인 엔진을 사용하는 고객의 경우, 이 엔진들은 이미 Metal을 지원하고 있습니다. 그래픽 프로그래밍을 즐기거나 성능을 중요시하여 iOS나 Mac을 선호하는 사용자의 경우, Metal을 사용해 볼 것을 권장합니다. 실망하지 않으실 것입니다.

현재의 Metal

지난 3년 간 우리의 입장에서 볼 때 Metal에 생긴 가장 큰 변화는 바로 Metal이 대규모로 폭넓게 도입되었다는 점입니다.

3년 전만 해도 시중 모든 기기의 ¼ 정도가 OpenGL을 이용했습니다. 하지만 현재 우리 사용자만 봐도 이 숫자는 2% 미만에 불과합니다. 즉 OpenGL 백엔드가 더 이상 중요하지 않다는 뜻입니다. 우리도 아직 OpenGL을 사용하고 있지만 오래 지속하지는 않을 예정입니다.

드라이버의 상태 또한 최상입니다. iOS에서 드라이버로 인한 문제는 거의 발생하지 않습니다. 문제가 생겨도 초기 프로토타입에서만 발생합니다. 프로토타입이 양산 단계에 이를 때쯤에면 문제는 대개 해결된 상태입니다.

우리는 얼마간의 시간을 들여 Metal 백엔드를 개선했습니다. 주 개선 영역은 아래와 같습니다.

셰이더 컴필레이션 툴체인 재작업

지난 3년 사이에 있었던 또 다른 사건은 Vulkan의 출시와 개발이었습니다. Metal과 Vulkan은 완전히 다른 API인 것처럼 보이는데(실제로 완전히 다릅니다), Vulkan을 이용하는 렌더러들은 성능이 뛰어난 오픈소스 툴들을 얻게 되는데, 이 툴들은 사용하기 쉬운 프로덕션 품질 컴필레이션 툴셋을 구성합니다.

우리는 (연산 셰이더를 비롯한 다양한 DX11 기능들을 이용하여) HLSL 소스코드를 SPIRV로 컴파일 작업하고, 이 SPIRV를 최적화하여 MSL(Metal 셰이딩 언어)로 변환할 수 있는 컴필레이션 툴체인을 구축하기 위해 우리가 보유한 라이브러리들을 이용했습니다. 새로 만든 툴체인은 DX9 HLSL 소스만 입력 데이터로 사용하고 복잡한 셰이더과 관련된 여러 가지 정확성 문제들을 가지고 있던 이전의 툴체인을 대체합니다.

위의 내용이 Apple과는 별 상관이 없다는 사실이 다소 모순적이기는 합니다. glslang(https://github.com/KhronosGroup/glslang), spirv-opt(https://github.com/KhronosGroup/SPIRV-Tools), SPIRV-Cross(https://github.com/KhronosGroup/SPIRV-Cross)의 컨트리뷰터들과 메인테이너들에게 깊은 감사를 표합니다. 우리는 새로 개발한 툴체인을 제공하기 위해 이 라이브러리들에 패치들을 기여했고, 우리의 셰이더들을 Vulkan, Metal, OpenGL API로 다시 타겟팅(리타겟팅)하기 위해 새 툴체인을 이용했습니다.

macOS 지원

macOS 포트는 언제나 잠재적 고려 대상이었지만, 우리가 일부 기능을 다시 사용하고 싶다고 생각하기 전까지는 주 관심 대상이 아니었습니다. 렌더링 속도를 높이고 미래의 잠재력을 확인해 보기 위해 macOS에서 Metal을 이용해 보기로 했습니다.

우선 구현 측면에서 전혀 어려운 작업이 아니었습니다. API(Metal)의 대부분은 대체로 똑같습니다. 윈도우 관리를 제외하면, 실질적인 개선이 필요한 부분은 메모리 할당뿐이었습니다. 모바일에는 버퍼, 텍스처를 위한 공유 메모리 공간이 있습니다. 반면 데스크톱에서 Metal은 자체적인 동영상 메모리를 갖춘 전용 GPU를 전제로 합니다.

이 문제는 관리된 리소스를 이용하여 빠르게 해결할 수 있습니다. Metal을 실행하면 알아서 데이터 복사를 진행합니다. 우리는 이런 방식으로 우리가 개발한 제품의 첫 번째 버전을 공개할 수 있었습니다. 그러나 추후 스크래치 버퍼를 이용하여 보다 명시적으로 리소스 데이터를 복사하기 위해 구현된 버전을 재작업했습니다. 결론적으로 시스템 메모리 오버헤드를 최소화할 수 있었습니다.

macOS와 iOS의 가장 큰 차이점은 안정성입니다. iOS의 경우, 한 가지 아키텍처에서 단 하나의 드라이버 벤더를 다루지만, macOS에서는 벤더 세 곳(Intel, AMD, NVidia) 모두를 지원해야 합니다. 또한 iOS에서는 다행히도 Metal을 이용할 수 있었던 *첫 번째* iOS 버전(iOS 8)을 건너뛸 수 있었습니다. macOS에서는 당시 Metal을 이용할 수 있던 고객이 거의 없었기 때문에 불가능했습니다. 이러한 문제들로 인하여 macOS에서는 Metal API의 아주 위험하지 않고 비교적 잘 알려지지 않은 부분에서 발생하는 수많은 드라이버 관련 문제들에 직면하게 되었습니다.

우리는 여전히 macOS Metal의 모든 버전(10.11 이상)을 지원합니다. 그러나 고치기 어려운 셰이더 컴파일러 버그들이 있는 일부 버전의 경우, 지원을 중단하고 레거시 OpenGL 백엔드로 전환하기 시작했습니다. 예를 들어, 10.11 버전에서는 Metal을 이용하려면 macOS 10.11.6이 있어야 합니다.

성능도 우리가 예상하는 수준과 일치했습니다. 시장 점유율의 경우, 현재 macOS 플랫폼에서 사용자 비율은 OpenGL이 25% 이하, Metal이 75% 이하입니다. 꽤 바람직한 비율입니다. 조만간 우리가 지원하는 다른 플랫폼에서는 OpenGL을 더 이상 사용하지 않을 것이므로 데스크톱 버전의 OpenGL 지원 중단이 실용적인 결정일 것입니다. 그러면 보다 쉽게 지원할 수 있고 우수한 성능을 이끌어낼 수 있는 API에 주력할 수 있게 됩니다.

성능 및 메모리 소비에 관한 반복

우리는 사용 중인 그래픽 API 기능들과 관련해서는 언제나 꽤 보수적인 행보를 보였습니다. Metal도 마찬가지입니다. 지난 수년 동안 Metal은 명시적인 힙을 갖춘 개선된 리소스 할당 API, Metal 2를 갖춘 타일 셰이더, 인수 버퍼, GPU측 명령어 생성 등 여러 번의 대규모 기능 업데이트를 거쳐 왔습니다.

우리는 이러한 최신 기능들은 별로 사용하지 않습니다. 지금 보유한 버전으로도 적당히 우수한 성능을 이끌어낼 수 있고, 전반적으로 개선해야 할 사항에 주력하고자 합니다. 렌더러에서 매우 특수한 지원을 필요로 하고, 최신 버전의 하드웨어를 통해서만 접속이 가능한 타일 셰이더 같은 기능에는 별로 흥미가 없습니다.

그렇지만 단순히 속도를 높이기 위한 목적으로 백엔드의 여러 가지 부분들을 다루어보고 있습니다. 레벨 로딩 동안 스터터링 현상을 줄이기 위해 완전히 비동기적인 텍스처 업로드를 이용하거나(매우 수월), 위에서 언급한 macOS에서 메모리 최적화를 시도하거나, 캐시 미스를 줄여서 백엔드의 다양한 부분에 대해 CPU 디스패치를 최적화하거나, 새로운 섀도우 시스템에 필요한 메모리 용량을 현저히 줄이기 위해 메모리가 없는 텍스처 스토리지를 이용합니다(명시적인 지원이 필요한 몇 안 되는 최신 기능 중 하나입니다.)

향후 전망

전반적으로 Metal 기능을 향상시키는 데 너무 많은 시간을 할애하지 않는 것이 현명한 결정이었습니다. 3년 전에 작성한 코드는 대체로 잘 작동하고, 우수한 속도와 안정성을 보장하며, 성숙한 API의 좋은 지표가 됩니다. Metal 포팅 작업은 소요 시간, 우리 및 사용자를 위한 지속적인 이점 등을 고려하면 매우 현명한 투자 결정이었습니다.

우리는 다양한 API를 다루는 데 필요한 작업량을 얼마나 균형있게 배분해야 하는지 지속적으로 검토하고 있습니다. 앞으로 렌더링 프로젝트를 진행한다면 Metal API의 보다 최신 기능들을 더 자세히 살펴봐야 할 것입니다. 그렇게 되면 이와 관련하여 새로운 글 또한 작성할 계획입니다.


  1. 테스트 중에 발견한 버그를 고치는 데 1주일 정도 소요.
  2. A10에서 프레임당 128 KB정도의 데이터(32x16x32 RGBA8 영역 두 개)를 가리키는 숫자.

Roblox Corporation이나 이 블로그는 특정 회사나 서비스를 홍보하지 않습니다. 또한 블로그에 포함된 정보의 정확성, 신뢰성, 완전성에 대하여 어떠한 보장이나 약속도 하지 않습니다.

이 블로그 게시물은 Roblox 테크 블로그에 수록된 글입니다.