7.5 KiB
7.5 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frontend-webgpu-patterns | WebGPU — Browser GPU 컴퓨팅 / 그래픽 | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
WebGPU
WebGL 후속. Modern GPU API + compute shader. 그래픽 + GPU compute (ML inference, simulation). 2024+ Chrome / Edge / Safari / Firefox 지원.
📖 핵심 개념
- Adapter / Device: GPU handle.
- Shader: WGSL (WebGPU Shading Language).
- Pipeline: render or compute.
- Buffer: GPU 메모리.
💻 코드 패턴
Setup
if (!navigator.gpu) throw new Error('WebGPU not supported');
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter!.requestDevice();
캔버스 setup
const canvas = document.querySelector('canvas')!;
const ctx = canvas.getContext('webgpu')!;
const format = navigator.gpu.getPreferredCanvasFormat();
ctx.configure({ device, format, alphaMode: 'premultiplied' });
간단 render — 색칠된 삼각형
const shader = device.createShaderModule({
code: `
@vertex
fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
var p = array<vec2f, 3>(
vec2f(0.0, 0.5),
vec2f(-0.5, -0.5),
vec2f(0.5, -0.5)
);
return vec4f(p[i], 0.0, 1.0);
}
@fragment
fn fs() -> @location(0) vec4f {
return vec4f(1.0, 0.5, 0.0, 1.0);
}
`,
});
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: { module: shader, entryPoint: 'vs' },
fragment: { module: shader, entryPoint: 'fs', targets: [{ format }] },
});
function render() {
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: ctx.getCurrentTexture().createView(),
clearValue: [0, 0, 0, 1],
loadOp: 'clear',
storeOp: 'store',
}],
});
pass.setPipeline(pipeline);
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
}
render();
Compute shader (matrix multiply)
const shader = device.createShaderModule({
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> result: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3u) {
let i = id.x;
result[i] = a[i] * b[i] + 1.0;
}
`,
});
const pipeline = device.createComputePipeline({
layout: 'auto',
compute: { module: shader, entryPoint: 'main' },
});
const N = 1024 * 1024;
const aArr = new Float32Array(N).fill(2);
const bArr = new Float32Array(N).fill(3);
const aBuf = device.createBuffer({ size: aArr.byteLength, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
const bBuf = device.createBuffer({ size: bArr.byteLength, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
const resultBuf = device.createBuffer({ size: N * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });
device.queue.writeBuffer(aBuf, 0, aArr);
device.queue.writeBuffer(bBuf, 0, bArr);
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: 0, resource: { buffer: aBuf } },
{ binding: 1, resource: { buffer: bBuf } },
{ binding: 2, resource: { buffer: resultBuf } },
],
});
const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(Math.ceil(N / 64));
pass.end();
// CPU 로 read back
const readBuf = device.createBuffer({ size: N * 4, usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST });
encoder.copyBufferToBuffer(resultBuf, 0, readBuf, 0, N * 4);
device.queue.submit([encoder.finish()]);
await readBuf.mapAsync(GPUMapMode.READ);
const result = new Float32Array(readBuf.getMappedRange().slice(0));
readBuf.unmap();
console.log(result[0]); // 7
Texture / image
const img = await createImageBitmap(await fetch('/image.jpg').then(r => r.blob()));
const tex = device.createTexture({
size: [img.width, img.height],
format: 'rgba8unorm',
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
});
device.queue.copyExternalImageToTexture({ source: img }, { texture: tex }, [img.width, img.height]);
ML — Transformers.js (WebGPU backend)
import { pipeline, env } from '@xenova/transformers';
env.backends.onnx.preferredBackend = 'webgpu';
const pipe = await pipeline('text-generation', 'Xenova/Llama-3.2-1B-Instruct');
const out = await pipe('Hello', { max_new_tokens: 50 });
→ Browser 안 LLM 빠름 (WebGPU 가 WASM 보다 5-10x).
Compute — image filter
@group(0) @binding(0) var inputTex: texture_2d<f32>;
@group(0) @binding(1) var outputTex: texture_storage_2d<rgba8unorm, write>;
@compute @workgroup_size(8, 8)
fn blur(@builtin(global_invocation_id) id: vec3u) {
let coord = vec2i(id.xy);
var color = vec4f(0.0);
for (var dx = -2; dx <= 2; dx++) {
for (var dy = -2; dy <= 2; dy++) {
color += textureLoad(inputTex, coord + vec2i(dx, dy), 0);
}
}
color /= 25.0;
textureStore(outputTex, coord, color);
}
3D rendering
// Three.js + WebGPU renderer
import { WebGPURenderer } from 'three/examples/jsm/renderers/webgpu/WebGPURenderer.js';
const renderer = new WebGPURenderer({ canvas });
await renderer.init();
// 일반 Three.js scene
Babylon.js
import { Engine, WebGPUEngine } from '@babylonjs/core';
const engine = new WebGPUEngine(canvas);
await engine.initAsync();
Fallback (WebGL / WASM)
async function getRenderer() {
if (navigator.gpu) {
try {
const adapter = await navigator.gpu.requestAdapter();
if (adapter) return 'webgpu';
} catch {}
}
if ('WebGL2RenderingContext' in window) return 'webgl2';
return 'cpu';
}
Performance tips
- Workgroup size = multiple of 32 (보통 64).
- Buffer alignment 16 byte.
- 큰 buffer 보다 small batch.
- Texture > raw buffer for spatial.
- writeBuffer 보다 staging buffer + queue.
디버그
Chrome: chrome://gpu, Performance tab, GPU profiler.
Spector.js — WebGL/WebGPU frame capture.
Limitations (2026)
+ Major browsers 지원 (Chrome 113+, Safari 17.4+, Firefox 141+).
- Mobile: 일부 device 만.
- Compute shader = 안전 (서버 모델 download 가능).
- Atomic operations 일부 한정.
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| 3D 새 프로젝트 | WebGPU (Three.js / Babylon) |
| 기존 WebGL | 점진 마이그레이션 |
| ML inference | Transformers.js + WebGPU |
| GPU compute | WebGPU compute shader |
| 옛 browser 지원 | WebGL fallback |
| Game | Unity WebGPU / 자체 |
❌ 안티패턴
- No fallback: 옛 browser fail.
- 모든 frame writeBuffer 큰 data: bandwidth. staging.
- CPU read back 매 frame: 느림. GPU keep.
- 너무 작은 dispatch: launch overhead.
- Memory leak (destroy 안 함): GPU resources.
- Float64 가정: WebGPU = float32.
- Adapter / device 매번 request: cache.
🤖 LLM 활용 힌트
- Compute shader = ML / image / simulation 강력.
- Three.js / Babylon WebGPU renderer 가 가장 단순 시작.
- Transformers.js + WebGPU = browser LLM.