wgpu 1.2.0 → 1.2.2
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 +66 -0
- data/README.md +18 -2
- data/docs/README.md +2 -2
- data/docs/api_coverage.md +23 -15
- data/docs/async.md +13 -1
- data/docs/command_encoding.md +25 -0
- data/docs/errors.md +13 -0
- data/docs/getting_started_compute.md +1 -0
- data/docs/getting_started_rendering.md +5 -0
- data/docs/pipeline_descriptors.md +7 -2
- data/docs/releasing.md +11 -1
- data/docs/resource_lifetime.md +25 -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 +82 -27
- data/lib/wgpu/commands/compute_pass.rb +49 -6
- data/lib/wgpu/commands/render_bundle.rb +9 -1
- data/lib/wgpu/commands/render_bundle_encoder.rb +63 -9
- data/lib/wgpu/commands/render_pass.rb +116 -14
- data/lib/wgpu/core/adapter.rb +95 -13
- data/lib/wgpu/core/async_waiter.rb +30 -4
- data/lib/wgpu/core/canvas_context.rb +37 -2
- data/lib/wgpu/core/device.rb +377 -70
- data/lib/wgpu/core/instance.rb +20 -0
- data/lib/wgpu/core/queue.rb +143 -43
- data/lib/wgpu/core/surface.rb +55 -7
- data/lib/wgpu/data_types.rb +16 -0
- data/lib/wgpu/descriptor_helpers.rb +87 -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 +14 -0
- data/lib/wgpu/native/installer.rb +55 -18
- data/lib/wgpu/native/loader.rb +22 -0
- data/lib/wgpu/native/structs.rb +18 -1
- data/lib/wgpu/native_resource.rb +190 -3
- data/lib/wgpu/pipeline/bind_group.rb +16 -7
- data/lib/wgpu/pipeline/bind_group_layout.rb +20 -7
- data/lib/wgpu/pipeline/compute_pipeline.rb +25 -37
- data/lib/wgpu/pipeline/pipeline_layout.rb +12 -4
- data/lib/wgpu/pipeline/render_pipeline.rb +33 -48
- data/lib/wgpu/pipeline/shader_module.rb +57 -32
- data/lib/wgpu/resources/buffer.rb +330 -59
- data/lib/wgpu/resources/query_set.rb +13 -1
- data/lib/wgpu/resources/sampler.rb +10 -3
- data/lib/wgpu/resources/texture.rb +49 -12
- data/lib/wgpu/resources/texture_view.rb +25 -5
- 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 +85 -5
- metadata +12 -4
|
@@ -4,6 +4,10 @@ module WGPU
|
|
|
4
4
|
class CommandEncoder
|
|
5
5
|
attr_reader :handle
|
|
6
6
|
|
|
7
|
+
# Creates an encoder for commands submitted to a device queue.
|
|
8
|
+
# @param device [Device] owning device
|
|
9
|
+
# @param label [String, nil] optional debug label
|
|
10
|
+
# @raise [CommandError] if the native encoder cannot be created
|
|
7
11
|
def initialize(device, label: nil)
|
|
8
12
|
@device = device
|
|
9
13
|
@finished = false
|
|
@@ -20,10 +24,15 @@ module WGPU
|
|
|
20
24
|
desc[:label][:length] = 0
|
|
21
25
|
end
|
|
22
26
|
|
|
23
|
-
@handle = Native.wgpuDeviceCreateCommandEncoder(device
|
|
27
|
+
@handle = Native.wgpuDeviceCreateCommandEncoder(NativeResource.checked_handle(device, expected_class: Device), desc)
|
|
24
28
|
raise CommandError, "Failed to create command encoder" if @handle.null?
|
|
25
29
|
end
|
|
26
30
|
|
|
31
|
+
# Begins a compute pass, optionally yielding it for scoped recording.
|
|
32
|
+
# @param label [String, nil] optional debug label
|
|
33
|
+
# @param timestamp_writes [Hash, nil] timestamp query settings
|
|
34
|
+
# @yieldparam pass [ComputePass] newly created pass
|
|
35
|
+
# @return [ComputePass, Object] pass without a block, otherwise the block result
|
|
27
36
|
def begin_compute_pass(label: nil, timestamp_writes: nil)
|
|
28
37
|
ensure_can_begin_pass!
|
|
29
38
|
pass = ComputePass.new(self, label: label, timestamp_writes: timestamp_writes)
|
|
@@ -42,6 +51,10 @@ module WGPU
|
|
|
42
51
|
end
|
|
43
52
|
end
|
|
44
53
|
|
|
54
|
+
# Begins a render pass, optionally yielding it for scoped recording.
|
|
55
|
+
# @param color_attachments [Array<Hash>] color attachment descriptors
|
|
56
|
+
# @yieldparam pass [RenderPass] newly created pass
|
|
57
|
+
# @return [RenderPass, Object] pass without a block, otherwise the block result
|
|
45
58
|
def begin_render_pass(color_attachments:, depth_stencil_attachment: nil, occlusion_query_set: nil, timestamp_writes: nil, max_draw_count: nil, label: nil)
|
|
46
59
|
ensure_can_begin_pass!
|
|
47
60
|
pass = RenderPass.new(self,
|
|
@@ -67,32 +80,36 @@ module WGPU
|
|
|
67
80
|
end
|
|
68
81
|
end
|
|
69
82
|
|
|
83
|
+
# Copies bytes between buffers.
|
|
84
|
+
# @return [void]
|
|
70
85
|
def copy_buffer_to_buffer(source:, source_offset: 0, destination:, destination_offset: 0, size:)
|
|
71
86
|
raise CommandError, "Encoder already finished" if @finished
|
|
72
87
|
Native.wgpuCommandEncoderCopyBufferToBuffer(
|
|
73
88
|
@handle,
|
|
74
|
-
source
|
|
75
|
-
destination
|
|
89
|
+
NativeResource.checked_handle(source, expected_class: Buffer), source_offset,
|
|
90
|
+
NativeResource.checked_handle(destination, expected_class: Buffer), destination_offset,
|
|
76
91
|
size
|
|
77
92
|
)
|
|
78
93
|
end
|
|
79
94
|
|
|
95
|
+
# Copies buffer data into a texture region.
|
|
96
|
+
# @param source [Hash] buffer and layout descriptor
|
|
97
|
+
# @param destination [Hash] texture and origin descriptor
|
|
98
|
+
# @param copy_size [Hash, Array] extent to copy
|
|
99
|
+
# @return [void]
|
|
80
100
|
def copy_buffer_to_texture(source:, destination:, copy_size:)
|
|
81
101
|
raise CommandError, "Encoder already finished" if @finished
|
|
82
102
|
|
|
83
|
-
size =
|
|
84
|
-
size[:width] = copy_size[:width] || copy_size[0]
|
|
85
|
-
size[:height] = copy_size[:height] || copy_size[1] || 1
|
|
86
|
-
size[:depth_or_array_layers] = copy_size[:depth_or_array_layers] || copy_size[2] || 1
|
|
103
|
+
size = DescriptorHelpers.extent_3d(copy_size)
|
|
87
104
|
|
|
88
105
|
src = Native::ImageCopyBuffer.new
|
|
89
106
|
src[:layout][:offset] = source[:offset] || 0
|
|
90
107
|
src[:layout][:bytes_per_row] = source[:bytes_per_row]
|
|
91
108
|
src[:layout][:rows_per_image] = source[:rows_per_image] || size[:height]
|
|
92
|
-
src[:buffer] = source[:buffer]
|
|
109
|
+
src[:buffer] = NativeResource.checked_handle(source[:buffer], expected_class: Buffer)
|
|
93
110
|
|
|
94
111
|
dst = Native::ImageCopyTexture.new
|
|
95
|
-
dst[:texture] = destination[:texture]
|
|
112
|
+
dst[:texture] = NativeResource.checked_handle(destination[:texture], expected_class: Texture)
|
|
96
113
|
dst[:mip_level] = destination[:mip_level] || 0
|
|
97
114
|
dst[:origin][:x] = destination.dig(:origin, :x) || 0
|
|
98
115
|
dst[:origin][:y] = destination.dig(:origin, :y) || 0
|
|
@@ -106,16 +123,18 @@ module WGPU
|
|
|
106
123
|
Native.wgpuCommandEncoderCopyBufferToTexture(@handle, src, dst, size)
|
|
107
124
|
end
|
|
108
125
|
|
|
126
|
+
# Copies a texture region into a buffer.
|
|
127
|
+
# @param source [Hash] texture and origin descriptor
|
|
128
|
+
# @param destination [Hash] buffer and layout descriptor
|
|
129
|
+
# @param copy_size [Hash, Array] extent to copy
|
|
130
|
+
# @return [void]
|
|
109
131
|
def copy_texture_to_buffer(source:, destination:, copy_size:)
|
|
110
132
|
raise CommandError, "Encoder already finished" if @finished
|
|
111
133
|
|
|
112
|
-
size =
|
|
113
|
-
size[:width] = copy_size[:width] || copy_size[0]
|
|
114
|
-
size[:height] = copy_size[:height] || copy_size[1] || 1
|
|
115
|
-
size[:depth_or_array_layers] = copy_size[:depth_or_array_layers] || copy_size[2] || 1
|
|
134
|
+
size = DescriptorHelpers.extent_3d(copy_size)
|
|
116
135
|
|
|
117
136
|
src = Native::ImageCopyTexture.new
|
|
118
|
-
src[:texture] = source[:texture]
|
|
137
|
+
src[:texture] = NativeResource.checked_handle(source[:texture], expected_class: Texture)
|
|
119
138
|
src[:mip_level] = source[:mip_level] || 0
|
|
120
139
|
src[:origin][:x] = source.dig(:origin, :x) || 0
|
|
121
140
|
src[:origin][:y] = source.dig(:origin, :y) || 0
|
|
@@ -130,16 +149,21 @@ module WGPU
|
|
|
130
149
|
dst[:layout][:offset] = destination[:offset] || 0
|
|
131
150
|
dst[:layout][:bytes_per_row] = destination[:bytes_per_row]
|
|
132
151
|
dst[:layout][:rows_per_image] = destination[:rows_per_image] || size[:height]
|
|
133
|
-
dst[:buffer] = destination[:buffer]
|
|
152
|
+
dst[:buffer] = NativeResource.checked_handle(destination[:buffer], expected_class: Buffer)
|
|
134
153
|
|
|
135
154
|
Native.wgpuCommandEncoderCopyTextureToBuffer(@handle, src, dst, size)
|
|
136
155
|
end
|
|
137
156
|
|
|
157
|
+
# Copies one texture region into another texture.
|
|
158
|
+
# @param source [Hash] source texture and origin descriptor
|
|
159
|
+
# @param destination [Hash] destination texture and origin descriptor
|
|
160
|
+
# @param copy_size [Hash, Array] extent to copy
|
|
161
|
+
# @return [void]
|
|
138
162
|
def copy_texture_to_texture(source:, destination:, copy_size:)
|
|
139
163
|
raise CommandError, "Encoder already finished" if @finished
|
|
140
164
|
|
|
141
165
|
src = Native::ImageCopyTexture.new
|
|
142
|
-
src[:texture] = source[:texture]
|
|
166
|
+
src[:texture] = NativeResource.checked_handle(source[:texture], expected_class: Texture)
|
|
143
167
|
src[:mip_level] = source[:mip_level] || 0
|
|
144
168
|
src[:origin][:x] = source.dig(:origin, :x) || 0
|
|
145
169
|
src[:origin][:y] = source.dig(:origin, :y) || 0
|
|
@@ -151,7 +175,7 @@ module WGPU
|
|
|
151
175
|
)
|
|
152
176
|
|
|
153
177
|
dst = Native::ImageCopyTexture.new
|
|
154
|
-
dst[:texture] = destination[:texture]
|
|
178
|
+
dst[:texture] = NativeResource.checked_handle(destination[:texture], expected_class: Texture)
|
|
155
179
|
dst[:mip_level] = destination[:mip_level] || 0
|
|
156
180
|
dst[:origin][:x] = destination.dig(:origin, :x) || 0
|
|
157
181
|
dst[:origin][:y] = destination.dig(:origin, :y) || 0
|
|
@@ -162,37 +186,55 @@ module WGPU
|
|
|
162
186
|
name: "destination texture aspect"
|
|
163
187
|
)
|
|
164
188
|
|
|
165
|
-
size =
|
|
166
|
-
size[:width] = copy_size[:width] || copy_size[0]
|
|
167
|
-
size[:height] = copy_size[:height] || copy_size[1] || 1
|
|
168
|
-
size[:depth_or_array_layers] = copy_size[:depth_or_array_layers] || copy_size[2] || 1
|
|
189
|
+
size = DescriptorHelpers.extent_3d(copy_size)
|
|
169
190
|
|
|
170
191
|
Native.wgpuCommandEncoderCopyTextureToTexture(@handle, src, dst, size)
|
|
171
192
|
end
|
|
172
193
|
|
|
194
|
+
# Resolves query results into a destination buffer.
|
|
195
|
+
# @return [void]
|
|
173
196
|
def resolve_query_set(query_set:, first_query:, query_count:, destination:, destination_offset:)
|
|
174
197
|
raise CommandError, "Encoder already finished" if @finished
|
|
175
198
|
Native.wgpuCommandEncoderResolveQuerySet(
|
|
176
199
|
@handle,
|
|
177
|
-
query_set
|
|
200
|
+
NativeResource.checked_handle(query_set, expected_class: QuerySet),
|
|
178
201
|
first_query,
|
|
179
202
|
query_count,
|
|
180
|
-
destination
|
|
203
|
+
NativeResource.checked_handle(destination, expected_class: Buffer),
|
|
181
204
|
destination_offset
|
|
182
205
|
)
|
|
183
206
|
end
|
|
184
207
|
|
|
208
|
+
# Clears a byte range in a buffer to zero.
|
|
209
|
+
# @param buffer [Buffer] buffer to clear
|
|
210
|
+
# @param offset [Integer] first byte to clear
|
|
211
|
+
# @param size [Integer, nil] number of bytes to clear
|
|
212
|
+
# @return [void]
|
|
185
213
|
def clear_buffer(buffer, offset: 0, size: nil)
|
|
186
214
|
raise CommandError, "Encoder already finished" if @finished
|
|
187
|
-
|
|
188
|
-
|
|
215
|
+
buffer_handle = NativeResource.checked_handle(buffer, expected_class: Buffer)
|
|
216
|
+
offset = DataTypes.validate_alignment!(offset, 4, name: "clear offset")
|
|
217
|
+
size = DataTypes.validate_alignment!(size || (buffer.size - offset), 4, name: "clear size")
|
|
218
|
+
if offset > buffer.size || size > buffer.size - offset
|
|
219
|
+
raise ArgumentError, "clear range exceeds buffer size"
|
|
220
|
+
end
|
|
221
|
+
return if size.zero?
|
|
222
|
+
|
|
223
|
+
Native.wgpuCommandEncoderClearBuffer(@handle, buffer_handle, offset, size)
|
|
189
224
|
end
|
|
190
225
|
|
|
226
|
+
# Writes a GPU timestamp to a query set.
|
|
227
|
+
# @param query_set [QuerySet] timestamp query set
|
|
228
|
+
# @param query_index [Integer] destination query index
|
|
229
|
+
# @return [void]
|
|
191
230
|
def write_timestamp(query_set, query_index)
|
|
192
231
|
raise CommandError, "Encoder already finished" if @finished
|
|
193
|
-
Native.wgpuCommandEncoderWriteTimestamp(@handle, query_set
|
|
232
|
+
Native.wgpuCommandEncoderWriteTimestamp(@handle, NativeResource.checked_handle(query_set, expected_class: QuerySet), query_index)
|
|
194
233
|
end
|
|
195
234
|
|
|
235
|
+
# Starts a labeled group in GPU debugging tools.
|
|
236
|
+
# @param label [String] group label
|
|
237
|
+
# @return [void]
|
|
196
238
|
def push_debug_group(label)
|
|
197
239
|
raise CommandError, "Encoder already finished" if @finished
|
|
198
240
|
label_view = Native::StringView.new
|
|
@@ -202,11 +244,16 @@ module WGPU
|
|
|
202
244
|
Native.wgpuCommandEncoderPushDebugGroup(@handle, label_view)
|
|
203
245
|
end
|
|
204
246
|
|
|
247
|
+
# Ends the most recently pushed debug group.
|
|
248
|
+
# @return [void]
|
|
205
249
|
def pop_debug_group
|
|
206
250
|
raise CommandError, "Encoder already finished" if @finished
|
|
207
251
|
Native.wgpuCommandEncoderPopDebugGroup(@handle)
|
|
208
252
|
end
|
|
209
253
|
|
|
254
|
+
# Inserts a labeled point in GPU debugging tools.
|
|
255
|
+
# @param label [String] marker label
|
|
256
|
+
# @return [void]
|
|
210
257
|
def insert_debug_marker(label)
|
|
211
258
|
raise CommandError, "Encoder already finished" if @finished
|
|
212
259
|
label_view = Native::StringView.new
|
|
@@ -216,6 +263,10 @@ module WGPU
|
|
|
216
263
|
Native.wgpuCommandEncoderInsertDebugMarker(@handle, label_view)
|
|
217
264
|
end
|
|
218
265
|
|
|
266
|
+
# Finishes recording and returns a command buffer.
|
|
267
|
+
# @param label [String, nil] optional command buffer label
|
|
268
|
+
# @return [CommandBuffer]
|
|
269
|
+
# @raise [CommandError] if the encoder is finished, has an active pass, or native creation fails
|
|
219
270
|
def finish(label: nil)
|
|
220
271
|
raise CommandError, "Encoder already finished" if @finished
|
|
221
272
|
if @active_pass && !@active_pass.ended?
|
|
@@ -235,9 +286,13 @@ module WGPU
|
|
|
235
286
|
buffer_handle = Native.wgpuCommandEncoderFinish(@handle, desc)
|
|
236
287
|
raise CommandError, "Failed to finish command encoder" if buffer_handle.null?
|
|
237
288
|
|
|
238
|
-
CommandBuffer.new(buffer_handle)
|
|
289
|
+
CommandBuffer.new(buffer_handle, device: @device)
|
|
239
290
|
end
|
|
240
291
|
|
|
292
|
+
# Releases the native command encoder handle.
|
|
293
|
+
#
|
|
294
|
+
# Calling this method more than once has no effect.
|
|
295
|
+
# @return [void]
|
|
241
296
|
def release
|
|
242
297
|
return if @handle.null?
|
|
243
298
|
Native.wgpuCommandEncoderRelease(@handle)
|
|
@@ -4,6 +4,11 @@ module WGPU
|
|
|
4
4
|
class ComputePass
|
|
5
5
|
attr_reader :handle
|
|
6
6
|
|
|
7
|
+
# Begins a compute pass owned by the command encoder.
|
|
8
|
+
# @param encoder [CommandEncoder] owning encoder
|
|
9
|
+
# @param label [String, nil] optional debug label
|
|
10
|
+
# @param timestamp_writes [Hash, nil] beginning and ending timestamp query settings
|
|
11
|
+
# @raise [CommandError] if the native pass cannot be created
|
|
7
12
|
def initialize(encoder, label: nil, timestamp_writes: nil)
|
|
8
13
|
@encoder = encoder
|
|
9
14
|
@ended = false
|
|
@@ -20,7 +25,7 @@ module WGPU
|
|
|
20
25
|
@timestamp_writes = nil
|
|
21
26
|
if timestamp_writes
|
|
22
27
|
@timestamp_writes = Native::ComputePassTimestampWrites.new
|
|
23
|
-
@timestamp_writes[:query_set] = timestamp_writes.fetch(:query_set)
|
|
28
|
+
@timestamp_writes[:query_set] = NativeResource.checked_handle(timestamp_writes.fetch(:query_set), expected_class: QuerySet)
|
|
24
29
|
@timestamp_writes[:beginning_of_pass_write_index] = timestamp_writes[:beginning_of_pass_write_index] || 0xFFFFFFFF
|
|
25
30
|
@timestamp_writes[:end_of_pass_write_index] = timestamp_writes[:end_of_pass_write_index] || 0xFFFFFFFF
|
|
26
31
|
desc[:timestamp_writes] = @timestamp_writes.to_ptr
|
|
@@ -28,32 +33,53 @@ module WGPU
|
|
|
28
33
|
desc[:timestamp_writes] = nil
|
|
29
34
|
end
|
|
30
35
|
|
|
31
|
-
@handle = Native.wgpuCommandEncoderBeginComputePass(encoder
|
|
36
|
+
@handle = Native.wgpuCommandEncoderBeginComputePass(NativeResource.checked_handle(encoder, expected_class: CommandEncoder), desc)
|
|
32
37
|
raise CommandError, "Failed to begin compute pass" if @handle.null?
|
|
33
38
|
end
|
|
34
39
|
|
|
40
|
+
# Selects the compute pipeline used by subsequent dispatches.
|
|
41
|
+
# @param pipeline [ComputePipeline] pipeline to bind
|
|
42
|
+
# @return [void]
|
|
35
43
|
def set_pipeline(pipeline)
|
|
36
|
-
Native.wgpuComputePassEncoderSetPipeline(@handle, pipeline
|
|
44
|
+
Native.wgpuComputePassEncoderSetPipeline(@handle, NativeResource.checked_handle(pipeline, expected_class: ComputePipeline))
|
|
37
45
|
end
|
|
38
46
|
|
|
47
|
+
# Binds a resource group for subsequent dispatches.
|
|
48
|
+
# @param index [Integer] bind group index
|
|
49
|
+
# @param bind_group [BindGroup] group to bind
|
|
50
|
+
# @param dynamic_offsets [Array<Integer>] dynamic buffer offsets
|
|
51
|
+
# @return [void]
|
|
39
52
|
def set_bind_group(index, bind_group, dynamic_offsets: [])
|
|
40
53
|
if dynamic_offsets.empty?
|
|
41
|
-
Native.wgpuComputePassEncoderSetBindGroup(@handle, index, bind_group
|
|
54
|
+
Native.wgpuComputePassEncoderSetBindGroup(@handle, index, NativeResource.checked_handle(bind_group, expected_class: BindGroup), 0, nil)
|
|
42
55
|
else
|
|
43
56
|
offsets_ptr = FFI::MemoryPointer.new(:uint32, dynamic_offsets.size)
|
|
44
57
|
offsets_ptr.write_array_of_uint32(dynamic_offsets)
|
|
45
|
-
Native.wgpuComputePassEncoderSetBindGroup(@handle, index, bind_group
|
|
58
|
+
Native.wgpuComputePassEncoderSetBindGroup(@handle, index, NativeResource.checked_handle(bind_group, expected_class: BindGroup), dynamic_offsets.size, offsets_ptr)
|
|
46
59
|
end
|
|
47
60
|
end
|
|
48
61
|
|
|
62
|
+
# Dispatches a three-dimensional compute workgroup grid.
|
|
63
|
+
# @param x [Integer] workgroup count on the x axis
|
|
64
|
+
# @param y [Integer] workgroup count on the y axis
|
|
65
|
+
# @param z [Integer] workgroup count on the z axis
|
|
66
|
+
# @return [void]
|
|
49
67
|
def dispatch_workgroups(x, y = 1, z = 1)
|
|
50
68
|
Native.wgpuComputePassEncoderDispatchWorkgroups(@handle, x, y, z)
|
|
51
69
|
end
|
|
52
70
|
|
|
71
|
+
# Dispatches workgroups using arguments read from a buffer.
|
|
72
|
+
# @param buffer [Buffer] indirect argument buffer
|
|
73
|
+
# @param offset [Integer] byte offset of the arguments
|
|
74
|
+
# @return [void]
|
|
53
75
|
def dispatch_workgroups_indirect(buffer, offset: 0)
|
|
54
|
-
Native.wgpuComputePassEncoderDispatchWorkgroupsIndirect(@handle, buffer
|
|
76
|
+
Native.wgpuComputePassEncoderDispatchWorkgroupsIndirect(@handle, NativeResource.checked_handle(buffer, expected_class: Buffer), offset)
|
|
55
77
|
end
|
|
56
78
|
|
|
79
|
+
# Starts a labeled group in GPU debugging tools.
|
|
80
|
+
#
|
|
81
|
+
# @param label [String] group label
|
|
82
|
+
# @return [void]
|
|
57
83
|
def push_debug_group(label)
|
|
58
84
|
label_view = Native::StringView.new
|
|
59
85
|
label_ptr = FFI::MemoryPointer.from_string(label)
|
|
@@ -62,10 +88,17 @@ module WGPU
|
|
|
62
88
|
Native.wgpuComputePassEncoderPushDebugGroup(@handle, label_view)
|
|
63
89
|
end
|
|
64
90
|
|
|
91
|
+
# Ends the most recently pushed debug group.
|
|
92
|
+
#
|
|
93
|
+
# @return [void]
|
|
65
94
|
def pop_debug_group
|
|
66
95
|
Native.wgpuComputePassEncoderPopDebugGroup(@handle)
|
|
67
96
|
end
|
|
68
97
|
|
|
98
|
+
# Inserts a labeled point in GPU debugging tools.
|
|
99
|
+
#
|
|
100
|
+
# @param label [String] marker label
|
|
101
|
+
# @return [void]
|
|
69
102
|
def insert_debug_marker(label)
|
|
70
103
|
label_view = Native::StringView.new
|
|
71
104
|
label_ptr = FFI::MemoryPointer.from_string(label)
|
|
@@ -74,6 +107,8 @@ module WGPU
|
|
|
74
107
|
Native.wgpuComputePassEncoderInsertDebugMarker(@handle, label_view)
|
|
75
108
|
end
|
|
76
109
|
|
|
110
|
+
# Ends the pass if it has not already ended.
|
|
111
|
+
# @return [void]
|
|
77
112
|
def end_pass
|
|
78
113
|
return if @ended
|
|
79
114
|
|
|
@@ -82,14 +117,22 @@ module WGPU
|
|
|
82
117
|
@encoder.send(:pass_ended, self)
|
|
83
118
|
end
|
|
84
119
|
|
|
120
|
+
# Ends the pass.
|
|
121
|
+
# @return [void]
|
|
85
122
|
def end
|
|
86
123
|
end_pass
|
|
87
124
|
end
|
|
88
125
|
|
|
126
|
+
# Reports whether the pass has ended.
|
|
127
|
+
# @return [Boolean]
|
|
89
128
|
def ended?
|
|
90
129
|
@ended
|
|
91
130
|
end
|
|
92
131
|
|
|
132
|
+
# Releases the native compute pass encoder handle.
|
|
133
|
+
#
|
|
134
|
+
# Calling this method more than once has no effect.
|
|
135
|
+
# @return [void]
|
|
93
136
|
def release
|
|
94
137
|
return if @handle.null?
|
|
95
138
|
Native.wgpuComputePassEncoderRelease(@handle)
|
|
@@ -4,10 +4,18 @@ module WGPU
|
|
|
4
4
|
class RenderBundle
|
|
5
5
|
attr_reader :handle
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
# Wraps a reusable native render bundle.
|
|
8
|
+
# @param handle [FFI::Pointer] native render bundle handle
|
|
9
|
+
# @param device [Device, nil] device whose callbacks the render bundle may use
|
|
10
|
+
def initialize(handle, device: nil)
|
|
8
11
|
@handle = handle
|
|
12
|
+
@device = device
|
|
9
13
|
end
|
|
10
14
|
|
|
15
|
+
# Releases the native render bundle handle.
|
|
16
|
+
#
|
|
17
|
+
# Calling this method more than once has no effect.
|
|
18
|
+
# @return [void]
|
|
11
19
|
def release
|
|
12
20
|
return if @handle.null?
|
|
13
21
|
|
|
@@ -4,6 +4,15 @@ module WGPU
|
|
|
4
4
|
class RenderBundleEncoder
|
|
5
5
|
attr_reader :handle
|
|
6
6
|
|
|
7
|
+
# Creates an encoder for reusable render commands.
|
|
8
|
+
# @param device [Device] owning device
|
|
9
|
+
# @param color_formats [Array<Symbol, Integer>] color attachment formats
|
|
10
|
+
# @param depth_stencil_format [Symbol, Integer, nil] optional depth/stencil format
|
|
11
|
+
# @param sample_count [Integer] multisample count
|
|
12
|
+
# @param depth_read_only [Boolean] whether depth writes are disabled
|
|
13
|
+
# @param stencil_read_only [Boolean] whether stencil writes are disabled
|
|
14
|
+
# @param label [String, nil] optional debug label
|
|
15
|
+
# @raise [RenderBundleError] if the native encoder cannot be created
|
|
7
16
|
def initialize(device, color_formats:, depth_stencil_format: nil, sample_count: 1,
|
|
8
17
|
depth_read_only: false, stencil_read_only: false, label: nil)
|
|
9
18
|
@device = device
|
|
@@ -38,67 +47,99 @@ module WGPU
|
|
|
38
47
|
desc[:depth_read_only] = depth_read_only ? 1 : 0
|
|
39
48
|
desc[:stencil_read_only] = stencil_read_only ? 1 : 0
|
|
40
49
|
|
|
41
|
-
@handle = Native.wgpuDeviceCreateRenderBundleEncoder(device
|
|
50
|
+
@handle = Native.wgpuDeviceCreateRenderBundleEncoder(NativeResource.checked_handle(device, expected_class: Device), desc)
|
|
42
51
|
raise RenderBundleError, "Failed to create render bundle encoder" if @handle.null?
|
|
43
52
|
end
|
|
44
53
|
|
|
54
|
+
# Selects the pipeline used by subsequent bundle draws.
|
|
55
|
+
# @param pipeline [RenderPipeline] pipeline to bind
|
|
56
|
+
# @raise [RenderBundleError] if the encoder is finished
|
|
57
|
+
# @return [void]
|
|
45
58
|
def set_pipeline(pipeline)
|
|
46
59
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
47
60
|
|
|
48
|
-
Native.wgpuRenderBundleEncoderSetPipeline(@handle, pipeline
|
|
61
|
+
Native.wgpuRenderBundleEncoderSetPipeline(@handle, NativeResource.checked_handle(pipeline, expected_class: RenderPipeline))
|
|
49
62
|
end
|
|
50
63
|
|
|
64
|
+
# Binds a resource group for subsequent bundle draws.
|
|
65
|
+
# @param index [Integer] bind group index
|
|
66
|
+
# @param bind_group [BindGroup] group to bind
|
|
67
|
+
# @param dynamic_offsets [Array<Integer>, nil] dynamic buffer offsets
|
|
68
|
+
# @return [void]
|
|
51
69
|
def set_bind_group(index, bind_group, dynamic_offsets: nil)
|
|
52
70
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
53
71
|
|
|
54
72
|
if dynamic_offsets && !dynamic_offsets.empty?
|
|
55
73
|
offsets_ptr = FFI::MemoryPointer.new(:uint32, dynamic_offsets.size)
|
|
56
74
|
offsets_ptr.write_array_of_uint32(dynamic_offsets)
|
|
57
|
-
Native.wgpuRenderBundleEncoderSetBindGroup(@handle, index, bind_group
|
|
75
|
+
Native.wgpuRenderBundleEncoderSetBindGroup(@handle, index, NativeResource.checked_handle(bind_group, expected_class: BindGroup), dynamic_offsets.size, offsets_ptr)
|
|
58
76
|
else
|
|
59
|
-
Native.wgpuRenderBundleEncoderSetBindGroup(@handle, index, bind_group
|
|
77
|
+
Native.wgpuRenderBundleEncoderSetBindGroup(@handle, index, NativeResource.checked_handle(bind_group, expected_class: BindGroup), 0, nil)
|
|
60
78
|
end
|
|
61
79
|
end
|
|
62
80
|
|
|
81
|
+
# Binds a vertex buffer to a slot.
|
|
82
|
+
# @param slot [Integer] vertex buffer slot
|
|
83
|
+
# @param buffer [Buffer] vertex data buffer
|
|
84
|
+
# @return [void]
|
|
63
85
|
def set_vertex_buffer(slot, buffer, offset: 0, size: nil)
|
|
64
86
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
65
87
|
|
|
66
88
|
size ||= buffer.size - offset
|
|
67
|
-
Native.wgpuRenderBundleEncoderSetVertexBuffer(@handle, slot, buffer
|
|
89
|
+
Native.wgpuRenderBundleEncoderSetVertexBuffer(@handle, slot, NativeResource.checked_handle(buffer, expected_class: Buffer), offset, size)
|
|
68
90
|
end
|
|
69
91
|
|
|
92
|
+
# Binds an index buffer for indexed bundle draws.
|
|
93
|
+
# @param buffer [Buffer] index data buffer
|
|
94
|
+
# @param format [Symbol, Integer] index element format
|
|
95
|
+
# @return [void]
|
|
70
96
|
def set_index_buffer(buffer, format: :uint32, offset: 0, size: nil)
|
|
71
97
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
72
98
|
|
|
73
99
|
size ||= buffer.size - offset
|
|
74
100
|
format_value = Native::EnumHelper.coerce(Native::IndexFormat, format, name: "index format")
|
|
75
|
-
Native.wgpuRenderBundleEncoderSetIndexBuffer(@handle, buffer
|
|
101
|
+
Native.wgpuRenderBundleEncoderSetIndexBuffer(@handle, NativeResource.checked_handle(buffer, expected_class: Buffer), format_value, offset, size)
|
|
76
102
|
end
|
|
77
103
|
|
|
104
|
+
# Records a non-indexed draw in the bundle.
|
|
105
|
+
# @return [void]
|
|
78
106
|
def draw(vertex_count, instance_count: 1, first_vertex: 0, first_instance: 0)
|
|
79
107
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
80
108
|
|
|
81
109
|
Native.wgpuRenderBundleEncoderDraw(@handle, vertex_count, instance_count, first_vertex, first_instance)
|
|
82
110
|
end
|
|
83
111
|
|
|
112
|
+
# Records an indexed draw in the bundle.
|
|
113
|
+
# @return [void]
|
|
84
114
|
def draw_indexed(index_count, instance_count: 1, first_index: 0, base_vertex: 0, first_instance: 0)
|
|
85
115
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
86
116
|
|
|
87
117
|
Native.wgpuRenderBundleEncoderDrawIndexed(@handle, index_count, instance_count, first_index, base_vertex, first_instance)
|
|
88
118
|
end
|
|
89
119
|
|
|
120
|
+
# Records a non-indexed draw using buffer arguments.
|
|
121
|
+
# @param buffer [Buffer] indirect argument buffer
|
|
122
|
+
# @param offset [Integer] byte offset of the arguments
|
|
123
|
+
# @return [void]
|
|
90
124
|
def draw_indirect(buffer, offset: 0)
|
|
91
125
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
92
126
|
|
|
93
|
-
Native.wgpuRenderBundleEncoderDrawIndirect(@handle, buffer
|
|
127
|
+
Native.wgpuRenderBundleEncoderDrawIndirect(@handle, NativeResource.checked_handle(buffer, expected_class: Buffer), offset)
|
|
94
128
|
end
|
|
95
129
|
|
|
130
|
+
# Records an indexed draw using buffer arguments.
|
|
131
|
+
# @param buffer [Buffer] indirect argument buffer
|
|
132
|
+
# @param offset [Integer] byte offset of the arguments
|
|
133
|
+
# @return [void]
|
|
96
134
|
def draw_indexed_indirect(buffer, offset: 0)
|
|
97
135
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
98
136
|
|
|
99
|
-
Native.wgpuRenderBundleEncoderDrawIndexedIndirect(@handle, buffer
|
|
137
|
+
Native.wgpuRenderBundleEncoderDrawIndexedIndirect(@handle, NativeResource.checked_handle(buffer, expected_class: Buffer), offset)
|
|
100
138
|
end
|
|
101
139
|
|
|
140
|
+
# Starts a labeled group in GPU debugging tools.
|
|
141
|
+
# @param label [String] group label
|
|
142
|
+
# @return [void]
|
|
102
143
|
def push_debug_group(label)
|
|
103
144
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
104
145
|
|
|
@@ -109,12 +150,17 @@ module WGPU
|
|
|
109
150
|
Native.wgpuRenderBundleEncoderPushDebugGroup(@handle, label_view)
|
|
110
151
|
end
|
|
111
152
|
|
|
153
|
+
# Ends the most recently pushed debug group.
|
|
154
|
+
# @return [void]
|
|
112
155
|
def pop_debug_group
|
|
113
156
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
114
157
|
|
|
115
158
|
Native.wgpuRenderBundleEncoderPopDebugGroup(@handle)
|
|
116
159
|
end
|
|
117
160
|
|
|
161
|
+
# Inserts a labeled point in GPU debugging tools.
|
|
162
|
+
# @param label [String] marker label
|
|
163
|
+
# @return [void]
|
|
118
164
|
def insert_debug_marker(label)
|
|
119
165
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
120
166
|
|
|
@@ -125,6 +171,10 @@ module WGPU
|
|
|
125
171
|
Native.wgpuRenderBundleEncoderInsertDebugMarker(@handle, label_view)
|
|
126
172
|
end
|
|
127
173
|
|
|
174
|
+
# Finishes recording and creates an immutable render bundle.
|
|
175
|
+
# @param label [String, nil] optional bundle label
|
|
176
|
+
# @return [RenderBundle]
|
|
177
|
+
# @raise [RenderBundleError] if already finished or native creation fails
|
|
128
178
|
def finish(label: nil)
|
|
129
179
|
raise RenderBundleError, "Encoder already finished" if @finished
|
|
130
180
|
|
|
@@ -142,9 +192,13 @@ module WGPU
|
|
|
142
192
|
bundle_handle = Native.wgpuRenderBundleEncoderFinish(@handle, desc)
|
|
143
193
|
raise RenderBundleError, "Failed to finish render bundle encoder" if bundle_handle.null?
|
|
144
194
|
|
|
145
|
-
RenderBundle.new(bundle_handle)
|
|
195
|
+
RenderBundle.new(bundle_handle, device: @device)
|
|
146
196
|
end
|
|
147
197
|
|
|
198
|
+
# Releases the native render bundle encoder handle.
|
|
199
|
+
#
|
|
200
|
+
# Calling this method more than once has no effect.
|
|
201
|
+
# @return [void]
|
|
148
202
|
def release
|
|
149
203
|
return if @handle.null?
|
|
150
204
|
|