mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-08-24 02:34:23 -05:00
594 lines
27 KiB
Swift
594 lines
27 KiB
Swift
/******************************************************************************
|
|
Copyright (C) 2024 by Patrick Heyer <PatTheMav@users.noreply.github.com>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
******************************************************************************/
|
|
|
|
import Foundation
|
|
import Metal
|
|
|
|
private typealias ParserError = MetalError.OBSShaderParserError
|
|
private typealias ShaderError = MetalError.OBSShaderError
|
|
private typealias MetalShaderError = MetalError.MetalShaderError
|
|
|
|
/// Creates a ``MetalShader`` instance from the given shader string for use as a vertex shader.
|
|
/// - Parameters:
|
|
/// - device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
|
|
/// - shader: C character pointer with the contents of the `libobs` effect file
|
|
/// - file: C character pointer with the contents of the `libobs` effect file location
|
|
/// - error_string: Pointer for another C character pointer with the contents of an error description
|
|
/// - Returns: Opaque pointer to a new ``MetalShader`` instance on success or `nil` on error
|
|
///
|
|
/// The string pointed to by the `data` argument is a re-compiled shader string created from the associated "effect"
|
|
/// file (which will contain multiple effects). Each effect is made up of several passes (though usually only a single
|
|
/// pass is defined), each of which contains a vertex and fragment shader. This function is then called with just the
|
|
/// vertex shader string.
|
|
///
|
|
/// This vertex shader string needs to be parsed again and transpiled into a Metal shader string, which is handled by
|
|
/// the ``OBSShader`` class. The transpiled string is then used to create the actual ``MetalShader`` instance.
|
|
@_cdecl("device_vertexshader_create")
|
|
public func device_vertexshader_create(
|
|
device: UnsafeRawPointer, shader: UnsafePointer<CChar>, file: UnsafePointer<CChar>,
|
|
error_string: UnsafeMutablePointer<UnsafeMutablePointer<CChar>>
|
|
) -> OpaquePointer? {
|
|
let device: MetalDevice = unretained(device)
|
|
|
|
let content = String(cString: shader)
|
|
let fileLocation = String(cString: file)
|
|
|
|
do {
|
|
let obsShader = try OBSShader(type: .vertex, content: content, fileLocation: fileLocation)
|
|
let transpiled = try obsShader.transpiled()
|
|
|
|
guard let metaData = obsShader.metaData else {
|
|
OBSLog(.error, "device_vertexshader_create: No required metadata found for transpiled shader")
|
|
return nil
|
|
}
|
|
|
|
let metalShader = try MetalShader(device: device, source: transpiled, type: .vertex, data: metaData)
|
|
|
|
return metalShader.getRetained()
|
|
} catch let error as ParserError {
|
|
switch error {
|
|
case .parseFail(let description):
|
|
OBSLog(.error, "device_vertexshader_create: Error parsing shader.\n\(description)")
|
|
default:
|
|
OBSLog(.error, "device_vertexshader_create: Error parsing shader.\n\(error.description)")
|
|
}
|
|
} catch let error as ShaderError {
|
|
switch error {
|
|
case .transpileError(let description):
|
|
OBSLog(.error, "device_vertexshader_create: Error transpiling shader.\n\(description)")
|
|
case .parseError(let description):
|
|
OBSLog(.error, "device_vertexshader_create: OBS parser error.\n\(description)")
|
|
case .parseFail(let description):
|
|
OBSLog(.error, "device_vertexshader_create: OBS parser failure.\n\(description)")
|
|
default:
|
|
OBSLog(.error, "device_vertexshader_create: OBS shader error.\n\(error.description)")
|
|
}
|
|
} catch {
|
|
switch error {
|
|
case let error as MetalShaderError:
|
|
OBSLog(.error, "device_vertexshader_create: Error compiling shader.\n\(error.description)")
|
|
case let error as MetalError.MTLDeviceError:
|
|
OBSLog(.error, "device_vertexshader_create: Device error compiling shader.\n\(error.description)")
|
|
default:
|
|
OBSLog(.error, "device_vertexshader_create: Unknown error occurred")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/// Creates a ``MetalShader`` instance from the given shader string for use as a fragment shader.
|
|
/// - Parameters:
|
|
/// - device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
|
|
/// - shader: C character pointer with the contents of the `libobs` effect file
|
|
/// - file: C character pointer with the contents of the `libobs` effect file location
|
|
/// - error_string: Pointer for another C character pointer with the contents of an error description
|
|
/// - Returns: Opaque pointer to a new ``MetalShader`` instance on success or `nil` on error
|
|
///
|
|
/// The string pointed to by the `data` argument is a re-compiled shader string created from the associated "effect"
|
|
/// file (which will contain multiple effects). Each effect is made up of several passes (though usually only a single
|
|
/// pass is defined), each of which contains a vertex and fragment shader. This function is then called with just the
|
|
/// vertex shader string.
|
|
///
|
|
/// This fragment shader string needs to be parsed again and transpiled into a Metal shader string, which is handled by
|
|
/// the ``OBSShader`` class. The transpiled string is then used to create the actual ``MetalShader`` instance.
|
|
@_cdecl("device_pixelshader_create")
|
|
public func device_pixelshader_create(
|
|
device: UnsafeRawPointer, shader: UnsafePointer<CChar>, file: UnsafePointer<CChar>,
|
|
error_string: UnsafeMutablePointer<UnsafeMutablePointer<CChar>>
|
|
) -> OpaquePointer? {
|
|
let device: MetalDevice = unretained(device)
|
|
|
|
let content = String(cString: shader)
|
|
let fileLocation = String(cString: file)
|
|
|
|
do {
|
|
let obsShader = try OBSShader(type: .fragment, content: content, fileLocation: fileLocation)
|
|
let transpiled = try obsShader.transpiled()
|
|
|
|
guard let metaData = obsShader.metaData else {
|
|
OBSLog(.error, "device_pixelshader_create: No required metadata found for transpiled shader")
|
|
return nil
|
|
}
|
|
|
|
let metalShader = try MetalShader(device: device, source: transpiled, type: .fragment, data: metaData)
|
|
|
|
return metalShader.getRetained()
|
|
} catch let error as ParserError {
|
|
switch error {
|
|
case .parseFail(let description):
|
|
OBSLog(.error, "device_vertexshader_create: Error parsing shader.\n\(description)")
|
|
default:
|
|
OBSLog(.error, "device_vertexshader_create: Error parsing shader.\n\(error.description)")
|
|
}
|
|
} catch let error as ShaderError {
|
|
switch error {
|
|
case .transpileError(let description):
|
|
OBSLog(.error, "device_vertexshader_create: Error transpiling shader.\n\(description)")
|
|
case .parseError(let description):
|
|
OBSLog(.error, "device_vertexshader_create: OBS parser error.\n\(description)")
|
|
case .parseFail(let description):
|
|
OBSLog(.error, "device_vertexshader_create: OBS parser failure.\n\(description)")
|
|
default:
|
|
OBSLog(.error, "device_vertexshader_create: OBS shader error.\n\(error.description)")
|
|
}
|
|
} catch {
|
|
switch error {
|
|
case let error as MetalShaderError:
|
|
OBSLog(.error, "device_vertexshader_create: Error compiling shader.\n\(error.description)")
|
|
case let error as MetalError.MTLDeviceError:
|
|
OBSLog(.error, "device_vertexshader_create: Device error compiling shader.\n\(error.description)")
|
|
default:
|
|
OBSLog(.error, "device_vertexshader_create: Unknown error occurred")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/// Loads the ``MetalShader`` instance for use as the vertex shader for the current render pipeline descriptor.
|
|
/// - Parameters:
|
|
/// - device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
|
|
/// - vertShader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
///
|
|
/// This function will simply set up the ``MTLFunction`` wrapped by the ``MetalShader`` instance as the current
|
|
/// pipeline descriptor's `vertexFunction`. The Metal renderer will lazily create new render pipeline states for each
|
|
/// permutation of pipeline descriptors, which is a comparatively costly operation but will only occur once for any
|
|
/// such permutation.
|
|
///
|
|
/// > Note: If a `NULL` pointer is passed for the `vertShader` argument, the vertex function on the current render
|
|
/// pipeline descriptor will be _unset_.
|
|
///
|
|
@_cdecl("device_load_vertexshader")
|
|
public func device_load_vertexshader(device: UnsafeRawPointer, vertShader: UnsafeRawPointer?) {
|
|
let device: MetalDevice = unretained(device)
|
|
|
|
if let vertShader {
|
|
let shader: MetalShader = unretained(vertShader)
|
|
|
|
guard shader.type == .vertex else {
|
|
assertionFailure("device_load_vertexshader: Invalid shader type \(shader.type)")
|
|
return
|
|
}
|
|
|
|
device.renderState.vertexShader = shader
|
|
device.renderState.pipelineDescriptor.vertexFunction = shader.function
|
|
device.renderState.pipelineDescriptor.vertexDescriptor = shader.vertexDescriptor
|
|
} else {
|
|
device.renderState.vertexShader = nil
|
|
device.renderState.pipelineDescriptor.vertexFunction = nil
|
|
device.renderState.pipelineDescriptor.vertexDescriptor = nil
|
|
}
|
|
}
|
|
|
|
/// Loads the ``MetalShader`` instance for use as the fragment shader for the current render pipeline descriptor.
|
|
/// - Parameters:
|
|
/// - device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
|
|
/// - vertShader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
///
|
|
/// This function will simply set up the ``MTLFunction`` wrapped by the ``MetalShader`` instance as the current
|
|
/// pipeline descriptor's `fragmentFunction`. The Metal renderer will lazily create new render pipeline states for
|
|
/// each permutation of pipeline descriptors, which is a comparatively costly operation but will only occur once for
|
|
/// any such permutation.
|
|
///
|
|
/// As any fragment function is potentially associated with a number of textures and associated sampler states, the
|
|
/// associated arrays are reset whenever a new fragment function is set up.
|
|
///
|
|
/// > Note: If a `NULL` pointer is passed for the `pixelShader` argument, the fragment function on the current render
|
|
/// pipeline descriptor will be _unset_.
|
|
///
|
|
@_cdecl("device_load_pixelshader")
|
|
public func device_load_pixelshader(device: UnsafeRawPointer, pixelShader: UnsafeRawPointer?) {
|
|
let device: MetalDevice = unretained(device)
|
|
|
|
for index in 0..<Int(GS_MAX_TEXTURES) {
|
|
device.renderState.textures[index] = nil
|
|
device.renderState.samplers[index] = nil
|
|
}
|
|
|
|
if let pixelShader {
|
|
let shader: MetalShader = unretained(pixelShader)
|
|
|
|
guard shader.type == .fragment else {
|
|
assertionFailure("device_load_pixelshader: Invalid shader type \(shader.type)")
|
|
return
|
|
}
|
|
|
|
device.renderState.fragmentShader = shader
|
|
device.renderState.pipelineDescriptor.fragmentFunction = shader.function
|
|
|
|
if let samplers = shader.samplers {
|
|
device.renderState.samplers.replaceSubrange(0..<samplers.count, with: samplers)
|
|
}
|
|
} else {
|
|
device.renderState.pipelineDescriptor.fragmentFunction = nil
|
|
}
|
|
}
|
|
|
|
/// Gets the ``MetalShader`` set up as the current vertex shader for the pipeline
|
|
/// - Parameter device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
|
|
/// - Returns: Opaque pointer to ``MetalShader`` instance if a vertex shader is currently set up or `nil` otherwise
|
|
@_cdecl("device_get_vertex_shader")
|
|
public func device_get_vertex_shader(device: UnsafeRawPointer) -> OpaquePointer? {
|
|
let device: MetalDevice = unretained(device)
|
|
|
|
if let shader = device.renderState.vertexShader {
|
|
return shader.getUnretained()
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/// Gets the ``MetalShader`` set up as the current fragment shader for the pipeline
|
|
/// - Parameter device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
|
|
/// - Returns: Opaque pointer to ``MetalShader`` instance if a fragment shader is currently set up or `nil` otherwise
|
|
@_cdecl("device_get_pixel_shader")
|
|
public func device_get_pixel_shader(device: UnsafeRawPointer) -> OpaquePointer? {
|
|
let device: MetalDevice = unretained(device)
|
|
|
|
if let shader = device.renderState.fragmentShader {
|
|
return shader.getUnretained()
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
/// Requests the deinitialization of the ``MetalShader`` instance shared with `libobs`
|
|
/// - Parameter shader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
///
|
|
/// Ownership of the ``MetalShader`` instance will be transferred into the function and if this was the last strong
|
|
/// reference to it, the object will be automatically deinitialized and deallocated by Swift.
|
|
@_cdecl("gs_shader_destroy")
|
|
public func gs_shader_destroy(shader: UnsafeRawPointer) {
|
|
let _ = retained(shader) as MetalShader
|
|
}
|
|
|
|
/// Gets the number of uniform parameters used on the ``MetalShader``
|
|
/// - Parameter shader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
/// - Returns: Number of uniforms
|
|
@_cdecl("gs_shader_get_num_params")
|
|
public func gs_shader_get_num_params(shader: UnsafeRawPointer) -> UInt32 {
|
|
let shader: MetalShader = unretained(shader)
|
|
|
|
return UInt32(shader.uniforms.count)
|
|
}
|
|
|
|
/// Gets a uniform parameter from the ``MetalShader`` by its array index
|
|
/// - Parameters:
|
|
/// - shader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
/// - param: Array index of uniform parameter to get
|
|
/// - Returns: Opaque pointer to a ``ShaderUniform`` instance if index within uniform array bounds or `nil` otherwise
|
|
///
|
|
/// This function requires that the array indices of the uniforms array do not change for a ``MetalShader`` and also
|
|
/// that the exact order of uniforms is identical between `libobs`'s interpretation of the effects file and the
|
|
/// transpiled shader's analysis of the uniforms.
|
|
///
|
|
/// > Important: The opaque pointer for the ``ShaderUniform`` instance is passe unretained and as such can become
|
|
/// invalid when its owning ``MetalShader`` instance either is deinitialized itself or is replaced in the uniforms
|
|
/// array.
|
|
@_cdecl("gs_shader_get_param_by_idx")
|
|
public func gs_shader_get_param_by_idx(shader: UnsafeRawPointer, param: UInt32) -> OpaquePointer? {
|
|
let shader: MetalShader = unretained(shader)
|
|
|
|
guard param < shader.uniforms.count else {
|
|
return nil
|
|
}
|
|
|
|
let uniform = shader.uniforms[Int(param)]
|
|
let unretained = Unmanaged.passUnretained(uniform).toOpaque()
|
|
|
|
return OpaquePointer(unretained)
|
|
}
|
|
|
|
/// Gets a uniform parameter from the ``MetalShader`` by its name
|
|
/// - Parameters:
|
|
/// - shader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
/// - param: C character array pointer with the name of the requested uniform parameter
|
|
/// - Returns: Opaque pointer to a ``ShaderUniform`` instance if any uniform with the provided name was found or `nil`
|
|
/// otherwise
|
|
///
|
|
/// > Important: The opaque pointer for the ``ShaderUniform`` instance is passe unretained and as such can become
|
|
/// invalid when its owning ``MetalShader`` instance either is deinitialized itself or is replaced in the uniforms
|
|
/// array.
|
|
///
|
|
@_cdecl("gs_shader_get_param_by_name")
|
|
public func gs_shader_get_param_by_name(shader: UnsafeRawPointer, param: UnsafeMutablePointer<CChar>) -> OpaquePointer?
|
|
{
|
|
let shader: MetalShader = unretained(shader)
|
|
|
|
let paramName = String(cString: param)
|
|
|
|
for uniform in shader.uniforms {
|
|
if uniform.name == paramName {
|
|
let unretained = Unmanaged.passUnretained(uniform).toOpaque()
|
|
return OpaquePointer(unretained)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/// Gets the uniform parameter associated with the view projection matrix used by the ``MetalShader``
|
|
/// - Parameter shader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
/// - Returns: Opaque pointer to a ``ShaderUniform`` instance if a uniform for the view projection matrix was found
|
|
/// or `nil` otherwise
|
|
///
|
|
/// The uniform for the view projection matrix has the associated name `viewProj` in the Metal renderer, thus a
|
|
/// name-based lookup is used to find the associated ``ShaderUniform`` instance.
|
|
///
|
|
/// > Important: The opaque pointer for the ``ShaderUniform`` instance is passe unretained and as such can become
|
|
/// invalid when its owning ``MetalShader`` instance either is deinitialized itself or is replaced in the uniforms
|
|
/// array.
|
|
///
|
|
@_cdecl("gs_shader_get_viewproj_matrix")
|
|
public func gs_shader_get_viewproj_matrix(shader: UnsafeRawPointer) -> OpaquePointer? {
|
|
let shader: MetalShader = unretained(shader)
|
|
let paramName = "viewProj"
|
|
|
|
for uniform in shader.uniforms {
|
|
if uniform.name == paramName {
|
|
let unretained = Unmanaged.passUnretained(uniform).toOpaque()
|
|
return OpaquePointer(unretained)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/// Gets the uniform parameter associated with the world projection matrix used by the ``MetalShader``
|
|
/// - Parameter shader: Opaque pointer to ``MetalShader`` instance shared with `libobs`
|
|
/// - Returns: Opaque pointer to a ``ShaderUniform`` instance if a uniform for the world projection matrix was found
|
|
/// or `nil` otherwise
|
|
///
|
|
/// The uniform for the view projection matrix has the associated name `worldProj` in the Metal renderer, thus a
|
|
/// name-based lookup is used to find the associated ``ShaderUniform`` instance.
|
|
///
|
|
/// > Important: The opaque pointer for the ``ShaderUniform`` instance is passe unretained and as such can become
|
|
/// invalid when its owning ``MetalShader`` instance either is deinitialized itself or is replaced in the uniforms
|
|
/// array.
|
|
@_cdecl("gs_shader_get_world_matrix")
|
|
public func gs_shader_get_world_matrix(shader: UnsafeRawPointer) -> OpaquePointer? {
|
|
let shader: MetalShader = unretained(shader)
|
|
let paramName = "worldProj"
|
|
|
|
for uniform in shader.uniforms {
|
|
if uniform.name == paramName {
|
|
let unretained = Unmanaged.passUnretained(uniform).toOpaque()
|
|
return OpaquePointer(unretained)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
/// Gets the name and uniform type from the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - info: Pointer to a `gs_shader_param_info` struct pre-allocated by `libobs`
|
|
///
|
|
/// > Warning: The C character array pointer holding the name of the uniform is managed by Swift and might become
|
|
/// invalid at any point in time.
|
|
@_cdecl("gs_shader_get_param_info")
|
|
public func gs_shader_get_param_info(shaderParam: UnsafeRawPointer, info: UnsafeMutablePointer<gs_shader_param_info>) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
shaderUniform.name.withCString {
|
|
info.pointee.name = $0
|
|
}
|
|
info.pointee.type = shaderUniform.gsType
|
|
}
|
|
|
|
/// Sets a boolean value on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: Boolean value to set for the uniform
|
|
@_cdecl("gs_shader_set_bool")
|
|
public func gs_shader_set_bool(shaderParam: UnsafeRawPointer, val: Bool) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
withUnsafePointer(to: val) {
|
|
shaderUniform.setParameter(data: $0, size: MemoryLayout<Int32>.size)
|
|
}
|
|
}
|
|
|
|
/// Sets a 32-bit floating point value on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: 32-bit floating point value to set for the uniform
|
|
@_cdecl("gs_shader_set_float")
|
|
public func gs_shader_set_float(shaderParam: UnsafeRawPointer, val: Float32) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
withUnsafePointer(to: val) {
|
|
shaderUniform.setParameter(data: $0, size: MemoryLayout<Float32>.size)
|
|
}
|
|
}
|
|
|
|
/// Sets a 32-bit signed integer value on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: 32-bit signed integer value to set for the uniform
|
|
@_cdecl("gs_shader_set_int")
|
|
public func gs_shader_set_int(shaderParam: UnsafeRawPointer, val: Int32) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
withUnsafePointer(to: val) {
|
|
shaderUniform.setParameter(data: $0, size: MemoryLayout<Int32>.size)
|
|
}
|
|
}
|
|
|
|
/// Sets a 3x3 matrix of 32-bit floating point values on the ``ShaderUniform``instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: A 3x3 matrix of 32-bit floating point values
|
|
///
|
|
/// The 3x3 matrix is converted into a 4x4 matrix (padded with zeros) before actually being set as the uniform data
|
|
@_cdecl("gs_shader_set_matrix3")
|
|
public func gs_shader_set_matrix3(shaderParam: UnsafeRawPointer, val: UnsafePointer<matrix3>) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
var newMatrix = matrix4()
|
|
matrix4_from_matrix3(&newMatrix, val)
|
|
|
|
shaderUniform.setParameter(data: &newMatrix, size: MemoryLayout<matrix4>.size)
|
|
}
|
|
|
|
/// Sets a 4x4 matrix of 32-bit floating point values on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: A 4x4 matrix of 32-bit floating point values
|
|
@_cdecl("gs_shader_set_matrix4")
|
|
public func gs_shader_set_matrix4(shaderParam: UnsafeRawPointer, val: UnsafePointer<matrix4>) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
shaderUniform.setParameter(data: val, size: MemoryLayout<matrix4>.size)
|
|
}
|
|
|
|
/// Sets a vector of 2 32-bit floating point values on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: A vector of 2 32-bit floating point values
|
|
@_cdecl("gs_shader_set_vec2")
|
|
public func gs_shader_set_vec2(shaderParam: UnsafeRawPointer, val: UnsafePointer<vec2>) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
shaderUniform.setParameter(data: val, size: MemoryLayout<vec2>.size)
|
|
}
|
|
|
|
/// Sets a vector of 3 32-bit floating point values on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: A vector of 3 32-bit floating point values
|
|
@_cdecl("gs_shader_set_vec3")
|
|
public func gs_shader_set_vec3(shaderParam: UnsafeRawPointer, val: UnsafePointer<vec3>) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
shaderUniform.setParameter(data: val, size: MemoryLayout<vec3>.size)
|
|
}
|
|
|
|
/// Sets a vector of 4 32-bit floating point values on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: A vector of 4 32-bit floating point values
|
|
@_cdecl("gs_shader_set_vec4")
|
|
public func gs_shader_set_vec4(shaderParam: UnsafeRawPointer, val: UnsafePointer<vec4>) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
shaderUniform.setParameter(data: val, size: MemoryLayout<vec4>.size)
|
|
}
|
|
|
|
/// Sets up the data of a `gs_shader_texture` struct as a uniform on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: A pointer to a `gs_shader_struct` containing an opaque pointer to the actual ``MetalTexture`` instance
|
|
/// and an sRGB gamma state flag
|
|
///
|
|
/// The struct's data is copied verbatim into the uniform, which allows reconstruction of the pointer at a later point
|
|
/// as long as the actual ``MetalTexture`` instance still exists.
|
|
@_cdecl("gs_shader_set_texture")
|
|
public func gs_shader_set_texture(shaderParam: UnsafeRawPointer, val: UnsafePointer<gs_shader_texture>?) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
if let val {
|
|
shaderUniform.setParameter(data: val, size: MemoryLayout<gs_shader_texture>.size)
|
|
}
|
|
}
|
|
|
|
/// Sets an arbitrary value on the ``ShaderUniform`` instance
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - val: Opaque pointer to some unknown data for use as the uniform
|
|
/// - size: The size of the data available at the memory pointed to by the `val` argument
|
|
///
|
|
/// The ``ShaderUniform`` itself is set up to hold a specific uniform type, each of which is associated with a size of
|
|
/// bytes required for it. If the size of the data pointed to by `val` does not fit into this size, the uniform will
|
|
/// not be updated.
|
|
///
|
|
/// If the ``ShaderUniform`` expects a texture parameter, the pointer will be bound as memory of a `gs_shader_texture`
|
|
/// instance before setting it up.
|
|
@_cdecl("gs_shader_set_val")
|
|
public func gs_shader_set_val(shaderParam: UnsafeRawPointer, val: UnsafeRawPointer, size: UInt32) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
let size = Int(size)
|
|
let valueSize = shaderUniform.gsType.size
|
|
|
|
guard valueSize == size else {
|
|
assertionFailure("gs_shader_set_val: Required size of uniform does not match size of input")
|
|
return
|
|
}
|
|
|
|
if shaderUniform.gsType == GS_SHADER_PARAM_TEXTURE {
|
|
let shaderTexture = val.bindMemory(to: gs_shader_texture.self, capacity: 1)
|
|
|
|
shaderUniform.setParameter(data: shaderTexture, size: valueSize)
|
|
} else {
|
|
let bytes = val.bindMemory(to: UInt8.self, capacity: valueSize)
|
|
shaderUniform.setParameter(data: bytes, size: valueSize)
|
|
}
|
|
}
|
|
|
|
/// Resets the ``ShaderUniform``'s current data with its default data
|
|
/// - Parameter shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
///
|
|
/// Each ``ShaderUniform`` is optionally set up with a set of default data (stored as an array of bytes) which is
|
|
/// simply copied into the current values.
|
|
@_cdecl("gs_shader_set_default")
|
|
public func gs_shader_set_default(shaderParam: UnsafeRawPointer) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
if let defaultValues = shaderUniform.defaultValues {
|
|
shaderUniform.currentValues = Array(defaultValues)
|
|
}
|
|
}
|
|
|
|
/// Sets up the ``MTLSamplerState`` as the sampler state for the ``ShaderUniform``
|
|
/// - Parameters:
|
|
/// - shaderParam: Opaque pointer to ``ShaderUniform`` instance shared with `libobs`
|
|
/// - sampler: Opaque pointer to ``MTLSamplerState`` instance shared with `libobs`
|
|
///
|
|
/// If the uniform represents a texture for use in the associated shader, this function will also set up the provided
|
|
/// ``MTLSamplerState`` for the associated texture's texture slot.
|
|
@_cdecl("gs_shader_set_next_sampler")
|
|
public func gs_shader_set_next_sampler(shaderParam: UnsafeRawPointer, sampler: UnsafeRawPointer) {
|
|
let shaderUniform: MetalShader.ShaderUniform = unretained(shaderParam)
|
|
|
|
let samplerState = Unmanaged<MTLSamplerState>.fromOpaque(sampler).takeUnretainedValue()
|
|
|
|
shaderUniform.samplerState = samplerState
|
|
}
|