wgpu-cr
wgpu-cr
Crystal bindings for wgpu-native (the Rust implementation of WebGPU), in the spirit of wgpu-py.
Like wgpu-py, the project exposes two levels:
| Level | Module | Description |
|---|---|---|
| Low level (FFI) | LibWGPU |
1:1 binding to the WebGPU C API, generated automatically from webgpu.h. |
| High level | WGPU |
Idiomatic helpers (StringView, synchronous adapter/device requests, buffer mapping…). |
Status
✅ Working today:
- Automatic download of wgpu-native (lib + headers + spec).
- Full FFI binding generation: 199 functions, 92 structs, 54 enums, 5 bitflags, 23 handles, 10 callbacks.
- End-to-end compute (tested: a WGSL shader doubling an array on the GPU).
- Windowed rendering — a triangle in a GLFW window via a Metal surface (macOS).
- Adapter/device requests and buffer mapping (C ↔ Crystal callbacks).
- Log forwarding:
wgpuSetLogCallback/wgpuSetLogLevel(wgpu.h) +WGPU.set_log_stderr(level).
🚧 Coming next (wgpu-py parity):
- A complete object layer (
Device#create_buffer, etc.) on top of the FFI. - Surfaces on Linux (X11/Wayland) and Windows (HWND) — structs are bound, examples pending.
- Render helpers (vertex buffers, textures, samplers, depth).
- Bindings for the native
wgpu.hextensions (DevicePoll, etc.).
Requirements
- Crystal ≥ 1.16
curlandunzip
Installation
git clone <repo> && cd wgpu-cr
shards install # triggers the postinstall (download_wgpu.sh)
Or manually:
./scripts/download_wgpu.sh # latest wgpu-native release
crystal run scripts/generate_bindings.cr
Downloading wgpu-native
The script detects the OS/architecture, fetches the right release and installs vendor/wgpu-native/ (lib + headers + webgpu.yml), then writes the link flags into src/wgpu/link.cr.
./scripts/download_wgpu.sh # latest version
./scripts/download_wgpu.sh v29.0.0.0 # pinned version
WGPU_NATIVE_BUILD=debug ./scripts/download_wgpu.sh
Variables: WGPU_NATIVE_VERSION, WGPU_NATIVE_BUILD (release/debug), WGPU_NATIVE_OS, WGPU_NATIVE_ARCH.
Regenerating the binding
The binding is generated from vendor/wgpu-native/include/webgpu/webgpu.h (the ABI source of truth):
crystal run scripts/generate_bindings.cr # writes src/wgpu/native.cr
Example — compute
crystal run examples/compute.cr
wgpu-cr 0.1.0 (wgpu-native v29.0.0.0)
Input : 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, … (256 elements)
Output : 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, …
✅ GPU computation correct (each element × 2)
See examples/compute.cr for the full pipeline: instance → adapter → device → buffer → WGSL shader → pipeline → bind group → dispatch → copy → mapping → read back.
Example — triangle in a window
crystal run examples/triangle.cr
Opens a GLFW window and renders a triangle. The windowing glue lives in examples/lib_glfw.cr (GLFW + a few Objective-C calls to attach a CAMetalLayer) — kept out of the core binding on purpose.
- macOS only for now (Cocoa/Metal native surface). Linux (X11/Wayland) and Windows (HWND) surfaces are bound in
LibWGPUbut not yet wired into an example. - Requires GLFW:
brew install glfw. WGPU_FRAMES=Nauto-quits after N frames (used for headless testing).
The render path: GLFW window → Metal surface → adapter/device → render pipeline → per-frame (acquire texture → render pass → present).
Tests
crystal spec
Architecture
scripts/download_wgpu.sh # fetches wgpu-native (lib + headers + spec)
scripts/generate_bindings.cr # webgpu.h -> src/wgpu/native.cr (lib LibWGPU)
src/wgpu.cr # entry point (require "wgpu")
src/wgpu/native.cr # generated FFI binding (do not edit)
src/wgpu/link.cr # generated link flags (do not edit)
src/wgpu/api.cr # idiomatic WGPU layer
examples/compute.cr # GPU compute (headless)
examples/triangle.cr # windowed render (GLFW, macOS)
examples/lib_glfw.cr # GLFW + Objective-C glue for the window example
vendor/wgpu-native/ # downloaded artifacts (gitignored)
The generator parses the C header directly (it is regular and itself generated): it extracts handles, enums, bitflags, callbacks, structs and functions, then emits a lib LibWGPU whose memory layout matches the C ABI exactly.
macOS / linker note
Some Homebrew installs ship an lld whose version does not match libLLVM, which breaks Crystal's default link (Symbol not found … llvm:🆑:ParseCommandLineOptions). The binding therefore forces Apple's system linker (-fuse-ld=/usr/bin/ld) in src/wgpu/link.cr. The "clean" system-side fix is brew reinstall lld to align the versions.
License
MIT — see LICENSE.
wgpu-cr
- 2
- 0
- 0
- 1
- 0
- about 6 hours ago
- August 19, 2026
MIT License
Wed, 19 Aug 2026 18:01:06 GMT