Skip to content

v0.28.0: Browser WebGPU backend — Pure Go WASM support#180

Merged
kolkov merged 8 commits into
mainfrom
release/v0.28.0
May 15, 2026
Merged

v0.28.0: Browser WebGPU backend — Pure Go WASM support#180
kolkov merged 8 commits into
mainfrom
release/v0.28.0

Conversation

@kolkov
Copy link
Copy Markdown
Contributor

@kolkov kolkov commented May 15, 2026

Summary

Browser WebGPU backend — complete syscall/jsnavigator.gpu implementation. Same public API, same user code — GOOS=js GOARCH=wasm go build produces a working WASM binary. Verified in Chrome: all smoke tests pass.

Closes #70.

5 Phases

  • Phase 1: Instance + Adapter + Device — navigator.gpu, pre-bound JS methods (Ebiten pattern), promise→goroutine async
  • Phase 2: Resources + Pipelines — Buffer, Texture, ShaderModule (WGSL passthrough), BindGroup, RenderPipeline, ComputePipeline. 97 TextureFormats + 31 VertexFormats + all WebGPU enum conversions
  • Phase 3: Command Recording + Submit — CommandEncoder, RenderPassEncoder (13 methods), ComputePassEncoder, Queue.Submit/WriteBuffer/WriteTexture. Verified against Rust wgpu backend/webgpu.rs
  • Phase 4: Surface/Canvas — HTMLCanvasElement + GPUCanvasContext, Configure, GetCurrentTexture, Present (no-op)
  • Phase 5: Buffer Mapping — MapAsync, MappedRange (lazy copy, Rust OnceCell pattern), dirty write-back

Also in this release

  • Flaky TestThread_CallAsync fix — channel sync replaces time.Sleep
  • goffi v0.5.1 — struct ABI, XMM return, CGO_ENABLED=1
  • x/sys v0.44.0
  • Defensive NULL handle guard in TransitionTextures/Buffers (Vulkan, DX12)
  • Architecture docs updated — dual-path diagram (native/browser), COMPUTE-BACKENDS browser column

Stats

  • ~6500 LOC browser backend (4000 internal/browser + 2500 root wrappers)
  • 29+ tests (enum conversions, all run natively)
  • Zero external dependencies — only syscall/js
  • WASM binary: 3MB

Test plan

  • GOOS=js GOARCH=wasm go build . — compiles
  • Browser smoke test in Chrome — ALL TESTS PASSED (Instance, Adapter, Device, Buffer, ShaderModule, Submit, WriteBuffer)
  • go build ./... — native Windows, Linux, macOS
  • go test ./... — all pass
  • golangci-lint run --timeout=5m — 0 issues (Windows, Linux, macOS)
  • Cross-reference audit against Rust wgpu backend/webgpu.rs (4047 LOC) — complete

kolkov added 8 commits May 14, 2026 13:36
…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).
@kolkov kolkov merged commit ed1e9f7 into main May 15, 2026
10 checks passed
@kolkov kolkov deleted the release/v0.28.0 branch May 15, 2026 06:42
@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

❌ Patch coverage is 97.01493% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/browser/convert_enums.go 96.80% 8 Missing ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant