Class: WGPU::Buffer

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

Constant Summary

Constants included from NativeResource

NativeResource::GUARDED_METHOD_EXEMPTIONS

Instance Attribute Summary collapse

Attributes included from NativeResource

#label

Instance Method Summary collapse

Methods included from NativeResource

included, #inspect, #released?, #use

Constructor Details

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

Creates a GPU buffer with the requested size and usage.

Parameters:

  • device (Device)

    owning device

  • size (Integer)

    buffer size in bytes

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

    usage flags

  • mapped_at_creation (Boolean) (defaults to: false)

    whether to expose an initial mapped range

Raises:

  • (BufferError)

    if native validation or creation fails



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/wgpu/resources/buffer.rb', line 13

def initialize(device, label: nil, size:, usage:, mapped_at_creation: false)
  @device = device
  @size = size
  @usage =
    begin
      normalize_usage(usage)
    rescue ArgumentError => e
      raise ArgumentError, buffer_error_message(e.message, label)
    end
  @mapped = mapped_at_creation
  @map_state = mapped_at_creation ? :mapped : :unmapped
  @map_generation = 0
  @map_state_mutex = Mutex.new

  desc, keepalive = build_descriptor(
    label:,
    size:,
    usage: @usage,
    mapped_at_creation:
  )
  @descriptor_keepalive = keepalive

  device.push_error_scope(:validation)
  @handle = Native.wgpuDeviceCreateBuffer(device.handle, desc)
  error = device.pop_error_scope
  @descriptor_keepalive = nil

  if @handle.null? || (error[:type] && error[:type] != :no_error)
    msg = error[:message] || "Failed to create buffer"
    raise BufferError, buffer_error_message(msg, label)
  end
end

Instance Attribute Details

#handleObject (readonly)

Returns the value of attribute handle.

Returns:

  • (Object)


5
6
7
# File 'lib/wgpu/resources/buffer.rb', line 5

def handle
  @handle
end

#sizeInteger (readonly)

Returns the value of attribute size.

Returns:

  • (Integer)


5
6
7
# File 'lib/wgpu/resources/buffer.rb', line 5

def size
  @size
end

#usageInteger (readonly)

Returns the value of attribute usage.

Returns:

  • (Integer)


5
6
7
# File 'lib/wgpu/resources/buffer.rb', line 5

def usage
  @usage
end

Instance Method Details

#destroyvoid

This method returns an undefined value.

Destroys the buffer's storage.



230
231
232
233
# File 'lib/wgpu/resources/buffer.rb', line 230

def destroy
  Native.wgpuBufferDestroy(@handle)
  invalidate_map_state
end

#get_mapped_range(offset: 0, size: nil) ⇒ BufferMappedRange

Returns a writable view of a mapped byte range.

Parameters:

  • offset: (Integer) (defaults to: 0)
  • size: (Integer, nil) (defaults to: nil)

Returns:



74
75
76
# File 'lib/wgpu/resources/buffer.rb', line 74

def get_mapped_range(offset: 0, size: nil)
  mapped_range(offset: offset, size: size)
end

#map_async(mode, offset: 0, size: nil) ⇒ AsyncTask

Maps a range on a background task.

Parameters:

  • mode (Symbol, Integer)

    map access mode

  • (enum_value)
  • offset: (Integer) (defaults to: 0)
  • size: (Integer, nil) (defaults to: nil)

Returns:

  • (AsyncTask)

    task yielding true when mapped



104
105
106
107
108
109
110
111
# File 'lib/wgpu/resources/buffer.rb', line 104

def map_async(mode, offset: 0, size: nil)
  status_holder, _callback_token, future, generation =
    begin_map_request(mode, offset: offset, size: size)
  AsyncTask.new do
    wait_for_map(status_holder, future)
    finalize_map(status_holder, generation)
  end
end

#map_stateSymbol

Returns the current mapping state.

Returns:

  • (Symbol)


222
223
224
225
226
# File 'lib/wgpu/resources/buffer.rb', line 222

def map_state
  return map_state_mutex.synchronize { @map_state } unless Native.buffer_map_state_available?

  Native.wgpuBufferGetMapState(@handle) || map_state_mutex.synchronize { @map_state }
end

#map_sync(mode, offset: 0, size: nil, timeout: nil) ⇒ Boolean

Maps a range and waits for native completion.

Parameters:

  • mode (Symbol, Integer)

    map access mode

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

    maximum wait time in seconds

  • (enum_value)
  • offset: (Integer) (defaults to: 0)
  • size: (Integer, nil) (defaults to: nil)
  • timeout: (Numeric, nil) (defaults to: nil)

Returns:

  • (Boolean)

    true when mapped

Raises:



94
95
96
97
98
99
# File 'lib/wgpu/resources/buffer.rb', line 94

def map_sync(mode, offset: 0, size: nil, timeout: nil)
  status_holder, _callback_token, future, generation =
    begin_map_request(mode, offset: offset, size: size)
  wait_for_map(status_holder, future, timeout:)
  finalize_map(status_holder, generation)
end

#mapped_range(offset: 0, size: nil) ⇒ BufferMappedRange

Returns a writable view of a mapped byte range.

Parameters:

  • offset: (Integer) (defaults to: 0)
  • size: (Integer, nil) (defaults to: nil)

Returns:

Raises:

  • (BufferError)

    if the buffer is not mapped or no range is available



61
62
63
64
65
66
67
68
69
70
# File 'lib/wgpu/resources/buffer.rb', line 61

def mapped_range(offset: 0, size: nil)
  raise BufferError, "Buffer is not mapped" unless @mapped

  size ||= @size - offset
  offset, size = validate_map_range!(offset, size)
  ptr = Native.wgpuBufferGetMappedRange(@handle, offset, size)
  raise BufferError, "Failed to get mapped range" if ptr.null?

  BufferMappedRange.new(ptr, size)
end

#read_mapped(offset: 0, size: nil, type: nil) ⇒ String, Array

Reads mapped bytes, optionally decoding typed values.

Parameters:

  • type (Symbol, nil) (defaults to: nil)

    element type, or nil for raw bytes

  • offset: (Integer) (defaults to: 0)
  • size: (Integer, nil) (defaults to: nil)
  • type: (Symbol, nil) (defaults to: nil)

Returns:

  • (String, Array)


130
131
132
133
# File 'lib/wgpu/resources/buffer.rb', line 130

def read_mapped(offset: 0, size: nil, type: nil)
  bytes = read_mapped_data(offset: offset, size: size)
  type ? DataTypes.unpack(bytes, type:) : bytes
end

#read_mapped_data(offset: 0, size: nil) ⇒ String

Copies bytes from a const mapped range.

Parameters:

  • offset: (Integer) (defaults to: 0)
  • size: (Integer, nil) (defaults to: nil)

Returns:

  • (String)

    mapped bytes

Raises:



116
117
118
119
120
121
122
123
124
125
# File 'lib/wgpu/resources/buffer.rb', line 116

def read_mapped_data(offset: 0, size: nil)
  raise BufferError, "Buffer is not mapped" unless @mapped

  size ||= @size - offset
  offset, size = validate_map_range!(offset, size)
  ptr = Native.wgpuBufferGetConstMappedRange(@handle, offset, size)
  raise BufferError, "Failed to get mapped range" if ptr.null?

  ptr.read_bytes(size)
end

#read_mapped_float64s(offset: 0, count: nil) ⇒ Array<Float>

Reads mapped bytes as 64-bit floating-point values.

Parameters:

  • offset (Integer) (defaults to: 0)

    byte offset in the buffer

  • count (Integer, nil) (defaults to: nil)

    values to read; defaults to the remaining range

  • offset: (Integer) (defaults to: 0)
  • count: (Integer, nil) (defaults to: nil)

Returns:

  • (Array<Float>)

    decoded values

Raises:



186
187
188
# File 'lib/wgpu/resources/buffer.rb', line 186

def read_mapped_float64s(offset: 0, count: nil)
  read_mapped_values(type: :f64, offset:, count:)
end

#read_mapped_floats(offset: 0, count: nil) ⇒ Array<Float>

Reads mapped bytes as 32-bit floating-point values.

Parameters:

  • offset (Integer) (defaults to: 0)

    byte offset in the buffer

  • count (Integer, nil) (defaults to: nil)

    values to read; defaults to the remaining range

  • offset: (Integer) (defaults to: 0)
  • count: (Integer, nil) (defaults to: nil)

Returns:

  • (Array<Float>)

    decoded values

Raises:



156
157
158
# File 'lib/wgpu/resources/buffer.rb', line 156

def read_mapped_floats(offset: 0, count: nil)
  read_mapped_values(type: :f32, offset:, count:)
end

#read_mapped_int32s(offset: 0, count: nil) ⇒ Array<Integer>

Reads mapped bytes as signed 32-bit integers.

Parameters:

  • offset (Integer) (defaults to: 0)

    byte offset in the buffer

  • count (Integer, nil) (defaults to: nil)

    values to read; defaults to the remaining range

  • offset: (Integer) (defaults to: 0)
  • count: (Integer, nil) (defaults to: nil)

Returns:

  • (Array<Integer>)

    decoded values

Raises:



176
177
178
# File 'lib/wgpu/resources/buffer.rb', line 176

def read_mapped_int32s(offset: 0, count: nil)
  read_mapped_values(type: :i32, offset:, count:)
end

#read_mapped_uint16s(offset: 0, count: nil) ⇒ Array<Integer>

Reads mapped bytes as unsigned 16-bit integers.

Parameters:

  • offset (Integer) (defaults to: 0)

    byte offset in the buffer

  • count (Integer, nil) (defaults to: nil)

    values to read; defaults to the remaining range

  • offset: (Integer) (defaults to: 0)
  • count: (Integer, nil) (defaults to: nil)

Returns:

  • (Array<Integer>)

    decoded values

Raises:



196
197
198
# File 'lib/wgpu/resources/buffer.rb', line 196

def read_mapped_uint16s(offset: 0, count: nil)
  read_mapped_values(type: :u16, offset:, count:)
end

#read_mapped_uint32s(offset: 0, count: nil) ⇒ Array<Integer>

Reads mapped bytes as unsigned 32-bit integers.

Parameters:

  • offset (Integer) (defaults to: 0)

    byte offset in the buffer

  • count (Integer, nil) (defaults to: nil)

    values to read; defaults to the remaining range

  • offset: (Integer) (defaults to: 0)
  • count: (Integer, nil) (defaults to: nil)

Returns:

  • (Array<Integer>)

    decoded values

Raises:



166
167
168
# File 'lib/wgpu/resources/buffer.rb', line 166

def read_mapped_uint32s(offset: 0, count: nil)
  read_mapped_values(type: :u32, offset:, count:)
end

#read_mapped_uint8s(offset: 0, count: nil) ⇒ Array<Integer>

Reads mapped bytes as unsigned 8-bit integers.

Parameters:

  • offset (Integer) (defaults to: 0)

    byte offset in the buffer

  • count (Integer, nil) (defaults to: nil)

    values to read; defaults to the remaining range

  • offset: (Integer) (defaults to: 0)
  • count: (Integer, nil) (defaults to: nil)

Returns:

  • (Array<Integer>)

    decoded values

Raises:



206
207
208
# File 'lib/wgpu/resources/buffer.rb', line 206

def read_mapped_uint8s(offset: 0, count: nil)
  read_mapped_values(type: :u8, offset:, count:)
end

#read_mapped_values(type: :f32, offset: 0, count: nil) ⇒ Array

Reads mapped values of the requested element type.

Parameters:

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

    element type

  • count (Integer, nil) (defaults to: nil)

    number of values

  • type: (Symbol) (defaults to: :f32)
  • offset: (Integer) (defaults to: 0)
  • count: (Integer, nil) (defaults to: nil)

Returns:

  • (Array)


214
215
216
217
218
# File 'lib/wgpu/resources/buffer.rb', line 214

def read_mapped_values(type: :f32, offset: 0, count: nil)
  element_size = DataTypes.byte_size(type)
  size = count ? count * element_size : @size - offset
  DataTypes.unpack(read_mapped_data(offset:, size:), type:)
end

#releasevoid

This method returns an undefined value.

Releases the native buffer handle.

Calling this method more than once has no effect.



239
240
241
242
243
244
# File 'lib/wgpu/resources/buffer.rb', line 239

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

#unmapvoid

This method returns an undefined value.

Unmaps the buffer and invalidates its mapped ranges.



80
81
82
83
84
85
86
87
# File 'lib/wgpu/resources/buffer.rb', line 80

def unmap
  Native.wgpuBufferUnmap(@handle)
  map_state_mutex.synchronize do
    @map_generation = current_map_generation + 1
    @mapped = false
    @map_state = :unmapped
  end
end

#write(data, offset: 0, type: :f32) ⇒ void

This method returns an undefined value.

Writes typed data through the device's default queue.

Parameters:

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

    source data

  • offset (Integer) (defaults to: 0)

    destination byte offset

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

    source element type

  • (data)
  • offset: (Integer) (defaults to: 0)
  • type: (Symbol) (defaults to: :f32)


51
52
53
54
55
56
# File 'lib/wgpu/resources/buffer.rb', line 51

def write(data, offset: 0, type: :f32)
  ptr, byte_size = DataTypes.to_pointer(data, type:)
  DataTypes.validate_alignment!(offset, 4, name: "offset")
  DataTypes.validate_alignment!(byte_size, 4, name: "data size")
  Native.wgpuQueueWriteBuffer(@device.queue.handle, @handle, offset, ptr, byte_size)
end

#write_mapped(data, offset: 0, type: :f32) ⇒ void

This method returns an undefined value.

Writes typed data into a mapped range.

Parameters:

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

    source data

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

    source element type

  • (data)
  • offset: (Integer) (defaults to: 0)
  • type: (Symbol) (defaults to: :f32)

Raises:



139
140
141
142
143
144
145
146
147
148
# File 'lib/wgpu/resources/buffer.rb', line 139

def write_mapped(data, offset: 0, type: :f32)
  raise BufferError, "Buffer is not mapped" unless @mapped

  ptr, byte_size = DataTypes.to_pointer(data, type:)
  offset, byte_size = validate_map_range!(offset, byte_size)
  target = Native.wgpuBufferGetMappedRange(@handle, offset, byte_size)
  raise BufferError, "Failed to get mapped range" if target.null?

  target.put_bytes(0, ptr.read_bytes(byte_size))
end