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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +88 -0
- data/README.md +44 -5
- data/docs/README.md +22 -0
- data/docs/api_coverage.md +140 -0
- data/docs/async.md +41 -0
- data/docs/bind_groups.md +25 -0
- data/docs/buffer_data.md +37 -0
- data/docs/command_encoding.md +49 -0
- data/docs/errors.md +40 -0
- data/docs/getting_started_compute.md +62 -0
- data/docs/getting_started_rendering.md +62 -0
- data/docs/installation.md +94 -0
- data/docs/pipeline_descriptors.md +43 -0
- data/docs/releasing.md +32 -0
- data/docs/resource_lifetime.md +108 -0
- data/docs/shaders.md +32 -0
- data/docs/texture_readback.md +46 -0
- data/docs/troubleshooting.md +53 -0
- data/docs/upgrading_wgpu_native.md +37 -0
- data/ext/wgpu/extconf.rb +10 -142
- data/lib/wgpu/async_task.rb +19 -0
- data/lib/wgpu/commands/command_buffer.rb +25 -1
- data/lib/wgpu/commands/command_encoder.rb +123 -9
- data/lib/wgpu/commands/compute_pass.rb +53 -0
- data/lib/wgpu/commands/render_bundle.rb +9 -1
- data/lib/wgpu/commands/render_bundle_encoder.rb +65 -4
- data/lib/wgpu/commands/render_pass.rb +136 -8
- data/lib/wgpu/core/adapter.rb +123 -19
- data/lib/wgpu/core/async_waiter.rb +47 -4
- data/lib/wgpu/core/canvas_context.rb +32 -2
- data/lib/wgpu/core/device.rb +399 -53
- data/lib/wgpu/core/instance.rb +28 -4
- data/lib/wgpu/core/queue.rb +197 -51
- data/lib/wgpu/core/surface.rb +64 -17
- data/lib/wgpu/data_types.rb +83 -0
- data/lib/wgpu/descriptor_helpers.rb +104 -0
- data/lib/wgpu/error.rb +70 -0
- data/lib/wgpu/logging.rb +63 -0
- data/lib/wgpu/native/abi_verifier.rb +143 -0
- data/lib/wgpu/native/callbacks.rb +10 -1
- data/lib/wgpu/native/capabilities.rb +32 -2
- data/lib/wgpu/native/distribution.rb +176 -0
- data/lib/wgpu/native/enum_helper.rb +80 -0
- data/lib/wgpu/native/enums.rb +68 -8
- data/lib/wgpu/native/fixtures/webgpu-v27.0.4.0-enums.h +848 -0
- data/lib/wgpu/native/functions.rb +21 -10
- data/lib/wgpu/native/installer.rb +223 -0
- data/lib/wgpu/native/loader.rb +61 -21
- data/lib/wgpu/native/structs.rb +18 -1
- data/lib/wgpu/native_resource.rb +342 -0
- data/lib/wgpu/pipeline/bind_group.rb +21 -0
- data/lib/wgpu/pipeline/bind_group_layout.rb +108 -41
- data/lib/wgpu/pipeline/compute_pipeline.rb +40 -50
- data/lib/wgpu/pipeline/pipeline_layout.rb +8 -0
- data/lib/wgpu/pipeline/render_pipeline.rb +207 -110
- data/lib/wgpu/pipeline/shader_module.rb +95 -28
- data/lib/wgpu/resources/buffer.rb +387 -85
- data/lib/wgpu/resources/query_set.rb +26 -12
- data/lib/wgpu/resources/sampler.rb +43 -20
- data/lib/wgpu/resources/texture.rb +89 -48
- data/lib/wgpu/resources/texture_view.rb +35 -7
- data/lib/wgpu/texture_format.rb +96 -0
- data/lib/wgpu/version.rb +1 -1
- data/lib/wgpu/window.rb +34 -1
- data/lib/wgpu.rb +32 -0
- data/sig/wgpu.rbs +460 -0
- metadata +33 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c118a2950771b2f34f06fcf4642634e57e8b1de07c26681b81aa94d6a1faaf93
|
|
4
|
+
data.tar.gz: b4f4cc4e97846d21e74144194f97ede7cb2704725cb5887a885345ceedd1c8f1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
-
|
|
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
|
-
|
|
127
|
+
command_buffer = encoder.finish
|
|
128
|
+
queue.submit(command_buffer)
|
|
120
129
|
|
|
121
130
|
# Read results
|
|
122
|
-
result = queue.read_buffer(buffer
|
|
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/`
|
|
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.
|
data/docs/bind_groups.md
ADDED
|
@@ -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.
|
data/docs/buffer_data.md
ADDED
|
@@ -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.
|