diff --git a/examples/iOS/SimpleImageFilter/SimpleImageFilter.xcodeproj/project.pbxproj b/examples/iOS/SimpleImageFilter/SimpleImageFilter.xcodeproj/project.pbxproj index 6d276f89..fedd8793 100644 --- a/examples/iOS/SimpleImageFilter/SimpleImageFilter.xcodeproj/project.pbxproj +++ b/examples/iOS/SimpleImageFilter/SimpleImageFilter.xcodeproj/project.pbxproj @@ -14,6 +14,9 @@ BCD985BA1CA43FD5001FF01F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BCD985B81CA43FD5001FF01F /* LaunchScreen.storyboard */; }; BCD985D51CA48F15001FF01F /* WID-small.jpg in Resources */ = {isa = PBXBuildFile; fileRef = BCD985D41CA48F15001FF01F /* WID-small.jpg */; }; BCFB058C1CBF17FD009B2333 /* Assets-iOS.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BCFB058B1CBF17FD009B2333 /* Assets-iOS.xcassets */; }; + CB3611A324357214007F3C0E /* Lambeau.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CB3611A224357214007F3C0E /* Lambeau.jpg */; }; + CB3611A5243572F9007F3C0E /* CustomBrightnessAdjustment.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB3611A4243572F9007F3C0E /* CustomBrightnessAdjustment.swift */; }; + CB3611A724357309007F3C0E /* CustomBrightnessAdjustment.metal in Sources */ = {isa = PBXBuildFile; fileRef = CB3611A624357309007F3C0E /* CustomBrightnessAdjustment.metal */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -63,6 +66,9 @@ BCD985BB1CA43FD5001FF01F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BCD985D41CA48F15001FF01F /* WID-small.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = "WID-small.jpg"; path = "../../../SharedAssets/WID-small.jpg"; sourceTree = ""; }; BCFB058B1CBF17FD009B2333 /* Assets-iOS.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = "Assets-iOS.xcassets"; path = "../../../SharedAssets/Assets-iOS.xcassets"; sourceTree = ""; }; + CB3611A224357214007F3C0E /* Lambeau.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = Lambeau.jpg; path = ../../../SharedAssets/Lambeau.jpg; sourceTree = ""; }; + CB3611A4243572F9007F3C0E /* CustomBrightnessAdjustment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomBrightnessAdjustment.swift; sourceTree = ""; }; + CB3611A624357309007F3C0E /* CustomBrightnessAdjustment.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = CustomBrightnessAdjustment.metal; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -107,6 +113,8 @@ children = ( BCD985AF1CA43FD5001FF01F /* AppDelegate.swift */, BCD985B11CA43FD5001FF01F /* ViewController.swift */, + CB3611A4243572F9007F3C0E /* CustomBrightnessAdjustment.swift */, + CB3611A624357309007F3C0E /* CustomBrightnessAdjustment.metal */, BCD985B31CA43FD5001FF01F /* Main.storyboard */, BCD985CA1CA44005001FF01F /* Resources */, ); @@ -118,6 +126,7 @@ children = ( BCFB058B1CBF17FD009B2333 /* Assets-iOS.xcassets */, BCD985D41CA48F15001FF01F /* WID-small.jpg */, + CB3611A224357214007F3C0E /* Lambeau.jpg */, BCD985B81CA43FD5001FF01F /* LaunchScreen.storyboard */, BCD985BB1CA43FD5001FF01F /* Info.plist */, ); @@ -167,8 +176,9 @@ TargetAttributes = { BCD985AB1CA43FD5001FF01F = { CreatedOnToolsVersion = 7.3; - DevelopmentTeam = J2U2U9GBML; + DevelopmentTeam = FLBD7VX6BF; LastSwiftMigration = 0940; + ProvisioningStyle = Automatic; }; }; }; @@ -177,6 +187,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -219,6 +230,7 @@ buildActionMask = 2147483647; files = ( BCD985BA1CA43FD5001FF01F /* LaunchScreen.storyboard in Resources */, + CB3611A324357214007F3C0E /* Lambeau.jpg in Resources */, BCD985D51CA48F15001FF01F /* WID-small.jpg in Resources */, BCFB058C1CBF17FD009B2333 /* Assets-iOS.xcassets in Resources */, BCD985B51CA43FD5001FF01F /* Main.storyboard in Resources */, @@ -233,6 +245,8 @@ buildActionMask = 2147483647; files = ( BCD985B21CA43FD5001FF01F /* ViewController.swift in Sources */, + CB3611A724357309007F3C0E /* CustomBrightnessAdjustment.metal in Sources */, + CB3611A5243572F9007F3C0E /* CustomBrightnessAdjustment.swift in Sources */, BCD985B01CA43FD5001FF01F /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -377,11 +391,14 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = J2U2U9GBML; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = SimpleImageFilter/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.redqueencoder.SimpleImageFilter; + PRODUCT_BUNDLE_IDENTIFIER = com.sunsetlakesoftware.SimpleImageFilter; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; @@ -394,7 +411,7 @@ DEVELOPMENT_TEAM = J2U2U9GBML; INFOPLIST_FILE = SimpleImageFilter/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.redqueencoder.SimpleImageFilter; + PRODUCT_BUNDLE_IDENTIFIER = com.sunsetlakesoftware.SimpleImageFilter; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; diff --git a/examples/iOS/SimpleImageFilter/SimpleImageFilter/CustomBrightnessAdjustment.metal b/examples/iOS/SimpleImageFilter/SimpleImageFilter/CustomBrightnessAdjustment.metal new file mode 100644 index 00000000..25f3fbf6 --- /dev/null +++ b/examples/iOS/SimpleImageFilter/SimpleImageFilter/CustomBrightnessAdjustment.metal @@ -0,0 +1,27 @@ +// +// CustomBrightnessAdjustment.metal +// SimpleImageFilter +// +// Created by yang on 2020/4/2. +// Copyright © 2020 Sunset Lake Software LLC. All rights reserved. +// + +#include +#include + +using namespace metal; + +typedef struct +{ + float brightness; +} BrightnessUniform; + +fragment half4 brightnessFragment(SingleInputVertexIO fragmentInput [[stage_in]], + texture2d inputTexture [[texture(0)]], + constant BrightnessUniform& uniform [[ buffer(1) ]]) +{ + constexpr sampler quadSampler; + half4 color = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate); + + return half4(color.rgb + uniform.brightness, color.a); +} diff --git a/examples/iOS/SimpleImageFilter/SimpleImageFilter/CustomBrightnessAdjustment.swift b/examples/iOS/SimpleImageFilter/SimpleImageFilter/CustomBrightnessAdjustment.swift new file mode 100644 index 00000000..989ae72e --- /dev/null +++ b/examples/iOS/SimpleImageFilter/SimpleImageFilter/CustomBrightnessAdjustment.swift @@ -0,0 +1,21 @@ +// +// CustomBrightnessAdjustment.swift +// SimpleImageFilter +// +// Created by yang on 2020/4/2. +// Copyright © 2020 Sunset Lake Software LLC. All rights reserved. +// + +import GPUImage +import Foundation + +class CustomBrightnessAdjustment: BasicOperation { + public var brightness:Float = 0.0 { didSet { uniformSettings["brightness"] = brightness } } + + public init() { + let libraryPath = Bundle.main.path(forResource: "default", ofType: "metallib")! + super.init(fragmentFunctionName:"brightnessFragment", fragmentLibraryPath: libraryPath, numberOfInputs:1) + + ({brightness = 0.0})() + } +} diff --git a/examples/iOS/SimpleImageFilter/SimpleImageFilter/ViewController.swift b/examples/iOS/SimpleImageFilter/SimpleImageFilter/ViewController.swift index f2a2d90e..628da7b1 100644 --- a/examples/iOS/SimpleImageFilter/SimpleImageFilter/ViewController.swift +++ b/examples/iOS/SimpleImageFilter/SimpleImageFilter/ViewController.swift @@ -7,6 +7,7 @@ class ViewController: UIViewController { var picture:PictureInput! var filter:SaturationAdjustment! + var customFilter: CustomBrightnessAdjustment! override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() @@ -28,7 +29,10 @@ class ViewController: UIViewController { // Filtering image for display picture = PictureInput(image:UIImage(named:"WID-small.jpg")!) filter = SaturationAdjustment() - picture --> filter --> renderView + // demo for define custom filter outside GPUImage framework bundle + customFilter = CustomBrightnessAdjustment() + customFilter.brightness = 0.5 + picture --> filter --> customFilter --> renderView picture.processImage() } } diff --git a/framework/GPUImage.xcodeproj/project.pbxproj b/framework/GPUImage.xcodeproj/project.pbxproj index 2d3240f0..a9d7e62e 100644 --- a/framework/GPUImage.xcodeproj/project.pbxproj +++ b/framework/GPUImage.xcodeproj/project.pbxproj @@ -269,7 +269,7 @@ 79CB6E3F210A106B0042F87B /* SubtractBlend.metal in Sources */ = {isa = PBXBuildFile; fileRef = 79CB6E3D210A106B0042F87B /* SubtractBlend.metal */; }; 79CB6E41210A53CA0042F87B /* BlendShaderTypes.metal in Sources */ = {isa = PBXBuildFile; fileRef = 79CB6E40210A53C90042F87B /* BlendShaderTypes.metal */; }; 79CB6E42210A53CA0042F87B /* BlendShaderTypes.metal in Sources */ = {isa = PBXBuildFile; fileRef = 79CB6E40210A53C90042F87B /* BlendShaderTypes.metal */; }; - 79CB6E45210A55CB0042F87B /* BlendShaderTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 79CB6E44210A55CB0042F87B /* BlendShaderTypes.h */; }; + 79CB6E45210A55CB0042F87B /* BlendShaderTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 79CB6E44210A55CB0042F87B /* BlendShaderTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; 79CB6E46210A55CB0042F87B /* BlendShaderTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 79CB6E44210A55CB0042F87B /* BlendShaderTypes.h */; }; 79DD50C4213450BE004EF308 /* SwirlDistortion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DD50C3213450BE004EF308 /* SwirlDistortion.swift */; }; 79DD50C5213450BE004EF308 /* SwirlDistortion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79DD50C3213450BE004EF308 /* SwirlDistortion.swift */; }; @@ -350,7 +350,7 @@ BC7BA27420F2BD1E006B5F4B /* ShaderUniformSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC7BA27320F2BD1E006B5F4B /* ShaderUniformSettings.swift */; }; BC7BA27720F2C269006B5F4B /* BrightnessAdjustment.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC7BA27620F2C269006B5F4B /* BrightnessAdjustment.swift */; }; BC7BA27920F2C2CF006B5F4B /* BrightnessAdjustment.metal in Sources */ = {isa = PBXBuildFile; fileRef = BC7BA27820F2C2CF006B5F4B /* BrightnessAdjustment.metal */; }; - BC7BA27B20F2C5E8006B5F4B /* OperationShaderTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7BA27A20F2C5E8006B5F4B /* OperationShaderTypes.h */; }; + BC7BA27B20F2C5E8006B5F4B /* OperationShaderTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7BA27A20F2C5E8006B5F4B /* OperationShaderTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; BC7BA27C20F2C5E8006B5F4B /* OperationShaderTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7BA27A20F2C5E8006B5F4B /* OperationShaderTypes.h */; }; BC7BA28120F599DD006B5F4B /* MonochromeFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC7BA28020F599DD006B5F4B /* MonochromeFilter.swift */; }; BC7BA28220F599DD006B5F4B /* MonochromeFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC7BA28020F599DD006B5F4B /* MonochromeFilter.swift */; }; @@ -377,7 +377,7 @@ BCC6AB60210E5E7900F9803A /* TextureSamplingOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCC6AB5E210E5E7900F9803A /* TextureSamplingOperation.swift */; }; BCC6AB62210E5ECE00F9803A /* NearbyTexelSampling.metal in Sources */ = {isa = PBXBuildFile; fileRef = BCC6AB61210E5ECE00F9803A /* NearbyTexelSampling.metal */; }; BCC6AB63210E5ECE00F9803A /* NearbyTexelSampling.metal in Sources */ = {isa = PBXBuildFile; fileRef = BCC6AB61210E5ECE00F9803A /* NearbyTexelSampling.metal */; }; - BCC6AB65210E5FF600F9803A /* TexelSamplingTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = BCC6AB64210E5FF600F9803A /* TexelSamplingTypes.h */; }; + BCC6AB65210E5FF600F9803A /* TexelSamplingTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = BCC6AB64210E5FF600F9803A /* TexelSamplingTypes.h */; settings = {ATTRIBUTES = (Public, ); }; }; BCC6AB66210E5FF600F9803A /* TexelSamplingTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = BCC6AB64210E5FF600F9803A /* TexelSamplingTypes.h */; }; BCC6AB69210E62EB00F9803A /* Convolution3x3.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCC6AB68210E62EB00F9803A /* Convolution3x3.swift */; }; BCC6AB6A210E62EB00F9803A /* Convolution3x3.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCC6AB68210E62EB00F9803A /* Convolution3x3.swift */; }; @@ -931,8 +931,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - BCC6AB65210E5FF600F9803A /* TexelSamplingTypes.h in Headers */, BC7BA27B20F2C5E8006B5F4B /* OperationShaderTypes.h in Headers */, + BCC6AB65210E5FF600F9803A /* TexelSamplingTypes.h in Headers */, 79CB6E45210A55CB0042F87B /* BlendShaderTypes.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/framework/Source/BasicOperation.swift b/framework/Source/BasicOperation.swift index e0e288a8..97035da0 100644 --- a/framework/Source/BasicOperation.swift +++ b/framework/Source/BasicOperation.swift @@ -36,12 +36,12 @@ open class BasicOperation: ImageProcessingOperation { var useNormalizedTextureCoordinates = true var metalPerformanceShaderPathway: ((MTLCommandBuffer, [UInt:Texture], Texture) -> ())? - public init(vertexFunctionName: String? = nil, fragmentFunctionName: String, numberOfInputs: UInt = 1, operationName: String = #file) { + public init(vertexFunctionName: String? = nil, vertexLibraryPath: String? = nil, fragmentFunctionName: String, fragmentLibraryPath: String? = nil, numberOfInputs: UInt = 1, operationName: String = #file) { self.maximumInputs = numberOfInputs self.operationName = operationName let concreteVertexFunctionName = vertexFunctionName ?? defaultVertexFunctionNameForInputs(numberOfInputs) - let (pipelineState, lookupTable) = generateRenderPipelineState(device:sharedMetalRenderingDevice, vertexFunctionName:concreteVertexFunctionName, fragmentFunctionName:fragmentFunctionName, operationName:operationName) + let (pipelineState, lookupTable) = generateRenderPipelineState(device:sharedMetalRenderingDevice, vertexFunctionName:concreteVertexFunctionName, vertexLibraryPath: vertexLibraryPath, fragmentFunctionName:fragmentFunctionName, fragmentLibraryPath: fragmentLibraryPath, operationName:operationName) self.renderPipelineState = pipelineState self.uniformSettings = ShaderUniformSettings(uniformLookupTable:lookupTable) } diff --git a/framework/Source/MetalRendering.swift b/framework/Source/MetalRendering.swift index ec891738..2074566b 100644 --- a/framework/Source/MetalRendering.swift +++ b/framework/Source/MetalRendering.swift @@ -62,12 +62,12 @@ extension MTLCommandBuffer { } } -func generateRenderPipelineState(device:MetalRenderingDevice, vertexFunctionName:String, fragmentFunctionName:String, operationName:String) -> (MTLRenderPipelineState, [String:(Int, MTLDataType)]) { - guard let vertexFunction = device.shaderLibrary.makeFunction(name: vertexFunctionName) else { +func generateRenderPipelineState(device:MetalRenderingDevice, vertexFunctionName:String, vertexLibraryPath: String? = nil, fragmentFunctionName:String, fragmentLibraryPath: String? = nil, operationName:String) -> (MTLRenderPipelineState, [String:(Int, MTLDataType)]) { + guard let vertexFunction = device.library(for: vertexLibraryPath).makeFunction(name: vertexFunctionName) else { fatalError("\(operationName): could not compile vertex function \(vertexFunctionName)") } - guard let fragmentFunction = device.shaderLibrary.makeFunction(name: fragmentFunctionName) else { + guard let fragmentFunction = device.library(for: fragmentLibraryPath).makeFunction(name: fragmentFunctionName) else { fatalError("\(operationName): could not compile fragment function \(fragmentFunctionName)") } diff --git a/framework/Source/MetalRenderingDevice.swift b/framework/Source/MetalRenderingDevice.swift index cf984698..a4fe663b 100644 --- a/framework/Source/MetalRenderingDevice.swift +++ b/framework/Source/MetalRenderingDevice.swift @@ -12,6 +12,19 @@ public class MetalRenderingDevice { public let commandQueue: MTLCommandQueue public let shaderLibrary: MTLLibrary public let metalPerformanceShadersAreSupported: Bool + + func library(for path: String? = nil) -> MTLLibrary { + guard let path = path else { return shaderLibrary } + guard libraryMap[path] == nil else { return libraryMap[path]! } + do { + let library = try device.makeLibrary(filepath: path) + libraryMap[path] = library + return library + } catch { + fatalError("Could not load library for bundle: \(path)") + } + } + private var libraryMap: [String: MTLLibrary] = [:] lazy var passthroughRenderState: MTLRenderPipelineState = { let (pipelineState, _) = generateRenderPipelineState(device:self, vertexFunctionName:"oneInputVertex", fragmentFunctionName:"passthroughFragment", operationName:"Passthrough") @@ -41,6 +54,7 @@ public class MetalRenderingDevice { let metalLibraryPath = frameworkBundle.path(forResource: "default", ofType: "metallib")! self.shaderLibrary = try device.makeLibrary(filepath:metalLibraryPath) + libraryMap[metalLibraryPath] = self.shaderLibrary } catch { fatalError("Could not load library") } diff --git a/framework/Source/TextureSamplingOperation.swift b/framework/Source/TextureSamplingOperation.swift index c6391aa6..1193d1f5 100644 --- a/framework/Source/TextureSamplingOperation.swift +++ b/framework/Source/TextureSamplingOperation.swift @@ -1,7 +1,7 @@ open class TextureSamplingOperation: BasicOperation { // public var overriddenTexelSize:Size? - override public init(vertexFunctionName: String? = "nearbyTexelSampling", + public init(vertexFunctionName: String? = "nearbyTexelSampling", fragmentFunctionName: String, numberOfInputs: UInt = 1, operationName: String = #file) {