123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- /******************************************************************************
- Copyright (C) 2024 by Patrick Heyer <[email protected]>
- 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
- }
|