iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
Software Development

渲染與GPU編程系列 第 17

Day 16|WebGPU 是什麼?與 WebGL 的差異與優勢

  • 分享至 

  • xImage
  •  

先用一句大白話:WebGL 像在瀏覽器裡使用「老派的 OpenGL ES」來畫圖;WebGPU 則把「現代顯示卡的工作方式(Vulkan / Metal / Direct3D 12)」帶進網頁世界。
換句話說,WebGPU 給你更接近原生的效能更清楚的資源/流程控制,還多了通用運算(Compute),能做的事不只畫三角形,還能跑機器學習、粒子模擬、影像處理等。


1) WebGPU 是什麼?(它解決了什麼)

  • WebGPU 是瀏覽器內建的 GPU API,由 W3C 團隊制定,背後對應平台原生 API:Windows 對應 D3D12、Linux/Android 對應 Vulkan、macOS/iOS 對應 Metal

  • 它提供兩大能力

    1. 繪圖(Graphics):像傳統渲染管線一樣,畫出 2D/3D 畫面。
    2. 通用運算(Compute):不透過像素著色器也能用 GPU 算東西(濾鏡、物理、ML…)。
  • 為什麼重要:以前用 WebGL,做很多進階效果必須「鑽漏洞」;WebGPU 把這些能力正規化,而且與現代顯卡設計一一對齊,效能與可預測性更好。


2) WebGL 的位置與限制(為什麼需要下一代)

  • WebGL 1/2 分別對應 OpenGL ES 2.0/3.0,屬於「狀態機」的古早風格:你不停 glBind...glEnable... 改全域狀態,再 draw

  • 這種方式好上手,但也有幾個痛點:

    • 需要透過「小技巧」才能做通用運算(把計算塞進片段著色器)。
    • 每次繪製前都在改狀態,CPU 端開銷較高;不利大場景與多執行緒。
    • 某些平台上的驅動最佳化是黑箱,效果不穩定、很難預測瓶頸在哪。
  • 結論:WebGL 非常適合入門與廣泛兼容;但當你想做更大規模、更寫實、更大量運算的內容時,就會碰到天花板。


3) WebGPU 的核心觀念(四個名詞就夠)

  • Adapter / Device / Queue
    你先向瀏覽器要一張「顯卡(Adapter)」→ 拿到「裝置(Device)」→ 透過「佇列(Queue)」把工作交給 GPU。
  • Command Encoder / Pass Encoder
    你在 CPU 端「錄指令」(像把要做的事寫成一卷帶),包含「Render Pass」或「Compute Pass」。錄好後一次丟給 Queue。
  • Pipeline
    把固定狀態(著色器、輸入格式、光柵化、混色…)預先打包,切換快、可預測。
  • Bind Group
    把要給著色器用的資源(Buffer / Texture / Sampler)成套管理,一次綁定,取代 WebGL 零碎的 glBind*

這幾個詞對應原生 API(Vulkan/D3D12/Metal)的設計,所以學會 WebGPU,也就學會了現代 GPU 的思考方式。


4) WebGPU vs WebGL:重點差異一圖看懂

主題 WebGL(OpenGL ES風格) WebGPU(現代顯式API) 對你的意義
API 風格 全域狀態機、即時改狀態再 draw 先錄好指令再一次提交 CPU 開銷更低、可多執行緒準備工作
資源綁定 glBind* 分散又頻繁 Bind Group 成套綁定 更少樣板、更快切換
管線狀態 零碎開關 Pipeline 物件一次打包 效能更穩、難犯錯
Shader 語言 GLSL WGSL(更安全、為 Web 設計) 編譯訊息清楚、避免未定義行為
Compute 幾乎沒有(要繞路) 一等公民(Compute Pass) ML/影像處理/模擬更容易
記憶體/同步 驅動多幫你猜 你明確宣告用途/用法 可預測、可最佳化
安全模型 舊 API 補救 以 Web 安全為前提(沙箱) 不易崩潰/越界,錯誤早揭示

5) 什麼時候該選 WebGPU?(三種典型場景)

  1. 需要通用運算:例如即時濾鏡、GPGPU 粒子、Web 上的小型機器學習。
  2. 大場景或大量 Draw:例如大量實例(Instancing)、大量材質切換。WebGPU 的 Pipeline/BindGroup 能有效降低 CPU 頻寬。
  3. 長期維護的新專案:你希望 API 不會過時、效能與工具越來越好。

若你只是快速畫圖、想兼容最舊的裝置,WebGL 仍是穩妥選擇;但新專案預設就用 WebGPU,會省很多「把舊 API 推到極限」的力氣。


6) WGSL 是什麼?(WebGPU 的著色器語言)

  • WGSL(WebGPU Shading Language) 是 Web 專用的著色器語言,語法清晰、型別嚴格。
  • 與 GLSL 相比,WGSL 把一些容易出錯的行為明確規範,錯誤訊息也更易讀。
  • 它支援 vertex / fragment / compute 三種入口點,能直接表達資源綁定位置工作群組大小等資訊。

7) 最小「三角形」心智流程(一步步超白話)

  1. 拿到 GPUnavigator.gpu.requestAdapter()adapter.requestDevice()

  2. 設定畫布canvas.getContext('webgpu')configure(指定格式、尺寸)。

  3. 準備資源:建立 GPUBuffer(頂點)、寫一小段 WGSL(VS/FS)。

  4. 建立 Pipeline:把著色器 + 固定狀態打包成 GPURenderPipeline

  5. 每幀渲染

    • context.getCurrentTexture() 拿可寫入的畫面。
    • device.createCommandEncoder()beginRenderPass()setPipeline/setVertexBuffer/drawendqueue.submit()

8) 最小可運行範例(三角形;僅示意,重點在流程)

WGSL(shader.wgsl)

struct VSOut {
  @builtin(position) pos : vec4<f32>,
  @location(0) color : vec3<f32>,
};

@vertex
fn vs_main(@builtin(vertex_index) vid : u32) -> VSOut {
  var p = array<vec2<f32>, 3>(
    vec2<f32>( 0.0,  0.6),
    vec2<f32>(-0.6, -0.6),
    vec2<f32>( 0.6, -0.6));
  var c = array<vec3<f32>, 3>(
    vec3<f32>(1.0, 0.2, 0.2),
    vec3<f32>(0.2, 1.0, 0.2),
    vec3<f32>(0.2, 0.4, 1.0));
  var o : VSOut;
  o.pos = vec4<f32>(p[vid], 0.0, 1.0);
  o.color = c[vid];
  return o;
}

@fragment
fn fs_main(@location(0) color : vec3<f32>) -> @location(0) vec4<f32> {
  return vec4<f32>(color, 1.0);
}

JavaScript(main.js)

const canvas = document.querySelector('canvas');
const adapter = await navigator.gpu.requestAdapter();
const device  = await adapter.requestDevice();
const ctx = canvas.getContext('webgpu');

const format = navigator.gpu.getPreferredCanvasFormat();
ctx.configure({ device, format, alphaMode: 'opaque' });

const module = device.createShaderModule({
  code: await (await fetch('shader.wgsl')).text()
});

const pipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex:   { module, entryPoint: 'vs_main' },
  fragment: { module, entryPoint: 'fs_main',
              targets: [{ format }] },
  primitive: { topology: 'triangle-list', cullMode: 'none' }
});

function frame(){
  const encoder = device.createCommandEncoder();
  const view = ctx.getCurrentTexture().createView();
  const pass = encoder.beginRenderPass({
    colorAttachments: [{
      view,
      clearValue: { r: 0.05, g: 0.06, b: 0.1, a: 1 },
      loadOp: 'clear', storeOp: 'store'
    }]
  });
  pass.setPipeline(pipeline);
  pass.draw(3);                  // 3 個頂點
  pass.end();
  device.queue.submit([encoder.finish()]);
  requestAnimationFrame(frame);
}
frame();

(index.html)

<!doctype html>

<html>
  <head>
    <meta charset="utf-8">
    <title>WebGPU Life</title>
  </head>
  <body>
     <script src="main.js" type="module"></script>
    <canvas width="512" height="512"></canvas>   

  </body>
</html>

你可以直接放到一個簡單的靜態網站(或本地端伺服器)跑起來,看見彩色三角形。

result


9) Compute(通用運算)為什麼改變遊戲規則?

  • 在 WebGL,你很難「不靠畫圖」就用 GPU 算東西;而 WebGPU 的 Compute Shader 讓你直接定義資料工作(像一個平行迴圈)。
  • 例子:把一張影像做高斯模糊、把 10 萬個粒子做速度/位置更新、把矩陣乘起來做推論前處理…
  • 和圖形渲染一樣,你會:建立 Buffer → 建 BindGroup → 建 ComputePipeline → 在 Compute Pass 派工(dispatchWorkgroups)→ 再把結果拿去畫或讀回 CPU。

10) 效能、相容性與安全(開發時你會關心的)

  • 效能:因為 API 風格接近原生,WebGPU 通常能讓 CPU 開銷顯著下降;在大量 draw 或頻繁切換資源時,優勢更明顯。
  • 相容性:現代桌面與行動瀏覽器已陸續支援(Chrome/Edge/Safari/Firefox 有不同進度)。舊裝置可能只能跑 WebGL。
  • 安全:WebGPU 以 Web 安全為前提(沙箱、越界檢查、嚴格驗證),你的內容不容易把整個瀏覽器拖垮;同時錯誤訊息清楚,除錯更友善。

11) 從 WebGL 過來應該怎麼轉念?

  • 把「隨時 glBind」→ 換成「預先建立 Pipeline/BindGroup,每幀只做最少切換」。
  • 把「即時改狀態然後 draw」→ 換成「先錄命令(Encoder → Pass)再提交」。
  • 把「所有事都在片段著色器硬塞」→ 改為「有 Graphics Pass 也有 Compute Pass,各司其職」。

12) 常見坑位(幫你少走彎路)

  1. Canvas 沒 configure 就畫 → 會報錯:記得 context.configure({ device, format })
  2. WGSL 型別/綁定不一致 → JS 的 BindGroupLayout 與 WGSL 的 @group/@binding 必須一一對應。
  3. Uniform/Storage 對齊 → WGSL 有嚴格的記憶體對齊規則,建議先用簡單 struct(vec4/mat4)避免踩洞。
  4. 忘了 storeOp → 不設定或設錯,畫完可能不保留內容。
  5. 在熱路徑不斷 create 物件 → Pipeline/BindGroup 在初始化做,不要每幀重建

13) 我下一步可以做什麼?

  • 把三角形改成旋轉正方形:加一個 uniform 資料(時間/矩陣),感受資料流。
  • 上貼圖:建立 GPUTexture + Sampler,在 WGSL 取樣。
  • 做一個小 Compute:用 Compute 把一個陣列全部平方,再在畫面上把結果畫成直方圖。
  • 把 WebGL 舊專案某個效果換到 WebGPU:你會體會 BindGroup/Pipeline 的好處。

14) 一句話總結

WebGL 讓網頁能「畫 3D」,WebGPU 讓網頁能「像原生程式一樣運用 GPU」。
它提供明確的指令錄製、現代化的資源綁定、與一等的 Compute 支援,既能提升效能,也讓大型專案更好維護。
如果你正準備新專案、或想把 Web 上的即時圖形/運算做得更穩更快,WebGPU 是更好的起點


上一篇
Day 15|深入 Descriptor Set 與 Pipeline Layout (延伸)
下一篇
Day 17|第一個 WebGPU 專案:環境與初始化
系列文
渲染與GPU編程22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言