v0.28.0: Browser WebGPU backend — Pure Go WASM support#180
Merged
Conversation
…call/js Browser WebGPU backend in internal/browser/ (727 LOC, 8 files): - Instance: navigator.gpu access, RequestAdapter - Adapter: GPUAdapter wrapper, RequestDevice - Device: 11 pre-bound creation methods (Ebiten pattern) - Queue: ref holder (methods in Phase 3) - Promise utility: goroutine+channel async→sync - Type conversion: Features (11 mapped), Limits (28 fields) - Error types: JSError, sentinel errors Root _browser.go files delegate to internal/browser/. Zero external dependencies — only syscall/js. GOOS=js GOARCH=wasm go build . passes.
…sion internal/browser/: Buffer, Texture, TextureView, Sampler, ShaderModule, BindGroupLayout, BindGroup, PipelineLayout, RenderPipeline, ComputePipeline. convert_enums.go: 97 TextureFormats, 31 VertexFormats, all WebGPU enums (BlendFactor, CompareFunction, StencilOp, AddressMode, FilterMode, etc.) convert_resources.go: JS descriptor builders for all resource types including full RenderPipeline descriptor (vertex/fragment/primitive/ depth-stencil/multisample state). 22 table-driven tests cover every enum mapping. 0 lint issues. Device pre-bound methods wired to create all resource types. 2605 LOC added, zero external dependencies.
CommandEncoder (8 pre-bound methods), RenderPassEncoder (13 methods), ComputePassEncoder (5 methods), Queue Submit/WriteBuffer/WriteTexture. Verified against Rust wgpu backend/webgpu.rs patterns: - Dynamic offsets via Uint32Array (Rust set_bind_group variant) - WriteBuffer via js.CopyBytesToJS (Rust Uint8Array::from) - SetVertexBuffer size=0 omits param (Rust no-size variant) - RenderPass clear value only when loadOp=clear - TransitionTextures/Buffers no-op (browser handles barriers) - Command buffers consumed on Submit (marked released) 975 LOC added, zero external dependencies.
Surface wraps HTMLCanvasElement + GPUCanvasContext. Two constructors: CreateSurface (DOM lookup by data-raw-handle attr or first canvas) and CreateSurfaceFromCanvas (direct js.Value). Configure sets canvas dimensions + GPUCanvasContext.configure(). GetCurrentTexture returns frame texture. Present is no-op (browser auto-presents). GetSurfaceCapabilities returns preferred format via navigator.gpu.getPreferredCanvasFormat(). Verified against Rust wgpu WebSurface patterns: present=empty, canvas dimensions in configure(), Mailbox/Immediate rejected. TextureFormatFromJS reverse map for preferred format detection. 598 LOC added, 29 tests pass, zero external dependencies.
MapAsync/Map with Promise-based goroutine+channel pattern. MappedRange with lazy copy (Rust OnceCell pattern): Bytes() reads from JS ArrayBuffer on first access, BytesMut() marks dirty, Release() auto-flushes dirty data back to JS (Rust Drop pattern). Verified against Rust wgpu WebBuffer/WebBufferMappedRange: - getMappedRange called once, ArrayBuffer cached (Rust set_mapped_range) - Uint8Array sub-range views for offset access - CopyBytesToGo/CopyBytesToJS for cross-boundary transfer - mappedAtCreation sets mapState + records range 471 LOC added. All 5 phases complete. Zero external dependencies.
CopyBufferToTexture was pre-bound in internal/browser but missing from root encoder_browser.go. ClearBuffer also added. Both verified against Rust wgpu backend/webgpu.rs copy_buffer_to_texture / clear_buffer.
CHANGELOG: browser WebGPU backend (WASM-001) — 5 phases, ~6500 LOC. README: Browser backend in features table, WASM build instructions. ROADMAP: v0.28.0, WebAssembly marked DONE, released versions updated. ARCHITECTURE: dual-path diagram (native/browser), internal/browser/ section. COMPUTE-BACKENDS: Browser column in support matrix + browser section. Closes #70 (WASM support request).
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Browser WebGPU backend — complete
syscall/js→navigator.gpuimplementation. Same public API, same user code —GOOS=js GOARCH=wasm go buildproduces a working WASM binary. Verified in Chrome: all smoke tests pass.Closes #70.
5 Phases
navigator.gpu, pre-bound JS methods (Ebiten pattern), promise→goroutine asyncbackend/webgpu.rsAlso in this release
Stats
syscall/jsTest plan
GOOS=js GOARCH=wasm go build .— compilesgo build ./...— native Windows, Linux, macOSgo test ./...— all passgolangci-lint run --timeout=5m— 0 issues (Windows, Linux, macOS)backend/webgpu.rs(4047 LOC) — complete