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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -0
  3. data/README.md +44 -5
  4. data/docs/README.md +22 -0
  5. data/docs/api_coverage.md +140 -0
  6. data/docs/async.md +41 -0
  7. data/docs/bind_groups.md +25 -0
  8. data/docs/buffer_data.md +37 -0
  9. data/docs/command_encoding.md +49 -0
  10. data/docs/errors.md +40 -0
  11. data/docs/getting_started_compute.md +62 -0
  12. data/docs/getting_started_rendering.md +62 -0
  13. data/docs/installation.md +94 -0
  14. data/docs/pipeline_descriptors.md +43 -0
  15. data/docs/releasing.md +32 -0
  16. data/docs/resource_lifetime.md +108 -0
  17. data/docs/shaders.md +32 -0
  18. data/docs/texture_readback.md +46 -0
  19. data/docs/troubleshooting.md +53 -0
  20. data/docs/upgrading_wgpu_native.md +37 -0
  21. data/ext/wgpu/extconf.rb +10 -142
  22. data/lib/wgpu/async_task.rb +19 -0
  23. data/lib/wgpu/commands/command_buffer.rb +25 -1
  24. data/lib/wgpu/commands/command_encoder.rb +123 -9
  25. data/lib/wgpu/commands/compute_pass.rb +53 -0
  26. data/lib/wgpu/commands/render_bundle.rb +9 -1
  27. data/lib/wgpu/commands/render_bundle_encoder.rb +65 -4
  28. data/lib/wgpu/commands/render_pass.rb +136 -8
  29. data/lib/wgpu/core/adapter.rb +123 -19
  30. data/lib/wgpu/core/async_waiter.rb +47 -4
  31. data/lib/wgpu/core/canvas_context.rb +32 -2
  32. data/lib/wgpu/core/device.rb +399 -53
  33. data/lib/wgpu/core/instance.rb +28 -4
  34. data/lib/wgpu/core/queue.rb +197 -51
  35. data/lib/wgpu/core/surface.rb +64 -17
  36. data/lib/wgpu/data_types.rb +83 -0
  37. data/lib/wgpu/descriptor_helpers.rb +104 -0
  38. data/lib/wgpu/error.rb +70 -0
  39. data/lib/wgpu/logging.rb +63 -0
  40. data/lib/wgpu/native/abi_verifier.rb +143 -0
  41. data/lib/wgpu/native/callbacks.rb +10 -1
  42. data/lib/wgpu/native/capabilities.rb +32 -2
  43. data/lib/wgpu/native/distribution.rb +176 -0
  44. data/lib/wgpu/native/enum_helper.rb +80 -0
  45. data/lib/wgpu/native/enums.rb +68 -8
  46. data/lib/wgpu/native/fixtures/webgpu-v27.0.4.0-enums.h +848 -0
  47. data/lib/wgpu/native/functions.rb +21 -10
  48. data/lib/wgpu/native/installer.rb +223 -0
  49. data/lib/wgpu/native/loader.rb +61 -21
  50. data/lib/wgpu/native/structs.rb +18 -1
  51. data/lib/wgpu/native_resource.rb +342 -0
  52. data/lib/wgpu/pipeline/bind_group.rb +21 -0
  53. data/lib/wgpu/pipeline/bind_group_layout.rb +108 -41
  54. data/lib/wgpu/pipeline/compute_pipeline.rb +40 -50
  55. data/lib/wgpu/pipeline/pipeline_layout.rb +8 -0
  56. data/lib/wgpu/pipeline/render_pipeline.rb +207 -110
  57. data/lib/wgpu/pipeline/shader_module.rb +95 -28
  58. data/lib/wgpu/resources/buffer.rb +387 -85
  59. data/lib/wgpu/resources/query_set.rb +26 -12
  60. data/lib/wgpu/resources/sampler.rb +43 -20
  61. data/lib/wgpu/resources/texture.rb +89 -48
  62. data/lib/wgpu/resources/texture_view.rb +35 -7
  63. data/lib/wgpu/texture_format.rb +96 -0
  64. data/lib/wgpu/version.rb +1 -1
  65. data/lib/wgpu/window.rb +34 -1
  66. data/lib/wgpu.rb +32 -0
  67. data/sig/wgpu.rbs +460 -0
  68. metadata +33 -16
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+
5
+ module WGPU
6
+ module Native
7
+ module Distribution
8
+ VERSION = "v27.0.4.0"
9
+ RELEASE_BASE_URL = "https://github.com/gfx-rs/wgpu-native/releases/download/#{VERSION}"
10
+ VERSION_COMPONENTS = VERSION.delete_prefix("v").split(".").map { |part| Integer(part, 10) }.freeze
11
+ unless VERSION_COMPONENTS.length == 4 && VERSION_COMPONENTS.all? { |part| part.between?(0, 255) }
12
+ raise "wgpu-native VERSION must have four byte-sized components: #{VERSION}"
13
+ end
14
+ # wgpuGetVersion packs vMAJOR.MINOR.PATCH.BUILD into four big-endian bytes.
15
+ ENCODED_VERSION = VERSION_COMPONENTS.reduce(0) { |encoded, part| (encoded << 8) | part }
16
+ UNIMPLEMENTED_CAPABILITIES = {
17
+ compilation_info: [VERSION].freeze,
18
+ buffer_map_state: [VERSION].freeze,
19
+ pipeline_async: [VERSION].freeze
20
+ }.freeze
21
+
22
+ ARTIFACTS = [
23
+ {
24
+ pattern: /x86_64-linux/,
25
+ archive: "wgpu-linux-x86_64-release.zip",
26
+ library: "libwgpu_native.so",
27
+ sha256: "271481ef76fbf3ea09631a6079e9493636ecf813cd9c92306c44a1a452991ba1"
28
+ },
29
+ {
30
+ pattern: /aarch64-linux/,
31
+ archive: "wgpu-linux-aarch64-release.zip",
32
+ library: "libwgpu_native.so",
33
+ sha256: "a2f22248200997b69373273b10d50a58164f6ed840877289f3e46bff317b134e"
34
+ },
35
+ {
36
+ pattern: /x86_64-darwin/,
37
+ archive: "wgpu-macos-x86_64-release.zip",
38
+ library: "libwgpu_native.dylib",
39
+ sha256: "660fe9be59b555ec1d7c839e5cf8b6c71762938af61ab444a7a58dd87970dba2"
40
+ },
41
+ {
42
+ pattern: /arm64-darwin/,
43
+ archive: "wgpu-macos-aarch64-release.zip",
44
+ library: "libwgpu_native.dylib",
45
+ sha256: "15367c26fdbe6892db35007d39f3883593384e777360b70e6bd704cb5dedde53"
46
+ },
47
+ {
48
+ pattern: /(?:x64|x86_64)-(?:mingw|mswin)/,
49
+ archive: "wgpu-windows-x86_64-msvc-release.zip",
50
+ library: "wgpu_native.dll",
51
+ sha256: "f14ca334b4d253881bde2605bd147f332178d705f56fbd74f81458797c77fce1"
52
+ }
53
+ ].map(&:freeze).freeze
54
+
55
+ module_function
56
+
57
+ # Selects the native release artifact for a Ruby platform.
58
+ # @param platform [String] Ruby platform identifier
59
+ # @return [Hash] artifact metadata
60
+ # @raise [LoadError] if the platform is unsupported
61
+ def artifact_for(platform = RUBY_PLATFORM)
62
+ raise LoadError, unsupported_platform_message(platform) if platform.include?("musl")
63
+
64
+ artifact = ARTIFACTS.find { |candidate| candidate[:pattern].match?(platform) }
65
+ return artifact if artifact
66
+
67
+ raise LoadError, unsupported_platform_message(platform)
68
+ end
69
+
70
+ # Returns the preferred versioned native-library cache directory.
71
+ #
72
+ # @param env [Hash] environment used for cache overrides
73
+ # @param home [String] user home directory
74
+ # @param host_os [String] host operating-system identifier
75
+ # @return [String] absolute cache directory
76
+ def primary_cache_dir(env: ENV, home: Dir.home, host_os: RbConfig::CONFIG["host_os"])
77
+ override = present_value(env["WGPU_CACHE_DIR"])
78
+ return File.join(File.expand_path(override), VERSION) if override
79
+
80
+ xdg_cache = present_value(env["XDG_CACHE_HOME"])
81
+ return File.join(File.expand_path(xdg_cache), "wgpu-ruby", VERSION) if xdg_cache
82
+
83
+ File.join(default_cache_base(env:, home:, host_os:), "wgpu-ruby", VERSION)
84
+ end
85
+
86
+ # Returns the legacy versioned cache directory.
87
+ #
88
+ # @param home [String] user home directory
89
+ # @return [String] absolute legacy cache directory
90
+ def legacy_cache_dir(home: Dir.home)
91
+ File.join(File.expand_path(home), ".cache", "wgpu-ruby", VERSION)
92
+ end
93
+
94
+ # Returns cache directories in lookup order.
95
+ #
96
+ # @param env [Hash] environment used for cache overrides
97
+ # @param home [String] user home directory
98
+ # @param host_os [String] host operating-system identifier
99
+ # @return [Array<String>] unique cache directories
100
+ def cache_directories(env: ENV, home: Dir.home, host_os: RbConfig::CONFIG["host_os"])
101
+ [primary_cache_dir(env:, home:, host_os:), legacy_cache_dir(home:)].uniq
102
+ end
103
+
104
+ # Returns candidate cached library paths for a platform.
105
+ #
106
+ # @param platform [String] Ruby platform identifier
107
+ # @param env [Hash] environment used for cache overrides
108
+ # @param home [String] user home directory
109
+ # @param host_os [String] host operating-system identifier
110
+ # @return [Array<String>] candidate shared-library paths
111
+ # @raise [LoadError] if the platform is unsupported
112
+ def library_paths(platform: RUBY_PLATFORM, env: ENV, home: Dir.home,
113
+ host_os: RbConfig::CONFIG["host_os"])
114
+ library = artifact_for(platform)[:library]
115
+ cache_directories(env:, home:, host_os:).map { |directory| File.join(directory, "lib", library) }
116
+ end
117
+
118
+ # Builds the download URL for an artifact entry.
119
+ #
120
+ # @param artifact [Hash] entry from {ARTIFACTS}
121
+ # @return [String] release archive URL
122
+ def release_url(artifact)
123
+ "#{RELEASE_BASE_URL}/#{artifact.fetch(:archive)}"
124
+ end
125
+
126
+ # Decodes the packed native version into a release tag.
127
+ #
128
+ # @param encoded_version [Integer] four-byte packed version
129
+ # @return [String] version in +vMAJOR.MINOR.PATCH.BUILD+ form
130
+ def version_string(encoded_version)
131
+ components = [24, 16, 8, 0].map { |shift| (encoded_version >> shift) & 0xFF }
132
+ "v#{components.join(".")}"
133
+ end
134
+
135
+ # Reports whether a native capability is implemented by the pinned release.
136
+ # @param name [Symbol] capability name
137
+ # @return [Boolean]
138
+ def capability_implemented?(name)
139
+ !UNIMPLEMENTED_CAPABILITIES.fetch(name, []).include?(VERSION)
140
+ end
141
+
142
+ # Builds an actionable unsupported-platform message.
143
+ #
144
+ # @param platform [String] Ruby platform identifier
145
+ # @return [String] diagnostic message
146
+ def unsupported_platform_message(platform)
147
+ supported = ARTIFACTS.map { |artifact| artifact[:pattern].inspect }.join(", ")
148
+ <<~MESSAGE.chomp
149
+ Unsupported platform: #{platform}
150
+ Supported 64-bit platforms: #{supported}
151
+ Build wgpu-native for this host and set WGPU_LIB_PATH to the shared library.
152
+ MESSAGE
153
+ end
154
+
155
+ def default_cache_base(env:, home:, host_os:)
156
+ case host_os
157
+ when /darwin/
158
+ File.join(File.expand_path(home), "Library", "Caches")
159
+ when /mingw|mswin/
160
+ local_app_data = present_value(env["LOCALAPPDATA"])
161
+ local_app_data || File.join(File.expand_path(home), "AppData", "Local")
162
+ else
163
+ File.join(File.expand_path(home), ".cache")
164
+ end
165
+ end
166
+ private_class_method :default_cache_base
167
+
168
+ def present_value(value)
169
+ value unless value.nil? || value.empty?
170
+ end
171
+ private_class_method :present_value
172
+ end
173
+
174
+ WGPU_VERSION = Distribution::VERSION
175
+ end
176
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WGPU
4
+ module Native
5
+ module EnumHelper
6
+ module_function
7
+
8
+ # Converts a symbolic enum member to its integer value.
9
+ # @param enum [FFI::Enum, Hash] enum mapping
10
+ # @param value [Symbol, Integer] member or native value
11
+ # @param name [String] name used in validation errors
12
+ # @return [Integer]
13
+ # @raise [ArgumentError] if the value is invalid
14
+ def coerce(enum, value, name: "enum")
15
+ return value if value.is_a?(Integer)
16
+ raise ArgumentError, "#{name} must be a Symbol or Integer, got #{value.class}" unless value.is_a?(Symbol)
17
+
18
+ mapping = mapping_for(enum)
19
+ result = mapping[value]
20
+ return result unless result.nil?
21
+
22
+ raise ArgumentError, unknown_value_message(name, value, mapping.keys)
23
+ end
24
+
25
+ # Converts symbolic flag names to their combined integer bitset.
26
+ #
27
+ # @param enum [FFI::Enum, Hash] flag mapping
28
+ # @param value [Symbol, Integer, Array<Symbol>] flags to convert
29
+ # @param name [String] name used in validation errors
30
+ # @return [Integer] combined bitset
31
+ # @raise [ArgumentError] if a flag is unknown or has an invalid type
32
+ def coerce_flags(enum, value, name: "flags")
33
+ return value if value.is_a?(Integer)
34
+
35
+ values = value.is_a?(Array) ? value : [value]
36
+ unless values.all? { |item| item.is_a?(Symbol) }
37
+ raise ArgumentError, "#{name} must be a Symbol, Integer, or Array of Symbols"
38
+ end
39
+
40
+ values.reduce(0) { |flags, item| flags | coerce(enum, item, name:) }
41
+ end
42
+
43
+ # Expands a bitset into its independent symbolic flags.
44
+ # @param enum [FFI::Enum, Hash] flag mapping
45
+ # @param value [Integer] combined bitset
46
+ # @return [Array<Symbol>]
47
+ def decompose_flags(enum, value)
48
+ raise ArgumentError, "flag value must be an Integer" unless value.is_a?(Integer)
49
+
50
+ mapping = mapping_for(enum)
51
+ return [:none] if value.zero? && mapping.key?(:none)
52
+
53
+ mapping.filter_map do |symbol, bit|
54
+ symbol if bit.positive? && power_of_two?(bit) && (value & bit) == bit
55
+ end
56
+ end
57
+
58
+ def mapping_for(enum)
59
+ mapping = enum.respond_to?(:to_h) ? enum.to_h : enum
60
+ unless mapping.respond_to?(:key?) && mapping.respond_to?(:keys)
61
+ raise ArgumentError, "enum must be an FFI::Enum or Hash"
62
+ end
63
+
64
+ mapping
65
+ end
66
+ private_class_method :mapping_for
67
+
68
+ def unknown_value_message(name, value, candidates)
69
+ formatted = candidates.grep(Symbol).sort.map(&:inspect).join(", ")
70
+ "Unknown #{name} #{value.inspect}. Valid values: #{formatted}"
71
+ end
72
+ private_class_method :unknown_value_message
73
+
74
+ def power_of_two?(value)
75
+ (value & (value - 1)).zero?
76
+ end
77
+ private_class_method :power_of_two?
78
+ end
79
+ end
80
+ end
@@ -61,6 +61,21 @@ module WGPU
61
61
  :unknown, 0x00000004
62
62
  )
63
63
 
64
+ CreatePipelineAsyncStatus = enum(
65
+ :success, 0x00000001,
66
+ :instance_dropped, 0x00000002,
67
+ :validation_error, 0x00000003,
68
+ :internal_error, 0x00000004,
69
+ :unknown, 0x00000005
70
+ )
71
+
72
+ DeviceLostReason = enum(
73
+ :unknown, 0x00000001,
74
+ :destroyed, 0x00000002,
75
+ :instance_dropped, 0x00000003,
76
+ :failed_creation, 0x00000004
77
+ )
78
+
64
79
  BufferMapState = enum(
65
80
  :unmapped, 0x00000001,
66
81
  :pending, 0x00000002,
@@ -283,7 +298,9 @@ module WGPU
283
298
  :sint32, 0x00000024,
284
299
  :sint32x2, 0x00000025,
285
300
  :sint32x3, 0x00000026,
286
- :sint32x4, 0x00000027
301
+ :sint32x4, 0x00000027,
302
+ :unorm10_10_10_2, 0x00000028,
303
+ :unorm8x4_bgra, 0x00000029
287
304
  )
288
305
 
289
306
  IndexFormat = enum(
@@ -366,11 +383,11 @@ module WGPU
366
383
  :undefined, 0x00000000,
367
384
  :never, 0x00000001,
368
385
  :less, 0x00000002,
369
- :less_equal, 0x00000003,
370
- :greater, 0x00000004,
371
- :greater_equal, 0x00000005,
372
- :equal, 0x00000006,
373
- :not_equal, 0x00000007,
386
+ :equal, 0x00000003,
387
+ :less_equal, 0x00000004,
388
+ :greater, 0x00000005,
389
+ :not_equal, 0x00000006,
390
+ :greater_equal, 0x00000007,
374
391
  :always, 0x00000008
375
392
  )
376
393
 
@@ -467,7 +484,9 @@ module WGPU
467
484
  :timeout, 0x00000003,
468
485
  :outdated, 0x00000004,
469
486
  :lost, 0x00000005,
470
- :error, 0x00000006
487
+ :out_of_memory, 0x00000006,
488
+ :device_lost, 0x00000007,
489
+ :error, 0x00000008
471
490
  )
472
491
 
473
492
  QueryType = enum(
@@ -523,6 +542,15 @@ module WGPU
523
542
  :info, 0x00000003
524
543
  )
525
544
 
545
+ LogLevel = enum(
546
+ :off, 0x00000000,
547
+ :error, 0x00000001,
548
+ :warn, 0x00000002,
549
+ :info, 0x00000003,
550
+ :debug, 0x00000004,
551
+ :trace, 0x00000005
552
+ )
553
+
526
554
  FeatureName = enum(
527
555
  :undefined, 0x00000000,
528
556
  :depth_clip_control, 0x00000001,
@@ -540,7 +568,39 @@ module WGPU
540
568
  :float32_filterable, 0x0000000D,
541
569
  :float32_blendable, 0x0000000E,
542
570
  :clip_distances, 0x0000000F,
543
- :dual_source_blending, 0x00000010
571
+ :dual_source_blending, 0x00000010,
572
+ # wgpu-native extensions from wgpu.h.
573
+ :push_constants, 0x00030001,
574
+ :texture_adapter_specific_format_features, 0x00030002,
575
+ :multi_draw_indirect_count, 0x00030004,
576
+ :vertex_writable_storage, 0x00030005,
577
+ :texture_binding_array, 0x00030006,
578
+ :sampled_texture_and_storage_buffer_array_non_uniform_indexing, 0x00030007,
579
+ :pipeline_statistics_query, 0x00030008,
580
+ :storage_resource_binding_array, 0x00030009,
581
+ :partially_bound_binding_array, 0x0003000A,
582
+ :texture_format_16bit_norm, 0x0003000B,
583
+ :texture_compression_astc_hdr, 0x0003000C,
584
+ :mappable_primary_buffers, 0x0003000E,
585
+ :buffer_binding_array, 0x0003000F,
586
+ :uniform_buffer_and_storage_texture_array_non_uniform_indexing, 0x00030010,
587
+ :polygon_mode_line, 0x00030013,
588
+ :polygon_mode_point, 0x00030014,
589
+ :conservative_rasterization, 0x00030015,
590
+ :spirv_shader_passthrough, 0x00030017,
591
+ :vertex_attribute_64bit, 0x00030019,
592
+ :texture_format_nv12, 0x0003001A,
593
+ :ray_query, 0x0003001C,
594
+ :shader_f64, 0x0003001D,
595
+ :shader_i16, 0x0003001E,
596
+ :shader_primitive_index, 0x0003001F,
597
+ :shader_early_depth_test, 0x00030020,
598
+ :subgroup, 0x00030021,
599
+ :subgroup_vertex, 0x00030022,
600
+ :subgroup_barrier, 0x00030023,
601
+ :timestamp_query_inside_encoders, 0x00030024,
602
+ :timestamp_query_inside_passes, 0x00030025,
603
+ :shader_int64, 0x00030026
544
604
  )
545
605
  end
546
606
  end