Class: WGPU::ShaderModule

Inherits:
Object
  • Object
show all
Includes:
NativeResource
Defined in:
lib/wgpu/pipeline/shader_module.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, code: nil, spirv: nil, compilation_hints: [], validate: false) ⇒ ShaderModule

Creates a shader module from WGSL, GLSL, or SPIR-V input.

Parameters:

  • device (Device)

    owning device

  • code (String, Array<Integer>, nil) (defaults to: nil)

    shader source or binary

  • spirv (String, Array<Integer>, nil) (defaults to: nil)

    explicit SPIR-V input

  • validate (Boolean) (defaults to: false)

    whether to fetch and raise compilation errors

Raises:

  • (ShaderError)

    if native validation, creation, or compilation 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
45
46
47
48
49
50
# File 'lib/wgpu/pipeline/shader_module.rb', line 13

def initialize(device, label: nil, code: nil, spirv: nil, compilation_hints: [], validate: false)
  @device = device
  @pointers = []
  @compilation_hints = compilation_hints
  source = select_source(code, spirv)

  source_ptr = build_shader_source(source, label: label)

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

  device.push_error_scope(:validation)
  @handle = Native.wgpuDeviceCreateShaderModule(device.handle, desc)
  error = device.pop_error_scope

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

  return unless validate

  begin
    validate_compilation!(label)
  rescue StandardError
    release
    raise
  end
end

Instance Attribute Details

#handleObject (readonly)

Returns the value of attribute handle.

Returns:

  • (Object)


5
6
7
# File 'lib/wgpu/pipeline/shader_module.rb', line 5

def handle
  @handle
end

Instance Method Details

#get_compilation_infoHash

Fetches compiler diagnostics for the shader.

Returns:

  • (Hash)

    request status and compilation messages

Raises:

  • (ShaderError)

    if the pinned native library cannot provide diagnostics



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
# File 'lib/wgpu/pipeline/shader_module.rb', line 55

def get_compilation_info
  unless Native.compilation_info_available?
    raise ShaderError,
      "Shader compilation info is not implemented by wgpu-native #{Native::Distribution::VERSION}"
  end

  result_holder = { done: false, status: nil, messages: [] }
  instance = @device.adapter&.instance

  callback_lifetime_release = device_callback_lifetime_lease
  callback_token = nil
  callback = FFI::Function.new(
    :void, [:uint32, :pointer, :pointer, :pointer]
  ) do |status, compilation_info_ptr, _userdata1, _userdata2|
    begin
      result_holder[:status] = Native::CompilationInfoRequestStatus[status]

      unless compilation_info_ptr.null?
        info = Native::CompilationInfo.new(compilation_info_ptr)
        count = info[:message_count]
        if count > 0 && !info[:messages].null?
          count.times do |i|
            msg_ptr = info[:messages] + (i * Native::CompilationMessage.size)
            msg = Native::CompilationMessage.new(msg_ptr)
            message_text = if msg[:message][:data] && !msg[:message][:data].null? && msg[:message][:length] > 0
                             msg[:message][:data].read_string(msg[:message][:length])
                           else
                             ""
                           end
            result_holder[:messages] << CompilationMessage.new(
              type: msg[:type],
              message: message_text,
              line_num: msg[:line_num],
              line_pos: msg[:line_pos],
              offset: msg[:offset],
              length: msg[:length]
            )
          end
        end
      end
      result_holder[:done] = true
    ensure
      CallbackKeepalive.release(self, callback_token)
      callback_lifetime_release.call
    end
  end

  callback_info = Native::CompilationInfoCallbackInfo.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(self, callback)
  future =
    begin
      Native.wgpuShaderModuleGetCompilationInfo(@handle, callback_info)
    rescue StandardError
      CallbackKeepalive.release(self, callback_token)
      callback_lifetime_release.call
      raise
    end
  AsyncWaiter.wait(status_holder: result_holder, instance: instance, device: @device, future: future)

  {
    status: result_holder[:status],
    messages: result_holder[:messages]
  }
end

#get_compilation_info_asyncAsyncTask

Fetches compiler diagnostics on a background task.

Returns:

  • (AsyncTask)

    task yielding compilation information



128
129
130
# File 'lib/wgpu/pipeline/shader_module.rb', line 128

def get_compilation_info_async
  AsyncTask.new { get_compilation_info }
end

#releasevoid

This method returns an undefined value.

Releases the native shader module handle.

Calling this method more than once has no effect.



136
137
138
139
140
# File 'lib/wgpu/pipeline/shader_module.rb', line 136

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