--- id: frontend-webgpu-patterns title: WebGPU — Browser GPU 컴퓨팅 / 그래픽 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [frontend, webgpu, gpu, vibe-coding] tech_stack: { language: "TS / WGSL", applicable_to: ["Frontend"] } applied_in: [] aliases: [WebGPU, WGSL, compute shader, render pipeline, GPU buffer, browser GPU] --- # 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 ```ts if (!navigator.gpu) throw new Error('WebGPU not supported'); const adapter = await navigator.gpu.requestAdapter(); const device = await adapter!.requestDevice(); ``` ### 캔버스 setup ```ts const canvas = document.querySelector('canvas')!; const ctx = canvas.getContext('webgpu')!; const format = navigator.gpu.getPreferredCanvasFormat(); ctx.configure({ device, format, alphaMode: 'premultiplied' }); ``` ### 간단 render — 색칠된 삼각형 ```ts const shader = device.createShaderModule({ code: ` @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f { var p = array( 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) ```ts const shader = device.createShaderModule({ code: ` @group(0) @binding(0) var a: array; @group(0) @binding(1) var b: array; @group(0) @binding(2) var result: array; @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 ```ts 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) ```ts 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 ```wgsl @group(0) @binding(0) var inputTex: texture_2d; @group(0) @binding(1) var outputTex: texture_storage_2d; @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 ```ts // 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 ```ts import { Engine, WebGPUEngine } from '@babylonjs/core'; const engine = new WebGPUEngine(canvas); await engine.initAsync(); ``` ### Fallback (WebGL / WASM) ```ts 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. ## 🔗 관련 문서 - [[Frontend_Three_R3F]] - [[Frontend_WASM_Integration]] - [[AI_Local_LLM_Inference]]