diff --git a/Examples/ExampleMacOS/ExampleMacOS/Logic/Functions.swift b/Examples/ExampleMacOS/ExampleMacOS/Logic/Functions.swift index 309ad7d..57b3db3 100644 --- a/Examples/ExampleMacOS/ExampleMacOS/Logic/Functions.swift +++ b/Examples/ExampleMacOS/ExampleMacOS/Logic/Functions.swift @@ -12,30 +12,23 @@ class MyCompute1: SCMetalComputeFunction { @EMArgument("tex") var tex: SCMetalTexture = .init(texture: nil, usage: .read_write) @EMArgument("col") var col: Float = 0 - init() { - super.init( - functionName: "myCompute1", - impl: [ - "tex.write(float4(col, 0.1, col, 1), gid);" - ] - ) + @ShaderStringBuilder + override var impl: String { + "tex.write(float4(col, 0.1, col, 1), gid);" } } class MyRender1: SCMetalRenderFunction { - init() { - super.init( - functionName: "myRender1", - vertImpl: [ - "rd.size = 1;", - "rd.position = input;", - "rd.color = float4(1, 0.6, 0.8, 1);", - ], - fragImpl: [ - "return rd.color;" - ], - targetPixelFormat: .bgra8Unorm - ) + @ShaderStringBuilder + override var vertImpl: String { + "rd.size = 1;" + "rd.position = input;" + "rd.color = float4(1, 0.6, 0.8, 1);" + } + + @ShaderStringBuilder + override var fragImpl: String { + "return rd.color;" } } diff --git a/Examples/ExampleMacOS/ExampleMacOS/Logic/MyRenderer.swift b/Examples/ExampleMacOS/ExampleMacOS/Logic/MyRenderer.swift index e6d3f44..bef0de7 100644 --- a/Examples/ExampleMacOS/ExampleMacOS/Logic/MyRenderer.swift +++ b/Examples/ExampleMacOS/ExampleMacOS/Logic/MyRenderer.swift @@ -18,7 +18,7 @@ class MyRenderer: ShaderRenderer { }() let compute1 = MyCompute1() - let render1 = MyRender1() + let render1 = MyRender1(targetPixelFormat: .bgra8Unorm) override func draw(view: MTKView, drawable: CAMetalDrawable) { let dispatch = SCMetalDispatch() diff --git a/Examples/ExampleiOS/ExampleiOS/Logic/Functions.swift b/Examples/ExampleiOS/ExampleiOS/Logic/Functions.swift index acf36d8..1fad2ea 100644 --- a/Examples/ExampleiOS/ExampleiOS/Logic/Functions.swift +++ b/Examples/ExampleiOS/ExampleiOS/Logic/Functions.swift @@ -12,30 +12,23 @@ class MyCompute1: SCMetalComputeFunction { @EMArgument("tex") var tex: SCMetalTexture = .init(texture: nil, usage: .read_write) @EMArgument("col") var col: Float = 0 - init() { - super.init( - functionName: "myCompute1", - impl: [ - "tex.write(float4(col, 0.1, col, 1), gid);" - ] - ) + @ShaderStringBuilder + override var impl: String { + "tex.write(float4(col, 0.1, col, 1), gid);" } } class MyRender1: SCMetalRenderFunction { - init() { - super.init( - functionName: "myRender1", - vertImpl: [ - "rd.size = 1;", - "rd.position = input;", - "rd.color = float4(1, 0.6, 0.8, 1);", - ], - fragImpl: [ - "return rd.color;" - ], - targetPixelFormat: .bgra8Unorm - ) + @ShaderStringBuilder + override var vertImpl: String { + "rd.size = 1;" + "rd.position = input;" + "rd.color = float4(1, 0.6, 0.8, 1);" + } + + @ShaderStringBuilder + override var fragImpl: String { + "return rd.color;" } } diff --git a/Examples/ExampleiOS/ExampleiOS/Logic/MyRenderer.swift b/Examples/ExampleiOS/ExampleiOS/Logic/MyRenderer.swift index e86aa92..6d625b2 100644 --- a/Examples/ExampleiOS/ExampleiOS/Logic/MyRenderer.swift +++ b/Examples/ExampleiOS/ExampleiOS/Logic/MyRenderer.swift @@ -18,7 +18,7 @@ class MyRenderer: ShaderRenderer { }() let compute1 = MyCompute1() - let render1 = MyRender1() + let render1 = MyRender1(targetPixelFormat: .bgra8Unorm) override func draw(view: MTKView, drawable: CAMetalDrawable) { let dispatch = SCMetalDispatch() diff --git a/Package.swift b/Package.swift index fb6a9b1..28ab23e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.7 +// swift-tools-version: 5.8 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Sources/EasyMetalShader/Builder/ShaderStringBuilder.swift b/Sources/EasyMetalShader/Builder/ShaderStringBuilder.swift new file mode 100644 index 0000000..e05355e --- /dev/null +++ b/Sources/EasyMetalShader/Builder/ShaderStringBuilder.swift @@ -0,0 +1,30 @@ +// +// File.swift +// +// +// Created by Yuki Kuwashima on 2024/01/09. +// + +import Foundation + +@resultBuilder +public struct ShaderStringBuilder { + public static func buildBlock(_ component: String) -> String{ + component + } + public static func buildBlock(_ components: String...) -> String { + components.joined() + } + public static func buildBlock(_ components: [String]) -> String { + components.joined() + } + public static func buildBlock(_ components: [String], _ components2: [String]) -> String { + components.joined() + components2.joined() + } + public static func buildArray(_ components: [String]) -> String { + components.joined() + } + public static func buildArray(_ components: [[String]]) -> String { + components.joined().joined() + } +} diff --git a/Sources/EasyMetalShader/Pipelines/SCMetalComputeFunction.swift b/Sources/EasyMetalShader/Pipelines/SCMetalComputeFunction.swift index e3b7a34..50c72dd 100644 --- a/Sources/EasyMetalShader/Pipelines/SCMetalComputeFunction.swift +++ b/Sources/EasyMetalShader/Pipelines/SCMetalComputeFunction.swift @@ -17,15 +17,21 @@ open class SCMetalComputeFunction: NSObject, SCMetalFunction { public var args: [String: SCMetalArgument] = [:] - public init(functionName: String, impl: [String]) { - + @ShaderStringBuilder + open var impl: String { + "" + } + + public override init() { super.init() MirrorUtil.setInitialValue(for: self) + let tempFunctionName = "f" + UUID().uuidString.lowercased().replacingOccurrences(of: "-", with: "") + var functionImpl = "" functionImpl += Self.initialMetalHeader - functionImpl += "kernel void \(functionName)(" + functionImpl += "kernel void \(tempFunctionName)(" for (i, key) in args.keys.enumerated() { switch args[key] { @@ -91,7 +97,7 @@ open class SCMetalComputeFunction: NSObject, SCMetalFunction { } } - functionImpl += impl.joined() + functionImpl += impl functionImpl += "}" let library = try! ShaderCore.device.makeLibrary( @@ -100,7 +106,7 @@ open class SCMetalComputeFunction: NSObject, SCMetalFunction { ) self.computePipelineState = try! ShaderCore.device.makeComputePipelineState( function: library.makeFunction( - name: functionName + name: tempFunctionName )! ) } diff --git a/Sources/EasyMetalShader/Pipelines/SCMetalRenderFunction.swift b/Sources/EasyMetalShader/Pipelines/SCMetalRenderFunction.swift index 309cce0..fe84058 100644 --- a/Sources/EasyMetalShader/Pipelines/SCMetalRenderFunction.swift +++ b/Sources/EasyMetalShader/Pipelines/SCMetalRenderFunction.swift @@ -10,6 +10,7 @@ import simd @objcMembers open class SCMetalRenderFunction: NSObject, SCMetalFunction { + private static let initialMetalHeader = MetalPreLibrary.include + MetalPreLibrary.rand + MetalPreLibrary.svd + MetalPreLibrary.rasterizerData public var args: [String: SCMetalArgument] = [:] @@ -19,17 +20,21 @@ open class SCMetalRenderFunction: NSObject, SCMetalFunction { var renderTargetTexture: MTLTexture! var needsClear: Bool = false - public init(functionName: String, vertImpl: [String], fragImpl: [String], targetPixelFormat: MTLPixelFormat) { - + @ShaderStringBuilder open var vertImpl: String { "" } + @ShaderStringBuilder open var fragImpl: String { "" } + + public init(targetPixelFormat: MTLPixelFormat) { super.init() MirrorUtil.setInitialValue(for: self) + let tempFunctionName = "f" + UUID().uuidString.lowercased().replacingOccurrences(of: "-", with: "") + var functionImpl = "" functionImpl += Self.initialMetalHeader //vertex - functionImpl += "vertex RasterizerData \(functionName)_vert(" + functionImpl += "vertex RasterizerData \(tempFunctionName)_vert(" for (i, key) in args.keys.enumerated() { switch args[key] { @@ -96,12 +101,12 @@ open class SCMetalRenderFunction: NSObject, SCMetalFunction { } } - functionImpl += vertImpl.joined() + functionImpl += vertImpl functionImpl += "return rd;" functionImpl += "}" //fragment - functionImpl += "fragment float4 \(functionName)_frag(" + functionImpl += "fragment float4 \(tempFunctionName)_frag(" for (i, key) in args.keys.enumerated() { switch args[key] { @@ -169,7 +174,7 @@ open class SCMetalRenderFunction: NSObject, SCMetalFunction { } } - functionImpl += fragImpl.joined() + functionImpl += fragImpl functionImpl += "}" @@ -178,8 +183,8 @@ open class SCMetalRenderFunction: NSObject, SCMetalFunction { options: nil ) let descriptor = MTLRenderPipelineDescriptor() - descriptor.vertexFunction = library.makeFunction(name: functionName + "_vert") - descriptor.fragmentFunction = library.makeFunction(name: functionName + "_frag") + descriptor.vertexFunction = library.makeFunction(name: tempFunctionName + "_vert") + descriptor.fragmentFunction = library.makeFunction(name: tempFunctionName + "_frag") let vertexDesc = MTLVertexDescriptor() vertexDesc.attributes[0].format = .float4