WebGPU: Mở khoá quyền truy cập GPU hiện đại trong trình duyệt

Tìm hiểu cách WebGPU khai thác sức mạnh của GPU để mang lại hiệu suất học máy nhanh hơn và kết xuất đồ hoạ tốt hơn.

Corentin Wallez
Corentin Wallez
François Beaufort
François Beaufort

WebGPU API mới giúp tăng hiệu suất đáng kể trong khối lượng công việc đồ hoạ và học máy. Bài viết này khám phá cách WebGPU cải thiện giải pháp WebGL hiện tại, đồng thời xem trước các hoạt động phát triển trong tương lai. Nhưng trước tiên, hãy cung cấp một số thông tin về lý do phát triển WebGPU.

Ngữ cảnh trên WebGPU

WebGL ra mắt trên Chrome vào năm 2011. Bằng cách cho phép các ứng dụng web tận dụng GPU, WebGL mang đến trải nghiệm tuyệt vời trên web, từ Google Earth, video nhạc tương tác, đến bản trình bày 3D về bất động sản và nhiều nội dung khác. WebGL dựa trên gia đình API OpenGL được phát triển lần đầu tiên vào năm 1992. Lâu rồi không gặp! Và bạn có thể tưởng tượng rằng phần cứng GPU đã phát triển đáng kể kể từ thời điểm đó.

Để bắt kịp sự phát triển này, một loại API mới đã được phát triển để tương tác hiệu quả hơn với phần cứng GPU hiện đại. Các API như Direct3D 12, MetalVulkan. Các API mới này đã hỗ trợ các trường hợp sử dụng mới và đòi hỏi cao đối với việc lập trình GPU, chẳng hạn như sự bùng nổ của công nghệ học máy và những tiến bộ trong thuật toán kết xuất. WebGPU là phiên bản kế nhiệm của WebGL, mang đến những tiến bộ của lớp API hiện đại mới này cho Web.

WebGPU mở ra nhiều khả năng lập trình GPU mới trong trình duyệt. API này phản ánh tốt hơn cách hoạt động của phần cứng GPU hiện đại, đồng thời đặt nền tảng cho các tính năng GPU nâng cao hơn trong tương lai. API này đã được phát triển trong nhóm "GPU cho web" của W3C kể từ năm 2017 và là sản phẩm hợp tác giữa nhiều công ty như Apple, Google, Mozilla, Microsoft và Intel. Và sau 6 năm nỗ lực, chúng tôi rất vui mừng được thông báo rằng một trong những tính năng bổ sung lớn nhất cho nền tảng Web đã ra mắt!

WebGPU hiện có trong Chrome 113 trên ChromeOS, macOS và Windows, các nền tảng khác sẽ sớm ra mắt. Cảm ơn rất nhiều những người đóng góp khác cho Chromium, đặc biệt là Intel đã giúp chúng tôi thực hiện được điều này.

Bây giờ, hãy cùng xem một số trường hợp sử dụng thú vị mà WebGPU hỗ trợ.

Mở khoá khối lượng công việc GPU mới để kết xuất

Các tính năng WebGPU như shader điện toán cho phép chuyển các lớp thuật toán mới trên GPU. Ví dụ: các thuật toán có thể thêm nhiều chi tiết động hơn vào cảnh, mô phỏng các hiện tượng vật lý và nhiều tính năng khác! Thậm chí, có những khối lượng công việc trước đây chỉ có thể thực hiện trong JavaScript nhưng giờ đây có thể chuyển sang GPU.

Video sau đây cho thấy thuật toán marching cubes được dùng để tạo hình tam giác cho bề mặt của các quả bóng này. Trong 20 giây đầu tiên của video, thuật toán (khi đang chạy trong JavaScript) gặp khó khăn trong việc theo kịp trang chỉ chạy ở tốc độ 8 khung hình/giây, dẫn đến ảnh động bị giật. Để duy trì hiệu suất trong JavaScript, chúng ta cần giảm mức độ chi tiết xuống rất nhiều.

Sự khác biệt giữa hai cách này rõ ràng như ban ngày và ban đêm khi chúng ta chuyển cùng một thuật toán sang chương trình đổ bóng điện toán. Bạn có thể thấy sự khác biệt này trong video sau 20 giây. Hiệu suất cải thiện đáng kể khi trang hiện chạy ở tốc độ 60 khung hình/giây mượt mà và vẫn còn nhiều không gian hiệu suất cho các hiệu ứng khác. Ngoài ra, vòng lặp JavaScript chính của trang được giải phóng hoàn toàn cho các tác vụ khác, đảm bảo rằng các lượt tương tác với trang vẫn có khả năng phản hồi.

Bản minh hoạ metaballs

WebGPU cũng hỗ trợ các hiệu ứng hình ảnh phức tạp mà trước đây không thực tế. Trong ví dụ sau, được tạo trong thư viện Babylon.js phổ biến, bề mặt đại dương đang được mô phỏng hoàn toàn trên GPU. Độ chân thực của hiệu ứng động được tạo ra từ nhiều sóng độc lập được thêm vào nhau. Tuy nhiên, việc mô phỏng trực tiếp từng sóng sẽ quá tốn kém.

Bản minh hoạ đại dương

Đó là lý do bản minh hoạ sử dụng một thuật toán nâng cao có tên là Biến đổi Fourier nhanh. Thay vì biểu thị tất cả các sóng dưới dạng dữ liệu vị trí phức tạp, phương thức này sử dụng dữ liệu phổ hiệu quả hơn nhiều để thực hiện các phép tính. Sau đó, mỗi khung hình sẽ sử dụng phép biến đổi Fourier để chuyển đổi từ dữ liệu phổ sang dữ liệu vị trí biểu thị độ cao của sóng.

Dự đoán ML nhanh hơn

WebGPU cũng hữu ích trong việc tăng tốc máy học, đây đã trở thành một mục đích sử dụng chính của GPU trong những năm gần đây.

Trong một thời gian dài, các nhà phát triển sáng tạo đã sử dụng lại API kết xuất của WebGL để thực hiện các thao tác không phải kết xuất, chẳng hạn như tính toán máy học. Tuy nhiên, điều này đòi hỏi bạn phải vẽ các pixel của tam giác để bắt đầu quá trình tính toán, đồng thời đóng gói và giải nén dữ liệu tensor trong hoạ tiết một cách cẩn thận thay vì truy cập bộ nhớ cho nhiều mục đích chung hơn.

Hình minh hoạ về sự thiếu hiệu quả trong một quá trình thực thi toán tử học máy bằng WebGL, bao gồm cả việc tải bộ nhớ thừa, tính toán thừa và một số giá trị được ghi cho mỗi luồng.
Một lần thực thi toán tử học máy bằng WebGL.

Việc sử dụng WebGL theo cách này đòi hỏi nhà phát triển phải điều chỉnh mã của họ theo kỳ vọng của một API chỉ được thiết kế để vẽ. Cùng với việc thiếu các tính năng cơ bản như quyền truy cập bộ nhớ dùng chung giữa các phép tính, điều này dẫn đến công việc trùng lặp và hiệu suất không tối ưu.

Chương trình đổ bóng điện toán là tính năng mới chính của WebGPU và giúp loại bỏ những vấn đề này. Chương trình đổ bóng điện toán cung cấp một mô hình lập trình linh hoạt hơn, tận dụng bản chất song song khổng lồ của GPU mà không bị ràng buộc bởi cấu trúc nghiêm ngặt của các thao tác kết xuất.

Nhiều mức tăng hiệu quả trong chương trình đổ bóng điện toán WebGPU, bao gồm cả tải bộ nhớ dùng chung, tính toán dùng chung và ghi linh hoạt vào bộ nhớ.
Hiệu suất của chương trình đổ bóng điện toán WebGPU.

Chương trình đổ bóng điện toán mang đến nhiều cơ hội hơn để chia sẻ dữ liệu và kết quả tính toán trong các nhóm công việc đổ bóng nhằm nâng cao hiệu quả. Điều này có thể mang lại lợi ích đáng kể so với các nỗ lực trước đây để sử dụng WebGL cho cùng một mục đích.

Ví dụ về mức tăng hiệu quả mà điều này có thể mang lại: Cổng ban đầu của mô hình khuếch tán hình ảnh trong TensorFlow.js cho thấy mức tăng hiệu suất gấp 3 lần trên nhiều phần cứng khi chuyển từ WebGL sang WebGPU. Trên một số phần cứng được kiểm thử, hình ảnh được kết xuất trong vòng chưa đến 10 giây. Và vì đây là một bản chuyển đổi sớm, nên chúng tôi tin rằng có thể cải thiện nhiều hơn nữa trong cả WebGPU và TensorFlow.js! Hãy xem bài viết Tính năng mới của công nghệ học máy trên web trong năm 2023? Phiên Google I/O.

Tuy nhiên, WebGPU không chỉ mang các tính năng của GPU lên web.

Được thiết kế dành cho JavaScript

Các tính năng hỗ trợ những trường hợp sử dụng này đã được cung cấp cho các nhà phát triển dành riêng cho nền tảng máy tính và thiết bị di động trong một thời gian. Tuy nhiên, chúng tôi vẫn gặp khó khăn trong việc cung cấp các tính năng này theo cách tự nhiên trên nền tảng web.

WebGPU được phát triển dựa trên kinh nghiệm của hơn một thập kỷ các nhà phát triển làm việc tuyệt vời với WebGL. Chúng tôi đã có thể nắm bắt được những vấn đề mà họ gặp phải, những nút thắt cổ chai mà họ gặp phải và những vấn đề mà họ nêu ra, đồng thời chuyển tất cả ý kiến phản hồi đó vào API mới này.

Chúng tôi nhận thấy mô hình trạng thái toàn cục của WebGL khiến việc tạo các thư viện và ứng dụng có khả năng kết hợp, mạnh mẽ trở nên khó khăn và dễ hỏng. Vì vậy, WebGPU giúp giảm đáng kể lượng trạng thái mà nhà phát triển cần theo dõi trong khi gửi lệnh GPU.

Chúng tôi biết rằng việc gỡ lỗi các ứng dụng WebGL rất khó khăn, vì vậy, WebGPU bao gồm các cơ chế xử lý lỗi linh hoạt hơn mà không làm giảm hiệu suất của bạn. Chúng tôi đã nỗ lực hết sức để đảm bảo rằng mọi thông báo mà bạn nhận được từ API đều dễ hiểu và có thể hành động.

Chúng tôi cũng nhận thấy rằng thường xuyên chi phí phát sinh khi thực hiện quá nhiều lệnh gọi JavaScript là nút thắt cổ chai đối với các ứng dụng WebGL phức tạp. Do đó, API WebGPU ít giao tiếp hơn, vì vậy, bạn có thể hoàn thành nhiều việc hơn với ít lệnh gọi hàm hơn. Chúng ta tập trung vào việc xác thực trọng tải lớn ở phía trước, giữ cho vòng lặp vẽ quan trọng càng gọn nhẹ càng tốt. Ngoài ra, chúng tôi cung cấp các API mới như Gói kết xuất, cho phép bạn ghi lại trước một số lượng lớn lệnh vẽ và phát lại các lệnh đó bằng một lệnh gọi duy nhất.

Để minh hoạ sự khác biệt đáng kể mà một tính năng như gói kết xuất có thể mang lại, sau đây là một bản minh hoạ khác của Babylon.js. Trình kết xuất WebGL 2 của họ có thể thực thi tất cả các lệnh gọi JavaScript để kết xuất cảnh phòng trưng bày nghệ thuật này khoảng 500 lần mỗi giây. Khá là cao!

Phòng tranh

Tuy nhiên, trình kết xuất WebGPU của họ cho phép một tính năng mà họ gọi là Kết xuất tổng quan nhanh. Được xây dựng dựa trên các gói kết xuất WebGPU, tính năng này cho phép gửi cùng một cảnh nhanh hơn gấp 10 lần. Điều này giúp giảm đáng kể mức hao tổn, cho phép WebGPU kết xuất các cảnh phức tạp hơn, đồng thời cho phép các ứng dụng thực hiện nhiều việc hơn với JavaScript song song.

Các API đồ hoạ hiện đại nổi tiếng là phức tạp, đánh đổi sự đơn giản để có cơ hội tối ưu hoá cực độ. Mặt khác, WebGPU tập trung vào khả năng tương thích đa nền tảng, tự động xử lý các chủ đề khó khăn như đồng bộ hoá tài nguyên trong hầu hết các trường hợp.

Điều này có tác dụng phụ là WebGPU dễ học và dễ sử dụng. API này dựa vào các tính năng hiện có của nền tảng web cho những việc như tải hình ảnh và video, đồng thời dựa vào các mẫu JavaScript nổi tiếng như Promises cho các thao tác không đồng bộ. Điều này giúp giảm thiểu lượng mã nguyên mẫu cần thiết. Bạn có thể tạo hình tam giác đầu tiên trên màn hình chỉ với chưa đến 50 dòng mã.

<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>

Kết luận

Chúng tôi rất vui khi thấy tất cả các khả năng mới mà WebGPU mang đến cho nền tảng web. Chúng tôi cũng rất mong được thấy tất cả các trường hợp sử dụng mới thú vị mà bạn sẽ tìm thấy cho WebGPU!

Một hệ sinh thái thư viện và khung sống động đã được xây dựng xung quanh WebGL và hệ sinh thái đó cũng rất mong muốn đón nhận WebGPU. Hỗ trợ WebGPU đang được tiến hành hoặc đã hoàn tất trong nhiều thư viện WebGL Javascript phổ biến. Trong một số trường hợp, việc tận dụng các lợi ích của WebGPU có thể đơn giản như thay đổi một cờ!

Babylon.js, Construct 3, Google Earth, Google Meet, PlayCanvas, Sketchfab, Three.JS, TensorFlow.js và Unity.
Khung, ứng dụng và thư viện có cổng WebGPU đã hoàn tất hoặc đang diễn ra.

bản phát hành đầu tiên trong Chrome 113 này chỉ là bước khởi đầu. Mặc dù bản phát hành ban đầu của chúng tôi dành cho Windows, ChromeOS và MacOS, nhưng chúng tôi dự định sẽ đưa WebGPU đến các nền tảng còn lại như Android và Linux trong tương lai gần.

Không chỉ nhóm Chrome đang nỗ lực ra mắt WebGPU. Quá trình triển khai cũng đang diễn ra trong Firefox và WebKit.

Ngoài ra, các tính năng mới đang được thiết kế tại W3C và có thể được hiển thị khi có sẵn trong phần cứng. Ví dụ: Trong Chrome, chúng tôi dự định sớm bật tính năng hỗ trợ số dấu phẩy động 16 bit trong chương trình đổ bónglớp hướng dẫn DP4a để cải thiện hiệu suất học máy hơn nữa.

WebGPU là một API mở rộng giúp mang lại hiệu suất đáng kinh ngạc nếu bạn đầu tư vào API này. Hôm nay, chúng ta chỉ có thể đề cập đến các lợi ích của WebGPU ở cấp cao, nhưng nếu bạn muốn bắt đầu với WebGPU, hãy xem Lớp học lập trình giới thiệu của chúng tôi, Ứng dụng WebGPU đầu tiên của bạn. Trong lớp học lập trình này, bạn sẽ xây dựng phiên bản GPU của Trò chơi cuộc sống cổ điển của Conway. Lớp học lập trình này sẽ hướng dẫn bạn từng bước trong quy trình này để bạn có thể thử ngay cả khi đây là lần đầu tiên bạn phát triển GPU.

Mẫu WebGPU cũng là một nơi phù hợp để bạn làm quen với API này. Các ví dụ này trải dài từ "tam giác hello" truyền thống đến quy trình kết xuất và tính toán hoàn chỉnh hơn, minh hoạ nhiều kỹ thuật. Cuối cùng, hãy tham khảo các tài nguyên khác của chúng tôi.