diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc25fe4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store + +# Xcode +# this ignores dummy workspace files in xcodeproj dir +ParticleCam.xcodeproj/* +!ParticleCam.xcodeproj/project.pbxproj diff --git a/ParticleCam.xcodeproj/project.pbxproj b/ParticleCam.xcodeproj/project.pbxproj index 5fc1472..f70d0de 100644 --- a/ParticleCam.xcodeproj/project.pbxproj +++ b/ParticleCam.xcodeproj/project.pbxproj @@ -121,12 +121,14 @@ 3EA930931B75BFFA0067276D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0700; + LastUpgradeCheck = 1010; ORGANIZATIONNAME = "Simon Gladman"; TargetAttributes = { 3EA9309A1B75BFFA0067276D = { CreatedOnToolsVersion = 7.0; - DevelopmentTeam = ZBFYF9JG5V; + DevelopmentTeam = 6CFA54MQCP; + LastSwiftMigration = 1010; + ProvisioningStyle = Manual; }; }; }; @@ -206,13 +208,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -251,13 +263,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -276,6 +298,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; TARGETED_DEVICE_FAMILY = 2; VALIDATE_PRODUCT = YES; }; @@ -287,11 +310,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = 6CFA54MQCP; INFOPLIST_FILE = ParticleCam/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = uk.co.flexmonkey.ParticleCam; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = "(dan jan 16) Dev Any App"; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -302,11 +329,15 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ParticleCam/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = uk.co.flexmonkey.ParticleCam; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/ParticleCam.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ParticleCam.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index a08862e..0000000 --- a/ParticleCam.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/ParticleCam.xcodeproj/project.xcworkspace/xcuserdata/simongladman.xcuserdatad/UserInterfaceState.xcuserstate b/ParticleCam.xcodeproj/project.xcworkspace/xcuserdata/simongladman.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 564866f..0000000 Binary files a/ParticleCam.xcodeproj/project.xcworkspace/xcuserdata/simongladman.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/ParticleCam.xcodeproj/xcuserdata/simongladman.xcuserdatad/xcschemes/ParticleCam.xcscheme b/ParticleCam.xcodeproj/xcuserdata/simongladman.xcuserdatad/xcschemes/ParticleCam.xcscheme deleted file mode 100644 index 3703cc7..0000000 --- a/ParticleCam.xcodeproj/xcuserdata/simongladman.xcuserdatad/xcschemes/ParticleCam.xcscheme +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ParticleCam.xcodeproj/xcuserdata/simongladman.xcuserdatad/xcschemes/xcschememanagement.plist b/ParticleCam.xcodeproj/xcuserdata/simongladman.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 15756a3..0000000 --- a/ParticleCam.xcodeproj/xcuserdata/simongladman.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - ParticleCam.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 3EA9309A1B75BFFA0067276D - - primary - - - - - diff --git a/ParticleCam/AppDelegate.swift b/ParticleCam/AppDelegate.swift index 7693892..081511c 100644 --- a/ParticleCam/AppDelegate.swift +++ b/ParticleCam/AppDelegate.swift @@ -13,34 +13,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { - // Override point for customization after application launch. + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { return true } - - func applicationWillResignActive(application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - } - - func applicationWillEnterForeground(application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - } - diff --git a/ParticleCam/Info.plist b/ParticleCam/Info.plist index 879c6cf..39e0209 100644 --- a/ParticleCam/Info.plist +++ b/ParticleCam/Info.plist @@ -42,5 +42,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + NSCameraUsageDescription + Camera access is used to get live video feed for particle processing diff --git a/ParticleCam/ParticleLab.swift b/ParticleCam/ParticleLab.swift index e392c2e..1b9e425 100644 --- a/ParticleCam/ParticleLab.swift +++ b/ParticleCam/ParticleLab.swift @@ -25,12 +25,12 @@ import MetalPerformanceShaders class ParticleCamFilter: MetalImageFilter { - let particleCount = ParticleCount.OneMillion.rawValue + let particleCount = ParticleCount.oneMillion.rawValue let alignment:Int = 0x4000 let particlesMemoryByteSize:Int - var particlesMemory:UnsafeMutablePointer = nil - let particlesVoidPtr: COpaquePointer + var particlesMemory:UnsafeMutableRawPointer? = nil + let particlesVoidPtr: OpaquePointer let particlesParticlePtr: UnsafeMutablePointer let particlesParticleBufferPtr: UnsafeMutableBufferPointer @@ -38,23 +38,23 @@ class ParticleCamFilter: MetalImageFilter { [unowned self] in - return self.device.newBufferWithBytesNoCopy(self.particlesMemory, + return self.device.makeBuffer(bytesNoCopy: self.particlesMemory!, length: Int(self.particlesMemoryByteSize), - options: .CPUCacheModeDefaultCache, - deallocator: nil) + options: MTLResourceOptions(), + deallocator: nil)! }() - let particleSize = sizeof(Particle) + let particleSize = MemoryLayout.size // MARK: Initialisation init() { - particlesMemoryByteSize = particleCount * sizeof(Particle) + particlesMemoryByteSize = particleCount * MemoryLayout.size posix_memalign(&particlesMemory, alignment, particlesMemoryByteSize) - particlesVoidPtr = COpaquePointer(particlesMemory) + particlesVoidPtr = OpaquePointer(particlesMemory!) particlesParticlePtr = UnsafeMutablePointer(particlesVoidPtr) particlesParticleBufferPtr = UnsafeMutableBufferPointer(start: particlesParticlePtr, count: particleCount) @@ -109,11 +109,11 @@ class ParticleCamFilter: MetalImageFilter enum ParticleCount: Int { - case QuarterMillion = 262144 - case HalfMillion = 524288 - case OneMillion = 1048576 - case TwoMillion = 2097152 - case FourMillion = 4194304 + case quarterMillion = 262144 + case halfMillion = 524288 + case oneMillion = 1048576 + case twoMillion = 2097152 + case fourMillion = 4194304 } // Particles use x and y for position and z and w for velocity diff --git a/ParticleCam/ViewController.swift b/ParticleCam/ViewController.swift index cc06395..0be3cae 100644 --- a/ParticleCam/ViewController.swift +++ b/ParticleCam/ViewController.swift @@ -12,7 +12,7 @@ class ViewController: UIViewController, CameraCaptureHelperDelegate { let imageView = MetalImageView() - let cameraCaptureHelper = CameraCaptureHelper(cameraPosition: .Front) + let cameraCaptureHelper = CameraCaptureHelper(cameraPosition: .front) let particleCamFilter = ParticleCamFilter() @@ -36,7 +36,7 @@ class ViewController: UIViewController, CameraCaptureHelperDelegate } - func newCameraImage(cameraCaptureHelper: CameraCaptureHelper, image: CIImage) + func newCameraImage(_ cameraCaptureHelper: CameraCaptureHelper, image: CIImage) { particleCamFilter.inputImage = image diff --git a/ParticleCam/classes/CameraCaptureHelper.swift b/ParticleCam/classes/CameraCaptureHelper.swift index cdb1b4e..1852c74 100644 --- a/ParticleCam/classes/CameraCaptureHelper.swift +++ b/ParticleCam/classes/CameraCaptureHelper.swift @@ -20,24 +20,36 @@ import UIKit class CameraCaptureHelper: NSObject { let captureSession = AVCaptureSession() - let cameraPosition: AVCaptureDevicePosition + let cameraPosition: AVCaptureDevice.Position weak var delegate: CameraCaptureHelperDelegate? + var videoOrientation: AVCaptureVideoOrientation = .landscapeLeft - required init(cameraPosition: AVCaptureDevicePosition) + var statusBarObserveHandle: NSObjectProtocol? + + deinit { + statusBarObserveHandle.map { NotificationCenter.default.removeObserver($0) } + } + + required init(cameraPosition: AVCaptureDevice.Position) { self.cameraPosition = cameraPosition super.init() initialiseCaptureSession() + + videoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue)! + statusBarObserveHandle = NotificationCenter.default.addObserver(forName: UIApplication.didChangeStatusBarOrientationNotification, object: nil, queue: nil) { [weak self] _ in + self?.videoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue)! + } } - private func initialiseCaptureSession() + fileprivate func initialiseCaptureSession() { - captureSession.sessionPreset = AVCaptureSessionPresetiFrame1280x720 + captureSession.sessionPreset = .iFrame1280x720 - guard let camera = (AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) as! [AVCaptureDevice]) + guard let camera = AVCaptureDevice.devices(for: .video) .filter({ $0.position == cameraPosition }) .first else { @@ -58,7 +70,7 @@ class CameraCaptureHelper: NSObject let videoOutput = AVCaptureVideoDataOutput() videoOutput.setSampleBufferDelegate(self, - queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL)) + queue: DispatchQueue(label: "sample buffer delegate", attributes: [])) if captureSession.canAddOutput(videoOutput) { @@ -71,19 +83,19 @@ class CameraCaptureHelper: NSObject extension CameraCaptureHelper: AVCaptureVideoDataOutputSampleBufferDelegate { - func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) + func captureOutput(_ captureOutput: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { - connection.videoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.sharedApplication().statusBarOrientation.rawValue)! + connection.videoOrientation = videoOrientation guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } - dispatch_async(dispatch_get_main_queue()) + DispatchQueue.main.async { self.delegate?.newCameraImage(self, - image: CIImage(CVPixelBuffer: pixelBuffer)) + image: CIImage(cvPixelBuffer: pixelBuffer)) } } @@ -91,5 +103,5 @@ extension CameraCaptureHelper: AVCaptureVideoDataOutputSampleBufferDelegate protocol CameraCaptureHelperDelegate: class { - func newCameraImage(cameraCaptureHelper: CameraCaptureHelper, image: CIImage) + func newCameraImage(_ cameraCaptureHelper: CameraCaptureHelper, image: CIImage) } diff --git a/ParticleCam/classes/ImageView.swift b/ParticleCam/classes/ImageView.swift index eb0fcdb..7c1238d 100644 --- a/ParticleCam/classes/ImageView.swift +++ b/ParticleCam/classes/ImageView.swift @@ -16,26 +16,26 @@ import MetalKit class MetalImageView: MTKView { - let colorSpace = CGColorSpaceCreateDeviceRGB()! + let colorSpace = CGColorSpaceCreateDeviceRGB() lazy var commandQueue: MTLCommandQueue = - { - [unowned self] in - - return self.device!.newCommandQueue() - }() + { + [unowned self] in + + return self.device!.makeCommandQueue()! + }() lazy var ciContext: CIContext = - { - [unowned self] in - - return CIContext(MTLDevice: self.device!) - }() + { + [unowned self] in + + return CIContext(mtlDevice: self.device!) + }() override init(frame frameRect: CGRect, device: MTLDevice?) { super.init(frame: frameRect, - device: device ?? MTLCreateSystemDefaultDevice()) + device: device ?? MTLCreateSystemDefaultDevice()) if super.device == nil { @@ -52,25 +52,19 @@ class MetalImageView: MTKView /// The image to display var image: CIImage? - { - didSet - { - renderImage() - } - } - - func renderImage() - { - guard let - image = image, - targetTexture = currentDrawable?.texture else + + override func draw() { + super.draw() + + guard let image = image, + let targetTexture = currentDrawable?.texture else { return } - let commandBuffer = commandQueue.commandBuffer() + let commandBuffer = commandQueue.makeCommandBuffer()! - let bounds = CGRect(origin: CGPointZero, size: drawableSize) + let bounds = CGRect(origin: CGPoint.zero, size: drawableSize) let originX = image.extent.origin.x let originY = image.extent.origin.y @@ -80,16 +74,16 @@ class MetalImageView: MTKView let scale = min(scaleX, scaleY) let scaledImage = image - .imageByApplyingTransform(CGAffineTransformMakeTranslation(-originX, -originY)) - .imageByApplyingTransform(CGAffineTransformMakeScale(scale, scale)) + .transformed(by: CGAffineTransform(translationX: -originX, y: -originY)) + .transformed(by: CGAffineTransform(scaleX: scale, y: scale)) ciContext.render(scaledImage, - toMTLTexture: targetTexture, - commandBuffer: commandBuffer, - bounds: bounds, - colorSpace: colorSpace) + to: targetTexture, + commandBuffer: commandBuffer, + bounds: bounds, + colorSpace: colorSpace) - commandBuffer.presentDrawable(currentDrawable!) + commandBuffer.present(currentDrawable!) commandBuffer.commit() } @@ -105,21 +99,21 @@ class MetalImageView: MTKView class OpenGLImageView: GLKView { - let eaglContext = EAGLContext(API: .OpenGLES2) + let eaglContext = EAGLContext(api: .openGLES2) lazy var ciContext: CIContext = - { - [unowned self] in - - return CIContext(EAGLContext: self.eaglContext, - options: [kCIContextWorkingColorSpace: NSNull()]) - }() + { + [unowned self] in + + return CIContext(eaglContext: self.eaglContext!, + options: [.workingColorSpace: NSNull()]) + }() override init(frame: CGRect) { - super.init(frame: frame, context: eaglContext) + super.init(frame: frame, context: eaglContext!) - context = self.eaglContext + context = self.eaglContext! delegate = self } @@ -135,7 +129,7 @@ class OpenGLImageView: GLKView /// The image to display var image: CIImage? - { + { didSet { setNeedsDisplay() @@ -145,7 +139,7 @@ class OpenGLImageView: GLKView extension OpenGLImageView: GLKViewDelegate { - func glkView(view: GLKView, drawInRect rect: CGRect) + func glkView(_ view: GLKView, drawIn rect: CGRect) { guard let image = image else { @@ -153,32 +147,32 @@ extension OpenGLImageView: GLKViewDelegate } let targetRect = image.extent.aspectFitInRect( - target: CGRect(origin: CGPointZero, - size: CGSize(width: drawableWidth, - height: drawableHeight))) + target: CGRect(origin: CGPoint.zero, + size: CGSize(width: drawableWidth, + height: drawableHeight))) let ciBackgroundColor = CIColor( - color: backgroundColor ?? UIColor.whiteColor()) - - ciContext.drawImage(CIImage(color: ciBackgroundColor), - inRect: CGRect(x: 0, - y: 0, - width: drawableWidth, - height: drawableHeight), - fromRect: CGRect(x: 0, - y: 0, - width: drawableWidth, - height: drawableHeight)) - - ciContext.drawImage(image, - inRect: targetRect, - fromRect: image.extent) + color: backgroundColor ?? UIColor.white) + + ciContext.draw(CIImage(color: ciBackgroundColor), + in: CGRect(x: 0, + y: 0, + width: drawableWidth, + height: drawableHeight), + from: CGRect(x: 0, + y: 0, + width: drawableWidth, + height: drawableHeight)) + + ciContext.draw(image, + in: targetRect, + from: image.extent) } } extension CGRect { - func aspectFitInRect(target target: CGRect) -> CGRect + func aspectFitInRect(target: CGRect) -> CGRect { let scale: CGFloat = { @@ -195,8 +189,8 @@ extension CGRect let y = target.midY - height / 2 return CGRect(x: x, - y: y, - width: width, - height: height) + y: y, + width: width, + height: height) } } diff --git a/ParticleCam/classes/MetalFilter.swift b/ParticleCam/classes/MetalFilter.swift index 0632d79..1f00ce1 100644 --- a/ParticleCam/classes/MetalFilter.swift +++ b/ParticleCam/classes/MetalFilter.swift @@ -19,38 +19,38 @@ import CoreImage class MetalFilter: CIFilter { let device: MTLDevice = MTLCreateSystemDefaultDevice()! - let colorSpace = CGColorSpaceCreateDeviceRGB()! + let colorSpace = CGColorSpaceCreateDeviceRGB() lazy var ciContext: CIContext = { [unowned self] in - return CIContext(MTLDevice: self.device) + return CIContext(mtlDevice: self.device) }() lazy var commandQueue: MTLCommandQueue = { [unowned self] in - return self.device.newCommandQueue() + return self.device.makeCommandQueue()! }() lazy var defaultLibrary: MTLLibrary = { [unowned self] in - return self.device.newDefaultLibrary()! + return self.device.makeDefaultLibrary()! }() lazy var pipelineState: MTLComputePipelineState = { [unowned self] in - let kernelFunction = self.defaultLibrary.newFunctionWithName(self.functionName)! + let kernelFunction = self.defaultLibrary.makeFunction(name: self.functionName)! do { - let pipelineState = try self.device.newComputePipelineStateWithFunction(kernelFunction) + let pipelineState = try self.device.makeComputePipelineState(function: kernelFunction) return pipelineState } catch @@ -85,7 +85,7 @@ class MetalFilter: CIFilter } if let imageFilter = self as? MetalImageFilter, - inputImage = imageFilter.inputImage + let inputImage = imageFilter.inputImage { return imageFromComputeShader(width: inputImage.extent.width, height: inputImage.extent.height, @@ -124,17 +124,18 @@ class MetalFilter: CIFilter fatalError("textureInvalid() not implemented in MetalFilter") } - func imageFromComputeShader(width width: CGFloat, height: CGFloat, inputImage: CIImage?) -> CIImage + func imageFromComputeShader(width: CGFloat, height: CGFloat, inputImage: CIImage?) -> CIImage { if textureDescriptor == nil { - textureDescriptor = MTLTextureDescriptor.texture2DDescriptorWithPixelFormat(.RGBA8Unorm, + textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .rgba8Unorm, width: Int(width), height: Int(height), mipmapped: false) - kernelInputTexture = device.newTextureWithDescriptor(textureDescriptor!) - kernelOutputTexture = device.newTextureWithDescriptor(textureDescriptor!) + textureDescriptor?.usage = [.shaderRead, .shaderWrite] + kernelInputTexture = device.makeTexture(descriptor: textureDescriptor!) + kernelOutputTexture = device.makeTexture(descriptor: textureDescriptor!) threadgroupsPerGrid = MTLSizeMake( textureDescriptor!.width / threadsPerThreadgroup.width, @@ -143,55 +144,55 @@ class MetalFilter: CIFilter if clearOnStep { - kernelOutputTexture = device.newTextureWithDescriptor(textureDescriptor!) + kernelOutputTexture = device.makeTexture(descriptor: textureDescriptor!) } - let commandBuffer = commandQueue.commandBuffer() + let commandBuffer = commandQueue.makeCommandBuffer()! if let imageFilter = self as? MetalImageFilter, - inputImage = imageFilter.inputImage + let inputImage = imageFilter.inputImage { ciContext.render(inputImage, - toMTLTexture: kernelInputTexture!, + to: kernelInputTexture!, commandBuffer: commandBuffer, bounds: inputImage.extent, colorSpace: colorSpace) } - let commandEncoder = commandBuffer.computeCommandEncoder() + let commandEncoder = commandBuffer.makeComputeCommandEncoder()! commandEncoder.setComputePipelineState(pipelineState) // populate float buffers using kCIAttributeIdentity as buffer index - for inputKey in inputKeys where attributes[inputKey]?[kCIAttributeClass] == "NSNumber" + for inputKey in inputKeys where (attributes[inputKey] as? NSDictionary)?[kCIAttributeClass] as? String == "NSNumber" { if let bufferIndex = (attributes[inputKey] as! [String:AnyObject])[kCIAttributeIdentity] as? Int, - var bufferValue = valueForKey(inputKey) as? Float + var bufferValue = value(forKey: inputKey) as? Float { - let buffer = device.newBufferWithBytes(&bufferValue, - length: sizeof(Float), - options: MTLResourceOptions.CPUCacheModeDefaultCache) + let buffer = device.makeBuffer(bytes: &bufferValue, + length: MemoryLayout.size, + options: MTLResourceOptions()) - commandEncoder.setBuffer(buffer, offset: 0, atIndex: bufferIndex) + commandEncoder.setBuffer(buffer, offset: 0, index: bufferIndex) } } // populate color buffers using kCIAttributeIdentity as buffer index - for inputKey in inputKeys where attributes[inputKey]?[kCIAttributeClass] == "CIColor" + for inputKey in inputKeys where (attributes[inputKey] as? NSDictionary)?[kCIAttributeClass] as? String == "CIColor" { if let bufferIndex = (attributes[inputKey] as! [String:AnyObject])[kCIAttributeIdentity] as? Int, - bufferValue = valueForKey(inputKey) as? CIColor + let bufferValue = value(forKey: inputKey) as? CIColor { var color = float4(Float(bufferValue.red), Float(bufferValue.green), Float(bufferValue.blue), Float(bufferValue.alpha)) - let buffer = device.newBufferWithBytes(&color, - length: sizeof(float4), - options: MTLResourceOptions.CPUCacheModeDefaultCache) + let buffer = device.makeBuffer(bytes: &color, + length: MemoryLayout.size, + options: MTLResourceOptions()) - commandEncoder.setBuffer(buffer, offset: 0, atIndex: bufferIndex) + commandEncoder.setBuffer(buffer, offset: 0, index: bufferIndex) } } @@ -201,18 +202,18 @@ class MetalFilter: CIFilter { for indexedBuffer in indexedBuffers { - commandEncoder.setBuffer(indexedBuffer.buffer, offset: 0, atIndex: indexedBuffer.index) + commandEncoder.setBuffer(indexedBuffer.buffer, offset: 0, index: indexedBuffer.index) } } if self is MetalImageFilter { - commandEncoder.setTexture(kernelInputTexture, atIndex: 0) - commandEncoder.setTexture(kernelOutputTexture, atIndex: 1) + commandEncoder.setTexture(kernelInputTexture, index: 0) + commandEncoder.setTexture(kernelOutputTexture, index: 1) } else if self is MetalGeneratorFilter { - commandEncoder.setTexture(kernelOutputTexture, atIndex: 0) + commandEncoder.setTexture(kernelOutputTexture, index: 0) } commandEncoder.dispatchThreadgroups(customThreadgroupsPerGrid() ?? threadgroupsPerGrid!, @@ -222,8 +223,8 @@ class MetalFilter: CIFilter commandBuffer.commit() - return CIImage(MTLTexture: kernelOutputTexture!, - options: [kCIImageColorSpace: colorSpace]) + return CIImage(mtlTexture: kernelOutputTexture!, + options: [.colorSpace: colorSpace])! } } @@ -236,7 +237,7 @@ class MetalGeneratorFilter: MetalFilter override func textureInvalid() -> Bool { - if let textureDescriptor = textureDescriptor where + if let textureDescriptor = textureDescriptor, textureDescriptor.width != Int(inputWidth) || textureDescriptor.height != Int(inputHeight) { @@ -254,7 +255,7 @@ class MetalImageFilter: MetalFilter override func textureInvalid() -> Bool { if let textureDescriptor = textureDescriptor, - inputImage = inputImage where + let inputImage = inputImage, textureDescriptor.width != Int(inputImage.extent.width) || textureDescriptor.height != Int(inputImage.extent.height) { @@ -264,4 +265,3 @@ class MetalImageFilter: MetalFilter return false } } -