import UIKit
import Metal
class FlipView: UIView {
@IBOutlet weak var imageView: UIImageView!
var metalLayer: CAMetalLayer?
var renderer: MTLRenderPass?
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let originalImage UIImage(named: “originalImage.jpg”) else { return }
let imageData originalImage.cgImage!
let imageRect CGRect(x: 0, y: 0, width: imageData.width, height: imageData.height)
// Create a Metal device and renderer
if let metalLayer CAMetalLayer() {
metalLayer.frame rect
metalLayer.device MTLCreateSystemDefaultDevice().makeObject(forKeyPath: kCFAllocatorDefaultNameKeyPath) as! MTLDevice
metalLayer.pixelFormat MTLPixelFormat.default().makeObject(forKeyPath: kCFAllocatorDefaultNameKeyPath) as! MTLPixelFormat
// Create a Metal render pass and draw our image as a texture on the screen
guard let renderer MTLRenderPassCreate() else { return }
renderer.colorAttachments[0].loadAction .clear
renderer.colorAttachments[0].clearColor MTLClearColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
renderer.presentation.framebufferOnly true
guard let commandQueue metalLayer.device?.makeCommandQueue() else { return }
let commandBuffer commandQueue?.makeCommandBuffer()!
let renderEncoder commandBuffer.makeRenderCommandEncoder(description: “Flip view”)
// Flip the image using a custom Metal function
flipImage(imageData, renderEncoder: renderEncoder)
// Present the render pass on the metal layer
metalLayer.presentation.framebufferOnly false
commandBuffer.commit()
}
}
}
class FlipViewController: UIViewController {
@IBOutlet weak var flipView: FlipView!
override func viewDidLoad() {
super.viewDidLoad()
// Create a Metal device and renderer
if let metalLayer CAMetalLayer() {
metalLayer.frame view.bounds
view.layer.addSublayer(metalLayer)
guard let renderer MTLRenderPassCreate() else { return }
renderer.colorAttachments[0].loadAction .clear
renderer.colorAttachments[0].clearColor MTLClearColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
renderer.presentation.framebufferOnly true
guard let commandQueue metalLayer.device?.makeCommandQueue() else { return }
let commandBuffer commandQueue?.makeCommandBuffer()!
let renderEncoder commandBuffer.makeRenderCommandEncoder(description: “Flip view”)
// Flip the image using a custom Metal function
flipImage(imageData, renderEncoder: renderEncoder)
// Present the render pass on the metal layer
metalLayer.presentation.framebufferOnly false
commandBuffer.commit()
}
}
func flipImage(_ imageData: CVPixelBuffer, renderEncoder: MTLRenderCommandEncoder) {
// Create a Metal sampler and set the texture coordinates
let samplerState MTLSamplerState(textureCoordinate: .uv, filter: .linear)
let sampler MTLSamplerCreate(samplerState)!
// Create a Metal render pass descriptor
guard let renderPassDescriptor MTLOcclusionQueryRenderPassDescriptor() else { return }
// Set the render pass descriptor's color attachment and create a Metal render pass
renderPassDescriptor.colorAttachments[0].loadAction .clear
renderPassDescriptor.colorAttachments[0].clearColor MTLClearColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
renderPassDescriptor.presentation.framebufferOnly true
guard let renderPass MTLRenderPassCreate(device: metalLayer?.device, descriptor: renderPassDescriptor) else { return }
// Create a Metal drawable and set the render pass
let drawable MTLDrawable(pixelFormat: imageData.pixelFormat, width: imageData.width, height: imageData.height, options: [])
renderPass?.addDrawable(drawable)
// Create a Metal command group and add the render pass to it
guard let commandGroup metalLayer?.device?.makeCommandGroup() else { return }
let drawCommand metalLayer?.device?.makeDrawCommandEncoder()!
drawCommand.renderPass renderPass
drawCommand.drawable drawable
// Create a Metal command buffer and add the draw command to it
let commandBuffer commandGroup.makeCommandBuffer()!
drawCommand.encodeDrawable(drawable, on: commandBuffer)
// Flip the image using a custom Metal function
renderEncoder.setRenderPass(renderPass, index: 0)
renderEncoder.drawPrimitives(type: .triangles, indexBuffer: metalLayer?.device?.makeIndexBuffer()!.makeObject(forKeyPath: kCFAllocatorDefaultNameKeyPath) as! MTLIndexBuffer, indexCount: 6, indexBufferOffset: 0, indexBufferBindBase: 0, indexVertexType: .uint16, indexVertexOffset: 0, indexVertexCount: 3 * 2, indexVertexStride: 4 * sizeof(UInt16))
// Present the render pass on the metal layer
commandGroup.present(commandBuffer)
commandBuffer.commit()
}
}