WebGPU: 브라우저에서 최신 GPU 액세스 활용

WebGPU가 GPU의 성능을 활용하여 머신러닝 성능과 그래픽 렌더링을 개선하는 방법을 알아보세요.

새로운 WebGPU API를 사용하면 그래픽 및 머신러닝 워크로드에서 성능이 대폭 향상됩니다. 이 문서에서는 WebGPU가 현재 WebGL의 솔루션을 어떻게 개선했는지 살펴보고 향후 개발 내용을 살짝 살펴봅니다. 하지만 먼저 WebGPU가 개발된 이유에 관한 맥락을 살펴보겠습니다.

WebGPU의 컨텍스트

2011년 Chrome에 WebGL이 도입되었습니다. WebGL은 웹 애플리케이션이 GPU를 활용하도록 함으로써 Google 어스, 대화형 뮤직비디오, 3D 부동산 둘러보기 등에 이르기까지 웹에서 놀라운 경험을 제공합니다. WebGL은 1992년에 처음 개발된 OpenGL API 제품군을 기반으로 했습니다. 꽤 오래됐네! 그 이후로 GPU 하드웨어가 크게 발전했다고 생각할 수 있습니다.

이러한 발전에 발맞추기 위해 최신 GPU 하드웨어와 보다 효율적으로 상호작용할 수 있는 새로운 종류의 API가 개발되었습니다. Direct3D 12, Metal, Vulkan 등의 API 이러한 새로운 API는 머신러닝의 폭발적인 증가와 렌더링 알고리즘의 발전과 같이 새롭고 까다로운 GPU 프로그래밍 사용 사례를 지원했습니다. WebGPU는 이 새로운 최신 API 클래스의 발전을 웹에 제공하는 WebGL의 후속 제품입니다.

WebGPU를 사용하면 브라우저에서 다양한 새로운 GPU 프로그래밍 가능성을 활용할 수 있습니다. 최신 GPU 하드웨어의 작동 방식을 더 잘 반영하는 동시에 향후 고급 GPU 기능을 위한 기반을 마련합니다. 이 API는 2017년부터 W3C의 '웹용 GPU' 그룹에 포함되어 왔으며 Apple, Google, Mozilla, Microsoft, Intel과 같은 여러 기업 간의 협업을 통해 탄생했습니다. 6년의 작업 끝에 드디어 웹 플랫폼에 추가된 가장 큰 기능 중 하나를 사용할 수 있게 되었다는 기쁜 소식을 전해 드립니다.

현재 ChromeOS, macOS, Windows의 Chrome 113에서 WebGPU를 사용할 수 있으며 다른 플랫폼에서도 곧 지원될 예정입니다. 다른 Chromium 참여자와 Intel의 도움을 주신 분께 깊은 감사의 말씀을 전합니다.

이제 WebGPU로 가능한 몇 가지 흥미로운 사용 사례를 살펴보겠습니다.

렌더링을 위한 새로운 GPU 워크로드 활용

컴퓨팅 셰이더와 같은 WebGPU 기능을 사용하면 새로운 알고리즘 클래스를 GPU에 포팅할 수 있습니다. 예를 들어 장면에 더 동적인 디테일을 더하고 물리적인 현상 등을 시뮬레이션할 수 있는 알고리즘이 있습니다. 이전에는 JavaScript로만 수행할 수 있었던 워크로드도 이제는 GPU로 옮길 수 있습니다.

다음 동영상은 marching cubes 알고리즘을 사용하여 이러한 메타볼의 표면을 삼각 측량하는 데 사용됩니다. 동영상의 처음 20초 동안은 알고리즘이 JavaScript로 실행될 때 8FPS로만 실행되는 페이지를 따라잡기 어려워 애니메이션 버벅거림이 발생합니다. JavaScript에서 성능을 유지하려면 세부정보 수준을 크게 줄여야 합니다.

동일한 알고리즘을 컴퓨팅 셰이더로 이동하면 야간과 하루의 차이가 벌어집니다. 이 내용은 20초 후에 동영상에서 확인할 수 있습니다. 이제 페이지가 60FPS에서 원활하게 실행되므로 성능이 크게 향상되며 다른 효과를 위한 성능 헤드룸도 여전히 많이 있습니다. 또한 페이지의 기본 JavaScript 루프에서 다른 작업을 위한 작업을 완전히 해제하므로 페이지와의 상호작용이 응답성을 유지합니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> 메타볼 데모

WebGPU는 전에는 실용적이지 않았던 복잡한 시각 효과도 지원합니다. 인기 있는 Babylon.js 라이브러리에서 만든 다음 예에서는 해수면을 전적으로 GPU로 시뮬레이션합니다. 사실적인 역학 관계는 서로 합쳐지는 수많은 독립적인 파동을 통해 만들어집니다. 하지만 각 웨이브를 직접 시뮬레이션하는 것은 비용이 너무 많이 듭니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> 해양 데모

따라서 이 데모에서는 빠른 푸리에 변환이라는 고급 알고리즘을 사용합니다. 모든 파동을 복잡한 위치 데이터로 표현하는 대신 계산 수행에 훨씬 더 효율적인 스펙트럼 데이터를 사용합니다. 그런 다음 각 프레임은 푸리에 변환을 사용하여 스펙트럼 데이터를 파장의 높이를 나타내는 위치 데이터로 변환합니다.

더 빠른 ML 추론

WebGPU는 최근 몇 년 동안 GPU의 주요 용도가 된 머신러닝을 가속화하는 데에도 유용합니다.

오랫동안 광고 소재 개발자는 WebGL의 렌더링 API를 재사용하여 머신러닝 계산과 같은 렌더링이 아닌 작업을 수행해 왔습니다. 그러나 이를 위해서는 계산을 시작하기 위한 방법으로 삼각형 픽셀을 그리고 범용 메모리 액세스 대신 텍스처에서 텐서 데이터를 신중하게 패킹하고 압축해제해야 합니다.

<ph type="x-smartling-placeholder">
</ph> 중복 메모리 로드, 중복 계산, 스레드당 작성된 소수의 값 등 WebGL을 사용한 단일 ML 연산자 실행의 비효율성을 보여주는 그림입니다. <ph type="x-smartling-placeholder">
</ph> WebGL을 사용한 단일 ML 연산자 실행

이런 식으로 WebGL을 사용하려면 개발자가 그리기 전용으로 설계된 API의 기대에 부응하는 코드를 어색하게 따라야 합니다. 계산 간 공유 메모리 액세스와 같은 기본 기능의 부족으로 인해 중복 작업이 발생하고 성능이 최적화되지 않습니다.

컴퓨팅 셰이더는 WebGPU의 새로운 주요 기능이며 이러한 고충을 제거합니다. 컴퓨팅 셰이더는 렌더링 작업의 엄격한 구조에 의해 제약을 받지 않으면서 GPU의 대규모 병렬 특성을 활용하는 더 유연한 프로그래밍 모델을 제공합니다.

<ph type="x-smartling-placeholder">
</ph> 공유 메모리 로드, 공유 계산, 유연한 메모리 쓰기 등 WebGPU 컴퓨팅 셰이더의 다양한 효율성 향상 <ph type="x-smartling-placeholder">
</ph> WebGPU 컴퓨팅 셰이더 효율성.

컴퓨팅 셰이더는 셰이더 작업 그룹 내에서 데이터와 계산 결과를 공유할 수 있는 더 많은 기회를 제공하여 효율성을 높입니다. 이로 인해 이전에 동일한 목적으로 WebGL을 사용하려고 시도했던 것보다 상당한 이점을 얻을 수 있습니다.

이를 통해 얻을 수 있는 효율성 향상의 예로, TensorFlow.js에서 이미지 확산 모델의 초기 포트는 WebGL에서 WebGPU로 이동할 때 다양한 하드웨어에서 3배의 성능 향상을 보여줍니다. 테스트한 하드웨어 중 일부에서는 이미지가 10초 이내에 렌더링되었습니다. 초기 포트이기 때문에 WebGPU와 TensorFlow.js 모두에서 훨씬 더 많은 개선이 가능하다고 생각합니다. 2023년 웹 ML의 새로운 소식을 확인해 보세요. Google I/O 세션입니다.

그러나 WebGPU는 GPU 기능을 웹에 제공하는 것만이 아닙니다.

JavaScript용 우선 설계

한동안 이러한 사용 사례를 지원하는 기능은 플랫폼별 데스크톱 및 모바일 개발자들에게 제공되어 왔으며, 웹 플랫폼의 자연스러운 일부처럼 느껴지는 방식으로 이러한 기능을 노출하는 것은 쉽지 않은 과제였습니다.

WebGPU는 WebGL로 놀라운 작업을 해 온 10여 년의 개발자 경험을 토대로 개발되었습니다. 우리는 그들이 겪은 문제, 직면한 병목 현상, 그들이 제기한 문제를 파악하여 이러한 모든 피드백을 새로운 API에 전달할 수 있었습니다.

WebGL의 전역 상태 모델로 인해 강력하고 구성 가능한 라이브러리와 애플리케이션을 만들기가 어렵고 취약해집니다. 따라서 WebGPU는 개발자가 GPU 명령어를 전송하는 동안 추적해야 하는 상태의 양을 크게 줄입니다.

WebGL 애플리케이션을 디버깅하기가 어렵다는 의견에 따라 WebGPU에는 성능을 저하하지 않는 더 유연한 오류 처리 메커니즘이 포함되어 있습니다. 또한 API에서 반환되는 모든 메시지를 이해하기 쉽고 실행 가능하도록 만들기 위해 노력했습니다.

또한 너무 많은 JavaScript 호출을 수행하는 오버헤드가 복잡한 WebGL 애플리케이션의 병목 현상인 경우가 빈번하다는 사실도 확인했습니다. 따라서 WebGPU API는 채팅이 덜 복잡하므로 더 적은 함수 호출로 더 많은 작업을 수행할 수 있습니다. 여기서는 중요한 그리기 루프를 최대한 가볍게 유지하면서 고강도 검증을 미리 실행하는 데 중점을 둡니다. 또한 Google은 많은 수의 그리기 명령어를 미리 기록하고 한 번의 호출로 재생할 수 있는 Render Bundle과 같은 새로운 API를 제공합니다.

렌더링 번들과 같은 기능으로 얻을 수 있는 극적인 차이를 보여드리기 위해 Babylon.js의 또 다른 데모를 보여 드리겠습니다. WebGL 2 렌더기는 모든 JavaScript 호출을 실행하여 이 아트 갤러리 장면을 초당 약 500회 렌더링할 수 있습니다. 꽤 좋죠!

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> 아트 갤러리

그러나 WebGPU 렌더러는 스냅샷 렌더링이라는 기능을 사용 설정합니다. WebGPU 렌더링 번들을 기반으로 빌드된 이 기능을 사용하면 동일한 장면을 10배 이상 빠르게 제출할 수 있습니다. 이로 인해 오버헤드가 크게 감소하여 WebGPU가 더 복잡한 장면을 렌더링하는 동시에 애플리케이션에서 JavaScript로 더 많은 작업을 동시에 수행할 수 있습니다.

최신 그래픽 API는 복잡성으로 유명하며, 단순성을 위해 극단적인 최적화 기회를 얻는 것과 다릅니다. 반면 WebGPU는 크로스 플랫폼 호환성에 중점을 두어 대부분의 경우 리소스 동기화와 같이 전통적으로 어려운 주제를 자동으로 처리합니다.

이는 WebGPU를 쉽게 배우고 사용할 수 있다는 긍정적인 부작용을 제공합니다. 이미지 및 동영상 로딩과 같은 작업에 웹 플랫폼의 기존 기능을 활용하고 비동기 작업에 프로미스와 같은 잘 알려진 JavaScript 패턴을 사용합니다. 따라서 필요한 상용구 코드의 양을 최소한으로 유지하는 데 도움이 됩니다. 50줄 미만의 코드로 첫 번째 삼각형을 화면에 표시할 수 있습니다.

<canvas id="canvas" width="512" height="512"></canvas>
<script type="module">
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();

  const context = canvas.getContext("webgpu");
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({ device, format });

  const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
  const shaderModule = device.createShaderModule({ code });
  const pipeline = device.createRenderPipeline({
    layout: "auto",
    vertex: {
      module: shaderModule,
      entryPoint: "vertexMain",
    },
    fragment: {
      module: shaderModule,
      entryPoint: "fragmentMain",
      targets: [{ format }],
    },
  });
  const commandEncoder = device.createCommandEncoder();
  const colorAttachments = [
    {
      view: context.getCurrentTexture().createView(),
      loadOp: "clear",
      storeOp: "store",
    },
  ];
  const passEncoder = commandEncoder.beginRenderPass({ colorAttachments });
  passEncoder.setPipeline(pipeline);
  passEncoder.draw(3);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
</script>

결론

WebGPU가 웹 플랫폼에 가져올 새로운 가능성을 보게 되어 기쁩니다. WebGPU와 관련해 발견할 수 있는 새롭고 멋진 사용 사례를 모두 보게 되길 기대합니다.

WebGL을 중심으로 활기 넘치는 라이브러리 및 프레임워크 생태계가 구축되었으며 WebGPU를 수용하고자 하는 생태계도 있습니다. WebGPU 지원이 진행 중이거나 이미 많은 인기 있는 JavaScript WebGL 라이브러리에서 이미 완료되어 있으며 경우에 따라 WebGPU의 이점을 활용하는 것이 단일 플래그를 변경하는 것만큼 간단할 수도 있습니다.

<ph type="x-smartling-placeholder">
</ph> Babylon.js, Struct 3, Google 어스, Google Meet, PlayCanvas, Sketchfab, Three.JS, TensorFlow.js, Unity
완료 또는 진행 중인 WebGPU 포트가 있는 프레임워크, 애플리케이션, 라이브러리

이번 Chrome 113의 첫 번째 출시는 시작에 불과합니다. 초기 릴리스는 Windows, ChromeOS, MacOS용이지만, 조만간 Android 및 Linux 등 나머지 플랫폼에도 WebGPU를 제공할 계획입니다.

WebGPU 출시를 위해 노력하는 것은 Chrome팀만이 아닙니다. Firefox와 WebKit에서도 구현 작업이 진행 중입니다.

또한 새로운 기능은 이미 W3C에서 설계되어 있으며, 하드웨어에서 사용 가능한 경우 이를 공개할 수 있습니다. 예를 들어 Chrome에서는 머신러닝 성능을 더욱 향상시키기 위해 셰이더에서 16비트 부동 소수점 수 지원을 지원하고 곧 DP4a 클래스 명령을 지원할 계획입니다.

WebGPU는 투자할 경우 놀라운 성능을 제공하는 광범위한 API입니다. 지금은 WebGPU의 이점을 개략적으로만 설명했지만 WebGPU를 시작하려면 입문 Codelab인 첫 번째 WebGPU 앱을 확인하세요. 이 Codelab에서는 클래식 Conway's Game of Life의 GPU 버전을 빌드합니다. 이 Codelab에서는 GPU 개발을 처음 하는 경우에도 사용해 볼 수 있도록 이 프로세스를 단계별로 안내합니다.

WebGPU 샘플에서도 API를 살펴볼 수 있습니다. 전통적인 '안녕하세요 삼각형'부터 보다 완전한 렌더링 및 컴퓨팅 파이프라인을 만들어 다양한 기법을 시연할 수 있습니다. 마지막으로 다른 리소스도 확인해 보세요.