How do I properly set tagged color data in MTKView and CIContext?

I have provided a test UIKit app which displays three different images, side by side, each inside a separate MTKView. Each image is tagged with a different color profile:

  • Display P3
  • uRGB
  • Test RGB (from an image supplied in Apple's ImageApp sample).

I set up default values for all color spaces and formats. I then check if the image is tagged and, if so, I override those values with state from the tagged color space.

The variables I am setting:

  • “workingColorSpace” in the Metal CIContext, default = sRGB
  • “workingFormat” in the Metal CIContext, default = RGBAf
  • “outputColorSpace” in the Metal CIContext, default = displayP3
  • “colorPixelFormat” in the MTKView, default = bgra8Unorm
  • “colorSpace” in a CIRenderDestination that I use in the MTKView delegate draw method

The “colorSpace” default value = CGColorSpaceCreateDeviceRGB()

I also set “pixelFormat” in CIRenderDestination with the MTKView.colorPixelFormat.

If the image is tagged, I override the following values with the tagged colorSpace:

  • CIContext.workingColorSpace
  • CIContext.outputColorSpace
  • CIRenderDestination.colorSpace

If the tagged colorSpace.isWideGamutRGB = true, then I set the CIRenderDestination.colorSpace to extendedSRGB, ignoring the color space in the tagged wide gamut color space, as well as set the colorPixelFormat = bgr10_xr

Results:

  • The above scenario will properly render the DisplayP3 image, and the uRGB image. The “Test RGB” image fails:

  • If I do not override the CIRenderDestination.colorSpace with a value from the tagged image, then the “Test RGB” image succeeds, but the “uRGB” image fails to render properly:

Question: Do I have everything hooked up correctly and, if so, why does one image fail, and the other succeed?

Link to sample project:

https://www.dropbox.com/scl/fi/57u2fcrgdvys7jtzykzxt/ColorSpaceTest.zip?rlkey=unjeeiu7mi0wx9wfpylt78nwd&dl=0

Replies

I think I solved it. I set the colorspace on the underlying CAMetalLayer of the MTKView (iOS/Catalyst does not let you set this directly on MTKView):

Add the following code at the end of the init method in MTKImageView.swift:

if let taggedColorSpace = image.colorSpace,
   let metalLayer = self.layer as? CAMetalLayer {
        metalLayer.colorspace = taggedColorSpace
}

All three images now properly display for me:

Update: If the colorspace supports wideGamut, then I set the colorspace in the CAMetalLayer to extendedSRGB, instead of the tagged colorspace:

if let taggedColorSpace = image.colorSpace,
   let metalLayer = self.layer as? CAMetalLayer {
       metalLayer.colorspace = isWideGamutRGB ? CGColorSpace(name: CGColorSpace.extendedSRGB) : taggedColorSpace
}