wgpu 1.1.0 → 1.2.1

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/README.md +44 -5
  4. data/docs/README.md +22 -0
  5. data/docs/api_coverage.md +140 -0
  6. data/docs/async.md +41 -0
  7. data/docs/bind_groups.md +25 -0
  8. data/docs/buffer_data.md +37 -0
  9. data/docs/command_encoding.md +49 -0
  10. data/docs/errors.md +40 -0
  11. data/docs/getting_started_compute.md +62 -0
  12. data/docs/getting_started_rendering.md +62 -0
  13. data/docs/installation.md +94 -0
  14. data/docs/pipeline_descriptors.md +43 -0
  15. data/docs/releasing.md +32 -0
  16. data/docs/resource_lifetime.md +108 -0
  17. data/docs/shaders.md +32 -0
  18. data/docs/texture_readback.md +46 -0
  19. data/docs/troubleshooting.md +53 -0
  20. data/docs/upgrading_wgpu_native.md +37 -0
  21. data/ext/wgpu/extconf.rb +10 -142
  22. data/lib/wgpu/async_task.rb +19 -0
  23. data/lib/wgpu/commands/command_buffer.rb +25 -1
  24. data/lib/wgpu/commands/command_encoder.rb +123 -9
  25. data/lib/wgpu/commands/compute_pass.rb +53 -0
  26. data/lib/wgpu/commands/render_bundle.rb +9 -1
  27. data/lib/wgpu/commands/render_bundle_encoder.rb +65 -4
  28. data/lib/wgpu/commands/render_pass.rb +136 -8
  29. data/lib/wgpu/core/adapter.rb +123 -19
  30. data/lib/wgpu/core/async_waiter.rb +47 -4
  31. data/lib/wgpu/core/canvas_context.rb +32 -2
  32. data/lib/wgpu/core/device.rb +399 -53
  33. data/lib/wgpu/core/instance.rb +28 -4
  34. data/lib/wgpu/core/queue.rb +197 -51
  35. data/lib/wgpu/core/surface.rb +64 -17
  36. data/lib/wgpu/data_types.rb +83 -0
  37. data/lib/wgpu/descriptor_helpers.rb +104 -0
  38. data/lib/wgpu/error.rb +70 -0
  39. data/lib/wgpu/logging.rb +63 -0
  40. data/lib/wgpu/native/abi_verifier.rb +143 -0
  41. data/lib/wgpu/native/callbacks.rb +10 -1
  42. data/lib/wgpu/native/capabilities.rb +32 -2
  43. data/lib/wgpu/native/distribution.rb +176 -0
  44. data/lib/wgpu/native/enum_helper.rb +80 -0
  45. data/lib/wgpu/native/enums.rb +68 -8
  46. data/lib/wgpu/native/fixtures/webgpu-v27.0.4.0-enums.h +848 -0
  47. data/lib/wgpu/native/functions.rb +21 -10
  48. data/lib/wgpu/native/installer.rb +223 -0
  49. data/lib/wgpu/native/loader.rb +61 -21
  50. data/lib/wgpu/native/structs.rb +18 -1
  51. data/lib/wgpu/native_resource.rb +342 -0
  52. data/lib/wgpu/pipeline/bind_group.rb +21 -0
  53. data/lib/wgpu/pipeline/bind_group_layout.rb +108 -41
  54. data/lib/wgpu/pipeline/compute_pipeline.rb +40 -50
  55. data/lib/wgpu/pipeline/pipeline_layout.rb +8 -0
  56. data/lib/wgpu/pipeline/render_pipeline.rb +207 -110
  57. data/lib/wgpu/pipeline/shader_module.rb +95 -28
  58. data/lib/wgpu/resources/buffer.rb +387 -85
  59. data/lib/wgpu/resources/query_set.rb +26 -12
  60. data/lib/wgpu/resources/sampler.rb +43 -20
  61. data/lib/wgpu/resources/texture.rb +89 -48
  62. data/lib/wgpu/resources/texture_view.rb +35 -7
  63. data/lib/wgpu/texture_format.rb +96 -0
  64. data/lib/wgpu/version.rb +1 -1
  65. data/lib/wgpu/window.rb +34 -1
  66. data/lib/wgpu.rb +32 -0
  67. data/sig/wgpu.rbs +460 -0
  68. metadata +33 -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: c118a2950771b2f34f06fcf4642634e57e8b1de07c26681b81aa94d6a1faaf93
4
+ data.tar.gz: b4f4cc4e97846d21e74144194f97ede7cb2704725cb5887a885345ceedd1c8f1
5
5
  SHA512:
6
- metadata.gz: 3430e9a25cdc932eb8441903b9f5f5aa83ebdafd34d56311ac8f794240a983b9adb6745fef484293dc968fb76b7e1f5da7813faa5a63b46b46126bb817e1b2eb
7
- data.tar.gz: 75b6031fc4e7654541e6e8596434f8c1e3c4b24d89a16d5b946a29a40ba8da0b6082e395d8ac0a47928e7bc56b2e1e473a350051d78b9a9e6edc4945d293deed
6
+ metadata.gz: 5fad367a0475a31c846fa57151a01d6fda7aed9a5592f6167237117da8967df7269a7ac0233059a174be0803794dc844ee4660cd1383ce3fa858009620100036
7
+ data.tar.gz: 967d67b899a1ca01e5e805407677772aeaec152d72ede7b31746a8baef6d5fa04544863f7d8e70a4bb2804506ccf8fdd58036c5d5a99c49cfe338be73d667504
data/CHANGELOG.md ADDED
@@ -0,0 +1,88 @@
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.1 - 2026-07-24
11
+
12
+ ### Added
13
+
14
+ - Add reusable staging buffers to `Queue#read_buffer` and
15
+ `Queue#read_texture`, together with a padded texture-readback example and
16
+ guide.
17
+ - Support WGSL override constants and omitted entry points across compute,
18
+ vertex, and fragment pipeline stages.
19
+ - Add a pinned wgpu-native v27.0.4.0 header fixture, ABI update tooling, and
20
+ cross-platform native artifact verification.
21
+ - Complete RBS and YARD coverage for the public API and expand acceptance
22
+ coverage for typed buffers, descriptors, errors, timeouts, resource
23
+ lifetimes, and GPU examples.
24
+
25
+ ### Changed
26
+
27
+ - Centralize native capability metadata and validate enum, callback, struct,
28
+ and function ABI expectations against the pinned wgpu-native release.
29
+ - Make compute and rendering examples verify their results, and enforce
30
+ documentation coverage, SDL3-free installation, release checks, and strict
31
+ lavapipe GPU coverage in CI.
32
+
33
+ ### Fixed
34
+
35
+ - Retain callbacks, user data, devices, and instances through dependent
36
+ resource and pending-operation lifetimes, preventing use-after-free crashes
37
+ after release, garbage collection, or timeout.
38
+ - Reject out-of-bounds mapped ranges and prevent late buffer, queue, shader,
39
+ and error-scope callbacks from corrupting completed operation state.
40
+ - Preserve row padding and clean up temporary resources during buffer and
41
+ texture readback, including repeated reads with caller-owned staging buffers.
42
+ - Recover rendering loops from timed-out, outdated, and lost surface frames,
43
+ report fatal acquisition states explicitly, and release every acquired
44
+ texture and view.
45
+ - Track adopted native handles in leak diagnostics and keep release operations
46
+ idempotent across wrapper types.
47
+ - Correct the isolated core-gem dependency path and make Windows native
48
+ artifact checks independent of shell quoting.
49
+
50
+ ## 1.2.0 - 2026-07-23
51
+
52
+ ### Added
53
+
54
+ - Add typed buffer data, texture layout, shader diagnostics, GPU errors, and
55
+ synchronous timeout APIs.
56
+ - Add ensure-safe command pass blocks, auto pipeline layouts, resource guards,
57
+ leak diagnostics, and callback keepalive.
58
+ - Add checksum-verified wgpu-native installation and ABI verification.
59
+ - Add headless rendering pixel verification, 3D/array texture round-trips,
60
+ async/error/timestamp examples, and GPU CI coverage.
61
+ - Add block-scoped resource cleanup, native diagnostic logging, RBS
62
+ signatures, YARD documentation, and Trusted Publishing release automation.
63
+
64
+ ### Changed
65
+
66
+ - Make the SDL3 Ruby gem optional for compute-only users.
67
+ - Validate descriptor shapes, enum values, buffer alignment, and texture
68
+ readback layout before native calls.
69
+ - Treat command buffers as consumed after submission and expose typed surface
70
+ acquisition status.
71
+
72
+ ### Fixed
73
+
74
+ - Correct `CompareFunction` values and add missing v27 surface status and
75
+ vertex format enum entries discovered by header verification.
76
+ - Guard exported-but-unimplemented v27 functions before they can abort Ruby,
77
+ expose native extension feature names, and avoid v27 query-set double
78
+ removal after `destroy`.
79
+
80
+ ## 1.1.0 - 2026-02-16
81
+
82
+ - Align bindings with wgpu v27 async ABI.
83
+ - Add shared async waiting for adapter/device.
84
+ - Migrate buffer/queue/shader async completion paths.
85
+
86
+ ## 1.0.0 - 2026-02-15
87
+
88
+ - 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
 
@@ -51,6 +53,7 @@ export WGPU_LIB_PATH=/path/to/libwgpu_native.so
51
53
 
52
54
  ### Basic Setup
53
55
 
56
+ <!-- wgpu-example: run; expect: Using: -->
54
57
  ```ruby
55
58
  require 'wgpu'
56
59
 
@@ -60,10 +63,15 @@ device = adapter.request_device
60
63
  queue = device.queue
61
64
 
62
65
  puts "Using: #{adapter.info[:device]} (#{adapter.info[:backend_type]})"
66
+
67
+ device.release
68
+ adapter.release
69
+ instance.release
63
70
  ```
64
71
 
65
72
  ### Compute Shader Example
66
73
 
74
+ <!-- wgpu-example: run; expect: [0.0, 2.0, 4.0 -->
67
75
  ```ruby
68
76
  require 'wgpu'
69
77
 
@@ -116,19 +124,29 @@ pass.set_pipeline(pipeline)
116
124
  pass.set_bind_group(0, bind_group)
117
125
  pass.dispatch_workgroups(input_data.size / 64)
118
126
  pass.end_pass
119
- queue.submit([encoder.finish])
127
+ command_buffer = encoder.finish
128
+ queue.submit(command_buffer)
120
129
 
121
130
  # Read results
122
- result = queue.read_buffer(buffer, device: device)
131
+ result = queue.read_buffer(buffer)
123
132
  output_data = result.unpack("f*")
124
133
 
125
134
  puts output_data[0, 10].inspect
126
135
  # => [0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0]
136
+
137
+ [
138
+ command_buffer, pass, encoder, pipeline, pipeline_layout,
139
+ bind_group, bind_group_layout, shader, buffer
140
+ ].each(&:release)
141
+ device.release
142
+ adapter.release
143
+ instance.release
127
144
  ```
128
145
 
129
146
  ## Examples
130
147
 
131
- See the `examples/` directory for more complete examples:
148
+ See the [`examples/` guide](examples/README.md) for prerequisites, expected
149
+ results, and more complete examples:
132
150
 
133
151
  Compute examples:
134
152
  - `01_adapter_info.rb` - Query GPU adapter information
@@ -138,6 +156,14 @@ Compute examples:
138
156
  - `05_image_blur.rb` - Image processing with box filter
139
157
  - `06_parallel_reduction.rb` - Parallel sum reduction
140
158
 
159
+ Headless validation examples:
160
+
161
+ - `12_headless_render.rb` - Offscreen triangle and pixel verification
162
+ - `13_error_handling.rb` - Typed, labeled validation errors
163
+ - `14_async_map.rb` - Async mapping through a forced GC cycle
164
+ - `15_timestamp_query.rb` - Feature-gated timestamp query resolution
165
+ - `16_texture_readback.rb` - Aligned readback of a 65-pixel-wide texture with reusable staging
166
+
141
167
  Rendering examples (SDL3):
142
168
  - `07_triangle.rb` - Basic triangle rendering
143
169
  - `08_colored_quad.rb` - Indexed colored quad rendering
@@ -156,8 +182,14 @@ Rendering examples require SDL3 on your system:
156
182
  ```bash
157
183
  # macOS
158
184
  brew install sdl3
185
+
186
+ # Gemfile
187
+ gem "sdl3", "~> 1.0"
159
188
  ```
160
189
 
190
+ The core `wgpu` gem does not depend on SDL3. Only code that explicitly requires
191
+ `wgpu/window` needs the optional Ruby gem and system library.
192
+
161
193
  ## API Overview
162
194
 
163
195
  ### Core Objects
@@ -207,6 +239,13 @@ bundle install
207
239
  bundle exec rake spec
208
240
  ```
209
241
 
242
+ See [Resource lifetime](docs/resource_lifetime.md) before building long-running
243
+ applications, and use the [API coverage matrix](docs/api_coverage.md) to check
244
+ the current relationship to the WebGPU specification. The
245
+ [documentation index](docs/README.md) links the compute/rendering guides,
246
+ buffer/texture rules, async and error handling, troubleshooting, and release
247
+ operations.
248
+
210
249
  ## Contributing
211
250
 
212
251
  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
+ The published [API reference](https://www.rubydoc.info/gems/wgpu) is generated
21
+ with `bundle exec yard doc`. Static API signatures live in `sig/wgpu.rbs` and validate with
22
+ `bundle exec rbs -I sig validate`.
@@ -0,0 +1,140 @@
1
+ # WebGPU API coverage
2
+
3
+ This page records the public Ruby API implemented by wgpu-ruby 1.2 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, limits, device-lost notification, and uncaptured-error subscriptions are exposed. |
37
+ | `GPUDeviceLostInfo` | callback `reason` and `message` | ◐ | `Device#on_device_lost` exposes the native reason and message without a separate wrapper object. |
38
+ | `GPUError` | `WGPU::GPUError` | ✅ | Typed value object with `type`, `message`, `to_h`, and exception conversion. |
39
+ | `GPUExternalTexture` | — | ❌ | Browser video/external-texture import is not exposed. |
40
+ | `GPUInternalError` | `WGPU::InternalError` | ◐ | Represented as a Ruby exception converted from `GPUError`. |
41
+ | `GPUOutOfMemoryError` | `WGPU::OutOfMemoryError` | ◐ | Represented as a Ruby exception converted from `GPUError`. |
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` | `Device#on_uncaptured_error` | ◐ | The callback receives `WGPU::GPUError`; there is no DOM event wrapper. |
57
+ | `GPUValidationError` | `WGPU::ValidationError` | ◐ | Validation errors are translated during resource creation and typed error-scope handling. |
58
+ | `WGSLLanguageFeatures` | — | ❌ | |
59
+ | `GPUObjectBase` | `WGPU::NativeResource` | ✅ | All native wrappers share `handle`, `label`, `released?`, `use`, `inspect`, idempotent release, and use-after-release guards. |
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. Every native wrapper also has the common
80
+ `label`, `released?`, `use`, `inspect`, and idempotent `release` methods from
81
+ `WGPU::NativeResource`.
82
+
83
+ | Ruby class | Public class methods | Public instance methods |
84
+ |---|---|---|
85
+ | `WGPU` | — | module methods `log_level`, `log_level=`, `on_log` |
86
+ | `WGPU::Instance` | — | `request_adapter`, `request_adapter_async`, `enumerate_adapters`, `enumerate_adapters_async`, `process_events`, `get_canvas_context`, `release`, `handle` |
87
+ | `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` |
88
+ | `WGPU::Device` | `request` | `queue`, `adapter`, `adapter_info`, `features`, `has_feature?`, `limits`, all `create_*` methods, `push_error_scope`, `pop_error_scope`, `pop_error_scope_async`, `pop_error_scope_typed`, `with_error_scope`, `on_uncaptured_error`, `on_device_lost`, `poll`, `destroy`, `release`, `handle` |
89
+ | `WGPU::Queue` | — | `submit`, `write_buffer`, `write_texture`, `read_buffer`, `read_texture`, `on_submitted_work_done`, `on_submitted_work_done_async`, `release`, `handle` |
90
+ | `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` |
91
+ | `WGPU::CanvasContext` | — | `configure`, `unconfigure`, `get_current_texture`, `present`, `get_configuration`, `get_preferred_format`, `set_physical_size`, `physical_size`, `release` |
92
+ | `WGPU::Buffer` | — | `write`, `mapped_range`, `get_mapped_range`, `unmap`, `map_sync`, `map_async`, `read_mapped_data`, `read_mapped`, `write_mapped`, typed `read_mapped_*` methods, `read_mapped_values`, `map_state`, `size`, `usage`, `destroy`, `release`, `handle` |
93
+ | `WGPU::BufferMappedRange` | — | `read`, `write`, `read_bytes`, `write_bytes`, and typed `read_*` / `write_*` methods |
94
+ | `WGPU::Texture` | `from_handle` | `create_view`, `width`, `height`, `depth_or_array_layers`, `size`, `mip_level_count`, `sample_count`, `dimension`, `format`, `usage`, `surface_status`, `destroy`, `release`, `handle` |
95
+ | `WGPU::TextureView` | `from_handle` | `texture`, `size`, `release`, `handle` |
96
+ | `WGPU::Sampler` | — | `release`, `handle` |
97
+ | `WGPU::QuerySet` | — | `count`, `type`, `destroy`, `release`, `handle` |
98
+ | `WGPU::ShaderModule` | — | `get_compilation_info`, `get_compilation_info_async`, `release`, `handle` |
99
+ | `WGPU::BindGroupLayout` | `from_handle` | `release`, `handle` |
100
+ | `WGPU::BindGroup` | — | `release`, `handle` |
101
+ | `WGPU::PipelineLayout` | — | `release`, `handle` |
102
+ | `WGPU::ComputePipeline` | — | `get_bind_group_layout`, `release`, `handle` |
103
+ | `WGPU::RenderPipeline` | — | `get_bind_group_layout`, `release`, `handle` |
104
+ | `WGPU::CommandEncoder` | — | `begin_compute_pass`, `begin_render_pass`, copy/clear/query/debug methods, `finish`, `release`, `handle` |
105
+ | `WGPU::CommandBuffer` | — | `release`, `handle` |
106
+ | `WGPU::ComputePass` | — | pipeline/bind-group setup, dispatch/debug methods, `end_pass`, `end`, `release`, `handle` |
107
+ | `WGPU::RenderPass` | — | pipeline/bind-group/buffer setup, draw/state/query/debug methods, `end_pass`, `end`, `release`, `handle` |
108
+ | `WGPU::RenderBundleEncoder` | — | pipeline/bind-group/buffer setup, draw/debug methods, `finish`, `release`, `handle` |
109
+ | `WGPU::RenderBundle` | — | `release`, `handle` |
110
+ | `WGPU::AsyncTask` | — | `wait`, `value`, `then`, `complete?`, `pending?`, `error` |
111
+ | `WGPU::GPUError` | `from_hash` | `type`, `message`, `exception_class`, `raise!`, `to_h` |
112
+ | `WGPU::CompilationMessage` | — | `type`, `message`, `line_num`/`line`, `line_pos`/`column`, `offset`, `length`, `to_s` |
113
+ | `WGPU::DataTypes` | `pack`, `unpack`, `byte_size`, `to_pointer`, `validate_alignment!` | — |
114
+ | `WGPU::TextureFormat` | `block_size`, `block_dimensions`, `bytes_per_row`, `aligned_bytes_per_row`, `block_info` | — |
115
+ | `WGPU::Window::SDLWindow` | — | `create_surface`, event/key helpers, `drawable_size`, `close` |
116
+
117
+ ## Examples as executable specifications
118
+
119
+ | Example | Purpose | Principal wgpu-ruby APIs exercised |
120
+ |---|---|---|
121
+ | `01_adapter_info.rb` | Adapter discovery and reporting | `Instance#enumerate_adapters`, `#request_adapter`, adapter info/features/limits |
122
+ | `02_compute_basic.rb` | Minimal storage-buffer compute | buffer mapping, bind groups/layouts, compute pipeline/pass, submit, readback |
123
+ | `03_buffer_operations.rb` | Buffer write, copy, map, and read | `create_buffer_with_data`, `Queue#write_buffer`, buffer copy, `map_sync` |
124
+ | `04_matrix_multiply.rb` | Multi-buffer compute | typed byte upload, storage/uniform bindings, workgroup dispatch, readback |
125
+ | `05_image_blur.rb` | 2D compute workload | multiple storage buffers, 2D dispatch, readback |
126
+ | `06_parallel_reduction.rb` | Iterative compute reduction | repeated dispatch/submission, `Queue#write_buffer`, readback |
127
+ | `07_triangle.rb` | Basic surface rendering | SDL surface setup, render pipeline/pass, draw, present |
128
+ | `08_colored_quad.rb` | Indexed vertex rendering | vertex/index buffers, render pipeline/pass, indexed draw |
129
+ | `09_clear_color.rb` | Per-frame clear and presentation | current texture/view, render pass clear, submit, present |
130
+ | `10_textured_quad.rb` | Texture sampling | texture upload/view, sampler, texture bind group, draw |
131
+ | `11_rotating_cube.rb` | Depth-tested 3D rendering | vertex/index/uniform/depth resources, pipeline, per-frame uniform write, draw |
132
+ | `12_headless_render.rb` | Offscreen triangle and readback | render-to-texture, block render pass, aligned texture readback, pixel assertions |
133
+ | `13_error_handling.rb` | Typed and labeled validation error | `ArgumentError`, operation/label context |
134
+ | `14_async_map.rb` | Async map and callback retention | `map_async`, `AsyncTask`, typed mapped reads, GC stress |
135
+ | `15_timestamp_query.rb` | Feature-gated GPU timestamps | timestamp pass writes, query resolution, u64 readback |
136
+ | `16_texture_readback.rb` | Non-aligned-width texture readback | texture row alignment helpers, caller-owned reusable staging |
137
+
138
+ When a public API changes, the corresponding example is part of the acceptance
139
+ test surface. Compute and headless examples are automated in GPU CI; SDL
140
+ window examples remain manual integration checks.
data/docs/async.md ADDED
@@ -0,0 +1,41 @@
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
+ The exported `wgpuDeviceCreateComputePipelineAsync` and
23
+ `wgpuDeviceCreateRenderPipelineAsync` functions are also panic stubs in
24
+ wgpu-native v27. Pipeline `*_async` methods therefore retain the safe Ruby
25
+ Thread implementation until those native entry points are implemented.
26
+
27
+ Synchronous adapter/device requests, `Buffer#map_sync`,
28
+ `Device#pop_error_scope`, and `Queue#on_submitted_work_done` accept
29
+ `timeout:` in seconds. The default `nil` preserves the prior unbounded wait.
30
+ Expiry raises `WGPU::TimeoutError`.
31
+
32
+ `Device.request` can time out only when its adapter is associated with an
33
+ `Instance`. When adopting a native adapter, pass `instance:` to
34
+ `Adapter.from_handle`; without an instance there is no safe event-progress
35
+ boundary for cleaning up a device that completes after timeout.
36
+
37
+ `*_async` methods return `WGPU::AsyncTask`, a convenience wrapper backed by a
38
+ Ruby Thread. Concurrent operations on the same WebGPU object are not
39
+ guaranteed safe. Prefer synchronous operations or external serialization when
40
+ ordering matters. Rendering event loops should call `instance.process_events`
41
+ 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,49 @@
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.
25
+
26
+ ## Queries and debug markers
27
+
28
+ Pass descriptors accept `timestamp_writes:` with a query set and beginning/end
29
+ indices. Render passes additionally accept `occlusion_query_set:` and expose
30
+ `begin_occlusion_query` / `end_occlusion_query`. Copy completed query values
31
+ into a buffer with `CommandEncoder#resolve_query_set`; timestamp queries
32
+ require the adapter's `:timestamp_query` feature and a device requested with
33
+ that feature.
34
+
35
+ [`examples/15_timestamp_query.rb`](../examples/15_timestamp_query.rb) shows the
36
+ complete feature-gated timestamp flow, including query resolution and typed
37
+ `u64` readback.
38
+
39
+ Command encoders, compute/render passes, and render bundle encoders expose
40
+ `push_debug_group`, `pop_debug_group`, and `insert_debug_marker`. Labels are
41
+ forwarded directly to wgpu-native for capture/debugging tools:
42
+
43
+ ```ruby
44
+ encoder.push_debug_group("upload and dispatch")
45
+ encoder.insert_debug_marker("resources ready")
46
+ encoder.pop_debug_group
47
+ ```
48
+
49
+ Debug groups must be balanced before the encoder or pass is finished.
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,62 @@
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
+ <!-- wgpu-example: run; expect: [2, 4, 6, 8] -->
7
+ ```ruby
8
+ require "wgpu"
9
+
10
+ instance = WGPU::Instance.new
11
+ adapter = instance.request_adapter(timeout: 10)
12
+ device = adapter.request_device(timeout: 10)
13
+
14
+ shader = device.create_shader_module(
15
+ code: <<~WGSL,
16
+ @group(0) @binding(0) var<storage, read_write> values: array<u32>;
17
+
18
+ @compute @workgroup_size(4)
19
+ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
20
+ values[id.x] *= 2u;
21
+ }
22
+ WGSL
23
+ )
24
+
25
+ buffer = device.create_buffer_with_data(
26
+ data: [1, 2, 3, 4],
27
+ type: :u32,
28
+ usage: %i[storage copy_src copy_dst]
29
+ )
30
+
31
+ pipeline = device.create_compute_pipeline(
32
+ layout: :auto,
33
+ compute: { module: shader }
34
+ )
35
+ layout = pipeline.get_bind_group_layout(0)
36
+ group = device.create_bind_group(
37
+ layout: layout,
38
+ entries: [{ binding: 0, buffer: buffer }]
39
+ )
40
+
41
+ encoder = device.create_command_encoder
42
+ encoder.begin_compute_pass do |pass|
43
+ pass.set_pipeline(pipeline)
44
+ pass.set_bind_group(0, group)
45
+ pass.dispatch_workgroups(1)
46
+ end
47
+ command_buffer = encoder.finish
48
+ device.queue.submit(command_buffer)
49
+
50
+ bytes = device.queue.read_buffer(buffer)
51
+ puts WGPU::DataTypes.unpack(bytes, type: :u32).inspect
52
+
53
+ [command_buffer, encoder, group, layout, pipeline, buffer, shader].each(&:release)
54
+ device.release
55
+ adapter.release
56
+ instance.release
57
+ ```
58
+
59
+ The full executable version is
60
+ [`examples/02_compute_basic.rb`](../examples/02_compute_basic.rb). For
61
+ production code, put resource release in `ensure` blocks and register
62
+ `Device#on_uncaptured_error` during startup.