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

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

새로운 WebGPU API를 사용하면 그래픽 및 머신러닝 워크로드에서 엄청난 성능 향상을 기대할 수 있습니다. 이 문서에서는 WebGPU가 WebGL의 현재 솔루션보다 어떻게 개선되는지 살펴보고 향후 개발 상황을 살짝 살펴봅니다. 하지만 먼저 WebGPU가 개발된 이유에 관한 몇 가지 컨텍스트를 살펴보겠습니다.

WebGPU에 관한 컨텍스트

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

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

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에 포팅할 수 있습니다. 예를 들어 장면에 동적인 디테일을 더하거나 물리적 현상을 시뮬레이션하는 알고리즘을 들 수 있습니다. 이전에는 자바스크립트로만 실행할 수 있었던 워크로드도 GPU로 이전할 수 있습니다.

다음 동영상은 이러한 메타볼의 표면을 삼각하는 데 사용되는 행진 큐브 알고리즘을 보여줍니다. 동영상의 처음 20초 동안 자바스크립트로 실행 중인 알고리즘은 8FPS로만 실행되는 페이지를 따라잡기 어려워 애니메이션 버벅거림이 발생합니다. JavaScript에서 성능을 유지하려면 세부 정보 수준을 많이 낮춰야 합니다.

동일한 알고리즘을 컴퓨팅 셰이더로 이동하면 밤낮으로 차이가 납니다. 컴퓨팅 셰이더는 20초 후 동영상에서 볼 수 있습니다. 이제 페이지가 매끄러운 60FPS로 실행되므로 성능이 크게 개선되며 다른 효과를 위한 성능 개선 여지는 여전히 많습니다. 또한 페이지의 기본 자바스크립트 루프가 다른 작업을 위해 완전히 해제되어 페이지와의 상호작용이 응답성을 유지합니다.

메타볼 데모

또한 WebGPU를 사용하면 전에는 실용적이지 않았던 복잡한 시각 효과를 사용할 수 있습니다. 인기 있는 Babylon.js 라이브러리에서 생성된 다음 예에서는 해수면이 전적으로 GPU에서 시뮬레이션됩니다. 사실적인 역학은 여러 독립적인 파동이 서로 더해져 만들어집니다. 그러나 각 웨이브를 직접 시뮬레이션하는 데는 너무 많은 비용이 듭니다.

해양 데모

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

더 빠른 ML 추론

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

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

WebGL을 사용한 단일 ML 연산자 실행의 비효율성(예: 중복 메모리 로드, 중복 계산, 스레드당 작성된 값 수가 적음)을 보여주는 그림
WebGL을 사용한 단일 ML 연산자 실행입니다.

이러한 방식으로 WebGL을 사용하려면 개발자가 그리기 전용으로 설계된 API의 기대치를 어색하게 풀어야 합니다. 계산 간의 공유 메모리 액세스와 같은 기본 기능의 부족과 결합되면 중복 작업 및 최적의 성능을 발휘하지 못합니다.

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

공유 메모리 로드, 공유 계산, 유연한 메모리 쓰기 등 WebGPU 컴퓨팅 셰이더의 다양한 효율성 향상
WebGPU 컴퓨팅 셰이더 효율성입니다.

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

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

하지만 WebGPU는 웹에 GPU 기능을 가져오는 것만이 아닙니다.

자바스크립트에 우선하여 설계

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

WebGPU는 WebGL로 놀라운 작업을 해온 10여 년의 개발자들로부터 얻은 결실을 바탕으로 개발되었습니다. 이 과정에서 발생한 문제, 발생한 병목 현상, 발생한 문제 등을 받아 이 모든 의견을 새로운 API에 반영할 수 있었습니다.

우리는 WebGL의 전역 상태 모델로 인해 강력하고 구성 가능한 라이브러리와 애플리케이션을 만드는 것이 어렵고 취약하다는 사실을 확인했습니다. 따라서 WebGPU를 사용하면 개발자가 GPU 명령어를 전송하는 동안 추적해야 하는 상태의 양을 크게 줄일 수 있습니다.

WebGL 애플리케이션을 디버깅하는 것이 어렵다는 의견이 있었습니다. 그래서 WebGPU에는 성능을 저하시키지 않는 더 유연한 오류 처리 메커니즘이 포함되어 있습니다. 또한 API를 통해 반환되는 모든 메시지가 쉽게 이해하고 실행 가능하도록 하기 위해 최선을 다하고 있습니다.

또한, 너무 많은 JavaScript 호출을 하는 오버헤드가 복잡한 WebGL 애플리케이션에서 병목 현상을 일으키는 경우가 많다는 점도 확인했습니다. 따라서 WebGPU API가 수다스러움이 적으므로 함수 호출 수를 줄여 더 많은 작업을 수행할 수 있습니다. 우리는 고강도 유효성 검사를 미리 수행하고 중요한 그리기 루프를 가능한 한 가볍게 유지하는 데 중점을 둡니다. 또한 렌더링 번들과 같은 새로운 API를 제공하므로 많은 수의 그리기 명령어를 미리 기록하고 한 번의 호출로 재생할 수 있습니다.

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

아트 갤러리

하지만 WebGPU 렌더러는 Snapshot Rendering이라고 하는 기능을 사용 설정합니다. 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를 수용하기를 원하고 있습니다. 널리 사용되는 여러 JavaScript WebGL 라이브러리에서 WebGPU 지원이 진행 중이거나 이미 완료되었습니다. 일부 경우에는 단일 플래그를 변경하는 것만큼이나 간단하게 WebGPU의 이점을 활용할 수 있습니다.

Babylon.js, Composition 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를 시작하려면 입문 Codelab인 첫 번째 WebGPU 앱을 확인해 보세요. 이 Codelab에서는 클래식 Conway's Game of Life의 GPU 버전을 빌드합니다. 이 Codelab에서는 단계별로 프로세스를 안내하므로 GPU 개발을 처음 하는 경우에도 사용해 볼 수 있습니다.

WebGPU 샘플도 API를 익히는 데 좋습니다. 기존의 '안녕하세요 삼각형'부터 보다 완전한 렌더링 및 컴퓨팅 파이프라인에 이르기까지 다양한 기술을 보여줍니다. 다른 리소스도 확인해 보세요.