wgpu 1.2.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 +40 -0
- data/README.md +18 -2
- data/docs/README.md +2 -2
- data/docs/api_coverage.md +23 -15
- data/docs/async.md +10 -0
- data/docs/command_encoding.md +25 -0
- data/docs/getting_started_compute.md +1 -0
- data/docs/pipeline_descriptors.md +7 -2
- data/docs/releasing.md +11 -1
- data/docs/resource_lifetime.md +16 -2
- data/docs/texture_readback.md +27 -0
- data/docs/troubleshooting.md +5 -0
- data/docs/upgrading_wgpu_native.md +16 -5
- data/lib/wgpu/async_task.rb +19 -0
- data/lib/wgpu/commands/command_buffer.rb +14 -1
- data/lib/wgpu/commands/command_encoder.rb +58 -1
- data/lib/wgpu/commands/compute_pass.rb +43 -0
- data/lib/wgpu/commands/render_bundle.rb +9 -1
- data/lib/wgpu/commands/render_bundle_encoder.rb +55 -1
- data/lib/wgpu/commands/render_pass.rb +102 -0
- data/lib/wgpu/core/adapter.rb +91 -12
- data/lib/wgpu/core/async_waiter.rb +15 -0
- data/lib/wgpu/core/canvas_context.rb +32 -0
- data/lib/wgpu/core/device.rb +296 -46
- data/lib/wgpu/core/instance.rb +20 -0
- data/lib/wgpu/core/queue.rb +139 -24
- data/lib/wgpu/core/surface.rb +49 -1
- data/lib/wgpu/data_types.rb +16 -0
- data/lib/wgpu/descriptor_helpers.rb +65 -0
- data/lib/wgpu/error.rb +15 -0
- data/lib/wgpu/native/abi_verifier.rb +37 -3
- data/lib/wgpu/native/callbacks.rb +6 -0
- data/lib/wgpu/native/capabilities.rb +16 -2
- data/lib/wgpu/native/distribution.rb +63 -0
- data/lib/wgpu/native/enum_helper.rb +17 -0
- data/lib/wgpu/native/enums.rb +8 -0
- data/lib/wgpu/native/fixtures/webgpu-v27.0.4.0-enums.h +848 -0
- data/lib/wgpu/native/functions.rb +11 -0
- data/lib/wgpu/native/installer.rb +48 -17
- data/lib/wgpu/native/loader.rb +22 -0
- data/lib/wgpu/native/structs.rb +18 -1
- data/lib/wgpu/native_resource.rb +174 -3
- data/lib/wgpu/pipeline/bind_group.rb +9 -0
- data/lib/wgpu/pipeline/bind_group_layout.rb +17 -4
- data/lib/wgpu/pipeline/compute_pipeline.rb +20 -32
- data/lib/wgpu/pipeline/pipeline_layout.rb +8 -0
- data/lib/wgpu/pipeline/render_pipeline.rb +27 -42
- data/lib/wgpu/pipeline/shader_module.rb +54 -29
- data/lib/wgpu/resources/buffer.rb +258 -31
- data/lib/wgpu/resources/query_set.rb +12 -0
- data/lib/wgpu/resources/sampler.rb +7 -0
- data/lib/wgpu/resources/texture.rb +45 -6
- data/lib/wgpu/resources/texture_view.rb +24 -4
- data/lib/wgpu/texture_format.rb +14 -0
- data/lib/wgpu/version.rb +1 -1
- data/lib/wgpu/window.rb +26 -0
- data/sig/wgpu.rbs +84 -5
- metadata +3 -1
data/lib/wgpu/core/adapter.rb
CHANGED
|
@@ -4,27 +4,62 @@ module WGPU
|
|
|
4
4
|
class Adapter
|
|
5
5
|
attr_reader :handle, :instance
|
|
6
6
|
|
|
7
|
+
# Wraps an existing native adapter handle.
|
|
8
|
+
# @param handle [FFI::Pointer] native adapter handle
|
|
9
|
+
# @param instance [Instance, nil] instance that owns the adapter
|
|
10
|
+
# @return [Adapter]
|
|
7
11
|
def self.from_handle(handle, instance: nil)
|
|
8
|
-
adapter =
|
|
9
|
-
adapter.instance_variable_set(:@handle, handle)
|
|
12
|
+
adapter = adopt_native_handle(handle)
|
|
10
13
|
adapter.instance_variable_set(:@instance, instance)
|
|
11
14
|
adapter
|
|
12
15
|
end
|
|
13
16
|
|
|
17
|
+
# Requests an adapter and waits for the native callback.
|
|
18
|
+
#
|
|
19
|
+
# @param instance [Instance] instance used for discovery and callback progress
|
|
20
|
+
# @param power_preference [Symbol, Integer] preferred power profile
|
|
21
|
+
# @param backend [Symbol, Integer, nil] backend to restrict discovery to
|
|
22
|
+
# @param feature_level [Symbol, Integer] requested WebGPU feature level
|
|
23
|
+
# @param force_fallback_adapter [Boolean] whether to require a fallback adapter
|
|
24
|
+
# @param compatible_surface [Surface, nil] surface the adapter must support
|
|
25
|
+
# @param timeout [Numeric, nil] maximum wait time in seconds
|
|
26
|
+
# @return [Adapter] requested adapter
|
|
27
|
+
# @raise [AdapterError] if no adapter can be acquired
|
|
28
|
+
# @raise [TimeoutError] if the request exceeds +timeout+
|
|
14
29
|
def self.request(instance, power_preference: :high_performance, backend: nil, feature_level: :core,
|
|
15
30
|
force_fallback_adapter: false, compatible_surface: nil, timeout: nil)
|
|
16
31
|
adapter_ptr = FFI::MemoryPointer.new(:pointer)
|
|
17
|
-
status_holder = {
|
|
32
|
+
status_holder = {
|
|
33
|
+
done: false,
|
|
34
|
+
value: nil,
|
|
35
|
+
message: nil,
|
|
36
|
+
abandoned: false,
|
|
37
|
+
cleanup_claimed: false,
|
|
38
|
+
mutex: Mutex.new
|
|
39
|
+
}
|
|
18
40
|
|
|
41
|
+
callback_token = nil
|
|
19
42
|
callback = FFI::Function.new(
|
|
20
43
|
:void, [:uint32, :pointer, Native::StringView.by_value, :pointer, :pointer]
|
|
21
44
|
) do |status, adapter, message, _userdata1, _userdata2|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
status_holder[:
|
|
45
|
+
abandoned_adapter = nil
|
|
46
|
+
begin
|
|
47
|
+
status_holder[:mutex].synchronize do
|
|
48
|
+
status_holder[:value] = Native::RequestAdapterStatus[status]
|
|
49
|
+
if message[:data] && !message[:data].null? && message[:length] > 0
|
|
50
|
+
status_holder[:message] = message[:data].read_string(message[:length])
|
|
51
|
+
end
|
|
52
|
+
adapter_ptr.write_pointer(adapter)
|
|
53
|
+
status_holder[:done] = true
|
|
54
|
+
if status_holder[:abandoned] && !status_holder[:cleanup_claimed]
|
|
55
|
+
status_holder[:cleanup_claimed] = true
|
|
56
|
+
abandoned_adapter = adapter
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
Native.wgpuAdapterRelease(abandoned_adapter) if abandoned_adapter && !abandoned_adapter.null?
|
|
60
|
+
ensure
|
|
61
|
+
CallbackKeepalive.release(instance, callback_token)
|
|
25
62
|
end
|
|
26
|
-
adapter_ptr.write_pointer(adapter)
|
|
27
|
-
status_holder[:done] = true
|
|
28
63
|
end
|
|
29
64
|
|
|
30
65
|
options = Native::RequestAdapterOptions.new
|
|
@@ -55,12 +90,26 @@ module WGPU
|
|
|
55
90
|
callback_info[:userdata2] = nil
|
|
56
91
|
|
|
57
92
|
callback_token = CallbackKeepalive.retain(instance, callback)
|
|
93
|
+
future =
|
|
94
|
+
begin
|
|
95
|
+
Native.wgpuInstanceRequestAdapter(instance.handle, options, callback_info)
|
|
96
|
+
rescue StandardError
|
|
97
|
+
CallbackKeepalive.release(instance, callback_token)
|
|
98
|
+
raise
|
|
99
|
+
end
|
|
100
|
+
|
|
58
101
|
begin
|
|
59
|
-
status_holder[:done] = false
|
|
60
|
-
future = Native.wgpuInstanceRequestAdapter(instance.handle, options, callback_info)
|
|
61
102
|
AsyncWaiter.wait(status_holder: status_holder, instance: instance, future: future, timeout: timeout)
|
|
62
|
-
|
|
63
|
-
|
|
103
|
+
rescue TimeoutError
|
|
104
|
+
abandoned_adapter = status_holder[:mutex].synchronize do
|
|
105
|
+
status_holder[:abandoned] = true
|
|
106
|
+
next unless status_holder[:done] && !status_holder[:cleanup_claimed]
|
|
107
|
+
|
|
108
|
+
status_holder[:cleanup_claimed] = true
|
|
109
|
+
adapter_ptr.read_pointer
|
|
110
|
+
end
|
|
111
|
+
Native.wgpuAdapterRelease(abandoned_adapter) if abandoned_adapter && !abandoned_adapter.null?
|
|
112
|
+
raise
|
|
64
113
|
end
|
|
65
114
|
|
|
66
115
|
handle = adapter_ptr.read_pointer
|
|
@@ -72,11 +121,16 @@ module WGPU
|
|
|
72
121
|
new(handle, instance: instance)
|
|
73
122
|
end
|
|
74
123
|
|
|
124
|
+
# Wraps a native adapter handle.
|
|
125
|
+
# @param handle [FFI::Pointer] native adapter handle
|
|
126
|
+
# @param instance [Instance, nil] instance that owns the adapter
|
|
75
127
|
def initialize(handle, instance: nil)
|
|
76
128
|
@handle = handle
|
|
77
129
|
@instance = instance
|
|
78
130
|
end
|
|
79
131
|
|
|
132
|
+
# Requests a logical device from this adapter.
|
|
133
|
+
# @return [Device]
|
|
80
134
|
def request_device(label: nil, required_features: [], required_limits: nil, timeout: nil)
|
|
81
135
|
Device.request(
|
|
82
136
|
self,
|
|
@@ -87,6 +141,8 @@ module WGPU
|
|
|
87
141
|
)
|
|
88
142
|
end
|
|
89
143
|
|
|
144
|
+
# Requests a logical device on a background task.
|
|
145
|
+
# @return [AsyncTask] task yielding a {Device}
|
|
90
146
|
def request_device_async(label: nil, required_features: [], required_limits: nil, timeout: nil)
|
|
91
147
|
AsyncTask.new do
|
|
92
148
|
request_device(
|
|
@@ -98,6 +154,8 @@ module WGPU
|
|
|
98
154
|
end
|
|
99
155
|
end
|
|
100
156
|
|
|
157
|
+
# Returns identifying and backend information for the adapter.
|
|
158
|
+
# @return [Hash]
|
|
101
159
|
def info
|
|
102
160
|
info_struct = Native::AdapterInfo.new
|
|
103
161
|
Native.wgpuAdapterGetInfo(@handle, info_struct)
|
|
@@ -117,22 +175,32 @@ module WGPU
|
|
|
117
175
|
result
|
|
118
176
|
end
|
|
119
177
|
|
|
178
|
+
# Returns the adapter's device name.
|
|
179
|
+
# @return [String]
|
|
120
180
|
def name
|
|
121
181
|
info[:device]
|
|
122
182
|
end
|
|
123
183
|
|
|
184
|
+
# Returns the adapter vendor name.
|
|
185
|
+
# @return [String]
|
|
124
186
|
def vendor
|
|
125
187
|
info[:vendor]
|
|
126
188
|
end
|
|
127
189
|
|
|
190
|
+
# Returns the backend used by the adapter.
|
|
191
|
+
# @return [Symbol, Integer]
|
|
128
192
|
def backend_type
|
|
129
193
|
info[:backend_type]
|
|
130
194
|
end
|
|
131
195
|
|
|
196
|
+
# Returns the adapter's device classification.
|
|
197
|
+
# @return [Symbol, Integer]
|
|
132
198
|
def adapter_type
|
|
133
199
|
info[:adapter_type]
|
|
134
200
|
end
|
|
135
201
|
|
|
202
|
+
# Lists optional features supported by the adapter.
|
|
203
|
+
# @return [Array<Symbol>]
|
|
136
204
|
def features
|
|
137
205
|
supported = Native::SupportedFeatures.new
|
|
138
206
|
Native.wgpuAdapterGetFeatures(@handle, supported)
|
|
@@ -146,10 +214,15 @@ module WGPU
|
|
|
146
214
|
result
|
|
147
215
|
end
|
|
148
216
|
|
|
217
|
+
# Reports whether the adapter supports a feature.
|
|
218
|
+
# @param feature [Symbol] feature name
|
|
219
|
+
# @return [Boolean]
|
|
149
220
|
def has_feature?(feature)
|
|
150
221
|
features.include?(feature)
|
|
151
222
|
end
|
|
152
223
|
|
|
224
|
+
# Returns the adapter resource limits.
|
|
225
|
+
# @return [Hash{Symbol => Integer}]
|
|
153
226
|
def limits
|
|
154
227
|
supported = Native::SupportedLimits.new
|
|
155
228
|
supported[:next_in_chain] = nil
|
|
@@ -157,11 +230,17 @@ module WGPU
|
|
|
157
230
|
limits_to_hash(supported[:limits])
|
|
158
231
|
end
|
|
159
232
|
|
|
233
|
+
# Returns a concise human-readable adapter description.
|
|
234
|
+
# @return [String]
|
|
160
235
|
def summary
|
|
161
236
|
info_hash = info
|
|
162
237
|
"#{info_hash[:device]} (#{info_hash[:adapter_type]}) via #{info_hash[:backend_type]}"
|
|
163
238
|
end
|
|
164
239
|
|
|
240
|
+
# Releases the native adapter handle.
|
|
241
|
+
#
|
|
242
|
+
# Calling this method more than once has no effect.
|
|
243
|
+
# @return [void]
|
|
165
244
|
def release
|
|
166
245
|
return if @handle.null?
|
|
167
246
|
Native.wgpuAdapterRelease(@handle)
|
|
@@ -10,10 +10,16 @@ module WGPU
|
|
|
10
10
|
|
|
11
11
|
module_function
|
|
12
12
|
|
|
13
|
+
# Returns the delay between callback progress polls.
|
|
14
|
+
# @return [Float] seconds
|
|
13
15
|
def poll_interval
|
|
14
16
|
@poll_interval ||= POLL_INTERVAL_SECONDS
|
|
15
17
|
end
|
|
16
18
|
|
|
19
|
+
# Sets the delay between callback progress polls.
|
|
20
|
+
# @param seconds [Numeric] positive delay in seconds
|
|
21
|
+
# @return [Float]
|
|
22
|
+
# @raise [ArgumentError] if the delay is not positive
|
|
17
23
|
def poll_interval=(seconds)
|
|
18
24
|
value = Float(seconds)
|
|
19
25
|
raise ArgumentError, "poll interval must be positive" unless value.positive?
|
|
@@ -21,6 +27,10 @@ module WGPU
|
|
|
21
27
|
@poll_interval = value
|
|
22
28
|
end
|
|
23
29
|
|
|
30
|
+
# Selects the native callback delivery mode for an operation.
|
|
31
|
+
#
|
|
32
|
+
# @param instance [Instance, nil] instance capable of processing events
|
|
33
|
+
# @return [Integer] native {Native::CallbackMode} value
|
|
24
34
|
def callback_mode(instance:)
|
|
25
35
|
if instance
|
|
26
36
|
callback_mode_value(:allow_process_events)
|
|
@@ -29,6 +39,11 @@ module WGPU
|
|
|
29
39
|
end
|
|
30
40
|
end
|
|
31
41
|
|
|
42
|
+
# Drives native event processing until a callback completes.
|
|
43
|
+
# @param status_holder [Hash] state whose +:done+ flag is set by the callback
|
|
44
|
+
# @param timeout [Numeric, nil] maximum wait time in seconds
|
|
45
|
+
# @return [void]
|
|
46
|
+
# @raise [TimeoutError] if completion exceeds the timeout
|
|
32
47
|
def wait(status_holder:, instance: nil, device: nil, future: nil, timeout: nil)
|
|
33
48
|
timeout = Float(timeout) if timeout
|
|
34
49
|
raise ArgumentError, "timeout must be non-negative" if timeout&.negative?
|
|
@@ -4,6 +4,9 @@ module WGPU
|
|
|
4
4
|
class CanvasContext
|
|
5
5
|
attr_reader :physical_size
|
|
6
6
|
|
|
7
|
+
# Creates a canvas context for platform presentation information.
|
|
8
|
+
# @param instance [Instance] owning WebGPU instance
|
|
9
|
+
# @param present_info [Hash] platform handles or an existing surface
|
|
7
10
|
def initialize(instance, present_info = {})
|
|
8
11
|
@instance = instance
|
|
9
12
|
@present_info = present_info || {}
|
|
@@ -12,21 +15,38 @@ module WGPU
|
|
|
12
15
|
@config = nil
|
|
13
16
|
end
|
|
14
17
|
|
|
18
|
+
# Updates the drawable's physical pixel size.
|
|
19
|
+
# @param width [Integer] width in pixels
|
|
20
|
+
# @param height [Integer] height in pixels
|
|
21
|
+
# @return [Array<Integer>] stored width and height
|
|
22
|
+
# @raise [ArgumentError] if either dimension is negative
|
|
15
23
|
def set_physical_size(width, height)
|
|
16
24
|
raise ArgumentError, "width and height must be non-negative" if width.to_i.negative? || height.to_i.negative?
|
|
17
25
|
|
|
18
26
|
@physical_size = [width.to_i, height.to_i]
|
|
19
27
|
end
|
|
20
28
|
|
|
29
|
+
# Returns the surface format preferred by an adapter.
|
|
30
|
+
#
|
|
31
|
+
# @param adapter [Adapter] adapter used to query surface capabilities
|
|
32
|
+
# @return [Symbol] preferred texture format
|
|
21
33
|
def get_preferred_format(adapter)
|
|
22
34
|
ensure_surface
|
|
23
35
|
@surface.get_preferred_format(adapter)
|
|
24
36
|
end
|
|
25
37
|
|
|
38
|
+
# Returns the most recent canvas configuration.
|
|
39
|
+
#
|
|
40
|
+
# @return [Hash, nil] configuration options, or +nil+ when unconfigured
|
|
26
41
|
def get_configuration
|
|
27
42
|
@config
|
|
28
43
|
end
|
|
29
44
|
|
|
45
|
+
# Configures the backing surface for presentation.
|
|
46
|
+
# @param device [Device] device used to render frames
|
|
47
|
+
# @param format [Symbol, nil] surface texture format
|
|
48
|
+
# @return [Hash] resolved canvas configuration
|
|
49
|
+
# @raise [SurfaceError] if no surface exists or dimensions are not positive
|
|
30
50
|
def configure(device:, format: nil, usage: :render_attachment, view_formats: [], color_space: "srgb", tone_mapping: nil, alpha_mode: :opaque, width: nil, height: nil, present_mode: :fifo)
|
|
31
51
|
ensure_surface
|
|
32
52
|
|
|
@@ -59,21 +79,33 @@ module WGPU
|
|
|
59
79
|
}
|
|
60
80
|
end
|
|
61
81
|
|
|
82
|
+
# Removes the current surface configuration.
|
|
83
|
+
# @return [void]
|
|
62
84
|
def unconfigure
|
|
63
85
|
@surface&.unconfigure
|
|
64
86
|
@config = nil
|
|
65
87
|
end
|
|
66
88
|
|
|
89
|
+
# Acquires the texture for the current presentation frame.
|
|
90
|
+
#
|
|
91
|
+
# @return [Texture] acquired surface texture
|
|
92
|
+
# @raise [SurfaceError] if the context has not been configured
|
|
93
|
+
# @raise [SurfaceAcquisitionError] if acquisition fails
|
|
67
94
|
def get_current_texture
|
|
68
95
|
raise SurfaceError, "Canvas context must be configured before get_current_texture" unless @config
|
|
69
96
|
|
|
70
97
|
@surface.current_texture
|
|
71
98
|
end
|
|
72
99
|
|
|
100
|
+
# Presents the current surface texture.
|
|
101
|
+
# @return [void]
|
|
73
102
|
def present
|
|
74
103
|
@surface&.present
|
|
75
104
|
end
|
|
76
105
|
|
|
106
|
+
# Releases the backing surface and clears the configuration.
|
|
107
|
+
#
|
|
108
|
+
# @return [void]
|
|
77
109
|
def release
|
|
78
110
|
@surface&.release
|
|
79
111
|
@surface = nil
|