wgpu 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/README.md +26 -3
  4. data/docs/README.md +22 -0
  5. data/docs/api_coverage.md +132 -0
  6. data/docs/async.md +31 -0
  7. data/docs/bind_groups.md +25 -0
  8. data/docs/buffer_data.md +37 -0
  9. data/docs/command_encoding.md +24 -0
  10. data/docs/errors.md +40 -0
  11. data/docs/getting_started_compute.md +61 -0
  12. data/docs/getting_started_rendering.md +62 -0
  13. data/docs/installation.md +94 -0
  14. data/docs/pipeline_descriptors.md +38 -0
  15. data/docs/releasing.md +22 -0
  16. data/docs/resource_lifetime.md +94 -0
  17. data/docs/shaders.md +32 -0
  18. data/docs/texture_readback.md +19 -0
  19. data/docs/troubleshooting.md +48 -0
  20. data/docs/upgrading_wgpu_native.md +26 -0
  21. data/ext/wgpu/extconf.rb +10 -142
  22. data/lib/wgpu/commands/command_buffer.rb +11 -0
  23. data/lib/wgpu/commands/command_encoder.rb +65 -8
  24. data/lib/wgpu/commands/compute_pass.rb +10 -0
  25. data/lib/wgpu/commands/render_bundle_encoder.rb +10 -3
  26. data/lib/wgpu/commands/render_pass.rb +34 -8
  27. data/lib/wgpu/core/adapter.rb +36 -11
  28. data/lib/wgpu/core/async_waiter.rb +32 -4
  29. data/lib/wgpu/core/canvas_context.rb +0 -2
  30. data/lib/wgpu/core/device.rb +138 -42
  31. data/lib/wgpu/core/instance.rb +8 -4
  32. data/lib/wgpu/core/queue.rb +80 -49
  33. data/lib/wgpu/core/surface.rb +16 -17
  34. data/lib/wgpu/data_types.rb +67 -0
  35. data/lib/wgpu/descriptor_helpers.rb +39 -0
  36. data/lib/wgpu/error.rb +55 -0
  37. data/lib/wgpu/logging.rb +63 -0
  38. data/lib/wgpu/native/abi_verifier.rb +109 -0
  39. data/lib/wgpu/native/callbacks.rb +4 -1
  40. data/lib/wgpu/native/capabilities.rb +18 -2
  41. data/lib/wgpu/native/distribution.rb +113 -0
  42. data/lib/wgpu/native/enum_helper.rb +63 -0
  43. data/lib/wgpu/native/enums.rb +60 -8
  44. data/lib/wgpu/native/functions.rb +10 -10
  45. data/lib/wgpu/native/installer.rb +192 -0
  46. data/lib/wgpu/native/loader.rb +39 -21
  47. data/lib/wgpu/native_resource.rb +171 -0
  48. data/lib/wgpu/pipeline/bind_group.rb +12 -0
  49. data/lib/wgpu/pipeline/bind_group_layout.rb +91 -37
  50. data/lib/wgpu/pipeline/compute_pipeline.rb +28 -26
  51. data/lib/wgpu/pipeline/render_pipeline.rb +180 -68
  52. data/lib/wgpu/pipeline/shader_module.rb +50 -8
  53. data/lib/wgpu/resources/buffer.rb +148 -73
  54. data/lib/wgpu/resources/query_set.rb +14 -12
  55. data/lib/wgpu/resources/sampler.rb +36 -20
  56. data/lib/wgpu/resources/texture.rb +44 -42
  57. data/lib/wgpu/resources/texture_view.rb +11 -3
  58. data/lib/wgpu/texture_format.rb +82 -0
  59. data/lib/wgpu/version.rb +1 -1
  60. data/lib/wgpu/window.rb +8 -1
  61. data/lib/wgpu.rb +32 -0
  62. data/sig/wgpu.rbs +381 -0
  63. metadata +31 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd711bce02ed7be442c0f636460bf55f23df6e9b26cb7a6f07ed1b48b99ca78b
4
- data.tar.gz: f6ffe9530b72876da7b91805ab22b9a20dd065857bfc7fe99c66a79823fb4c75
3
+ metadata.gz: 65be5bedee12b2389a8bf8fd8ec2dcb883d739852178dda17cae6b682a26663e
4
+ data.tar.gz: 584a76214478803361befac5011bb22df20034f4b9e18731be6685b69877eabd
5
5
  SHA512:
6
- metadata.gz: 3430e9a25cdc932eb8441903b9f5f5aa83ebdafd34d56311ac8f794240a983b9adb6745fef484293dc968fb76b7e1f5da7813faa5a63b46b46126bb817e1b2eb
7
- data.tar.gz: 75b6031fc4e7654541e6e8596434f8c1e3c4b24d89a16d5b946a29a40ba8da0b6082e395d8ac0a47928e7bc56b2e1e473a350051d78b9a9e6edc4945d293deed
6
+ metadata.gz: cde23ae0101bf4e385adb161faca1221069ba15b275c066bcc1770aaab5f88e957bcaa7f8fcd06e1e711730fa75908fbee31e31140a06ba53c8acc55f4b634ed
7
+ data.tar.gz: d2d974230e674a282ca23a790eb16155730f2b5d9e97d0bc4df3c08822e862e0b17874c9c41b80155a5297bbda427c53ac35e77a7b455050ddb8c2da02031498
data/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## Unreleased
9
+
10
+ ## 1.2.0 - 2026-07-23
11
+
12
+ ### Added
13
+
14
+ - Add typed buffer data, texture layout, shader diagnostics, GPU errors, and
15
+ synchronous timeout APIs.
16
+ - Add ensure-safe command pass blocks, auto pipeline layouts, resource guards,
17
+ leak diagnostics, and callback keepalive.
18
+ - Add checksum-verified wgpu-native installation and ABI verification.
19
+ - Add headless rendering pixel verification, 3D/array texture round-trips,
20
+ async/error/timestamp examples, and GPU CI coverage.
21
+ - Add block-scoped resource cleanup, native diagnostic logging, RBS
22
+ signatures, YARD documentation, and Trusted Publishing release automation.
23
+
24
+ ### Changed
25
+
26
+ - Make the SDL3 Ruby gem optional for compute-only users.
27
+ - Validate descriptor shapes, enum values, buffer alignment, and texture
28
+ readback layout before native calls.
29
+ - Treat command buffers as consumed after submission and expose typed surface
30
+ acquisition status.
31
+
32
+ ### Fixed
33
+
34
+ - Correct `CompareFunction` values and add missing v27 surface status and
35
+ vertex format enum entries discovered by header verification.
36
+ - Guard exported-but-unimplemented v27 functions before they can abort Ruby,
37
+ expose native extension feature names, and avoid v27 query-set double
38
+ removal after `destroy`.
39
+
40
+ ## 1.1.0 - 2026-02-16
41
+
42
+ - Align bindings with wgpu v27 async ABI.
43
+ - Add shared async waiting for adapter/device.
44
+ - Migrate buffer/queue/shader async completion paths.
45
+
46
+ ## 1.0.0 - 2026-02-15
47
+
48
+ - Initial release
data/README.md CHANGED
@@ -4,7 +4,7 @@ Ruby bindings for [WebGPU](https://www.w3.org/TR/webgpu/) via [wgpu-native](http
4
4
 
5
5
  ## Features
6
6
 
7
- - Complete WebGPU API bindings using Ruby-FFI
7
+ - WebGPU object bindings using Ruby-FFI, with an explicit [API coverage matrix](docs/api_coverage.md)
8
8
  - GPU compute shaders (GPGPU)
9
9
  - Cross-platform support (macOS, Linux, Windows)
10
10
  - Automatic wgpu-native library download on gem install
@@ -12,7 +12,7 @@ Ruby bindings for [WebGPU](https://www.w3.org/TR/webgpu/) via [wgpu-native](http
12
12
  ## Requirements
13
13
 
14
14
  - Ruby 3.2+
15
- - Supported platforms:
15
+ - Supported platforms (64-bit only):
16
16
  - macOS (x86_64, arm64)
17
17
  - Linux (x86_64, aarch64)
18
18
  - Windows (x86_64)
@@ -38,6 +38,8 @@ gem install wgpu
38
38
  ```
39
39
 
40
40
  The wgpu-native library is automatically downloaded from GitHub Releases during installation.
41
+ See [Installation and native artifacts](docs/installation.md) for supported
42
+ artifacts, cache behavior, manual installation, and troubleshooting.
41
43
 
42
44
  ### Custom wgpu-native Build
43
45
 
@@ -128,7 +130,8 @@ puts output_data[0, 10].inspect
128
130
 
129
131
  ## Examples
130
132
 
131
- See the `examples/` directory for more complete examples:
133
+ See the [`examples/` guide](examples/README.md) for prerequisites, expected
134
+ results, and more complete examples:
132
135
 
133
136
  Compute examples:
134
137
  - `01_adapter_info.rb` - Query GPU adapter information
@@ -138,6 +141,13 @@ Compute examples:
138
141
  - `05_image_blur.rb` - Image processing with box filter
139
142
  - `06_parallel_reduction.rb` - Parallel sum reduction
140
143
 
144
+ Headless validation examples:
145
+
146
+ - `12_headless_render.rb` - Offscreen triangle and pixel verification
147
+ - `13_error_handling.rb` - Typed, labeled validation errors
148
+ - `14_async_map.rb` - Async mapping through a forced GC cycle
149
+ - `15_timestamp_query.rb` - Feature-gated timestamp query resolution
150
+
141
151
  Rendering examples (SDL3):
142
152
  - `07_triangle.rb` - Basic triangle rendering
143
153
  - `08_colored_quad.rb` - Indexed colored quad rendering
@@ -156,8 +166,14 @@ Rendering examples require SDL3 on your system:
156
166
  ```bash
157
167
  # macOS
158
168
  brew install sdl3
169
+
170
+ # Gemfile
171
+ gem "sdl3", "~> 1.0"
159
172
  ```
160
173
 
174
+ The core `wgpu` gem does not depend on SDL3. Only code that explicitly requires
175
+ `wgpu/window` needs the optional Ruby gem and system library.
176
+
161
177
  ## API Overview
162
178
 
163
179
  ### Core Objects
@@ -207,6 +223,13 @@ bundle install
207
223
  bundle exec rake spec
208
224
  ```
209
225
 
226
+ See [Resource lifetime](docs/resource_lifetime.md) before building long-running
227
+ applications, and use the [API coverage matrix](docs/api_coverage.md) to check
228
+ the current relationship to the WebGPU specification. The
229
+ [documentation index](docs/README.md) links the compute/rendering guides,
230
+ buffer/texture rules, async and error handling, troubleshooting, and release
231
+ operations.
232
+
210
233
  ## Contributing
211
234
 
212
235
  Bug reports and pull requests are welcome on GitHub at https://github.com/ydah/wgpu-ruby.
data/docs/README.md ADDED
@@ -0,0 +1,22 @@
1
+ # Documentation
2
+
3
+ - [Getting started: compute](getting_started_compute.md)
4
+ - [Getting started: rendering](getting_started_rendering.md)
5
+ - [API coverage](api_coverage.md)
6
+ - [Installation and native artifacts](installation.md)
7
+ - [Resource lifetime](resource_lifetime.md)
8
+ - [Async operations and polling](async.md)
9
+ - [GPU errors](errors.md)
10
+ - [Buffer data](buffer_data.md)
11
+ - [Texture readback](texture_readback.md)
12
+ - [Shaders and diagnostics](shaders.md)
13
+ - [Bind groups and layouts](bind_groups.md)
14
+ - [Pipeline descriptors](pipeline_descriptors.md)
15
+ - [Command encoding](command_encoding.md)
16
+ - [Troubleshooting](troubleshooting.md)
17
+ - [Upgrading wgpu-native](upgrading_wgpu_native.md)
18
+ - [Releasing](releasing.md)
19
+
20
+ Generated API documentation is built with `bundle exec yard doc`. Static API
21
+ signatures live in `sig/wgpu.rbs` and validate with
22
+ `bundle exec rbs -I sig validate`.
@@ -0,0 +1,132 @@
1
+ # WebGPU API coverage
2
+
3
+ This page records the public Ruby API implemented by wgpu-ruby 1.1 and its
4
+ relationship to the WebGPU object model. It is a baseline, not a claim that
5
+ every WebGPU feature is implemented.
6
+
7
+ The WebGPU names below follow the
8
+ [WebGPU Editor's Draft](https://gpuweb.github.io/gpuweb/). Browser-only APIs
9
+ such as DOM canvas discovery and external image import are intentionally
10
+ called out instead of being hidden by a general "complete" claim.
11
+
12
+ Legend:
13
+
14
+ - ✅: a public Ruby wrapper exists for the interface's core operations
15
+ - ◐: some operations or the returned data shape are implemented
16
+ - ❌: no public wrapper exists
17
+ - N/A: browser integration that does not map directly to a native Ruby binding
18
+
19
+ ## Object and supporting-interface coverage
20
+
21
+ | WebGPU interface | Ruby API | Status | Notes |
22
+ |---|---|:---:|---|
23
+ | `GPU` | `WGPU::Instance` | ◐ | Native entry point; adapter requests and event processing are exposed. Browser canvas-format and WGSL-language-feature queries are not. |
24
+ | `GPUAdapter` | `WGPU::Adapter` | ✅ | Adapter info, features, limits, and device requests are exposed. |
25
+ | `GPUAdapterInfo` | `Hash` from `Adapter#info` | ◐ | Returned as a Ruby hash rather than a value object. |
26
+ | `GPUBindGroup` | `WGPU::BindGroup` | ✅ | |
27
+ | `GPUBindGroupLayout` | `WGPU::BindGroupLayout` | ✅ | |
28
+ | `GPUBuffer` | `WGPU::Buffer` | ✅ | Mapping, destruction, and Ruby data helpers are included. |
29
+ | `GPUCanvasContext` | `WGPU::CanvasContext` | ◐ | Native-window presentation wrapper; no DOM `canvas` attribute. |
30
+ | `GPUCommandBuffer` | `WGPU::CommandBuffer` | ✅ | |
31
+ | `GPUCommandEncoder` | `WGPU::CommandEncoder` | ✅ | Buffer/texture copies, query resolution, timestamps, and debug markers are exposed. |
32
+ | `GPUCompilationInfo` | `ShaderModule#get_compilation_info` + `CompilationMessage` | ◐ | Typed diagnostics are ready, but pinned wgpu-native v27 exports only a panic stub; calls fail safely in Ruby. |
33
+ | `GPUCompilationMessage` | `WGPU::CompilationMessage` | ✅ | Message, type, line, column, offset, and length are typed fields. |
34
+ | `GPUComputePassEncoder` | `WGPU::ComputePass` | ✅ | |
35
+ | `GPUComputePipeline` | `WGPU::ComputePipeline` | ✅ | Auto layout and override constants are accepted. |
36
+ | `GPUDevice` | `WGPU::Device` | ◐ | Resource creation, error scopes, polling, features, and limits are exposed; device-lost and uncaptured-error subscriptions are not. |
37
+ | `GPUDeviceLostInfo` | — | ❌ | |
38
+ | `GPUError` | error hashes and `WGPU::Error` subclasses | ◐ | There is no common `GPUError` value object yet. |
39
+ | `GPUExternalTexture` | — | ❌ | Browser video/external-texture import is not exposed. |
40
+ | `GPUInternalError` | — | ❌ | |
41
+ | `GPUOutOfMemoryError` | — | ❌ | |
42
+ | `GPUPipelineError` | `WGPU::PipelineError` | ◐ | Ruby exception exists; native pipeline error data is not a value object. |
43
+ | `GPUPipelineLayout` | `WGPU::PipelineLayout` | ✅ | |
44
+ | `GPUQuerySet` | `WGPU::QuerySet` | ✅ | |
45
+ | `GPUQueue` | `WGPU::Queue` | ◐ | Submission, writes, work-done notification, and readback helpers are exposed; browser `copyExternalImageToTexture` is not. |
46
+ | `GPURenderBundle` | `WGPU::RenderBundle` | ✅ | |
47
+ | `GPURenderBundleEncoder` | `WGPU::RenderBundleEncoder` | ✅ | |
48
+ | `GPURenderPassEncoder` | `WGPU::RenderPass` | ✅ | |
49
+ | `GPURenderPipeline` | `WGPU::RenderPipeline` | ✅ | Auto layout and override constants are accepted. |
50
+ | `GPUSampler` | `WGPU::Sampler` | ✅ | |
51
+ | `GPUShaderModule` | `WGPU::ShaderModule` | ✅ | WGSL and wgpu-native SPIR-V/GLSL extensions are supported. |
52
+ | `GPUSupportedFeatures` | `Array<Symbol>` | ◐ | Represented as a Ruby array. |
53
+ | `GPUSupportedLimits` | `Hash` | ◐ | Represented as a Ruby hash. |
54
+ | `GPUTexture` | `WGPU::Texture` | ✅ | |
55
+ | `GPUTextureView` | `WGPU::TextureView` | ✅ | |
56
+ | `GPUUncapturedErrorEvent` | — | ❌ | |
57
+ | `GPUValidationError` | class-specific Ruby exceptions | ◐ | Validation errors are translated during resource creation. |
58
+ | `WGSLLanguageFeatures` | — | ❌ | |
59
+ | `GPUObjectBase` | `#handle`, labels on descriptors | ◐ | Common released-state behavior is not yet centralized. |
60
+ | `GPUPipelineBase` | `#get_bind_group_layout` | ✅ | Implemented by compute and render pipelines. |
61
+ | `GPUCommandsMixin` | `WGPU::CommandEncoder` | ✅ | |
62
+ | `GPUDebugCommandsMixin` | encoder/pass debug methods | ✅ | |
63
+ | `GPUBindingCommandsMixin` | pass/bundle binding methods | ✅ | |
64
+ | `GPURenderCommandsMixin` | render pass/bundle draw methods | ✅ | |
65
+ | `NavigatorGPU` | — | N/A | Browser-only discovery API. |
66
+
67
+ Descriptor dictionaries are represented as Ruby keyword arguments and nested
68
+ hashes, then converted to the matching `WGPU*Descriptor` FFI structs. The
69
+ implemented object APIs cover buffer, texture/view, sampler, bind group/layout,
70
+ pipeline layout, shader module, compute/render pipeline, command/pass/bundle,
71
+ query set, surface, and device/adapter/instance descriptors. Browser-only
72
+ descriptors (`GPUExternalTextureDescriptor`, external image copy descriptors,
73
+ and DOM canvas ownership) are not implemented.
74
+
75
+ ## Public Ruby API
76
+
77
+ Constructors are omitted where objects are normally returned by another
78
+ wrapper. `handle` readers are listed once here as a common escape hatch for
79
+ native interoperation.
80
+
81
+ | Ruby class | Public class methods | Public instance methods |
82
+ |---|---|---|
83
+ | `WGPU::Instance` | — | `request_adapter`, `request_adapter_async`, `enumerate_adapters`, `enumerate_adapters_async`, `process_events`, `get_canvas_context`, `release`, `handle` |
84
+ | `WGPU::Adapter` | `request`, `from_handle` | `request_device`, `request_device_async`, `info`, `name`, `vendor`, `adapter_type`, `backend_type`, `features`, `has_feature?`, `limits`, `summary`, `release`, `handle`, `instance` |
85
+ | `WGPU::Device` | `request` | `queue`, `adapter`, `adapter_info`, `features`, `has_feature?`, `limits`, all `create_*` methods, `push_error_scope`, `pop_error_scope`, `pop_error_scope_async`, `with_error_scope`, `poll`, `destroy`, `release`, `handle` |
86
+ | `WGPU::Queue` | — | `submit`, `write_buffer`, `write_texture`, `read_buffer`, `read_texture`, `on_submitted_work_done`, `on_submitted_work_done_async`, `release`, `handle` |
87
+ | `WGPU::Surface` | `from_metal_layer`, `from_windows_hwnd`, `from_xlib_window`, `from_wayland_surface` | `configure`, `unconfigure`, `current_texture`, `get_current_texture`, `present`, `get_configuration`, `get_preferred_format`, `capabilities`, `release`, `handle` |
88
+ | `WGPU::CanvasContext` | — | `configure`, `unconfigure`, `get_current_texture`, `present`, `get_configuration`, `get_preferred_format`, `set_physical_size`, `physical_size`, `release` |
89
+ | `WGPU::Buffer` | — | `write`, `mapped_range`, `get_mapped_range`, `unmap`, `map_sync`, `map_async`, `read_mapped_data`, `read_mapped`, `write_mapped`, `read_mapped_floats`, `map_state`, `size`, `usage`, `destroy`, `release`, `handle` |
90
+ | `WGPU::BufferMappedRange` | — | `read_bytes`, `write_bytes`, `read_floats`, `write_floats` |
91
+ | `WGPU::Texture` | `from_handle` | `create_view`, `width`, `height`, `depth_or_array_layers`, `size`, `mip_level_count`, `sample_count`, `dimension`, `format`, `usage`, `destroy`, `release`, `handle` |
92
+ | `WGPU::TextureView` | `from_handle` | `texture`, `size`, `release`, `handle` |
93
+ | `WGPU::Sampler` | — | `release`, `handle` |
94
+ | `WGPU::QuerySet` | — | `count`, `type`, `destroy`, `release`, `handle` |
95
+ | `WGPU::ShaderModule` | — | `get_compilation_info`, `get_compilation_info_async`, `release`, `handle` |
96
+ | `WGPU::BindGroupLayout` | `from_handle` | `release`, `handle` |
97
+ | `WGPU::BindGroup` | — | `release`, `handle` |
98
+ | `WGPU::PipelineLayout` | — | `release`, `handle` |
99
+ | `WGPU::ComputePipeline` | — | `get_bind_group_layout`, `release`, `handle` |
100
+ | `WGPU::RenderPipeline` | — | `get_bind_group_layout`, `release`, `handle` |
101
+ | `WGPU::CommandEncoder` | — | `begin_compute_pass`, `begin_render_pass`, copy/clear/query/debug methods, `finish`, `release`, `handle` |
102
+ | `WGPU::CommandBuffer` | — | `release`, `handle` |
103
+ | `WGPU::ComputePass` | — | pipeline/bind-group setup, dispatch/debug methods, `end_pass`, `end`, `release`, `handle` |
104
+ | `WGPU::RenderPass` | — | pipeline/bind-group/buffer setup, draw/state/query/debug methods, `end_pass`, `end`, `release`, `handle` |
105
+ | `WGPU::RenderBundleEncoder` | — | pipeline/bind-group/buffer setup, draw/debug methods, `finish`, `release`, `handle` |
106
+ | `WGPU::RenderBundle` | — | `release`, `handle` |
107
+ | `WGPU::AsyncTask` | — | `wait`, `value`, `then`, `complete?`, `pending?`, `error` |
108
+ | `WGPU::Window::SDLWindow` | — | `create_surface`, event/key helpers, `drawable_size`, `close` |
109
+
110
+ ## Examples as executable specifications
111
+
112
+ | Example | Purpose | Principal wgpu-ruby APIs exercised |
113
+ |---|---|---|
114
+ | `01_adapter_info.rb` | Adapter discovery and reporting | `Instance#enumerate_adapters`, `#request_adapter`, adapter info/features/limits |
115
+ | `02_compute_basic.rb` | Minimal storage-buffer compute | buffer mapping, bind groups/layouts, compute pipeline/pass, submit, readback |
116
+ | `03_buffer_operations.rb` | Buffer write, copy, map, and read | `create_buffer_with_data`, `Queue#write_buffer`, buffer copy, `map_sync` |
117
+ | `04_matrix_multiply.rb` | Multi-buffer compute | typed byte upload, storage/uniform bindings, workgroup dispatch, readback |
118
+ | `05_image_blur.rb` | 2D compute workload | multiple storage buffers, 2D dispatch, readback |
119
+ | `06_parallel_reduction.rb` | Iterative compute reduction | repeated dispatch/submission, `Queue#write_buffer`, readback |
120
+ | `07_triangle.rb` | Basic surface rendering | SDL surface setup, render pipeline/pass, draw, present |
121
+ | `08_colored_quad.rb` | Indexed vertex rendering | vertex/index buffers, render pipeline/pass, indexed draw |
122
+ | `09_clear_color.rb` | Per-frame clear and presentation | current texture/view, render pass clear, submit, present |
123
+ | `10_textured_quad.rb` | Texture sampling | texture upload/view, sampler, texture bind group, draw |
124
+ | `11_rotating_cube.rb` | Depth-tested 3D rendering | vertex/index/uniform/depth resources, pipeline, per-frame uniform write, draw |
125
+ | `12_headless_render.rb` | Offscreen triangle and readback | render-to-texture, block render pass, aligned texture readback, pixel assertions |
126
+ | `13_error_handling.rb` | Typed and labeled validation error | `BufferError`, operation/label context |
127
+ | `14_async_map.rb` | Async map and callback retention | `map_async`, `AsyncTask`, typed mapped reads, GC stress |
128
+ | `15_timestamp_query.rb` | Feature-gated GPU timestamps | timestamp pass writes, query resolution, u64 readback |
129
+
130
+ When a public API changes, the corresponding example is part of the acceptance
131
+ test surface. Compute and headless examples are automated in GPU CI; SDL
132
+ window examples remain manual integration checks.
data/docs/async.md ADDED
@@ -0,0 +1,31 @@
1
+ # Async operations and polling
2
+
3
+ wgpu-native v27 returns futures for adapter/device requests, buffer mapping,
4
+ error scopes, compilation info, and queue completion. wgpu-ruby keeps callback
5
+ objects alive until each operation finishes and selects the best available
6
+ progress mechanism:
7
+
8
+ 1. zero-time `wgpuInstanceWaitAny` polling;
9
+ 2. `Instance#process_events`;
10
+ 3. `Device#poll`;
11
+ 4. a short Ruby sleep when native polling cannot block.
12
+
13
+ wgpu-native v27 aborts when its unsupported timed-WaitAny instance feature is
14
+ requested, so wgpu-ruby deliberately leaves that feature disabled. The Ruby
15
+ poll interval defaults to 1 ms and can be adjusted with
16
+ `WGPU::AsyncWaiter.poll_interval=`.
17
+
18
+ That release also exports `wgpuBufferGetMapState` as an unimplemented panic
19
+ stub. `Buffer#map_state` is maintained by wgpu-ruby as `:unmapped`,
20
+ `:pending`, or `:mapped` while map operations run.
21
+
22
+ Synchronous adapter/device requests, `Buffer#map_sync`,
23
+ `Device#pop_error_scope`, and `Queue#on_submitted_work_done` accept
24
+ `timeout:` in seconds. The default `nil` preserves the prior unbounded wait.
25
+ Expiry raises `WGPU::TimeoutError`.
26
+
27
+ `*_async` methods return `WGPU::AsyncTask`, a convenience wrapper backed by a
28
+ Ruby Thread. Concurrent operations on the same WebGPU object are not
29
+ guaranteed safe. Prefer synchronous operations or external serialization when
30
+ ordering matters. Rendering event loops should call `instance.process_events`
31
+ or `device.poll` regularly.
@@ -0,0 +1,25 @@
1
+ # Bind groups and pipeline layouts
2
+
3
+ Each bind group layout entry requires `binding:`, `visibility:`, and exactly one
4
+ resource variant:
5
+
6
+ | Variant | Keys | Defaults |
7
+ |---|---|---|
8
+ | `buffer:` | `type`, `has_dynamic_offset`, `min_binding_size` | `:storage`, `false`, `0` |
9
+ | `sampler:` | `type` | `:filtering` |
10
+ | `texture:` | `sample_type`, `view_dimension`, `multisampled` | `:float`, `:d2`, `false` |
11
+ | `storage_texture:` | `format` (required), `access`, `view_dimension` | `:write_only`, `:d2` |
12
+
13
+ `visibility:` accepts one shader-stage Symbol, an integer bitmask, or an Array
14
+ such as `%i[vertex fragment]`. Unknown keys warn; missing required keys and
15
+ conflicting resource variants raise `ArgumentError` before FFI.
16
+
17
+ A bind group entry requires `binding:` and exactly one of `buffer:`,
18
+ `sampler:`, or `texture_view:`. Buffer entries may also include `offset:` and
19
+ `size:`.
20
+
21
+ Compute and render pipelines accept `layout: :auto` (also `"auto"` or `nil`).
22
+ Call `pipeline.get_bind_group_layout(index)` to obtain an inferred layout.
23
+ That returned wrapper owns a native reference; the caller must release it.
24
+ `examples/02_compute_basic.rb` demonstrates this path. Explicit
25
+ `PipelineLayout` objects remain fully supported.
@@ -0,0 +1,37 @@
1
+ # Buffer data
2
+
3
+ Ruby Arrays passed to buffer APIs use 32-bit floats by default, preserving the
4
+ original wgpu-ruby behavior. Pass `type:` to use another WebGPU scalar
5
+ representation:
6
+
7
+ | `type:` | Encoding | Bytes |
8
+ |---|---|---:|
9
+ | `:f32` | IEEE 754 float | 4 |
10
+ | `:f64` | IEEE 754 double | 8 |
11
+ | `:u32` | unsigned integer | 4 |
12
+ | `:i32` | signed integer | 4 |
13
+ | `:u16` | unsigned integer | 2 |
14
+ | `:u8` | unsigned integer | 1 |
15
+
16
+ The keyword is accepted by `Device#create_buffer_with_data`, `Buffer#write`,
17
+ `Buffer#write_mapped`, `Queue#write_buffer`, and `Queue#write_texture`.
18
+ Strings remain raw bytes and `FFI::Pointer` values remain unconverted.
19
+
20
+ ```ruby
21
+ buffer = device.create_buffer_with_data(
22
+ data: [1, 2, 3, 4],
23
+ type: :u32,
24
+ usage: %i[storage copy_src]
25
+ )
26
+
27
+ queue.write_buffer(buffer, 0, [10, 20], type: :u32)
28
+ ```
29
+
30
+ `BufferMappedRange#read` and `#write` expose the same `type:` keyword. The
31
+ existing `read_floats` / `write_floats` methods remain aliases for the `:f32`
32
+ path. Typed convenience pairs are also available for float64, uint32, int32,
33
+ uint16, and uint8.
34
+
35
+ WebGPU alignment errors are reported before entering FFI: queue write offsets
36
+ and sizes must be multiples of 4 bytes; mapped offsets must be multiples of 8
37
+ bytes and mapped sizes multiples of 4 bytes.
@@ -0,0 +1,24 @@
1
+ # Command encoding
2
+
3
+ Compute and render passes support both the original explicit form and an
4
+ ensure-safe block form:
5
+
6
+ ```ruby
7
+ encoder.begin_compute_pass do |pass|
8
+ pass.set_pipeline(pipeline)
9
+ pass.dispatch_workgroups(4)
10
+ end
11
+
12
+ encoder.begin_render_pass(color_attachments: attachments) do |pass|
13
+ pass.set_pipeline(pipeline)
14
+ pass.draw(3)
15
+ end
16
+ ```
17
+
18
+ The block form always ends and releases the pass, including when the block
19
+ raises, and returns the block's value. The explicit form remains compatible:
20
+ call `end_pass` (or `end`) and `release` yourself.
21
+
22
+ Only one pass may be active on a command encoder. `CommandEncoder#finish`
23
+ raises `WGPU::CommandError` while a pass is still active instead of handing
24
+ invalid state to wgpu-native. Calling `end_pass` more than once is harmless.
data/docs/errors.md ADDED
@@ -0,0 +1,40 @@
1
+ # GPU errors
2
+
3
+ `Device#pop_error_scope` keeps its v1.x Hash return value. New code may call
4
+ `pop_error_scope_typed`, which returns a `WGPU::GPUError` or `nil` for
5
+ `:no_error`.
6
+
7
+ `GPUError` has `type` and `message` readers, `to_h`, and `raise!`. `raise!`
8
+ maps WebGPU error types to `ValidationError`, `OutOfMemoryError`,
9
+ `InternalError`, or `DeviceLostError`.
10
+
11
+ Device-level callbacks can be installed after device creation:
12
+
13
+ ```ruby
14
+ device.on_uncaptured_error do |error|
15
+ warn "#{error.type}: #{error.message}"
16
+ end
17
+
18
+ device.on_device_lost do |reason, message|
19
+ warn "#{reason}: #{message}"
20
+ end
21
+ ```
22
+
23
+ wgpu-ruby installs native dispatch callbacks when requesting the device and
24
+ keeps them alive until release. User handlers can therefore be replaced without
25
+ recreating the native device. Without a handler, uncaptured errors and
26
+ unexpected device loss are written as warnings. Exceptions raised by a user
27
+ handler are caught at the FFI boundary and reported as warnings rather than
28
+ escaping through native callback code.
29
+
30
+ wgpu-native's process-wide diagnostic log can be routed into an application:
31
+
32
+ ```ruby
33
+ WGPU.on_log do |level, message|
34
+ MyLogger.public_send(level == :warn ? :warn : :debug, message)
35
+ end
36
+ WGPU.log_level = :info
37
+ ```
38
+
39
+ The callback is retained for the process lifetime (or until replaced), so a
40
+ Ruby GC cycle cannot invalidate the native callback pointer.
@@ -0,0 +1,61 @@
1
+ # Getting started: compute
2
+
3
+ Compute workloads need Ruby 3.2+, the `wgpu` gem, and a supported GPU driver.
4
+ They do not need SDL3.
5
+
6
+ ```ruby
7
+ require "wgpu"
8
+
9
+ instance = WGPU::Instance.new
10
+ adapter = instance.request_adapter(timeout: 10)
11
+ device = adapter.request_device(timeout: 10)
12
+
13
+ shader = device.create_shader_module(
14
+ code: <<~WGSL,
15
+ @group(0) @binding(0) var<storage, read_write> values: array<u32>;
16
+
17
+ @compute @workgroup_size(4)
18
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
19
+ values[id.x] *= 2u;
20
+ }
21
+ WGSL
22
+ )
23
+
24
+ buffer = device.create_buffer_with_data(
25
+ data: [1, 2, 3, 4],
26
+ type: :u32,
27
+ usage: %i[storage copy_src copy_dst]
28
+ )
29
+
30
+ pipeline = device.create_compute_pipeline(
31
+ layout: :auto,
32
+ compute: { module: shader }
33
+ )
34
+ layout = pipeline.get_bind_group_layout(0)
35
+ group = device.create_bind_group(
36
+ layout: layout,
37
+ entries: [{ binding: 0, buffer: buffer }]
38
+ )
39
+
40
+ encoder = device.create_command_encoder
41
+ encoder.begin_compute_pass do |pass|
42
+ pass.set_pipeline(pipeline)
43
+ pass.set_bind_group(0, group)
44
+ pass.dispatch_workgroups(1)
45
+ end
46
+ command_buffer = encoder.finish
47
+ device.queue.submit(command_buffer)
48
+
49
+ bytes = device.queue.read_buffer(buffer)
50
+ puts WGPU::DataTypes.unpack(bytes, type: :u32).inspect
51
+
52
+ [command_buffer, encoder, group, layout, pipeline, buffer, shader].each(&:release)
53
+ device.release
54
+ adapter.release
55
+ instance.release
56
+ ```
57
+
58
+ The full executable version is
59
+ [`examples/02_compute_basic.rb`](../examples/02_compute_basic.rb). For
60
+ production code, put resource release in `ensure` blocks and register
61
+ `Device#on_uncaptured_error` during startup.
@@ -0,0 +1,62 @@
1
+ # Getting started: rendering
2
+
3
+ Rendering adds a window-system integration. The bundled helper uses SDL3, but
4
+ surfaces themselves are independent of SDL and may be created from native
5
+ Metal, Win32, Xlib, or Wayland handles.
6
+
7
+ Add the optional dependency:
8
+
9
+ ```ruby
10
+ gem "wgpu"
11
+ gem "sdl3", "~> 1.0"
12
+ ```
13
+
14
+ Install the SDL3 system library, then load the helper explicitly:
15
+
16
+ ```ruby
17
+ require "wgpu"
18
+ require "wgpu/window"
19
+
20
+ window = WGPU::Window::SDLWindow.new(
21
+ title: "WebGPU",
22
+ width: 800,
23
+ height: 600
24
+ )
25
+ instance = WGPU::Instance.new
26
+ surface = window.create_surface(instance)
27
+ adapter = instance.request_adapter(compatible_surface: surface)
28
+ device = adapter.request_device
29
+
30
+ format = surface.capabilities(adapter).fetch(:formats).first
31
+ width, height = window.drawable_size
32
+ surface.configure(
33
+ device: device,
34
+ format: format,
35
+ width: width,
36
+ height: height,
37
+ present_mode: :fifo
38
+ )
39
+ ```
40
+
41
+ For every frame, acquire `surface.current_texture`, create a view, encode and
42
+ submit a render pass, call `surface.present`, and release frame-local objects.
43
+ The returned texture exposes `surface_status` as `:success_optimal` or
44
+ `:success_suboptimal`. Acquisition failures raise
45
+ `WGPU::SurfaceAcquisitionError`; inspect its `status` reader for `:timeout`,
46
+ `:outdated`, `:lost`, `:out_of_memory`, or `:device_lost`. Reconfigure on
47
+ `:outdated`/`:lost` after re-reading the drawable size.
48
+ When `drawable_size` changes, configure the surface again with positive pixel
49
+ dimensions. Do not render while a minimized window reports zero dimensions.
50
+
51
+ `Surface` is the low-level native-window API. `CanvasContext` owns and
52
+ delegates to a surface while retaining the familiar configure/acquire/present
53
+ shape. Integrations other than SDL3 can pass an `FFI::Pointer` obtained from
54
+ their window toolkit to `Surface.from_metal_layer`,
55
+ `Surface.from_windows_hwnd`, `Surface.from_xlib_window`, or
56
+ `Surface.from_wayland_surface`. The application must keep the corresponding
57
+ native window/display/layer alive longer than the surface; wgpu-ruby does not
58
+ take ownership of those platform objects.
59
+
60
+ [`examples/09_clear_color.rb`](../examples/09_clear_color.rb) is the smallest
61
+ resizable render loop. The other rendering examples cover vertex/index
62
+ buffers, textures, bind groups, depth testing, and uniform updates.