When I capture the contents of an MTKView into a UIImage, the resulting image looks qualitatively different, as shown below:
The code I use to generate the UIIm
let context = CIContext()
let texture = metalView.currentDrawable!.texture
let cImg = CIImage(mtlTexture: texture, options: nil)!
let cgImg = context.createCGImage(cImg, from: cImg.extent)!
let uiImg = UIImage(cgImage: cgImg)
Your CGColorSpace
is .sRGB
but your renderPipelineDescriptor's pixelFormat is .bgra8Unorm
. Try changing that line to:
renderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm_srgb
I've seen this issue in a couple of posts, but no clear answer. Here is what I've found:
For starters,
renderPipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm
should really just be set to the MTKView's native pixel format
renderPipelineDescriptor.colorAttachments[0].pixelFormat = self.colorPixelFormat
Secondly, when I set the CIImage's options:
let kciOptions = [kCIContextWorkingColorSpace: CGColorSpace(name: CGColorSpace.sRGB)!,
kCIContextOutputPremultiplied: true,
kCIContextUseSoftwareRenderer: false] as [String : Any]
It didn't matter what I set kCIContextWorkingColorSpace to, I never saw any visual difference regardless of what I used. The property I really needed to set is called KCIImageColorSpace. So the updated kciOptions looks like:
let kciOptions = [kCIImageColorSpace: CGColorSpaceCreateDeviceRGB(),
kCIContextOutputPremultiplied: true,
kCIContextUseSoftwareRenderer: false] as [String : Any]
In a similar way of using the view's native pixel format, calling CGColorSpaceCreateDeviceRGB() creates an RGB colorspace that is specific to the device being used.