Class: WGPU::Adapter

Inherits:
Object
  • Object
show all
Includes:
NativeResource
Defined in:
lib/wgpu/core/adapter.rb,
sig/wgpu.rbs

Constant Summary

Constants included from NativeResource

NativeResource::GUARDED_METHOD_EXEMPTIONS

Instance Attribute Summary collapse

Attributes included from NativeResource

#label

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NativeResource

included, #inspect, #released?, #use

Constructor Details

#initialize(handle, instance: nil) ⇒ Adapter

Wraps a native adapter handle.

Parameters:

  • handle (FFI::Pointer)

    native adapter handle

  • instance (Instance, nil) (defaults to: nil)

    instance that owns the adapter



127
128
129
130
# File 'lib/wgpu/core/adapter.rb', line 127

def initialize(handle, instance: nil)
  @handle = handle
  @instance = instance
end

Instance Attribute Details

#handleObject (readonly)

Returns the value of attribute handle.

Returns:

  • (Object)


5
6
7
# File 'lib/wgpu/core/adapter.rb', line 5

def handle
  @handle
end

#instanceInstance? (readonly)

Returns the value of attribute instance.

Returns:



5
6
7
# File 'lib/wgpu/core/adapter.rb', line 5

def instance
  @instance
end

Class Method Details

.from_handle(handle, instance: nil) ⇒ Adapter

Wraps an existing native adapter handle.

Parameters:

  • handle (FFI::Pointer)

    native adapter handle

  • instance (Instance, nil) (defaults to: nil)

    instance that owns the adapter

  • (Object)
  • instance: (Instance, nil) (defaults to: nil)

Returns:



11
12
13
14
15
# File 'lib/wgpu/core/adapter.rb', line 11

def self.from_handle(handle, instance: nil)
  adapter = adopt_native_handle(handle)
  adapter.instance_variable_set(:@instance, instance)
  adapter
end

.request(arg0, power_preference:, backend:, feature_level:, force_fallback_adapter:, compatible_surface:, timeout:) ⇒ Adapter .request(arg0, arg1) ⇒ Adapter

Requests an adapter and waits for the native callback.

Overloads:

  • .request(arg0, power_preference:, backend:, feature_level:, force_fallback_adapter:, compatible_surface:, timeout:) ⇒ Adapter

    Parameters:

    • arg0 (Instance)
    • power_preference: (enum_value)
    • backend: (enum_value, nil)
    • feature_level: (enum_value)
    • force_fallback_adapter: (Boolean)
    • compatible_surface: (Surface, nil)
    • timeout: (Numeric, nil)

    Returns:

  • .request(arg0, arg1) ⇒ Adapter

    Parameters:

    Returns:

Parameters:

  • instance (Instance)

    instance used for discovery and callback progress

  • power_preference (Symbol, Integer) (defaults to: :high_performance)

    preferred power profile

  • backend (Symbol, Integer, nil) (defaults to: nil)

    backend to restrict discovery to

  • feature_level (Symbol, Integer) (defaults to: :core)

    requested WebGPU feature level

  • force_fallback_adapter (Boolean) (defaults to: false)

    whether to require a fallback adapter

  • compatible_surface (Surface, nil) (defaults to: nil)

    surface the adapter must support

  • timeout (Numeric, nil) (defaults to: nil)

    maximum wait time in seconds

Returns:

Raises:



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/wgpu/core/adapter.rb', line 29

def self.request(instance, power_preference: :high_performance, backend: nil, feature_level: :core,
                 force_fallback_adapter: false, compatible_surface: nil, timeout: nil)
  adapter_ptr = FFI::MemoryPointer.new(:pointer)
  status_holder = {
    done: false,
    value: nil,
    message: nil,
    abandoned: false,
    cleanup_claimed: false,
    mutex: Mutex.new
  }

  callback_token = nil
  callback = FFI::Function.new(
    :void, [:uint32, :pointer, Native::StringView.by_value, :pointer, :pointer]
  ) do |status, adapter, message, _userdata1, _userdata2|
    abandoned_adapter = nil
    begin
      status_holder[:mutex].synchronize do
        status_holder[:value] = Native::RequestAdapterStatus[status]
        if message[:data] && !message[:data].null? && message[:length] > 0
          status_holder[:message] = message[:data].read_string(message[:length])
        end
        adapter_ptr.write_pointer(adapter)
        status_holder[:done] = true
        if status_holder[:abandoned] && !status_holder[:cleanup_claimed]
          status_holder[:cleanup_claimed] = true
          abandoned_adapter = adapter
        end
      end
      Native.wgpuAdapterRelease(abandoned_adapter) if abandoned_adapter && !abandoned_adapter.null?
    ensure
      CallbackKeepalive.release(instance, callback_token)
    end
  end

  options = Native::RequestAdapterOptions.new
  options[:next_in_chain] = nil
  options[:feature_level] = Native::EnumHelper.coerce(
    Native::FeatureLevel,
    feature_level,
    name: "feature level"
  )
  options[:power_preference] = Native::EnumHelper.coerce(
    Native::PowerPreference,
    power_preference,
    name: "power preference"
  )
  options[:force_fallback_adapter] = force_fallback_adapter ? 1 : 0
  options[:backend_type] = Native::EnumHelper.coerce(
    Native::BackendType,
    backend || :undefined,
    name: "backend type"
  )
  options[:compatible_surface] = compatible_surface&.handle

  callback_info = Native::RequestAdapterCallbackInfo.new
  callback_info[:next_in_chain] = nil
  callback_info[:mode] = AsyncWaiter.callback_mode(instance: instance)
  callback_info[:callback] = callback
  callback_info[:userdata1] = nil
  callback_info[:userdata2] = nil

  callback_token = CallbackKeepalive.retain(instance, callback)
  future =
    begin
      Native.wgpuInstanceRequestAdapter(instance.handle, options, callback_info)
    rescue StandardError
      CallbackKeepalive.release(instance, callback_token)
      raise
    end

  begin
    AsyncWaiter.wait(status_holder: status_holder, instance: instance, future: future, timeout: timeout)
  rescue TimeoutError
    abandoned_adapter = status_holder[:mutex].synchronize do
      status_holder[:abandoned] = true
      next unless status_holder[:done] && !status_holder[:cleanup_claimed]

      status_holder[:cleanup_claimed] = true
      adapter_ptr.read_pointer
    end
    Native.wgpuAdapterRelease(abandoned_adapter) if abandoned_adapter && !abandoned_adapter.null?
    raise
  end

  handle = adapter_ptr.read_pointer
  if handle.null? || status_holder[:value] != :success
    msg = status_holder[:message] || "Unknown error"
    raise AdapterError, "Failed to request adapter: #{msg}"
  end

  new(handle, instance: instance)
end

Instance Method Details

#adapter_typeSymbol, Integer

Returns the adapter's device classification.

Returns:

  • (Symbol, Integer)


198
199
200
# File 'lib/wgpu/core/adapter.rb', line 198

def adapter_type
  info[:adapter_type]
end

#backend_typeSymbol, Integer

Returns the backend used by the adapter.

Returns:

  • (Symbol, Integer)


192
193
194
# File 'lib/wgpu/core/adapter.rb', line 192

def backend_type
  info[:backend_type]
end

#featuresArray<Symbol>

Lists optional features supported by the adapter.

Returns:

  • (Array<Symbol>)


204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/wgpu/core/adapter.rb', line 204

def features
  supported = Native::SupportedFeatures.new
  Native.wgpuAdapterGetFeatures(@handle, supported)

  result = []
  if supported[:feature_count] > 0 && !supported[:features].null?
    supported[:features].read_array_of_uint32(supported[:feature_count]).each do |f|
      result << Native::FeatureName[f]
    end
  end
  result
end

#has_feature?(feature) ⇒ Boolean

Reports whether the adapter supports a feature.

Parameters:

  • feature (Symbol)

    feature name

  • (Symbol)

Returns:

  • (Boolean)


220
221
222
# File 'lib/wgpu/core/adapter.rb', line 220

def has_feature?(feature)
  features.include?(feature)
end

#infoHash

Returns identifying and backend information for the adapter.

Returns:

  • (Hash)


159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/wgpu/core/adapter.rb', line 159

def info
  info_struct = Native::AdapterInfo.new
  Native.wgpuAdapterGetInfo(@handle, info_struct)

  result = {
    vendor: string_view_to_string(info_struct[:vendor]),
    architecture: string_view_to_string(info_struct[:architecture]),
    device: string_view_to_string(info_struct[:device]),
    description: string_view_to_string(info_struct[:description]),
    backend_type: info_struct[:backend_type],
    adapter_type: info_struct[:adapter_type],
    vendor_id: info_struct[:vendor_id],
    device_id: info_struct[:device_id]
  }

  Native.wgpuAdapterInfoFreeMembers(info_struct)
  result
end

#limitsHash{Symbol => Integer}

Returns the adapter resource limits.

Returns:

  • (Hash{Symbol => Integer})


226
227
228
229
230
231
# File 'lib/wgpu/core/adapter.rb', line 226

def limits
  supported = Native::SupportedLimits.new
  supported[:next_in_chain] = nil
  Native.wgpuAdapterGetLimits(@handle, supported)
  limits_to_hash(supported[:limits])
end

#nameString

Returns the adapter's device name.

Returns:

  • (String)


180
181
182
# File 'lib/wgpu/core/adapter.rb', line 180

def name
  info[:device]
end

#releasevoid

This method returns an undefined value.

Releases the native adapter handle.

Calling this method more than once has no effect.



244
245
246
247
248
# File 'lib/wgpu/core/adapter.rb', line 244

def release
  return if @handle.null?
  Native.wgpuAdapterRelease(@handle)
  @handle = FFI::Pointer::NULL
end

#request_device(label:, required_features:, required_limits:, timeout:) ⇒ Device #request_device(arg0) ⇒ Device

Requests a logical device from this adapter.

Overloads:

  • #request_device(label:, required_features:, required_limits:, timeout:) ⇒ Device

    Parameters:

    • label: (String, nil)
    • required_features: (Array[enum_value])
    • required_limits: (Hash[Symbol, Integer], nil)
    • timeout: (Numeric, nil)

    Returns:

  • #request_device(arg0) ⇒ Device

    Parameters:

    • arg0 (Object)

    Returns:

Returns:



134
135
136
137
138
139
140
141
142
# File 'lib/wgpu/core/adapter.rb', line 134

def request_device(label: nil, required_features: [], required_limits: nil, timeout: nil)
  Device.request(
    self,
    label: label,
    required_features: required_features,
    required_limits: required_limits,
    timeout: timeout
  )
end

#request_device_async(label:, required_features:, required_limits:, timeout:) ⇒ AsyncTask[Device] #request_device_async(arg0) ⇒ AsyncTask[Device]

Requests a logical device on a background task.

Overloads:

  • #request_device_async(label:, required_features:, required_limits:, timeout:) ⇒ AsyncTask[Device]

    Parameters:

    • label: (String, nil)
    • required_features: (Array[enum_value])
    • required_limits: (Hash[Symbol, Integer], nil)
    • timeout: (Numeric, nil)

    Returns:

  • #request_device_async(arg0) ⇒ AsyncTask[Device]

    Parameters:

    • arg0 (Object)

    Returns:

Returns:



146
147
148
149
150
151
152
153
154
155
# File 'lib/wgpu/core/adapter.rb', line 146

def request_device_async(label: nil, required_features: [], required_limits: nil, timeout: nil)
  AsyncTask.new do
    request_device(
      label: label,
      required_features: required_features,
      required_limits: required_limits,
      timeout: timeout
    )
  end
end

#summaryString

Returns a concise human-readable adapter description.

Returns:

  • (String)


235
236
237
238
# File 'lib/wgpu/core/adapter.rb', line 235

def summary
  info_hash = info
  "#{info_hash[:device]} (#{info_hash[:adapter_type]}) via #{info_hash[:backend_type]}"
end

#vendorString

Returns the adapter vendor name.

Returns:

  • (String)


186
187
188
# File 'lib/wgpu/core/adapter.rb', line 186

def vendor
  info[:vendor]
end