d8a80f6272
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해 끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은 과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업. 도구: Datacollect/scripts/link_reconcile_apply.mjs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
198 lines
6.5 KiB
Markdown
198 lines
6.5 KiB
Markdown
---
|
|
id: wiki-2026-0508-webgpu
|
|
title: WebGPU
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [WebGPU API, WGSL, GPU Web]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.9
|
|
verification_status: applied
|
|
tags: [graphics, gpu, web, wgsl, compute]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: typescript
|
|
framework: webgpu
|
|
---
|
|
|
|
# WebGPU
|
|
|
|
## 매 한 줄
|
|
> **"매 modern explicit GPU API 매 browser 에 — Vulkan / Metal / D3D12 의 매 abstraction"**. 매 WebGL 의 매 후계자, 매 2023 매 Chrome 113 ship, 매 2026 매 Safari 18 / Firefox 130 stable, ML inference (transformers.js, ONNX Runtime Web) 와 high-end browser game 의 standard.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 vs WebGL
|
|
- WebGL: OpenGL ES 2.0 / 3.0 기반 — implicit state, fixed pipeline parts.
|
|
- WebGPU: Vulkan / Metal style — explicit pipeline state object, compute shader native.
|
|
- WGSL (WebGPU Shading Language): Rust-like syntax, browser 매 portable.
|
|
|
|
### 매 핵심 객체
|
|
- **Adapter**: physical GPU.
|
|
- **Device**: logical handle — buffer, texture, pipeline 만들기 사용.
|
|
- **Queue**: command submission.
|
|
- **Buffer / Texture**: GPU memory.
|
|
- **BindGroup**: shader 매 resource binding.
|
|
- **RenderPipeline / ComputePipeline**: compiled shader + state.
|
|
- **CommandEncoder → CommandBuffer**: GPU 명령 record + submit.
|
|
|
|
### 매 응용
|
|
1. transformers.js / ONNX Runtime Web: GPU-accelerated LLM in browser.
|
|
2. Babylon.js / Three.js (WebGPURenderer): high-end web 3D.
|
|
3. Figma / Canva: GPU-accelerated 2D.
|
|
4. Stable Diffusion Web (web-stable-diffusion).
|
|
5. Real-time particle / fluid sim (GPGPU).
|
|
|
|
## 💻 패턴
|
|
|
|
### Init + clear screen
|
|
```ts
|
|
const adapter = await navigator.gpu.requestAdapter();
|
|
if (!adapter) throw new Error("No WebGPU adapter");
|
|
const device = await adapter.requestDevice();
|
|
|
|
const canvas = document.querySelector("canvas")!;
|
|
const ctx = canvas.getContext("webgpu")!;
|
|
const format = navigator.gpu.getPreferredCanvasFormat();
|
|
ctx.configure({ device, format, alphaMode: "premultiplied" });
|
|
|
|
const enc = device.createCommandEncoder();
|
|
const pass = enc.beginRenderPass({
|
|
colorAttachments: [{
|
|
view: ctx.getCurrentTexture().createView(),
|
|
clearValue: { r: 0.1, g: 0.1, b: 0.15, a: 1 },
|
|
loadOp: "clear", storeOp: "store",
|
|
}],
|
|
});
|
|
pass.end();
|
|
device.queue.submit([enc.finish()]);
|
|
```
|
|
|
|
### Triangle render pipeline
|
|
```ts
|
|
const shader = device.createShaderModule({ code: `
|
|
@vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
|
|
let p = array(vec2f(0,0.5), vec2f(-0.5,-0.5), vec2f(0.5,-0.5));
|
|
return vec4f(p[i], 0, 1);
|
|
}
|
|
@fragment fn fs() -> @location(0) vec4f { return vec4f(1, 0.4, 0.2, 1); }
|
|
`});
|
|
|
|
const pipeline = device.createRenderPipeline({
|
|
layout: "auto",
|
|
vertex: { module: shader, entryPoint: "vs" },
|
|
fragment: { module: shader, entryPoint: "fs", targets: [{ format }] },
|
|
primitive: { topology: "triangle-list" },
|
|
});
|
|
```
|
|
|
|
### Uniform buffer + bind group
|
|
```ts
|
|
const uniform = device.createBuffer({
|
|
size: 16, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
});
|
|
device.queue.writeBuffer(uniform, 0, new Float32Array([0.5, 0.2, 0.8, 1]));
|
|
|
|
const bg = device.createBindGroup({
|
|
layout: pipeline.getBindGroupLayout(0),
|
|
entries: [{ binding: 0, resource: { buffer: uniform } }],
|
|
});
|
|
```
|
|
|
|
### Compute shader (vector add)
|
|
```ts
|
|
const code = `
|
|
@group(0) @binding(0) var<storage, read> a: array<f32>;
|
|
@group(0) @binding(1) var<storage, read> b: array<f32>;
|
|
@group(0) @binding(2) var<storage, read_write> out: array<f32>;
|
|
@compute @workgroup_size(64)
|
|
fn main(@builtin(global_invocation_id) id: vec3u) {
|
|
let i = id.x;
|
|
if (i >= arrayLength(&out)) { return; }
|
|
out[i] = a[i] + b[i];
|
|
}
|
|
`;
|
|
const cs = device.createShaderModule({ code });
|
|
const cp = device.createComputePipeline({
|
|
layout: "auto", compute: { module: cs, entryPoint: "main" },
|
|
});
|
|
// dispatch: workgroups = ceil(N / 64)
|
|
```
|
|
|
|
### Storage buffer readback
|
|
```ts
|
|
async function readBuffer(src: GPUBuffer, size: number) {
|
|
const staging = device.createBuffer({
|
|
size, usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
|
|
});
|
|
const enc = device.createCommandEncoder();
|
|
enc.copyBufferToBuffer(src, 0, staging, 0, size);
|
|
device.queue.submit([enc.finish()]);
|
|
await staging.mapAsync(GPUMapMode.READ);
|
|
const data = new Float32Array(staging.getMappedRange().slice(0));
|
|
staging.unmap();
|
|
return data;
|
|
}
|
|
```
|
|
|
|
### Texture upload (ImageBitmap)
|
|
```ts
|
|
const bmp = await createImageBitmap(await (await fetch("/img.png")).blob());
|
|
const tex = device.createTexture({
|
|
size: [bmp.width, bmp.height], format: "rgba8unorm",
|
|
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
});
|
|
device.queue.copyExternalImageToTexture({ source: bmp }, { texture: tex }, [bmp.width, bmp.height]);
|
|
```
|
|
|
|
### Device-lost handling
|
|
```ts
|
|
device.lost.then((info) => {
|
|
console.error("Device lost:", info.message, info.reason);
|
|
if (info.reason !== "destroyed") {
|
|
// 매 reinit pipeline
|
|
}
|
|
});
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| 2D canvas, simple chart | Canvas2D / SVG |
|
|
| Standard 3D (low-mid) | Three.js (auto WebGL/WebGPU) |
|
|
| GPGPU / ML inference | WebGPU + WGSL compute |
|
|
| Cutting-edge graphics demo | WebGPU direct |
|
|
| Wide compatibility (old Safari, Android Go) | WebGL2 fallback 유지 |
|
|
|
|
**기본값**: 신규 project 매 WebGPU + WebGL2 fallback (Three.js / Babylon 매 자동).
|
|
|
|
## 🔗 Graph
|
|
- 변형: [[WebGL]] · [[WebGL 20|WebGL2]] · [[Vulkan]] · [[Metal]]
|
|
- 응용: [[Three.js WebGPU]] · [[Babylonjs]]
|
|
- Adjacent: [[WGSL]] · [[GPGPU]] · [[Compute Shader]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: Browser-side ML, high-end web visualization, GPGPU port to browser.
|
|
**언제 X**: Old browser support 필수 (use WebGL2), simple UI animation (CSS / Canvas2D 충분).
|
|
|
|
## ❌ 안티패턴
|
|
- **WebGPU global singleton 매 sync init**: 매 async — `await requestAdapter`.
|
|
- **Buffer leak**: `destroy()` 안 부름 — long-running app 매 OOM.
|
|
- **Per-frame pipeline create**: 매 expensive — 매 cache.
|
|
- **Bind group mismatch**: layout/binding index mismatch 매 silent error 의 매 source.
|
|
- **No fallback path**: 매 unsupported environment 매 blank screen — feature detect 필수.
|
|
- **Texture without proper usage flags**: 매 runtime validation error.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (W3C WebGPU spec 2024 CR, Chrome 130 release notes, Safari 18 WebGPU enablement).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — pipeline init, compute shader, ML inference patterns |
|