TL;DR: In macOS 10.13, an MTLTexture
has a maximum width and height of 16,384. What strategies can you use to be able to process and display images larger than 16,384 pixels using Metal?
In a photo viewer that I'm currently working on, I've moved most of the viewing of images into a Metal backed view that uses Core Image for doing any image adjustments. This is working really well but I've recently started testing against some really large images (panoramas) and I'm now hitting some limits that I'm not entirely sure how to workaround while remaining relatively performant.
My current environment looks like this:
Load and decode an image from from an
NSURL
into anIOSurface
. This is done using either Image IO directly or a Core Image pipeline that renders into theIOSurface
. TheIOSurface
is then passed from an XPC service back into the main app.In the main app, a new
MTLTexture
is created that is backed by theIOSurface
. Then, aCIImage
is created from theMTLTexture
and thatCIImage
is used throughout an image pipeline as the root "source image".
However, if I attempt to open an image larger that 16,384 pixels in one dimension, then I'm unable to create the original IOSurface 16,384 on my laptop. (13" MBP-TB 2016)
But even if I could create a larger IOSurface
, then I'm still stuck with the same limit on the MTLTexture
.
See: Apple's Metal Feature Table Set
I'm curious what strategies others would recommend to allow one to open large image files while still taking advantage of Core Image and Metal.
One attempt I've made is to just have the root source image be a CIImage
that was created with a CGImageRef
. However, there's a significant drop in performance between that arrangement and a CIImage
backed by a texture for even smaller sized images.
Another idea I've had, but haven't yet explored, was to use CIImageProvider
in some capacity but I'm not entirely sure how I'd go about "tiling" potentially several IOSurfaces
or MTLTextures
, and if that even makes sense or if it would be better to just allocate a single large buffer to read from. (Or perhaps use dispatch_data
in some capacity?)
(macOS 10.13 or even 10.14 would be fine.)