최근 GTK에 GL과 Vulkan을 위한 두 가지 새로운 통합 렌더러(ngl, vulkan)가 추가되었습니다. 단일 소스 기반, 구현 세부, 새로운 기능(안티앨리어싱, 분수 배율, 임의의 그라디언트, dmabuf), 주의할 점, 성능, 기본값 변경, 향후 계획을 다룹니다.
최근, GTK에는 하나가 아니라 두 개의 새로운 렌더러가 추가되었습니다. 하나는 GL용이고 다른 하나는 Vulkan용입니다.
이름 짓기는 늘 어렵기 때문에, 기존 이름을 재사용해 각각 “ngl”과 “vulkan”이라고 부릅니다. 이들은 동일한 소스에서 빌드되므로, 우리는 이들을 “통합(unified)” 렌더러라고도 부릅니다.
그렇다면, 무엇이 이들을 흥미롭게 만들까요?
이미 언급했듯이, 두 렌더러는 같은 소스에서 빌드됩니다. 이는 Vulkan API를 따르도록 모델링되어 있으며, Vulkan과 GL(좀 더 구체적으로는 GL 3.3+와 GLES 3.0+)의 차이를 포괄하기 위한 몇 가지 추상화를 포함합니다. 덕분에 장면 그래프를 순회하고, 변환과 기타 상태를 유지하며, 텍스처와 글리프를 캐시하는 등 많은 인프라를 공유할 수 있고, 두 렌더러를 최신 상태로 동기화하고 동등한 수준으로 유지하기도 쉬워집니다.
이 통합 접근법을 더 확장해, macOS의 Metal 기반 렌더러나 Windows의 DirectX 기반 렌더러까지 포괄할 수 있을까요? 아마도요. Vulkan/GL 조합의 장점은 이들이 기본적으로 동일한 셰이더 언어(GLSL, 약간의 변형 포함)를 공유한다는 점입니다. Metal이나 DirectX는 그렇지 않습니다. 그런 플랫폼에서는 셰이더를 중복 작성하거나 SPIRV-Cross 같은 변환 도구를 사용해야 합니다.
이런 종류의 작업에 흥미가 있다면, 도움을 환영합니다.
기존 GL 렌더러는 각 렌더노드 타입마다 단순한 셰이더를 사용하고, 더 복잡한 콘텐츠에는 종종 오프스크린 렌더링에 의존합니다. 통합 렌더러에도 (더 강력한) 노드별 셰이더가 있지만, 오프스크린에 의존하는 대신 버퍼의 데이터를 해석하는 복잡한 셰이더도 사용합니다. 게임 프로그래밍에서는 이런 접근을 우버셰이더(ubershader)라고 부릅니다.
통합 렌더러 구현은 기존 GL 렌더러에 비해 최적화는 덜 되어 있으며, 정확성과 유지보수성에 초점을 맞춰 작성되었습니다. 그 결과, 훨씬 더 다양한 렌더노드 트리를 정확하게 처리할 수 있습니다.
언뜻 무해해 보이는 예를 보겠습니다:
repeat {
bounds: 0 0 50 50;
child: border {
outline: 0 0 4.3 4.3;
widths: 1.3;
}
}
gl(왼쪽) / ngl(오른쪽)
확대 보기
이 모든 작업을 한 이유는 분명한 이점이 있기 때문입니다. 물론 새로운 기능과 능력도 포함됩니다. 몇 가지를 살펴보겠습니다.
안티앨리어싱. 기존 GL 렌더러의 큰 문제는 미세한 디테일을 잃어버린다는 점입니다. 어떤 것이 한 줄의 픽셀 경계 사이에 들어갈 만큼 작다면, 그냥 사라져 버립니다. 특히 단축키 표시(밑줄) 같은 텍스트 밑줄에 영향을 줄 수 있습니다. 통합 렌더러는 안티앨리어싱을 수행하여 이런 경우를 더 잘 처리합니다. 이는 미세한 디테일을 보존할 뿐만 아니라, 도형의 테두리에 톱니 모양이 생기는 것을 방지해 줍니다.
GL vs NGL 확대 비교
분수 배율(fractional scaling). 안티앨리어싱은 분수 배율을 제대로 처리하는 기반이 되기도 합니다. 1200 × 800 창을 125%로 배율 설정했을 때, 통합 렌더러는 합성기가 2400 × 1600 이미지를 다운스케일하도록 두는 대신, 1500 × 1000 크기의 프레임버퍼를 사용합니다. 훨씬 적은 픽셀로 더 선명한 이미지를 얻습니다.
임의의 그라디언트. 기존 GL 렌더러는 최대 6개의 색상 스톱을 가진 선형, 방사형, 원추형 그라디언트를 처리합니다. 통합 렌더러는 무제한 개수의 색상 스톱을 허용합니다. 또한 새로운 렌더러는 그라디언트에도 안티앨리어싱을 적용하므로, 날카로운 경계도 부드러운 선으로 표현됩니다.
64개의 색상 스톱을 가진 선형 그라디언트
Dmabuf. 새로운 렌더러와는 잠시 벗어나, 우리는 지난 가을 dmabuf 지원과 그래픽 오프로딩 작업을 진행했습니다. 새로운 렌더러는 이를 지원하며, render_texture API를 통해 텍스처 생성을 요청받았을 때 dmabuf를 생성하도록 확장했습니다(현재는 Vulkan 렌더러만 해당).
새로운 기능이 있는 만큼, 새로운 함정이 생길 수도 있습니다. 앱 개발자라면 다음 사항에 유의하세요.
glshader 노드 없음. 네, 4.0 시절에는 멋진 데모용으로 유용했지만, 해당 노드들은 기존 GL 렌더러가 노출하는 GLSL API에 대한 가정에 깊게 묶여 있습니다. 따라서 새로운 렌더러는 이를 지원하지 않습니다.
문서에서도 경고했습니다:
문제가 있을 경우, 이 함수는 FALSE를 반환하고 오류를 보고합니다. 렌더링에 셰이더를 의존하기 전에 반드시 이 함수를 사용해 확인하고, 실패할 경우 더 단순한 셰이더나 셰이더 없이 동작하는 폴백을 사용해야 합니다.
다행히도, glshader 노드의 많은 사용 사례는 이제 더 이상 필요하지 않습니다. GTK가 4.0 이후 마스크 노드나 straight-alpha 텍스처 지원 같은 새로운 기능을 얻었기 때문입니다.
소수점 좌표. 기존 GL 렌더러는 좌표를 반올림했기 때문에, 소수점 좌표를 넘겨도 어느 정도 괜찮았습니다. 새로운 렌더러는 여러분이 지정한 위치에 정확히 배치합니다. 이는 때때로 의도치 않은 결과를 낳을 수 있으므로, 좌표가 원하는 위치에 정확히 들어가도록 주의해야 합니다.
특히, 반 픽셀 위치에 선을 놓아 정확히 한 줄의 픽셀을 채우는 식의 cairo 스타일 드로잉을 주의하세요.
드라이버 문제. 새로운 렌더러는 그래픽 드라이버를 새롭고 다른 방식으로 사용하므로, 드라이버 측 문제를 유발할 가능성이 있습니다.
문제가 드라이버 이슈처럼 보여도 GTK에 이슈를 보고해 주세요. 다양한 드라이버와 하드웨어에서 새로운 코드가 얼마나 잘(또는 잘 안) 동작하는지 파악하는 데 큰 도움이 됩니다.
아니요, 아직은 그렇지 않습니다.
기존 GL 렌더러는 속도를 위해 강하게 최적화되어 있습니다. 또한 훨씬 단순한 셰이더를 사용하며, 안티앨리어싱 같은 기능에 필요한 연산을 수행하지 않습니다. 우리는 언젠가 새로운 렌더러를 더 빠르게 만들고 싶지만, 새로운 기능과 정확성만으로도 그 목표에 도달하기 전부터 충분히 매력적입니다. 모든 GPU 기반 렌더러는 오늘날의 GTK 애플리케이션을 60 또는 144 fps로 렌더링하기에 충분히 빠릅니다.
그럼에도 불구하고, Vulkan 렌더러는 일부 비과학적 벤치마크에서 기존 GL 렌더러에 근접하거나 능가하기도 합니다. 새로운 GL 렌더러는 아직 알 수 없는 이유로 더 느립니다.
방금 릴리스된 4.13.6 스냅샷에서, 우리는 ngl 렌더러를 새로운 기본값으로 지정했습니다. 이는 시범적 조치로 — 다양한 애플리케이션과의 광범위한 테스트를 통해 프로덕션 준비가 되었는지 확인하려는 목적입니다. 중대한 문제가 나타나면 4.14에서는 gl 렌더러로 되돌릴 수 있습니다.
우리는 Vulkan 렌더러를 아직 기본값으로 삼지 않기로 했습니다. 몇 가지 애플리케이션 통합 측면에서 GL 렌더러들보다 뒤처져 있기 때문입니다. 예를 들어 WebKit GTK4 포트는 GL로 동작하며 Vulkan은 지원하지 않고, GtkGLArea와 GtkMediaStream은 현재 둘 다 Vulkan 렌더러가 직접 가져올 수 없는 GL 텍스처를 생성합니다. 이러한 이슈들은 멀지 않은 미래에 해결되길 바라며, 그때 기본 렌더러 결정을 다시 검토할 것입니다.
아주 오래된 하드웨어에서 GTK를 사용 중이라면, GPU 요구 사항이 더 적은 기존 GL 렌더러가 더 나을 수 있습니다. GSK_RENDERER 환경 변수를 사용해 렌더러 선택을 재정의할 수 있습니다:
GSK_RENDERER=gl
새 렌더러는 우리가 오랫동안 원해 왔던 다음과 같은 기능을 구현하기 위한 훌륭한 기반입니다.
이 가운데 일부는 가까운 미래와 중기적인 기간에 우리의 주요 작업 초점이 될 것입니다.
새 렌더러는 흥미로운 기능을 제공하며, 앞으로도 더 많은 기능이 추가될 것입니다.
직접 사용해 보고, 잘 동작하는 점과 그렇지 않은 점을 알려 주세요.