Class: WGPU::Device

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

Constant Summary collapse

LIMIT_FIELDS =
Native::Limits.members.freeze

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

checked_handle, included, #inspect, #released?, #use

Constructor Details

#initialize(handle, adapter: nil, label: nil, callback_state: nil, callback_lifetime: nil) ⇒ Device

Wraps a native device and obtains its default queue.

Parameters:

  • handle (FFI::Pointer)

    native device handle

  • adapter (Adapter, nil) (defaults to: nil)

    adapter that created the device

  • label (String, nil) (defaults to: nil)

    optional debug label

  • callback_lifetime (DeviceCallbackLifetime, nil) (defaults to: nil)

    shared native callback lifetime



209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/wgpu/core/device.rb', line 209

def initialize(handle, adapter: nil, label: nil, callback_state: nil, callback_lifetime: nil)
  @handle = handle
  @adapter = adapter
  @label = label
  @device_callback_lifetime = callback_lifetime
  @device_callback_state = callback_state || {
    mutex: Mutex.new,
    uncaptured_error: nil,
    device_lost: nil
  }
  @device_callback_tokens = []
  @queue = Queue.new(Native.wgpuDeviceGetQueue(@handle), device: self)
end

Instance Attribute Details

#adapterAdapter? (readonly)

Returns the value of attribute adapter.

Returns:



7
8
9
# File 'lib/wgpu/core/device.rb', line 7

def adapter
  @adapter
end

#handleObject (readonly)

Returns the value of attribute handle.

Returns:

  • (Object)


7
8
9
# File 'lib/wgpu/core/device.rb', line 7

def handle
  @handle
end

#queueQueue (readonly)

Returns the value of attribute queue.

Returns:



7
8
9
# File 'lib/wgpu/core/device.rb', line 7

def queue
  @queue
end

Class Method Details

.request(arg0, label:, required_features:, required_limits:, timeout:) ⇒ Device .request(arg0, arg1) ⇒ Device

Requests a logical device and waits for the native callback.

Overloads:

  • .request(arg0, label:, required_features:, required_limits:, timeout:) ⇒ Device

    Parameters:

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

    Returns:

  • .request(arg0, arg1) ⇒ Device

    Parameters:

    Returns:

Parameters:

  • adapter (Adapter)

    adapter that will create the device

  • label (String, nil) (defaults to: nil)

    optional debugging label

  • required_features (Array<Symbol, Integer>) (defaults to: [])

    features the device must enable

  • required_limits (Hash, nil) (defaults to: nil)

    minimum required limits

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

    maximum wait time in seconds

Returns:

  • (Device)

    requested device

Raises:

  • (DeviceError)

    if device creation fails

  • (TimeoutError)

    if the request exceeds timeout

  • (ArgumentError)

    if timeout is used without an instance-backed adapter



22
23
24
25
26
27
28
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/wgpu/core/device.rb', line 22

def self.request(adapter, label: nil, required_features: [], required_limits: nil, timeout: nil)
  timeout = AsyncWaiter.normalize_timeout(timeout)
  if timeout && !adapter.instance
    raise ArgumentError,
      "Device.request timeout requires an instance-backed adapter; " \
      "pass instance: to Adapter.from_handle"
  end

  device_ptr = FFI::MemoryPointer.new(:pointer)
  status_holder = {
    done: false,
    value: nil,
    message: nil,
    abandoned: false,
    cleanup_claimed: false,
    mutex: Mutex.new
  }
  device_callback_state = {
    mutex: Mutex.new,
    uncaptured_error: nil,
    device_lost: nil
  }

  callback_token = nil
  callback = FFI::Function.new(
    :void, [:uint32, :pointer, Native::StringView.by_value, :pointer, :pointer]
  ) do |status, device, message, _userdata1, _userdata2|
    cleanup_abandoned = false
    begin
      status_holder[:mutex].synchronize do
        status_holder[:value] = Native::RequestDeviceStatus[status]
        if message[:data] && !message[:data].null? && message[:length] > 0
          status_holder[:message] = message[:data].read_string(message[:length])
        end
        device_ptr.write_pointer(device)
        status_holder[:done] = true
        if status_holder[:abandoned] && !status_holder[:cleanup_claimed]
          status_holder[:cleanup_claimed] = true
          cleanup_abandoned = true
        end
      end
      if cleanup_abandoned
        if status_holder[:value] == :success && device && !device.null?
          release_abandoned_device(device, device_callback_state)
        else
          release_device_callback_keepalive(device_callback_state)
        end
      end
    ensure
      CallbackKeepalive.release(adapter, callback_token)
    end
  end

  queue_desc = Native::QueueDescriptor.new
  queue_desc[:next_in_chain] = nil
  queue_desc[:label][:data] = nil
  queue_desc[:label][:length] = 0

  device_lost_info = Native::DeviceLostCallbackInfo.new
  device_lost_info[:next_in_chain] = nil
  device_lost_info[:mode] = AsyncWaiter.callback_mode(instance: adapter.instance)
  device_lost_callback = build_device_lost_callback(device_callback_state)
  device_lost_info[:callback] = device_lost_callback
  device_lost_info[:userdata1] = nil
  device_lost_info[:userdata2] = nil

  error_info = Native::UncapturedErrorCallbackInfo.new
  error_info[:next_in_chain] = nil
  uncaptured_error_callback = build_uncaptured_error_callback(device_callback_state)
  error_info[:callback] = uncaptured_error_callback
  error_info[:userdata1] = nil
  error_info[:userdata2] = nil

  desc = Native::DeviceDescriptor.new
  desc[:next_in_chain] = nil
  if label
    label_ptr = FFI::MemoryPointer.from_string(label)
    desc[:label][:data] = label_ptr
    desc[:label][:length] = label.bytesize
  else
    desc[:label][:data] = nil
    desc[:label][:length] = 0
  end

  feature_values = normalize_required_features(required_features)
  if feature_values.empty?
    desc[:required_feature_count] = 0
    desc[:required_features] = nil
  else
    features_ptr = FFI::MemoryPointer.new(:uint32, feature_values.size)
    features_ptr.write_array_of_uint32(feature_values)
    desc[:required_feature_count] = feature_values.size
    desc[:required_features] = features_ptr
  end

  required_limits_struct = build_required_limits(adapter, required_limits)
  desc[:required_limits] = required_limits_struct ? required_limits_struct.to_ptr : nil
  desc[:default_queue] = queue_desc
  desc[:device_lost_callback_info] = device_lost_info
  desc[:uncaptured_error_callback_info] = error_info

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

  device_lost_token = CallbackKeepalive.retain(adapter, device_lost_callback)
  uncaptured_error_token = CallbackKeepalive.retain(adapter, uncaptured_error_callback)
  configure_device_callback_keepalive(
    device_callback_state,
    owner: adapter,
    tokens: [device_lost_token, uncaptured_error_token]
  )
  callback_token = CallbackKeepalive.retain(adapter, callback)
  future =
    begin
      Native.wgpuAdapterRequestDevice(NativeResource.checked_handle(adapter, expected_class: Adapter), desc, callback_info)
    rescue StandardError
      CallbackKeepalive.release(adapter, callback_token)
      release_device_callback_keepalive(device_callback_state)
      raise
    end

  begin
    AsyncWaiter.wait(
      status_holder: status_holder,
      instance: adapter.instance,
      future: future,
      timeout: timeout
    )
  rescue StandardError
    abandoned_device = nil
    cleanup_abandoned = status_holder[:mutex].synchronize do
      status_holder[:abandoned] = true
      next false unless status_holder[:done] && !status_holder[:cleanup_claimed]

      status_holder[:cleanup_claimed] = true
      abandoned_device = device_ptr.read_pointer
      true
    end
    if cleanup_abandoned
      if status_holder[:value] == :success && abandoned_device && !abandoned_device.null?
        release_abandoned_device(abandoned_device, device_callback_state)
      else
        release_device_callback_keepalive(device_callback_state)
      end
    end
    raise
  end

  handle = device_ptr.read_pointer
  if handle.null? || status_holder[:value] != :success
    release_device_callback_keepalive(device_callback_state)
    msg = status_holder[:message] || "Unknown error"
    raise DeviceError, "Failed to request device: #{msg}"
  end

  begin
    callback_lifetime = DeviceCallbackLifetime.new do
      release_device_callback_keepalive(device_callback_state)
    end
    device_callback_state[:mutex].synchronize do
      device_callback_state[:callback_lifetime] = callback_lifetime
    end
    device = new(
      handle,
      adapter: adapter,
      label: label,
      callback_state: device_callback_state,
      callback_lifetime: callback_lifetime
    )
    device.send(:adopt_device_callback_keepalive)
    device
  rescue StandardError
    device&.release
    release_device_callback_keepalive(device_callback_state)
    raise
  end
end

Instance Method Details

#adapter_infoHash?

Returns information about the adapter that created this device.

Returns:

  • (Hash, nil)


225
226
227
# File 'lib/wgpu/core/device.rb', line 225

def adapter_info
  @adapter&.info
end

#create_bind_group(label: nil, layout:, entries:) ⇒ BindGroup

Creates a bind group.

Parameters:

  • label: (String, nil) (defaults to: nil)
  • layout: (BindGroupLayout)
  • entries: (Array[Hash[Symbol, untyped]])

Returns:



262
263
264
# File 'lib/wgpu/core/device.rb', line 262

def create_bind_group(label: nil, layout:, entries:)
  BindGroup.new(self, label: label, layout: layout, entries: entries)
end

#create_bind_group_layout(label: nil, entries:) ⇒ BindGroupLayout

Creates a bind group layout.

Parameters:

  • label: (String, nil) (defaults to: nil)
  • entries: (Array[Hash[Symbol, untyped]])

Returns:



256
257
258
# File 'lib/wgpu/core/device.rb', line 256

def create_bind_group_layout(label: nil, entries:)
  BindGroupLayout.new(self, label: label, entries: entries)
end

#create_buffer(label: nil, size:, usage:, mapped_at_creation: false) ⇒ Buffer

Creates a GPU buffer.

Parameters:

  • label: (String, nil) (defaults to: nil)
  • size: (Integer)
  • usage: (flags)
  • mapped_at_creation: (Boolean) (defaults to: false)

Returns:



231
232
233
# File 'lib/wgpu/core/device.rb', line 231

def create_buffer(label: nil, size:, usage:, mapped_at_creation: false)
  Buffer.new(self, label: label, size: size, usage: usage, mapped_at_creation: mapped_at_creation)
end

#create_buffer_with_data(label: nil, data:, usage:, type: :f32) ⇒ Buffer

Creates a mapped buffer initialized from typed Ruby data.

Parameters:

  • data (Array, String, FFI::Pointer)

    source data

  • usage (Symbol, Array<Symbol>, Integer)

    buffer usage flags

  • type (Symbol) (defaults to: :f32)

    source element type

  • label: (String, nil) (defaults to: nil)
  • data: (data)
  • usage: (flags)
  • type: (Symbol) (defaults to: :f32)

Returns:



354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/wgpu/core/device.rb', line 354

def create_buffer_with_data(label: nil, data:, usage:, type: :f32)
  data_ptr, byte_size = DataTypes.to_pointer(data, type:)
  DataTypes.validate_alignment!(byte_size, 4, name: "buffer data size")
  buffer = create_buffer(
    label: label,
    size: byte_size,
    usage: usage,
    mapped_at_creation: true
  )
  buffer.mapped_range.write_bytes(data_ptr.read_bytes(byte_size))
  buffer.unmap
  buffer
end

#create_command_encoder(label: nil) ⇒ CommandEncoder

Creates a command encoder.

Parameters:

  • label: (String, nil) (defaults to: nil)

Returns:



250
251
252
# File 'lib/wgpu/core/device.rb', line 250

def create_command_encoder(label: nil)
  CommandEncoder.new(self, label: label)
end

#create_compute_pipeline(label: nil, layout:, compute:) ⇒ ComputePipeline

Creates a compute pipeline.

Parameters:

  • (Object)

Returns:



274
275
276
# File 'lib/wgpu/core/device.rb', line 274

def create_compute_pipeline(label: nil, layout:, compute:)
  ComputePipeline.new(self, label: label, layout: layout, compute: compute)
end

#create_compute_pipeline_async(label: nil, layout:, compute:) ⇒ AsyncTask

Creates a compute pipeline on a background task.

Parameters:

  • (Object)

Returns:



280
281
282
283
284
# File 'lib/wgpu/core/device.rb', line 280

def create_compute_pipeline_async(label: nil, layout:, compute:)
  AsyncTask.new do
    create_compute_pipeline(label: label, layout: layout, compute: compute)
  end
end

#create_pipeline_layout(label: nil, bind_group_layouts:) ⇒ PipelineLayout

Creates a pipeline layout.

Parameters:

  • label: (String, nil) (defaults to: nil)
  • bind_group_layouts: (Array[BindGroupLayout])

Returns:



268
269
270
# File 'lib/wgpu/core/device.rb', line 268

def create_pipeline_layout(label: nil, bind_group_layouts:)
  PipelineLayout.new(self, label: label, bind_group_layouts: bind_group_layouts)
end

#create_query_set(label: nil, type:, count:) ⇒ QuerySet

Creates a GPU query set.

Parameters:

  • label: (String, nil) (defaults to: nil)
  • type: (enum_value)
  • count: (Integer)

Returns:



370
371
372
# File 'lib/wgpu/core/device.rb', line 370

def create_query_set(label: nil, type:, count:)
  QuerySet.new(self, label: label, type: type, count: count)
end

#create_render_bundle_encoder(color_formats:, depth_stencil_format: nil, sample_count: 1, depth_read_only: false, stencil_read_only: false, label: nil) ⇒ RenderBundleEncoder

Creates an encoder for reusable render commands.

Parameters:

  • (Object)

Returns:



376
377
378
379
380
381
382
383
384
385
386
# File 'lib/wgpu/core/device.rb', line 376

def create_render_bundle_encoder(color_formats:, depth_stencil_format: nil, sample_count: 1,
                                 depth_read_only: false, stencil_read_only: false, label: nil)
  RenderBundleEncoder.new(self,
    color_formats: color_formats,
    depth_stencil_format: depth_stencil_format,
    sample_count: sample_count,
    depth_read_only: depth_read_only,
    stencil_read_only: stencil_read_only,
    label: label
  )
end

#create_render_pipeline(label: nil, layout:, vertex:, primitive: {}, depth_stencil: nil, multisample: {}, fragment: nil) ⇒ RenderPipeline

Creates a render pipeline.

Parameters:

  • (Object)

Returns:



288
289
290
291
292
293
294
295
296
297
298
# File 'lib/wgpu/core/device.rb', line 288

def create_render_pipeline(label: nil, layout:, vertex:, primitive: {}, depth_stencil: nil, multisample: {}, fragment: nil)
  RenderPipeline.new(self,
    label: label,
    layout: layout,
    vertex: vertex,
    primitive: primitive,
    depth_stencil: depth_stencil,
    multisample: multisample,
    fragment: fragment
  )
end

#create_render_pipeline_async(label: nil, layout:, vertex:, primitive: {}, depth_stencil: nil, multisample: {}, fragment: nil) ⇒ AsyncTask

Creates a render pipeline on a background task.

Parameters:

  • (Object)

Returns:



302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/wgpu/core/device.rb', line 302

def create_render_pipeline_async(label: nil, layout:, vertex:, primitive: {}, depth_stencil: nil, multisample: {}, fragment: nil)
  AsyncTask.new do
    create_render_pipeline(
      label: label,
      layout: layout,
      vertex: vertex,
      primitive: primitive,
      depth_stencil: depth_stencil,
      multisample: multisample,
      fragment: fragment
    )
  end
end

#create_sampler(label: nil, address_mode_u: :clamp_to_edge, address_mode_v: :clamp_to_edge, address_mode_w: :clamp_to_edge, mag_filter: :nearest, min_filter: :nearest, mipmap_filter: :nearest, lod_min_clamp: 0.0, lod_max_clamp: 32.0, compare: nil, max_anisotropy: 1) ⇒ Sampler

Creates a texture sampler.

Parameters:

  • (Object)

Returns:



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/wgpu/core/device.rb', line 333

def create_sampler(label: nil, address_mode_u: :clamp_to_edge, address_mode_v: :clamp_to_edge, address_mode_w: :clamp_to_edge, mag_filter: :nearest, min_filter: :nearest, mipmap_filter: :nearest, lod_min_clamp: 0.0, lod_max_clamp: 32.0, compare: nil, max_anisotropy: 1)
  Sampler.new(self,
    label: label,
    address_mode_u: address_mode_u,
    address_mode_v: address_mode_v,
    address_mode_w: address_mode_w,
    mag_filter: mag_filter,
    min_filter: min_filter,
    mipmap_filter: mipmap_filter,
    lod_min_clamp: lod_min_clamp,
    lod_max_clamp: lod_max_clamp,
    compare: compare,
    max_anisotropy: max_anisotropy
  )
end

#create_shader_module(label: nil, code: nil, spirv: nil, compilation_hints: [], validate: false) ⇒ ShaderModule

Creates a shader module from WGSL or SPIR-V source.

Parameters:

  • (Object)

Returns:



237
238
239
240
241
242
243
244
245
246
# File 'lib/wgpu/core/device.rb', line 237

def create_shader_module(label: nil, code: nil, spirv: nil, compilation_hints: [], validate: false)
  ShaderModule.new(
    self,
    label: label,
    code: code,
    spirv: spirv,
    compilation_hints: compilation_hints,
    validate: validate
  )
end

#create_texture(label: nil, size:, format:, usage:, dimension: :d2, mip_level_count: 1, sample_count: 1, view_formats: []) ⇒ Texture

Creates a texture.

Parameters:

  • (Object)

Returns:



318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/wgpu/core/device.rb', line 318

def create_texture(label: nil, size:, format:, usage:, dimension: :d2, mip_level_count: 1, sample_count: 1, view_formats: [])
  Texture.new(self,
    label: label,
    size: size,
    format: format,
    usage: usage,
    dimension: dimension,
    mip_level_count: mip_level_count,
    sample_count: sample_count,
    view_formats: view_formats
  )
end

#destroyvoid

This method returns an undefined value.

Destroys device-owned native resources.



516
517
518
519
# File 'lib/wgpu/core/device.rb', line 516

def destroy
  return if @handle.null?
  Native.wgpuDeviceDestroy(@handle)
end

#featuresArray<Symbol>

Lists optional features enabled on the device.

Returns:

  • (Array<Symbol>)


390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/wgpu/core/device.rb', line 390

def features
  supported = Native::SupportedFeatures.new
  Native.wgpuDeviceGetFeatures(@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
ensure
  Native.wgpuSupportedFeaturesFreeMembers(supported) if supported
end

#has_feature?(feature) ⇒ Boolean

Reports whether a feature is enabled on the device.

Parameters:

  • feature (Symbol)

    feature name

  • (Symbol)

Returns:

  • (Boolean)


408
409
410
# File 'lib/wgpu/core/device.rb', line 408

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

#limitsHash{Symbol => Integer}

Returns resource limits supported by the device.

Returns:

  • (Hash{Symbol => Integer})


414
415
416
417
418
419
# File 'lib/wgpu/core/device.rb', line 414

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

#on_device_lost {|reason, message, arg0, arg1| ... } ⇒ Device

Registers the handler invoked when the device is lost.

Yields:

Yield Parameters:

  • reason (Symbol)

    native device-lost reason

  • message (String)

    native diagnostic message

  • arg0 (Symbol)
  • arg1 (String)

Yield Returns:

  • (void)

Returns:

Raises:

  • (ArgumentError)

    if no block is provided



507
508
509
510
511
512
# File 'lib/wgpu/core/device.rb', line 507

def on_device_lost(&handler)
  raise ArgumentError, "on_device_lost requires a block" unless handler

  set_device_callback(:device_lost, handler)
  self
end

#on_uncaptured_error {|error, arg0| ... } ⇒ Device

Registers the handler for uncaptured GPU errors.

Yields:

Yield Parameters:

Yield Returns:

  • (void)

Returns:

Raises:

  • (ArgumentError)

    if no block is provided



495
496
497
498
499
500
# File 'lib/wgpu/core/device.rb', line 495

def on_uncaptured_error(&handler)
  raise ArgumentError, "on_uncaptured_error requires a block" unless handler

  set_device_callback(:uncaptured_error, handler)
  self
end

#poll(wait: false) ⇒ Integer

Processes device work, optionally waiting for queue progress.

Parameters:

  • wait (Boolean) (defaults to: false)

    whether to wait for submitted work

  • wait: (Boolean) (defaults to: false)

Returns:

  • (Integer)

    native poll status



424
425
426
427
428
429
430
431
# File 'lib/wgpu/core/device.rb', line 424

def poll(wait: false)
  if Native.device_poll_available?
    Native.wgpuDevicePoll(@handle, wait ? 1 : 0, nil)
  else
    @adapter&.instance&.process_events
    0
  end
end

#pop_error_scope(timeout: nil) ⇒ Hash

Pops the latest error scope and waits for its result.

Parameters:

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

    maximum wait time in seconds

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

Returns:

  • (Hash)

    native status, error type, and message



455
456
457
458
459
# File 'lib/wgpu/core/device.rb', line 455

def pop_error_scope(timeout: nil)
  timeout = AsyncWaiter.normalize_timeout(timeout)
  error_holder, future = begin_pop_error_scope
  wait_for_error_scope(error_holder, future, timeout: timeout)
end

#pop_error_scope_async(timeout: nil) ⇒ AsyncTask

Starts popping on the calling thread and waits for completion in a background task.

Parameters:

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

    maximum wait time in seconds

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

Returns:

  • (AsyncTask)

    task whose value is the error hash



465
466
467
468
469
# File 'lib/wgpu/core/device.rb', line 465

def pop_error_scope_async(timeout: nil)
  timeout = AsyncWaiter.normalize_timeout(timeout)
  error_holder, future = begin_pop_error_scope
  AsyncTask.new { wait_for_error_scope(error_holder, future, timeout: timeout) }
end

#pop_error_scope_typed(timeout: nil) ⇒ GPUError?

Pops the latest error scope as a typed error.

Parameters:

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

    maximum wait time in seconds

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

Returns:



474
475
476
# File 'lib/wgpu/core/device.rb', line 474

def pop_error_scope_typed(timeout: nil)
  GPUError.from_hash(pop_error_scope(timeout: timeout))
end

#push_error_scope(filter = :validation) ⇒ void

This method returns an undefined value.

Pushes a scope that captures matching GPU errors. Scopes belong to the pushing thread and serialize scoped work on this device. Pop on the same thread; do not wait here for another thread's scoped work.

Parameters:

  • filter (Symbol, Integer) (defaults to: :validation)

    error filter

  • (enum_value)


438
439
440
441
442
443
444
445
446
447
448
449
450
# File 'lib/wgpu/core/device.rb', line 438

def push_error_scope(filter = :validation)
  filter_value = Native::EnumHelper.coerce(Native::ErrorFilter, filter, name: "error filter")
  error_scope_monitor.enter
  begin
    ensure_not_released!
    Native.wgpuDevicePushErrorScope(@handle, filter_value)
    @error_scope_depth = (@error_scope_depth || 0) + 1
    @error_scope_owner = Thread.current
  rescue StandardError
    error_scope_monitor.exit
    raise
  end
end

#releasevoid

This method returns an undefined value.

Releases the default queue and native device handle.

Device callbacks remain alive until all derived wrappers and pending callback operations have also completed their native releases.

Calling this method more than once has no effect.



528
529
530
531
532
533
534
# File 'lib/wgpu/core/device.rb', line 528

def release
  @queue&.release
  return if @handle.null?
  Native.wgpuDeviceRelease(@handle)
  @handle = FFI::Pointer::NULL
  @device_callback_tokens = nil
end

#with_error_scope(filter = :validation) ⇒ Object

Runs a block inside an error scope and raises captured GPU errors.

Parameters:

  • filter (Symbol, Integer) (defaults to: :validation)

    error filter

Yield Returns:

  • (Object)

    block result

Returns:

  • (Object)

    block result

Raises:

  • (ArgumentError)


482
483
484
485
486
487
488
489
# File 'lib/wgpu/core/device.rb', line 482

def with_error_scope(filter = :validation)
  raise ArgumentError, "block is required" unless block_given?

  result = nil
  error = capture_error_scope(filter) { result = yield }
  GPUError.from_hash(error)&.raise!
  result
end