Figma 렌더링: Web (새 탭에서 열림)
Figma는 기존 WebGL 렌더러를 WebGPU 기반으로 확장해 GPU 병렬 처리와 더 명확한 오류 처리, 새로운 렌더링 최적화 기회를 확보했다. 다만 단순히 API를 교체하는 방식으로는 성능 향상을 보장할 수 없었기 때문에, WebGL 호환성을 유지하면서 그래픽 인터페이스와 셰이더·버퍼 처리 방식을 함께 재설계했다. 이 과정은 성능 회귀와 기능 중단을 피하기 위해 단계적으로 진행됐다. ## WebGL에서 WebGPU로 전환한 배경 - Figma는 2015년부터 브라우저에서 무한 캔버스를 구현하기 위해 WebGL을 사용했다. - 당시 WebGL은 3D 중심 API였지만, Figma는 이를 복잡한 2D 디자인 도구에도 적용할 수 있다고 판단했다. - 2023년 Chromium에 WebGPU 지원이 추가되면서 WebGL에서는 어려웠던 최적화가 가능해졌다. - 특히 컴퓨트 셰이더를 활용해 CPU 작업을 GPU의 대규모 병렬 처리로 옮길 수 있다. - WebGPU는 WebGL의 전역 상태 중심 구조보다 오류 처리가 명확하고, 상태 관리로 인한 버그도 줄일 수 있다. ## 드로 콜 인자를 명시적으로 관리 - 기존 WebGL 방식은 버텍스 버퍼, 텍스처, 머티리얼, 프레임버퍼 등을 전역 바인딩 지점에 먼저 연결한 뒤 `draw()`를 호출했다. - 바인딩된 리소스는 이후에도 유지되므로, 일부 입력을 갱신하지 않아 이전 상태가 남는 문제가 발생할 수 있었다. - Figma는 다음처럼 드로 콜에 필요한 리소스를 함수 인자로 직접 전달하도록 인터페이스를 변경했다. ```cpp context->draw(vertexBuffer, framebuffer, {texture}, material, …); ``` - WebGL 구현에서는 필요한 경우에만 실제 바인딩을 갱신하도록 지연 업데이트를 적용했다. - 이 변경은 WebGPU 도입 전에도 입력 누락으로 발생하던 WebGL 렌더러의 버그를 해결했다. - 각 드로 콜의 의존성이 코드에 명확히 드러나므로 유지보수성과 안정성도 향상됐다. ## GLSL과 WGSL을 함께 지원하는 셰이더 처리 - 셰이더는 GPU에서 실행되어 최종 픽셀을 생성하는 프로그램이다. - WebGL은 GLSL을 사용하지만 WebGPU는 WGSL을 사용하므로, 기존 GLSL 셰이더를 모두 WGSL로 수동 변환하면 두 버전을 중복 관리해야 했다. - Figma의 기존 셰이더는 WebGL 1용 구형 GLSL 형식이어서 일반적인 변환 도구만으로는 처리하기 어려웠다. - Figma는 자체 셰이더 프로세서와 오픈소스 도구 `naga`를 조합했다. - 기존 GLSL을 파싱한다. - 최신 GLSL 구조에 맞게 필요한 변환을 수행한다. - `naga`를 이용해 WGSL로 변환한다. - 최종적으로 GLSL과 WGSL을 모두 생성한다. - 변환 과정에서 셰이더 입력 타입과 데이터 레이아웃 같은 메타데이터도 추출해 애플리케이션에서 활용한다. - 파일 include 기능도 제공해 셰이더 코드의 모듈화와 재사용성을 높였다. ## WebGPU에 맞춘 유니폼 버퍼 설계 - 유니폼은 셰이더에 전달되는 전역 변수와 같은 데이터로, 색상이나 변환 행렬 등을 전달하는 데 사용된다. - WebGL에서는 각 유니폼을 개별적으로 설정할 수 있었다. ```javascript gl.uniform1f(locationAlpha, alphaValue); gl.uniformMatrix3fv(locationTransform, false, transformValue); ``` - Figma의 기존 인터페이스도 이 모델을 따라 유니폼을 하나씩 설정했다. - 그러나 WebGPU에서는 유니폼을 개별 호출로 전달할 수 없고, 여러 값을 하나의 유니폼 버퍼에 기록한 뒤 GPU에 한 번에 업로드해야 한다. - 따라서 WebGL API를 그대로 흉내 내 WebGPU를 구현하면 호출 오버헤드와 데이터 업로드 비용 때문에 성능이 오히려 저하될 수 있다. - WebGPU 전환의 핵심은 API 이름을 바꾸는 것이 아니라, 버퍼 레이아웃과 데이터 업로드 방식을 GPU 친화적으로 재설계하는 데 있다. ## 실용적인 결론 WebGPU 도입은 단순한 렌더링 API 교체가 아니라 상태 관리, 셰이더 컴파일, 유니폼 버퍼 구조까지 재설계하는 작업이다. 기존 API와의 호환성을 유지하되 드로 콜의 입력을 명시적으로 만들고, 셰이더 변환을 자동화하며, GPU 버퍼 단위로 데이터를 처리해야 성능과 안정성을 함께 확보할 수 있다.