wgpu 1.0.0 → 1.2.0
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 +48 -0
- data/README.md +26 -3
- data/docs/README.md +22 -0
- data/docs/api_coverage.md +132 -0
- data/docs/async.md +31 -0
- data/docs/bind_groups.md +25 -0
- data/docs/buffer_data.md +37 -0
- data/docs/command_encoding.md +24 -0
- data/docs/errors.md +40 -0
- data/docs/getting_started_compute.md +61 -0
- data/docs/getting_started_rendering.md +62 -0
- data/docs/installation.md +94 -0
- data/docs/pipeline_descriptors.md +38 -0
- data/docs/releasing.md +22 -0
- data/docs/resource_lifetime.md +94 -0
- data/docs/shaders.md +32 -0
- data/docs/texture_readback.md +19 -0
- data/docs/troubleshooting.md +48 -0
- data/docs/upgrading_wgpu_native.md +26 -0
- data/ext/wgpu/extconf.rb +10 -142
- data/lib/wgpu/commands/command_buffer.rb +11 -0
- data/lib/wgpu/commands/command_encoder.rb +65 -8
- data/lib/wgpu/commands/compute_pass.rb +10 -0
- data/lib/wgpu/commands/render_bundle_encoder.rb +10 -3
- data/lib/wgpu/commands/render_pass.rb +34 -8
- data/lib/wgpu/core/adapter.rb +49 -20
- data/lib/wgpu/core/async_waiter.rb +92 -0
- data/lib/wgpu/core/canvas_context.rb +0 -2
- data/lib/wgpu/core/device.rb +160 -52
- data/lib/wgpu/core/instance.rb +9 -5
- data/lib/wgpu/core/queue.rb +81 -57
- data/lib/wgpu/core/surface.rb +16 -17
- data/lib/wgpu/data_types.rb +67 -0
- data/lib/wgpu/descriptor_helpers.rb +39 -0
- data/lib/wgpu/error.rb +55 -0
- data/lib/wgpu/logging.rb +63 -0
- data/lib/wgpu/native/abi_verifier.rb +109 -0
- data/lib/wgpu/native/callbacks.rb +9 -6
- data/lib/wgpu/native/capabilities.rb +31 -0
- data/lib/wgpu/native/distribution.rb +113 -0
- data/lib/wgpu/native/enum_helper.rb +63 -0
- data/lib/wgpu/native/enums.rb +82 -13
- data/lib/wgpu/native/functions.rb +17 -8
- data/lib/wgpu/native/installer.rb +192 -0
- data/lib/wgpu/native/loader.rb +40 -21
- data/lib/wgpu/native/structs.rb +19 -5
- data/lib/wgpu/native_resource.rb +171 -0
- data/lib/wgpu/pipeline/bind_group.rb +12 -0
- data/lib/wgpu/pipeline/bind_group_layout.rb +91 -37
- data/lib/wgpu/pipeline/compute_pipeline.rb +28 -26
- data/lib/wgpu/pipeline/render_pipeline.rb +180 -68
- data/lib/wgpu/pipeline/shader_module.rb +51 -12
- data/lib/wgpu/resources/buffer.rb +167 -84
- data/lib/wgpu/resources/query_set.rb +14 -12
- data/lib/wgpu/resources/sampler.rb +36 -20
- data/lib/wgpu/resources/texture.rb +44 -42
- data/lib/wgpu/resources/texture_view.rb +11 -3
- data/lib/wgpu/texture_format.rb +82 -0
- data/lib/wgpu/version.rb +1 -1
- data/lib/wgpu/window.rb +8 -1
- data/lib/wgpu.rb +33 -0
- data/sig/wgpu.rbs +381 -0
- metadata +33 -16
data/lib/wgpu/native/enums.rb
CHANGED
|
@@ -50,13 +50,22 @@ module WGPU
|
|
|
50
50
|
:success, 0x00000001,
|
|
51
51
|
:instance_dropped, 0x00000002,
|
|
52
52
|
:unavailable, 0x00000003,
|
|
53
|
-
:error, 0x00000004
|
|
53
|
+
:error, 0x00000004,
|
|
54
|
+
:unknown, 0x00000005
|
|
54
55
|
)
|
|
55
56
|
|
|
56
57
|
RequestDeviceStatus = enum(
|
|
57
58
|
:success, 0x00000001,
|
|
58
59
|
:instance_dropped, 0x00000002,
|
|
59
|
-
:error, 0x00000003
|
|
60
|
+
:error, 0x00000003,
|
|
61
|
+
:unknown, 0x00000004
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
DeviceLostReason = enum(
|
|
65
|
+
:unknown, 0x00000001,
|
|
66
|
+
:destroyed, 0x00000002,
|
|
67
|
+
:instance_dropped, 0x00000003,
|
|
68
|
+
:failed_creation, 0x00000004
|
|
60
69
|
)
|
|
61
70
|
|
|
62
71
|
BufferMapState = enum(
|
|
@@ -65,11 +74,18 @@ module WGPU
|
|
|
65
74
|
:mapped, 0x00000003
|
|
66
75
|
)
|
|
67
76
|
|
|
77
|
+
CallbackMode = enum(
|
|
78
|
+
:wait_any_only, 0x00000001,
|
|
79
|
+
:allow_process_events, 0x00000002,
|
|
80
|
+
:allow_spontaneous, 0x00000003
|
|
81
|
+
)
|
|
82
|
+
|
|
68
83
|
MapAsyncStatus = enum(
|
|
69
84
|
:success, 0x00000001,
|
|
70
85
|
:instance_dropped, 0x00000002,
|
|
71
86
|
:error, 0x00000003,
|
|
72
|
-
:aborted, 0x00000004
|
|
87
|
+
:aborted, 0x00000004,
|
|
88
|
+
:unknown, 0x00000005
|
|
73
89
|
)
|
|
74
90
|
|
|
75
91
|
BufferUsage = {
|
|
@@ -274,7 +290,9 @@ module WGPU
|
|
|
274
290
|
:sint32, 0x00000024,
|
|
275
291
|
:sint32x2, 0x00000025,
|
|
276
292
|
:sint32x3, 0x00000026,
|
|
277
|
-
:sint32x4, 0x00000027
|
|
293
|
+
:sint32x4, 0x00000027,
|
|
294
|
+
:unorm10_10_10_2, 0x00000028,
|
|
295
|
+
:unorm8x4_bgra, 0x00000029
|
|
278
296
|
)
|
|
279
297
|
|
|
280
298
|
IndexFormat = enum(
|
|
@@ -357,11 +375,11 @@ module WGPU
|
|
|
357
375
|
:undefined, 0x00000000,
|
|
358
376
|
:never, 0x00000001,
|
|
359
377
|
:less, 0x00000002,
|
|
360
|
-
:
|
|
361
|
-
:
|
|
362
|
-
:
|
|
363
|
-
:
|
|
364
|
-
:
|
|
378
|
+
:equal, 0x00000003,
|
|
379
|
+
:less_equal, 0x00000004,
|
|
380
|
+
:greater, 0x00000005,
|
|
381
|
+
:not_equal, 0x00000006,
|
|
382
|
+
:greater_equal, 0x00000007,
|
|
365
383
|
:always, 0x00000008
|
|
366
384
|
)
|
|
367
385
|
|
|
@@ -458,7 +476,9 @@ module WGPU
|
|
|
458
476
|
:timeout, 0x00000003,
|
|
459
477
|
:outdated, 0x00000004,
|
|
460
478
|
:lost, 0x00000005,
|
|
461
|
-
:
|
|
479
|
+
:out_of_memory, 0x00000006,
|
|
480
|
+
:device_lost, 0x00000007,
|
|
481
|
+
:error, 0x00000008
|
|
462
482
|
)
|
|
463
483
|
|
|
464
484
|
QueryType = enum(
|
|
@@ -482,8 +502,16 @@ module WGPU
|
|
|
482
502
|
|
|
483
503
|
PopErrorScopeStatus = enum(
|
|
484
504
|
:success, 0x00000001,
|
|
485
|
-
:
|
|
486
|
-
:
|
|
505
|
+
:instance_dropped, 0x00000002,
|
|
506
|
+
:empty_stack, 0x00000003
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
WaitStatus = enum(
|
|
510
|
+
:success, 0x00000001,
|
|
511
|
+
:timed_out, 0x00000002,
|
|
512
|
+
:unsupported_timeout, 0x00000003,
|
|
513
|
+
:unsupported_count, 0x00000004,
|
|
514
|
+
:unsupported_mixed_sources, 0x00000005
|
|
487
515
|
)
|
|
488
516
|
|
|
489
517
|
QueueWorkDoneStatus = enum(
|
|
@@ -506,6 +534,15 @@ module WGPU
|
|
|
506
534
|
:info, 0x00000003
|
|
507
535
|
)
|
|
508
536
|
|
|
537
|
+
LogLevel = enum(
|
|
538
|
+
:off, 0x00000000,
|
|
539
|
+
:error, 0x00000001,
|
|
540
|
+
:warn, 0x00000002,
|
|
541
|
+
:info, 0x00000003,
|
|
542
|
+
:debug, 0x00000004,
|
|
543
|
+
:trace, 0x00000005
|
|
544
|
+
)
|
|
545
|
+
|
|
509
546
|
FeatureName = enum(
|
|
510
547
|
:undefined, 0x00000000,
|
|
511
548
|
:depth_clip_control, 0x00000001,
|
|
@@ -523,7 +560,39 @@ module WGPU
|
|
|
523
560
|
:float32_filterable, 0x0000000D,
|
|
524
561
|
:float32_blendable, 0x0000000E,
|
|
525
562
|
:clip_distances, 0x0000000F,
|
|
526
|
-
:dual_source_blending, 0x00000010
|
|
563
|
+
:dual_source_blending, 0x00000010,
|
|
564
|
+
# wgpu-native extensions from wgpu.h.
|
|
565
|
+
:push_constants, 0x00030001,
|
|
566
|
+
:texture_adapter_specific_format_features, 0x00030002,
|
|
567
|
+
:multi_draw_indirect_count, 0x00030004,
|
|
568
|
+
:vertex_writable_storage, 0x00030005,
|
|
569
|
+
:texture_binding_array, 0x00030006,
|
|
570
|
+
:sampled_texture_and_storage_buffer_array_non_uniform_indexing, 0x00030007,
|
|
571
|
+
:pipeline_statistics_query, 0x00030008,
|
|
572
|
+
:storage_resource_binding_array, 0x00030009,
|
|
573
|
+
:partially_bound_binding_array, 0x0003000A,
|
|
574
|
+
:texture_format_16bit_norm, 0x0003000B,
|
|
575
|
+
:texture_compression_astc_hdr, 0x0003000C,
|
|
576
|
+
:mappable_primary_buffers, 0x0003000E,
|
|
577
|
+
:buffer_binding_array, 0x0003000F,
|
|
578
|
+
:uniform_buffer_and_storage_texture_array_non_uniform_indexing, 0x00030010,
|
|
579
|
+
:polygon_mode_line, 0x00030013,
|
|
580
|
+
:polygon_mode_point, 0x00030014,
|
|
581
|
+
:conservative_rasterization, 0x00030015,
|
|
582
|
+
:spirv_shader_passthrough, 0x00030017,
|
|
583
|
+
:vertex_attribute_64bit, 0x00030019,
|
|
584
|
+
:texture_format_nv12, 0x0003001A,
|
|
585
|
+
:ray_query, 0x0003001C,
|
|
586
|
+
:shader_f64, 0x0003001D,
|
|
587
|
+
:shader_i16, 0x0003001E,
|
|
588
|
+
:shader_primitive_index, 0x0003001F,
|
|
589
|
+
:shader_early_depth_test, 0x00030020,
|
|
590
|
+
:subgroup, 0x00030021,
|
|
591
|
+
:subgroup_vertex, 0x00030022,
|
|
592
|
+
:subgroup_barrier, 0x00030023,
|
|
593
|
+
:timestamp_query_inside_encoders, 0x00030024,
|
|
594
|
+
:timestamp_query_inside_passes, 0x00030025,
|
|
595
|
+
:shader_int64, 0x00030026
|
|
527
596
|
)
|
|
528
597
|
end
|
|
529
598
|
end
|
|
@@ -9,7 +9,7 @@ module WGPU
|
|
|
9
9
|
[:pointer], :void
|
|
10
10
|
|
|
11
11
|
attach_function :wgpuInstanceRequestAdapter,
|
|
12
|
-
[:pointer, RequestAdapterOptions.by_ref, RequestAdapterCallbackInfo.by_value],
|
|
12
|
+
[:pointer, RequestAdapterOptions.by_ref, RequestAdapterCallbackInfo.by_value], Future.by_value
|
|
13
13
|
|
|
14
14
|
attach_function :wgpuInstanceEnumerateAdapters,
|
|
15
15
|
[:pointer, :pointer, :pointer], :size_t
|
|
@@ -17,6 +17,9 @@ module WGPU
|
|
|
17
17
|
attach_function :wgpuInstanceProcessEvents,
|
|
18
18
|
[:pointer], :void
|
|
19
19
|
|
|
20
|
+
attach_optional_function :wgpuInstanceWaitAny,
|
|
21
|
+
[:pointer, :size_t, :pointer, :uint64], WaitStatus
|
|
22
|
+
|
|
20
23
|
attach_function :wgpuAdapterRelease,
|
|
21
24
|
[:pointer], :void
|
|
22
25
|
|
|
@@ -24,7 +27,7 @@ module WGPU
|
|
|
24
27
|
[:pointer, AdapterInfo.by_ref], :void
|
|
25
28
|
|
|
26
29
|
attach_function :wgpuAdapterRequestDevice,
|
|
27
|
-
[:pointer, DeviceDescriptor.by_ref, RequestDeviceCallbackInfo.by_value],
|
|
30
|
+
[:pointer, DeviceDescriptor.by_ref, RequestDeviceCallbackInfo.by_value], Future.by_value
|
|
28
31
|
|
|
29
32
|
attach_function :wgpuAdapterGetFeatures,
|
|
30
33
|
[:pointer, :pointer], :void
|
|
@@ -71,8 +74,8 @@ module WGPU
|
|
|
71
74
|
attach_function :wgpuDeviceCreateCommandEncoder,
|
|
72
75
|
[:pointer, CommandEncoderDescriptor.by_ref], :pointer
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
77
|
+
attach_optional_function :wgpuDevicePoll,
|
|
78
|
+
[:pointer, :uint32, :pointer], :uint32
|
|
76
79
|
|
|
77
80
|
attach_function :wgpuQueueRelease,
|
|
78
81
|
[:pointer], :void
|
|
@@ -81,7 +84,7 @@ module WGPU
|
|
|
81
84
|
[:pointer, :size_t, :pointer], :void
|
|
82
85
|
|
|
83
86
|
attach_function :wgpuQueueOnSubmittedWorkDone,
|
|
84
|
-
[:pointer, QueueWorkDoneCallbackInfo.by_value],
|
|
87
|
+
[:pointer, QueueWorkDoneCallbackInfo.by_value], Future.by_value
|
|
85
88
|
|
|
86
89
|
attach_function :wgpuQueueWriteBuffer,
|
|
87
90
|
[:pointer, :pointer, :uint64, :pointer, :size_t], :void
|
|
@@ -96,7 +99,7 @@ module WGPU
|
|
|
96
99
|
[:pointer], :void
|
|
97
100
|
|
|
98
101
|
attach_function :wgpuBufferMapAsync,
|
|
99
|
-
[:pointer, :uint64, :size_t, :size_t, BufferMapCallbackInfo.by_value],
|
|
102
|
+
[:pointer, :uint64, :size_t, :size_t, BufferMapCallbackInfo.by_value], Future.by_value
|
|
100
103
|
|
|
101
104
|
attach_function :wgpuBufferUnmap,
|
|
102
105
|
[:pointer], :void
|
|
@@ -120,7 +123,7 @@ module WGPU
|
|
|
120
123
|
[:pointer], :void
|
|
121
124
|
|
|
122
125
|
attach_function :wgpuShaderModuleGetCompilationInfo,
|
|
123
|
-
[:pointer, CompilationInfoCallbackInfo.by_value],
|
|
126
|
+
[:pointer, CompilationInfoCallbackInfo.by_value], Future.by_value
|
|
124
127
|
|
|
125
128
|
attach_function :wgpuCommandEncoderRelease,
|
|
126
129
|
[:pointer], :void
|
|
@@ -363,7 +366,7 @@ module WGPU
|
|
|
363
366
|
[:pointer, ErrorFilter], :void
|
|
364
367
|
|
|
365
368
|
attach_function :wgpuDevicePopErrorScope,
|
|
366
|
-
[:pointer, PopErrorScopeCallbackInfo.by_value],
|
|
369
|
+
[:pointer, PopErrorScopeCallbackInfo.by_value], Future.by_value
|
|
367
370
|
|
|
368
371
|
attach_function :wgpuComputePipelineGetBindGroupLayout,
|
|
369
372
|
[:pointer, :uint32], :pointer
|
|
@@ -415,5 +418,11 @@ module WGPU
|
|
|
415
418
|
|
|
416
419
|
attach_function :wgpuRenderBundleEncoderInsertDebugMarker,
|
|
417
420
|
[:pointer, StringView.by_value], :void
|
|
421
|
+
|
|
422
|
+
attach_optional_function :wgpuSetLogCallback,
|
|
423
|
+
[:log_callback, :pointer], :void
|
|
424
|
+
|
|
425
|
+
attach_optional_function :wgpuSetLogLevel,
|
|
426
|
+
[LogLevel], :void
|
|
418
427
|
end
|
|
419
428
|
end
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "net/http"
|
|
6
|
+
require "uri"
|
|
7
|
+
|
|
8
|
+
require_relative "distribution"
|
|
9
|
+
|
|
10
|
+
module WGPU
|
|
11
|
+
module Native
|
|
12
|
+
class InstallError < StandardError; end
|
|
13
|
+
|
|
14
|
+
class Installer
|
|
15
|
+
attr_reader :platform
|
|
16
|
+
|
|
17
|
+
def initialize(platform: RUBY_PLATFORM, env: ENV, home: Dir.home,
|
|
18
|
+
host_os: RbConfig::CONFIG["host_os"], output: $stdout)
|
|
19
|
+
@platform = platform
|
|
20
|
+
@env = env
|
|
21
|
+
@home = home
|
|
22
|
+
@host_os = host_os
|
|
23
|
+
@output = output
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def install
|
|
27
|
+
return custom_library_path if custom_library_path
|
|
28
|
+
|
|
29
|
+
artifact = Distribution.artifact_for(platform)
|
|
30
|
+
cached_path = existing_library_path(artifact)
|
|
31
|
+
if cached_path
|
|
32
|
+
@output.puts "wgpu-native already cached at #{cached_path}"
|
|
33
|
+
return cached_path
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
install_artifact(artifact)
|
|
37
|
+
rescue LoadError, InstallError => error
|
|
38
|
+
raise InstallError, "#{error.message}\n\n#{recovery_instructions}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def clean_path
|
|
42
|
+
Distribution.primary_cache_dir(env: @env, home: @home, host_os: @host_os)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def custom_library_path
|
|
48
|
+
path = @env["WGPU_LIB_PATH"]
|
|
49
|
+
return if path.nil? || path.empty?
|
|
50
|
+
raise InstallError, "WGPU_LIB_PATH points to a non-existent file: #{path}" unless File.file?(path)
|
|
51
|
+
|
|
52
|
+
File.expand_path(path)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def existing_library_path(artifact)
|
|
56
|
+
Distribution.cache_directories(env: @env, home: @home, host_os: @host_os).each do |directory|
|
|
57
|
+
path = File.join(directory, "lib", artifact.fetch(:library))
|
|
58
|
+
return path if File.file?(path)
|
|
59
|
+
end
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def install_artifact(artifact)
|
|
64
|
+
cache_dir = clean_path
|
|
65
|
+
archive_path = File.join(cache_dir, artifact.fetch(:archive))
|
|
66
|
+
library_path = File.join(cache_dir, "lib", artifact.fetch(:library))
|
|
67
|
+
FileUtils.mkdir_p(cache_dir)
|
|
68
|
+
|
|
69
|
+
@output.puts "Downloading wgpu-native #{Distribution::VERSION} from GitHub..."
|
|
70
|
+
@output.puts " URL: #{Distribution.release_url(artifact)}"
|
|
71
|
+
download_file(Distribution.release_url(artifact), archive_path)
|
|
72
|
+
verify_checksum!(archive_path, artifact.fetch(:sha256))
|
|
73
|
+
|
|
74
|
+
@output.puts "Extracting to #{cache_dir}..."
|
|
75
|
+
extract_zip(archive_path, cache_dir)
|
|
76
|
+
raise InstallError, "Archive did not contain lib/#{artifact.fetch(:library)}" unless File.file?(library_path)
|
|
77
|
+
|
|
78
|
+
@output.puts "wgpu-native installed successfully!"
|
|
79
|
+
library_path
|
|
80
|
+
ensure
|
|
81
|
+
FileUtils.rm_f(archive_path) if archive_path
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def verify_checksum!(path, expected)
|
|
85
|
+
actual = Digest::SHA256.file(path).hexdigest
|
|
86
|
+
return if actual == expected
|
|
87
|
+
|
|
88
|
+
FileUtils.rm_f(path)
|
|
89
|
+
raise InstallError, "SHA-256 mismatch for #{File.basename(path)} (expected #{expected}, got #{actual})"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def download_file(url, destination)
|
|
93
|
+
return if curl_available? && download_with_curl(url, destination)
|
|
94
|
+
return if download_with_ruby(url, destination)
|
|
95
|
+
|
|
96
|
+
raise InstallError, "Download failed: #{url}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def curl_available?
|
|
100
|
+
system("curl", "--version", out: File::NULL, err: File::NULL)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def download_with_curl(url, destination)
|
|
104
|
+
system("curl", "-fsSL", "-o", destination, url)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def download_with_ruby(url, destination, redirects = 5)
|
|
108
|
+
raise InstallError, "Too many redirects while downloading #{url}" if redirects.zero?
|
|
109
|
+
|
|
110
|
+
uri = URI.parse(url)
|
|
111
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
112
|
+
http.use_ssl = uri.scheme == "https"
|
|
113
|
+
http.open_timeout = 10
|
|
114
|
+
http.read_timeout = 120
|
|
115
|
+
|
|
116
|
+
http.request(Net::HTTP::Get.new(uri.request_uri)) do |response|
|
|
117
|
+
case response
|
|
118
|
+
when Net::HTTPRedirection
|
|
119
|
+
location = response["location"]
|
|
120
|
+
raise InstallError, "Redirect response did not include a location" unless location
|
|
121
|
+
|
|
122
|
+
location = URI.join(url, location).to_s
|
|
123
|
+
return download_with_ruby(location, destination, redirects - 1)
|
|
124
|
+
when Net::HTTPSuccess
|
|
125
|
+
File.open(destination, "wb") do |file|
|
|
126
|
+
response.read_body { |chunk| file.write(chunk) }
|
|
127
|
+
end
|
|
128
|
+
return true
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
false
|
|
133
|
+
rescue SystemCallError, SocketError, URI::InvalidURIError => error
|
|
134
|
+
@output.puts "Ruby download failed: #{error.message}"
|
|
135
|
+
false
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def extract_zip(archive_path, destination)
|
|
139
|
+
return if extract_with_rubyzip(archive_path, destination)
|
|
140
|
+
return if windows? && extract_with_powershell(archive_path, destination)
|
|
141
|
+
return if extract_with_unzip(archive_path, destination)
|
|
142
|
+
|
|
143
|
+
raise InstallError, "Failed to extract zip; install the rubyzip gem or a supported system extractor"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def extract_with_rubyzip(archive_path, destination)
|
|
147
|
+
require "zip"
|
|
148
|
+
destination_root = "#{File.expand_path(destination)}#{File::SEPARATOR}"
|
|
149
|
+
|
|
150
|
+
Zip::File.open(archive_path) do |zip_file|
|
|
151
|
+
zip_file.each do |entry|
|
|
152
|
+
target = File.expand_path(entry.name, destination)
|
|
153
|
+
unless target.start_with?(destination_root)
|
|
154
|
+
raise InstallError, "Archive entry escapes destination: #{entry.name}"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
FileUtils.mkdir_p(entry.directory? ? target : File.dirname(target))
|
|
158
|
+
entry.extract(target) { true } unless entry.directory?
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
true
|
|
162
|
+
rescue LoadError
|
|
163
|
+
false
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def extract_with_powershell(archive_path, destination)
|
|
167
|
+
system(
|
|
168
|
+
"powershell",
|
|
169
|
+
"-NoProfile",
|
|
170
|
+
"-Command",
|
|
171
|
+
"Expand-Archive -Force -LiteralPath '#{archive_path}' -DestinationPath '#{destination}'"
|
|
172
|
+
)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def extract_with_unzip(archive_path, destination)
|
|
176
|
+
system("unzip", "-o", "-q", archive_path, "-d", destination)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def windows?
|
|
180
|
+
/mingw|mswin/.match?(platform)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def recovery_instructions
|
|
184
|
+
<<~INSTRUCTIONS.chomp
|
|
185
|
+
Download the matching #{Distribution::VERSION} artifact manually and set:
|
|
186
|
+
WGPU_LIB_PATH=/absolute/path/to/the/wgpu-native/shared-library
|
|
187
|
+
See docs/installation.md for platform details.
|
|
188
|
+
INSTRUCTIONS
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
data/lib/wgpu/native/loader.rb
CHANGED
|
@@ -1,53 +1,71 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "ffi"
|
|
4
|
-
|
|
4
|
+
require_relative "distribution"
|
|
5
5
|
|
|
6
6
|
module WGPU
|
|
7
7
|
module Native
|
|
8
|
-
|
|
8
|
+
module OptionalFunctions
|
|
9
|
+
def attach_optional_function(name, arguments, result)
|
|
10
|
+
attach_function(name, arguments, result)
|
|
11
|
+
optional_functions[name] = true
|
|
12
|
+
rescue FFI::NotFoundError
|
|
13
|
+
optional_functions[name] = false
|
|
14
|
+
define_singleton_method(name) do |*|
|
|
15
|
+
raise WGPU::Error,
|
|
16
|
+
"Optional wgpu-native function #{name} is unavailable in the loaded library " \
|
|
17
|
+
"(expected #{Distribution::VERSION})"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def optional_function_available?(name)
|
|
22
|
+
optional_functions.fetch(name, false)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def optional_capabilities
|
|
26
|
+
optional_functions.dup.freeze
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
9
30
|
|
|
10
|
-
|
|
31
|
+
def optional_functions
|
|
32
|
+
@optional_functions ||= {}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
extend FFI::Library
|
|
37
|
+
extend OptionalFunctions
|
|
11
38
|
|
|
12
39
|
class << self
|
|
13
40
|
def library_path
|
|
14
|
-
if ENV["WGPU_LIB_PATH"]
|
|
15
|
-
path = ENV["WGPU_LIB_PATH"]
|
|
41
|
+
if ENV["WGPU_LIB_PATH"] && !ENV["WGPU_LIB_PATH"].empty?
|
|
42
|
+
path = File.expand_path(ENV["WGPU_LIB_PATH"])
|
|
16
43
|
raise LoadError, "WGPU_LIB_PATH points to non-existent file: #{path}" unless File.exist?(path)
|
|
17
44
|
return path
|
|
18
45
|
end
|
|
19
46
|
|
|
20
|
-
cached_path = File.
|
|
21
|
-
return cached_path if
|
|
47
|
+
cached_path = Distribution.library_paths.find { |path| File.file?(path) }
|
|
48
|
+
return cached_path if cached_path
|
|
22
49
|
|
|
23
50
|
raise LoadError, <<~MSG
|
|
24
51
|
wgpu-native library not found.
|
|
25
|
-
|
|
52
|
+
Searched:
|
|
53
|
+
#{Distribution.library_paths.join("\n ")}
|
|
26
54
|
|
|
27
55
|
Try reinstalling the gem:
|
|
28
56
|
gem install wgpu
|
|
29
57
|
|
|
30
58
|
Or set WGPU_LIB_PATH environment variable to your custom wgpu-native build.
|
|
59
|
+
See docs/installation.md for manual installation instructions.
|
|
31
60
|
MSG
|
|
32
61
|
end
|
|
33
62
|
|
|
34
63
|
def cache_dir
|
|
35
|
-
|
|
64
|
+
Distribution.primary_cache_dir
|
|
36
65
|
end
|
|
37
66
|
|
|
38
67
|
def library_name
|
|
39
|
-
|
|
40
|
-
when /linux/ then "libwgpu_native.so"
|
|
41
|
-
when /darwin/ then "libwgpu_native.dylib"
|
|
42
|
-
when /mingw|mswin/ then "wgpu_native.dll"
|
|
43
|
-
else raise LoadError, "Unsupported OS: #{host_os}"
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
private
|
|
48
|
-
|
|
49
|
-
def host_os
|
|
50
|
-
RbConfig::CONFIG["host_os"]
|
|
68
|
+
Distribution.artifact_for.fetch(:library)
|
|
51
69
|
end
|
|
52
70
|
end
|
|
53
71
|
|
|
@@ -59,3 +77,4 @@ require_relative "enums"
|
|
|
59
77
|
require_relative "structs"
|
|
60
78
|
require_relative "callbacks"
|
|
61
79
|
require_relative "functions"
|
|
80
|
+
require_relative "capabilities"
|
data/lib/wgpu/native/structs.rb
CHANGED
|
@@ -17,6 +17,15 @@ module WGPU
|
|
|
17
17
|
:s_type, SType
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
class Future < FFI::Struct
|
|
21
|
+
layout :id, :uint64
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class FutureWaitInfo < FFI::Struct
|
|
25
|
+
layout :future, Future.by_value,
|
|
26
|
+
:completed, :uint32
|
|
27
|
+
end
|
|
28
|
+
|
|
20
29
|
class InstanceCapabilities < FFI::Struct
|
|
21
30
|
layout :next_in_chain, :pointer,
|
|
22
31
|
:timed_wait_any_enable, :uint32,
|
|
@@ -58,13 +67,15 @@ module WGPU
|
|
|
58
67
|
layout :next_in_chain, :pointer,
|
|
59
68
|
:mode, :uint32,
|
|
60
69
|
:callback, :pointer,
|
|
61
|
-
:
|
|
70
|
+
:userdata1, :pointer,
|
|
71
|
+
:userdata2, :pointer
|
|
62
72
|
end
|
|
63
73
|
|
|
64
74
|
class UncapturedErrorCallbackInfo < FFI::Struct
|
|
65
75
|
layout :next_in_chain, :pointer,
|
|
66
76
|
:callback, :pointer,
|
|
67
|
-
:
|
|
77
|
+
:userdata1, :pointer,
|
|
78
|
+
:userdata2, :pointer
|
|
68
79
|
end
|
|
69
80
|
|
|
70
81
|
class PopErrorScopeCallbackInfo < FFI::Struct
|
|
@@ -355,21 +366,24 @@ module WGPU
|
|
|
355
366
|
layout :next_in_chain, :pointer,
|
|
356
367
|
:mode, :uint32,
|
|
357
368
|
:callback, :pointer,
|
|
358
|
-
:
|
|
369
|
+
:userdata1, :pointer,
|
|
370
|
+
:userdata2, :pointer
|
|
359
371
|
end
|
|
360
372
|
|
|
361
373
|
class RequestDeviceCallbackInfo < FFI::Struct
|
|
362
374
|
layout :next_in_chain, :pointer,
|
|
363
375
|
:mode, :uint32,
|
|
364
376
|
:callback, :pointer,
|
|
365
|
-
:
|
|
377
|
+
:userdata1, :pointer,
|
|
378
|
+
:userdata2, :pointer
|
|
366
379
|
end
|
|
367
380
|
|
|
368
381
|
class BufferMapCallbackInfo < FFI::Struct
|
|
369
382
|
layout :next_in_chain, :pointer,
|
|
370
383
|
:mode, :uint32,
|
|
371
384
|
:callback, :pointer,
|
|
372
|
-
:
|
|
385
|
+
:userdata1, :pointer,
|
|
386
|
+
:userdata2, :pointer
|
|
373
387
|
end
|
|
374
388
|
|
|
375
389
|
class TextureViewDescriptor < FFI::Struct
|