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
|
@@ -4,6 +4,10 @@ module WGPU
|
|
|
4
4
|
class PipelineLayout
|
|
5
5
|
attr_reader :handle
|
|
6
6
|
|
|
7
|
+
# Creates a pipeline layout from ordered bind group layouts.
|
|
8
|
+
# @param device [Device] owning device
|
|
9
|
+
# @param bind_group_layouts [Array<BindGroupLayout>] layouts by group index
|
|
10
|
+
# @raise [PipelineError] if native validation or creation fails
|
|
7
11
|
def initialize(device, label: nil, bind_group_layouts:)
|
|
8
12
|
@device = device
|
|
9
13
|
|
|
@@ -34,6 +38,10 @@ module WGPU
|
|
|
34
38
|
end
|
|
35
39
|
end
|
|
36
40
|
|
|
41
|
+
# Releases the native pipeline layout handle.
|
|
42
|
+
#
|
|
43
|
+
# Calling this method more than once has no effect.
|
|
44
|
+
# @return [void]
|
|
37
45
|
def release
|
|
38
46
|
return if @handle.null?
|
|
39
47
|
Native.wgpuPipelineLayoutRelease(@handle)
|
|
@@ -4,6 +4,12 @@ module WGPU
|
|
|
4
4
|
class RenderPipeline
|
|
5
5
|
attr_reader :handle
|
|
6
6
|
|
|
7
|
+
# Creates a render pipeline.
|
|
8
|
+
# @param device [Device] owning device
|
|
9
|
+
# @param layout [PipelineLayout, :auto, nil] pipeline layout
|
|
10
|
+
# @param vertex [Hash] programmable vertex stage descriptor
|
|
11
|
+
# @param fragment [Hash, nil] optional fragment stage descriptor
|
|
12
|
+
# @raise [PipelineError] if native validation or creation fails
|
|
7
13
|
def initialize(device, label: nil, layout:, vertex:, primitive: {}, depth_stencil: nil, multisample: {}, fragment: nil)
|
|
8
14
|
@device = device
|
|
9
15
|
desc, @pointers = build_descriptor(
|
|
@@ -26,12 +32,20 @@ module WGPU
|
|
|
26
32
|
end
|
|
27
33
|
end
|
|
28
34
|
|
|
35
|
+
# Returns the bind group layout inferred or assigned at an index.
|
|
36
|
+
# @param index [Integer] bind group index
|
|
37
|
+
# @return [BindGroupLayout]
|
|
38
|
+
# @raise [PipelineError] if no native layout is returned
|
|
29
39
|
def get_bind_group_layout(index)
|
|
30
40
|
handle = Native.wgpuRenderPipelineGetBindGroupLayout(@handle, index)
|
|
31
41
|
raise PipelineError, "Failed to get bind group layout at index #{index}" if handle.null?
|
|
32
|
-
BindGroupLayout.from_handle(handle)
|
|
42
|
+
BindGroupLayout.from_handle(handle, device: @device)
|
|
33
43
|
end
|
|
34
44
|
|
|
45
|
+
# Releases the native render pipeline handle.
|
|
46
|
+
#
|
|
47
|
+
# Calling this method more than once has no effect.
|
|
48
|
+
# @return [void]
|
|
35
49
|
def release
|
|
36
50
|
return if @handle.null?
|
|
37
51
|
Native.wgpuRenderPipelineRelease(@handle)
|
|
@@ -66,15 +80,12 @@ module WGPU
|
|
|
66
80
|
vertex_state[:next_in_chain] = nil
|
|
67
81
|
vertex_state[:module] = vertex[:module].handle
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
vertex_state[:constant_count] = 0
|
|
76
|
-
vertex_state[:constants] = nil
|
|
77
|
-
setup_constants(vertex_state, vertex[:constants])
|
|
83
|
+
DescriptorHelpers.set_nullable_string_view(
|
|
84
|
+
vertex_state[:entry_point],
|
|
85
|
+
vertex[:entry_point],
|
|
86
|
+
keepalive: @pointers
|
|
87
|
+
)
|
|
88
|
+
DescriptorHelpers.set_constants(vertex_state, vertex[:constants], keepalive: @pointers)
|
|
78
89
|
|
|
79
90
|
buffers = vertex[:buffers] || []
|
|
80
91
|
if buffers.empty?
|
|
@@ -256,15 +267,12 @@ module WGPU
|
|
|
256
267
|
frag[:next_in_chain] = nil
|
|
257
268
|
frag[:module] = fragment[:module].handle
|
|
258
269
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
frag[:constant_count] = 0
|
|
266
|
-
frag[:constants] = nil
|
|
267
|
-
setup_constants(frag, fragment[:constants])
|
|
270
|
+
DescriptorHelpers.set_nullable_string_view(
|
|
271
|
+
frag[:entry_point],
|
|
272
|
+
fragment[:entry_point],
|
|
273
|
+
keepalive: @pointers
|
|
274
|
+
)
|
|
275
|
+
DescriptorHelpers.set_constants(frag, fragment[:constants], keepalive: @pointers)
|
|
268
276
|
|
|
269
277
|
targets = fragment[:targets] || []
|
|
270
278
|
if targets.empty?
|
|
@@ -363,28 +371,5 @@ module WGPU
|
|
|
363
371
|
return nil if layout.nil? || layout == :auto || layout == "auto"
|
|
364
372
|
layout.handle
|
|
365
373
|
end
|
|
366
|
-
|
|
367
|
-
def setup_constants(stage_state, constants)
|
|
368
|
-
return if constants.nil? || constants.empty?
|
|
369
|
-
|
|
370
|
-
constants_ptr = FFI::MemoryPointer.new(Native::ConstantEntry, constants.size)
|
|
371
|
-
@pointers << constants_ptr
|
|
372
|
-
|
|
373
|
-
constants.each_with_index do |(key, value), i|
|
|
374
|
-
entry_ptr = constants_ptr + (i * Native::ConstantEntry.size)
|
|
375
|
-
entry = Native::ConstantEntry.new(entry_ptr)
|
|
376
|
-
entry[:next_in_chain] = nil
|
|
377
|
-
|
|
378
|
-
key_str = key.to_s
|
|
379
|
-
key_ptr = FFI::MemoryPointer.from_string(key_str)
|
|
380
|
-
@pointers << key_ptr
|
|
381
|
-
entry[:key][:data] = key_ptr
|
|
382
|
-
entry[:key][:length] = key_str.bytesize
|
|
383
|
-
entry[:value] = value.to_f
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
stage_state[:constant_count] = constants.size
|
|
387
|
-
stage_state[:constants] = constants_ptr
|
|
388
|
-
end
|
|
389
374
|
end
|
|
390
375
|
end
|
|
@@ -4,6 +4,12 @@ module WGPU
|
|
|
4
4
|
class ShaderModule
|
|
5
5
|
attr_reader :handle
|
|
6
6
|
|
|
7
|
+
# Creates a shader module from WGSL, GLSL, or SPIR-V input.
|
|
8
|
+
# @param device [Device] owning device
|
|
9
|
+
# @param code [String, Array<Integer>, nil] shader source or binary
|
|
10
|
+
# @param spirv [String, Array<Integer>, nil] explicit SPIR-V input
|
|
11
|
+
# @param validate [Boolean] whether to fetch and raise compilation errors
|
|
12
|
+
# @raise [ShaderError] if native validation, creation, or compilation fails
|
|
7
13
|
def initialize(device, label: nil, code: nil, spirv: nil, compilation_hints: [], validate: false)
|
|
8
14
|
@device = device
|
|
9
15
|
@pointers = []
|
|
@@ -43,6 +49,9 @@ module WGPU
|
|
|
43
49
|
end
|
|
44
50
|
end
|
|
45
51
|
|
|
52
|
+
# Fetches compiler diagnostics for the shader.
|
|
53
|
+
# @return [Hash] request status and compilation messages
|
|
54
|
+
# @raise [ShaderError] if the pinned native library cannot provide diagnostics
|
|
46
55
|
def get_compilation_info
|
|
47
56
|
unless Native.compilation_info_available?
|
|
48
57
|
raise ShaderError,
|
|
@@ -52,34 +61,41 @@ module WGPU
|
|
|
52
61
|
result_holder = { done: false, status: nil, messages: [] }
|
|
53
62
|
instance = @device.adapter&.instance
|
|
54
63
|
|
|
64
|
+
callback_lifetime_release = device_callback_lifetime_lease
|
|
65
|
+
callback_token = nil
|
|
55
66
|
callback = FFI::Function.new(
|
|
56
67
|
:void, [:uint32, :pointer, :pointer, :pointer]
|
|
57
68
|
) do |status, compilation_info_ptr, _userdata1, _userdata2|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
begin
|
|
70
|
+
result_holder[:status] = Native::CompilationInfoRequestStatus[status]
|
|
71
|
+
|
|
72
|
+
unless compilation_info_ptr.null?
|
|
73
|
+
info = Native::CompilationInfo.new(compilation_info_ptr)
|
|
74
|
+
count = info[:message_count]
|
|
75
|
+
if count > 0 && !info[:messages].null?
|
|
76
|
+
count.times do |i|
|
|
77
|
+
msg_ptr = info[:messages] + (i * Native::CompilationMessage.size)
|
|
78
|
+
msg = Native::CompilationMessage.new(msg_ptr)
|
|
79
|
+
message_text = if msg[:message][:data] && !msg[:message][:data].null? && msg[:message][:length] > 0
|
|
80
|
+
msg[:message][:data].read_string(msg[:message][:length])
|
|
81
|
+
else
|
|
82
|
+
""
|
|
83
|
+
end
|
|
84
|
+
result_holder[:messages] << CompilationMessage.new(
|
|
85
|
+
type: msg[:type],
|
|
86
|
+
message: message_text,
|
|
87
|
+
line_num: msg[:line_num],
|
|
88
|
+
line_pos: msg[:line_pos],
|
|
89
|
+
offset: msg[:offset],
|
|
90
|
+
length: msg[:length]
|
|
91
|
+
)
|
|
92
|
+
end
|
|
81
93
|
end
|
|
82
94
|
end
|
|
95
|
+
result_holder[:done] = true
|
|
96
|
+
ensure
|
|
97
|
+
CallbackKeepalive.release(self, callback_token)
|
|
98
|
+
callback_lifetime_release.call
|
|
83
99
|
end
|
|
84
100
|
end
|
|
85
101
|
|
|
@@ -91,12 +107,15 @@ module WGPU
|
|
|
91
107
|
callback_info[:userdata2] = nil
|
|
92
108
|
|
|
93
109
|
callback_token = CallbackKeepalive.retain(self, callback)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
future =
|
|
111
|
+
begin
|
|
112
|
+
Native.wgpuShaderModuleGetCompilationInfo(@handle, callback_info)
|
|
113
|
+
rescue StandardError
|
|
114
|
+
CallbackKeepalive.release(self, callback_token)
|
|
115
|
+
callback_lifetime_release.call
|
|
116
|
+
raise
|
|
117
|
+
end
|
|
118
|
+
AsyncWaiter.wait(status_holder: result_holder, instance: instance, device: @device, future: future)
|
|
100
119
|
|
|
101
120
|
{
|
|
102
121
|
status: result_holder[:status],
|
|
@@ -104,10 +123,16 @@ module WGPU
|
|
|
104
123
|
}
|
|
105
124
|
end
|
|
106
125
|
|
|
126
|
+
# Fetches compiler diagnostics on a background task.
|
|
127
|
+
# @return [AsyncTask] task yielding compilation information
|
|
107
128
|
def get_compilation_info_async
|
|
108
129
|
AsyncTask.new { get_compilation_info }
|
|
109
130
|
end
|
|
110
131
|
|
|
132
|
+
# Releases the native shader module handle.
|
|
133
|
+
#
|
|
134
|
+
# Calling this method more than once has no effect.
|
|
135
|
+
# @return [void]
|
|
111
136
|
def release
|
|
112
137
|
return if @handle.null?
|
|
113
138
|
Native.wgpuShaderModuleRelease(@handle)
|