wgpu 1.1.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/README.md +26 -3
  4. data/docs/README.md +22 -0
  5. data/docs/api_coverage.md +132 -0
  6. data/docs/async.md +31 -0
  7. data/docs/bind_groups.md +25 -0
  8. data/docs/buffer_data.md +37 -0
  9. data/docs/command_encoding.md +24 -0
  10. data/docs/errors.md +40 -0
  11. data/docs/getting_started_compute.md +61 -0
  12. data/docs/getting_started_rendering.md +62 -0
  13. data/docs/installation.md +94 -0
  14. data/docs/pipeline_descriptors.md +38 -0
  15. data/docs/releasing.md +22 -0
  16. data/docs/resource_lifetime.md +94 -0
  17. data/docs/shaders.md +32 -0
  18. data/docs/texture_readback.md +19 -0
  19. data/docs/troubleshooting.md +48 -0
  20. data/docs/upgrading_wgpu_native.md +26 -0
  21. data/ext/wgpu/extconf.rb +10 -142
  22. data/lib/wgpu/commands/command_buffer.rb +11 -0
  23. data/lib/wgpu/commands/command_encoder.rb +65 -8
  24. data/lib/wgpu/commands/compute_pass.rb +10 -0
  25. data/lib/wgpu/commands/render_bundle_encoder.rb +10 -3
  26. data/lib/wgpu/commands/render_pass.rb +34 -8
  27. data/lib/wgpu/core/adapter.rb +36 -11
  28. data/lib/wgpu/core/async_waiter.rb +32 -4
  29. data/lib/wgpu/core/canvas_context.rb +0 -2
  30. data/lib/wgpu/core/device.rb +138 -42
  31. data/lib/wgpu/core/instance.rb +8 -4
  32. data/lib/wgpu/core/queue.rb +80 -49
  33. data/lib/wgpu/core/surface.rb +16 -17
  34. data/lib/wgpu/data_types.rb +67 -0
  35. data/lib/wgpu/descriptor_helpers.rb +39 -0
  36. data/lib/wgpu/error.rb +55 -0
  37. data/lib/wgpu/logging.rb +63 -0
  38. data/lib/wgpu/native/abi_verifier.rb +109 -0
  39. data/lib/wgpu/native/callbacks.rb +4 -1
  40. data/lib/wgpu/native/capabilities.rb +18 -2
  41. data/lib/wgpu/native/distribution.rb +113 -0
  42. data/lib/wgpu/native/enum_helper.rb +63 -0
  43. data/lib/wgpu/native/enums.rb +60 -8
  44. data/lib/wgpu/native/functions.rb +10 -10
  45. data/lib/wgpu/native/installer.rb +192 -0
  46. data/lib/wgpu/native/loader.rb +39 -21
  47. data/lib/wgpu/native_resource.rb +171 -0
  48. data/lib/wgpu/pipeline/bind_group.rb +12 -0
  49. data/lib/wgpu/pipeline/bind_group_layout.rb +91 -37
  50. data/lib/wgpu/pipeline/compute_pipeline.rb +28 -26
  51. data/lib/wgpu/pipeline/render_pipeline.rb +180 -68
  52. data/lib/wgpu/pipeline/shader_module.rb +50 -8
  53. data/lib/wgpu/resources/buffer.rb +148 -73
  54. data/lib/wgpu/resources/query_set.rb +14 -12
  55. data/lib/wgpu/resources/sampler.rb +36 -20
  56. data/lib/wgpu/resources/texture.rb +44 -42
  57. data/lib/wgpu/resources/texture_view.rb +11 -3
  58. data/lib/wgpu/texture_format.rb +82 -0
  59. data/lib/wgpu/version.rb +1 -1
  60. data/lib/wgpu/window.rb +8 -1
  61. data/lib/wgpu.rb +32 -0
  62. data/sig/wgpu.rbs +381 -0
  63. metadata +31 -16
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WGPU
4
+ module DescriptorHelpers
5
+ module_function
6
+
7
+ def set_label(descriptor, label, keepalive:)
8
+ if label
9
+ pointer = FFI::MemoryPointer.from_string(label)
10
+ keepalive << pointer
11
+ descriptor[:label][:data] = pointer
12
+ descriptor[:label][:length] = label.bytesize
13
+ else
14
+ descriptor[:label][:data] = nil
15
+ descriptor[:label][:length] = 0
16
+ end
17
+ end
18
+
19
+ def uint32_array(values, keepalive:)
20
+ return nil if values.empty?
21
+
22
+ pointer = FFI::MemoryPointer.new(:uint32, values.length)
23
+ pointer.write_array_of_uint32(values)
24
+ keepalive << pointer
25
+ pointer
26
+ end
27
+
28
+ def validate_keys!(options, allowed:, required: [], context: "descriptor")
29
+ return options unless options.is_a?(Hash)
30
+
31
+ missing = required - options.keys
32
+ raise ArgumentError, "#{context} is missing required keys: #{missing.map(&:inspect).join(", ")}" unless missing.empty?
33
+
34
+ unknown = options.keys - allowed
35
+ warn "Unknown #{context} keys: #{unknown.map(&:inspect).join(", ")}" unless unknown.empty?
36
+ options
37
+ end
38
+ end
39
+ end
data/lib/wgpu/error.rb CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  module WGPU
4
4
  class Error < StandardError; end
5
+ class ValidationError < Error; end
6
+ class OutOfMemoryError < Error; end
7
+ class InternalError < Error; end
8
+ class DeviceLostError < Error; end
9
+ class TimeoutError < Error; end
5
10
  class InitializationError < Error; end
6
11
  class AdapterError < Error; end
7
12
  class DeviceError < Error; end
@@ -12,5 +17,55 @@ module WGPU
12
17
  class PipelineError < Error; end
13
18
  class CommandError < Error; end
14
19
  class SurfaceError < Error; end
20
+ class SurfaceAcquisitionError < SurfaceError
21
+ attr_reader :status
22
+
23
+ def initialize(status, message = nil)
24
+ @status = status
25
+ super(message || "Failed to get current surface texture: #{status}")
26
+ end
27
+ end
15
28
  class RenderBundleError < Error; end
29
+
30
+ GPUError = Data.define(:type, :message) do
31
+ def self.from_hash(error)
32
+ return if error.nil? || error[:type].nil? || error[:type] == :no_error
33
+
34
+ new(type: error[:type], message: error[:message].to_s)
35
+ end
36
+
37
+ def exception_class
38
+ {
39
+ validation: ValidationError,
40
+ out_of_memory: OutOfMemoryError,
41
+ internal: InternalError,
42
+ device_lost: DeviceLostError
43
+ }.fetch(type, Error)
44
+ end
45
+
46
+ def raise!
47
+ raise exception_class, "GPU error (#{type}): #{message}"
48
+ end
49
+
50
+ def to_h
51
+ { type:, message: }
52
+ end
53
+ end
54
+
55
+ CompilationMessage = Data.define(
56
+ :type,
57
+ :message,
58
+ :line_num,
59
+ :line_pos,
60
+ :offset,
61
+ :length
62
+ ) do
63
+ alias line line_num
64
+ alias column line_pos
65
+
66
+ def to_s
67
+ location = line_num&.positive? ? "#{line_num}:#{line_pos}" : "unknown location"
68
+ "#{location}: #{type}: #{message}"
69
+ end
70
+ end
16
71
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WGPU
4
+ class << self
5
+ # Returns the configured wgpu-native log level.
6
+ attr_reader :log_level
7
+
8
+ # Sets the wgpu-native log level.
9
+ #
10
+ # @param level [Symbol, Integer] one of `:off`, `:error`, `:warn`, `:info`,
11
+ # `:debug`, or `:trace`
12
+ # @return [Symbol, Integer] the supplied level
13
+ def log_level=(level)
14
+ ensure_native_logging!
15
+ value = Native::EnumHelper.coerce(Native::LogLevel, level, name: "log level")
16
+ Native.wgpuSetLogLevel(value)
17
+ @log_level = Native::LogLevel[value]
18
+ end
19
+
20
+ # Registers a process-wide wgpu-native log handler.
21
+ #
22
+ # The native callback is retained by the WGPU module for the rest of the
23
+ # process, or until this method replaces it.
24
+ #
25
+ # @yieldparam level [Symbol] native log severity
26
+ # @yieldparam message [String] UTF-8 log message
27
+ # @return [WGPU]
28
+ def on_log(&handler)
29
+ raise ArgumentError, "block is required" unless handler
30
+
31
+ ensure_native_logging!
32
+ @log_handler = handler
33
+ @native_log_callback = FFI::Function.new(
34
+ :void,
35
+ [:uint32, Native::StringView.by_value, :pointer]
36
+ ) do |level, message, _userdata|
37
+ text =
38
+ if message[:data] && !message[:data].null? && message[:length].positive?
39
+ message[:data].read_string(message[:length])
40
+ else
41
+ ""
42
+ end
43
+ @log_handler.call(Native::LogLevel[level] || level, text)
44
+ rescue StandardError => e
45
+ warn "WGPU log handler failed: #{e.class}: #{e.message}"
46
+ end
47
+ Native.wgpuSetLogCallback(@native_log_callback, nil)
48
+ self
49
+ end
50
+
51
+ private
52
+
53
+ def ensure_native_logging!
54
+ return if Native.logging_available?
55
+
56
+ raise Error,
57
+ "wgpu-native logging is unavailable in the loaded library " \
58
+ "(expected #{Native::Distribution::VERSION})"
59
+ end
60
+ end
61
+
62
+ @log_level = :warn
63
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WGPU
4
+ module Native
5
+ class AbiVerifier
6
+ FORCE32_KEY = "force32"
7
+ EXTENSION_ENTRIES = {
8
+ "SType" => %w[invalid shadersourceglsl],
9
+ "FeatureName" => %w[
10
+ pushconstants textureadapterspecificformatfeatures multidrawindirectcount
11
+ vertexwritablestorage texturebindingarray
12
+ sampledtextureandstoragebufferarraynonuniformindexing
13
+ pipelinestatisticsquery storageresourcebindingarray
14
+ partiallyboundbindingarray textureformat16bitnorm
15
+ texturecompressionastchdr mappableprimarybuffers bufferbindingarray
16
+ uniformbufferandstoragetexturearraynonuniformindexing polygonmodeline
17
+ polygonmodepoint conservativerasterization spirvshaderpassthrough
18
+ vertexattribute64bit textureformatnv12 rayquery shaderf64 shaderi16
19
+ shaderprimitiveindex shaderearlydepthtest subgroup subgroupvertex
20
+ subgroupbarrier timestampqueryinsideencoders timestampqueryinsidepasses
21
+ shaderint64
22
+ ]
23
+ }.freeze
24
+
25
+ def initialize(header_path: nil, native: Native)
26
+ @header_path = header_path || self.class.default_header_path
27
+ @native = native
28
+ end
29
+
30
+ def verify!
31
+ differences = enum_differences
32
+ return true if differences.empty?
33
+
34
+ raise WGPU::Error, "wgpu-native ABI enum differences:\n#{differences.join("\n")}"
35
+ end
36
+
37
+ def enum_differences
38
+ header_enums = parse_header
39
+ ruby_enums.filter_map do |name, mapping|
40
+ header_mapping = header_enums[name]
41
+ next unless header_mapping
42
+
43
+ compare_enum(name, ruby_mapping(mapping), header_mapping)
44
+ end
45
+ end
46
+
47
+ def self.default_header_path
48
+ override = ENV["WGPU_HEADER_PATH"]
49
+ return File.expand_path(override) if override && !override.empty?
50
+
51
+ candidates = Distribution.cache_directories.map do |cache_dir|
52
+ File.join(cache_dir, "include", "webgpu", "webgpu.h")
53
+ end
54
+ path = candidates.find { |candidate| File.file?(candidate) }
55
+ return path if path
56
+
57
+ raise WGPU::Error, <<~MSG.chomp
58
+ Pinned #{Distribution::VERSION} webgpu.h was not found.
59
+ Run `bundle exec rake wgpu:install`, or set WGPU_HEADER_PATH.
60
+ Searched: #{candidates.join(", ")}
61
+ MSG
62
+ end
63
+
64
+ private
65
+
66
+ def parse_header
67
+ source = File.read(@header_path)
68
+ source.scan(
69
+ /typedef enum WGPU(\w+)\s*\{(.*?)\}\s*WGPU\1(?:\s+WGPU_ENUM_ATTRIBUTE)?;/m
70
+ ).to_h do |name, body|
71
+ entries = body.scan(
72
+ /WGPU#{Regexp.escape(name)}_([A-Za-z0-9_]+)\s*=\s*(0x[0-9A-Fa-f]+|\d+)/
73
+ ).to_h { |entry, value| [normalize(entry), Integer(value)] }
74
+ entries.delete(FORCE32_KEY)
75
+ [name, entries]
76
+ end
77
+ end
78
+
79
+ def ruby_enums
80
+ @native.constants(false).sort.filter_map do |constant_name|
81
+ value = @native.const_get(constant_name)
82
+ [constant_name.to_s, value.to_h] if value.is_a?(FFI::Enum)
83
+ end
84
+ end
85
+
86
+ def ruby_mapping(mapping)
87
+ mapping.to_h { |key, value| [normalize(key), value] }
88
+ end
89
+
90
+ def normalize(name)
91
+ normalized = name.to_s.delete("_").downcase
92
+ normalized.sub(/\A([123])d/, 'd\1')
93
+ end
94
+
95
+ def compare_enum(name, ruby_mapping, header_mapping)
96
+ missing = header_mapping.keys - ruby_mapping.keys
97
+ extra = ruby_mapping.keys - header_mapping.keys - EXTENSION_ENTRIES.fetch(name, [])
98
+ wrong = (header_mapping.keys & ruby_mapping.keys).filter_map do |key|
99
+ next if header_mapping[key] == ruby_mapping[key]
100
+
101
+ "#{key}=#{ruby_mapping[key]} (header #{header_mapping[key]})"
102
+ end
103
+ return if missing.empty? && extra.empty? && wrong.empty?
104
+
105
+ "#{name}: missing=#{missing.inspect}, extra=#{extra.inspect}, mismatched=#{wrong.inspect}"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -15,12 +15,15 @@ module WGPU
15
15
  [:pointer, ErrorType, StringView.by_value, :pointer, :pointer], :void
16
16
 
17
17
  callback :device_lost_callback,
18
- [:pointer, :uint32, StringView.by_value, :pointer, :pointer], :void
18
+ [:pointer, DeviceLostReason, StringView.by_value, :pointer, :pointer], :void
19
19
 
20
20
  callback :pop_error_scope_callback,
21
21
  [PopErrorScopeStatus, ErrorType, StringView.by_value, :pointer, :pointer], :void
22
22
 
23
23
  callback :queue_work_done_callback,
24
24
  [QueueWorkDoneStatus, :pointer, :pointer], :void
25
+
26
+ callback :log_callback,
27
+ [LogLevel, StringView.by_value, :pointer], :void
25
28
  end
26
29
  end
@@ -4,11 +4,27 @@ module WGPU
4
4
  module Native
5
5
  class << self
6
6
  def future_api?
7
- respond_to?(:wgpuInstanceWaitAny)
7
+ optional_function_available?(:wgpuInstanceWaitAny)
8
8
  end
9
9
 
10
10
  def device_poll_available?
11
- respond_to?(:wgpuDevicePoll)
11
+ optional_function_available?(:wgpuDevicePoll)
12
+ end
13
+
14
+ # wgpu-native v27 exports wgpuShaderModuleGetCompilationInfo, but the
15
+ # implementation is a Rust panic stub. Calling it aborts the process, so
16
+ # symbol presence alone cannot be used as a capability check.
17
+ def compilation_info_available?
18
+ Distribution::VERSION != "v27.0.4.0"
19
+ end
20
+
21
+ def buffer_map_state_available?
22
+ Distribution::VERSION != "v27.0.4.0"
23
+ end
24
+
25
+ def logging_available?
26
+ optional_function_available?(:wgpuSetLogCallback) &&
27
+ optional_function_available?(:wgpuSetLogLevel)
12
28
  end
13
29
  end
14
30
  end
@@ -0,0 +1,113 @@
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
+
11
+ ARTIFACTS = [
12
+ {
13
+ pattern: /x86_64-linux/,
14
+ archive: "wgpu-linux-x86_64-release.zip",
15
+ library: "libwgpu_native.so",
16
+ sha256: "271481ef76fbf3ea09631a6079e9493636ecf813cd9c92306c44a1a452991ba1"
17
+ },
18
+ {
19
+ pattern: /aarch64-linux/,
20
+ archive: "wgpu-linux-aarch64-release.zip",
21
+ library: "libwgpu_native.so",
22
+ sha256: "a2f22248200997b69373273b10d50a58164f6ed840877289f3e46bff317b134e"
23
+ },
24
+ {
25
+ pattern: /x86_64-darwin/,
26
+ archive: "wgpu-macos-x86_64-release.zip",
27
+ library: "libwgpu_native.dylib",
28
+ sha256: "660fe9be59b555ec1d7c839e5cf8b6c71762938af61ab444a7a58dd87970dba2"
29
+ },
30
+ {
31
+ pattern: /arm64-darwin/,
32
+ archive: "wgpu-macos-aarch64-release.zip",
33
+ library: "libwgpu_native.dylib",
34
+ sha256: "15367c26fdbe6892db35007d39f3883593384e777360b70e6bd704cb5dedde53"
35
+ },
36
+ {
37
+ pattern: /(?:x64|x86_64)-(?:mingw|mswin)/,
38
+ archive: "wgpu-windows-x86_64-msvc-release.zip",
39
+ library: "wgpu_native.dll",
40
+ sha256: "f14ca334b4d253881bde2605bd147f332178d705f56fbd74f81458797c77fce1"
41
+ }
42
+ ].map(&:freeze).freeze
43
+
44
+ module_function
45
+
46
+ def artifact_for(platform = RUBY_PLATFORM)
47
+ raise LoadError, unsupported_platform_message(platform) if platform.include?("musl")
48
+
49
+ artifact = ARTIFACTS.find { |candidate| candidate[:pattern].match?(platform) }
50
+ return artifact if artifact
51
+
52
+ raise LoadError, unsupported_platform_message(platform)
53
+ end
54
+
55
+ def primary_cache_dir(env: ENV, home: Dir.home, host_os: RbConfig::CONFIG["host_os"])
56
+ override = present_value(env["WGPU_CACHE_DIR"])
57
+ return File.join(File.expand_path(override), VERSION) if override
58
+
59
+ xdg_cache = present_value(env["XDG_CACHE_HOME"])
60
+ return File.join(File.expand_path(xdg_cache), "wgpu-ruby", VERSION) if xdg_cache
61
+
62
+ File.join(default_cache_base(env:, home:, host_os:), "wgpu-ruby", VERSION)
63
+ end
64
+
65
+ def legacy_cache_dir(home: Dir.home)
66
+ File.join(File.expand_path(home), ".cache", "wgpu-ruby", VERSION)
67
+ end
68
+
69
+ def cache_directories(env: ENV, home: Dir.home, host_os: RbConfig::CONFIG["host_os"])
70
+ [primary_cache_dir(env:, home:, host_os:), legacy_cache_dir(home:)].uniq
71
+ end
72
+
73
+ def library_paths(platform: RUBY_PLATFORM, env: ENV, home: Dir.home,
74
+ host_os: RbConfig::CONFIG["host_os"])
75
+ library = artifact_for(platform)[:library]
76
+ cache_directories(env:, home:, host_os:).map { |directory| File.join(directory, "lib", library) }
77
+ end
78
+
79
+ def release_url(artifact)
80
+ "#{RELEASE_BASE_URL}/#{artifact.fetch(:archive)}"
81
+ end
82
+
83
+ def unsupported_platform_message(platform)
84
+ supported = ARTIFACTS.map { |artifact| artifact[:pattern].inspect }.join(", ")
85
+ <<~MESSAGE.chomp
86
+ Unsupported platform: #{platform}
87
+ Supported 64-bit platforms: #{supported}
88
+ Build wgpu-native for this host and set WGPU_LIB_PATH to the shared library.
89
+ MESSAGE
90
+ end
91
+
92
+ def default_cache_base(env:, home:, host_os:)
93
+ case host_os
94
+ when /darwin/
95
+ File.join(File.expand_path(home), "Library", "Caches")
96
+ when /mingw|mswin/
97
+ local_app_data = present_value(env["LOCALAPPDATA"])
98
+ local_app_data || File.join(File.expand_path(home), "AppData", "Local")
99
+ else
100
+ File.join(File.expand_path(home), ".cache")
101
+ end
102
+ end
103
+ private_class_method :default_cache_base
104
+
105
+ def present_value(value)
106
+ value unless value.nil? || value.empty?
107
+ end
108
+ private_class_method :present_value
109
+ end
110
+
111
+ WGPU_VERSION = Distribution::VERSION
112
+ end
113
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WGPU
4
+ module Native
5
+ module EnumHelper
6
+ module_function
7
+
8
+ def coerce(enum, value, name: "enum")
9
+ return value if value.is_a?(Integer)
10
+ raise ArgumentError, "#{name} must be a Symbol or Integer, got #{value.class}" unless value.is_a?(Symbol)
11
+
12
+ mapping = mapping_for(enum)
13
+ result = mapping[value]
14
+ return result unless result.nil?
15
+
16
+ raise ArgumentError, unknown_value_message(name, value, mapping.keys)
17
+ end
18
+
19
+ def coerce_flags(enum, value, name: "flags")
20
+ return value if value.is_a?(Integer)
21
+
22
+ values = value.is_a?(Array) ? value : [value]
23
+ unless values.all? { |item| item.is_a?(Symbol) }
24
+ raise ArgumentError, "#{name} must be a Symbol, Integer, or Array of Symbols"
25
+ end
26
+
27
+ values.reduce(0) { |flags, item| flags | coerce(enum, item, name:) }
28
+ end
29
+
30
+ def decompose_flags(enum, value)
31
+ raise ArgumentError, "flag value must be an Integer" unless value.is_a?(Integer)
32
+
33
+ mapping = mapping_for(enum)
34
+ return [:none] if value.zero? && mapping.key?(:none)
35
+
36
+ mapping.filter_map do |symbol, bit|
37
+ symbol if bit.positive? && power_of_two?(bit) && (value & bit) == bit
38
+ end
39
+ end
40
+
41
+ def mapping_for(enum)
42
+ mapping = enum.respond_to?(:to_h) ? enum.to_h : enum
43
+ unless mapping.respond_to?(:key?) && mapping.respond_to?(:keys)
44
+ raise ArgumentError, "enum must be an FFI::Enum or Hash"
45
+ end
46
+
47
+ mapping
48
+ end
49
+ private_class_method :mapping_for
50
+
51
+ def unknown_value_message(name, value, candidates)
52
+ formatted = candidates.grep(Symbol).sort.map(&:inspect).join(", ")
53
+ "Unknown #{name} #{value.inspect}. Valid values: #{formatted}"
54
+ end
55
+ private_class_method :unknown_value_message
56
+
57
+ def power_of_two?(value)
58
+ (value & (value - 1)).zero?
59
+ end
60
+ private_class_method :power_of_two?
61
+ end
62
+ end
63
+ end
@@ -61,6 +61,13 @@ module WGPU
61
61
  :unknown, 0x00000004
62
62
  )
63
63
 
64
+ DeviceLostReason = enum(
65
+ :unknown, 0x00000001,
66
+ :destroyed, 0x00000002,
67
+ :instance_dropped, 0x00000003,
68
+ :failed_creation, 0x00000004
69
+ )
70
+
64
71
  BufferMapState = enum(
65
72
  :unmapped, 0x00000001,
66
73
  :pending, 0x00000002,
@@ -283,7 +290,9 @@ module WGPU
283
290
  :sint32, 0x00000024,
284
291
  :sint32x2, 0x00000025,
285
292
  :sint32x3, 0x00000026,
286
- :sint32x4, 0x00000027
293
+ :sint32x4, 0x00000027,
294
+ :unorm10_10_10_2, 0x00000028,
295
+ :unorm8x4_bgra, 0x00000029
287
296
  )
288
297
 
289
298
  IndexFormat = enum(
@@ -366,11 +375,11 @@ module WGPU
366
375
  :undefined, 0x00000000,
367
376
  :never, 0x00000001,
368
377
  :less, 0x00000002,
369
- :less_equal, 0x00000003,
370
- :greater, 0x00000004,
371
- :greater_equal, 0x00000005,
372
- :equal, 0x00000006,
373
- :not_equal, 0x00000007,
378
+ :equal, 0x00000003,
379
+ :less_equal, 0x00000004,
380
+ :greater, 0x00000005,
381
+ :not_equal, 0x00000006,
382
+ :greater_equal, 0x00000007,
374
383
  :always, 0x00000008
375
384
  )
376
385
 
@@ -467,7 +476,9 @@ module WGPU
467
476
  :timeout, 0x00000003,
468
477
  :outdated, 0x00000004,
469
478
  :lost, 0x00000005,
470
- :error, 0x00000006
479
+ :out_of_memory, 0x00000006,
480
+ :device_lost, 0x00000007,
481
+ :error, 0x00000008
471
482
  )
472
483
 
473
484
  QueryType = enum(
@@ -523,6 +534,15 @@ module WGPU
523
534
  :info, 0x00000003
524
535
  )
525
536
 
537
+ LogLevel = enum(
538
+ :off, 0x00000000,
539
+ :error, 0x00000001,
540
+ :warn, 0x00000002,
541
+ :info, 0x00000003,
542
+ :debug, 0x00000004,
543
+ :trace, 0x00000005
544
+ )
545
+
526
546
  FeatureName = enum(
527
547
  :undefined, 0x00000000,
528
548
  :depth_clip_control, 0x00000001,
@@ -540,7 +560,39 @@ module WGPU
540
560
  :float32_filterable, 0x0000000D,
541
561
  :float32_blendable, 0x0000000E,
542
562
  :clip_distances, 0x0000000F,
543
- :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
544
596
  )
545
597
  end
546
598
  end
@@ -17,11 +17,8 @@ module WGPU
17
17
  attach_function :wgpuInstanceProcessEvents,
18
18
  [:pointer], :void
19
19
 
20
- begin
21
- attach_function :wgpuInstanceWaitAny,
22
- [:pointer, :size_t, :pointer, :uint64], WaitStatus
23
- rescue FFI::NotFoundError
24
- end
20
+ attach_optional_function :wgpuInstanceWaitAny,
21
+ [:pointer, :size_t, :pointer, :uint64], WaitStatus
25
22
 
26
23
  attach_function :wgpuAdapterRelease,
27
24
  [:pointer], :void
@@ -77,11 +74,8 @@ module WGPU
77
74
  attach_function :wgpuDeviceCreateCommandEncoder,
78
75
  [:pointer, CommandEncoderDescriptor.by_ref], :pointer
79
76
 
80
- begin
81
- attach_function :wgpuDevicePoll,
82
- [:pointer, :uint32, :pointer], :uint32
83
- rescue FFI::NotFoundError
84
- end
77
+ attach_optional_function :wgpuDevicePoll,
78
+ [:pointer, :uint32, :pointer], :uint32
85
79
 
86
80
  attach_function :wgpuQueueRelease,
87
81
  [:pointer], :void
@@ -424,5 +418,11 @@ module WGPU
424
418
 
425
419
  attach_function :wgpuRenderBundleEncoderInsertDebugMarker,
426
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
427
427
  end
428
428
  end