Search code examples
core-graphicscore-animation

Fastest way to draw offscreen CALayer content


I'm looking for the fastest way to draw offscreen CALayer content (no alpha needed) on macOS. Note, that these examples aren't threaded, but the point is (and why I'm not just using CALayer.setNeedsDisplay) because I'm doing this drawing on a background thread.

My original code did this:

let bounds = layer.bounds.size
let contents = NSImage(size: size)
contents.lockFocusFlipped(true)
let context = NSGraphicsContext.current()!.cgContext
layer.draw(in: context)
contents.unlockFocus()
layer.contents = contents

Solution

  • My current best is quite a bit faster:

    let contentsScale = layer.contentsScale
    let width = Int(bounds.width * contentsScale)
    let height = Int(bounds.height * contentsScale)
    let bytesPerRow = width * 4
    let alignedBytesPerRow = ((bytesPerRow + (64 - 1)) / 64) * 64
    
    let context = CGContext(
        data: nil,
        width: width,
        height: height,
        bitsPerComponent: 8,
        bytesPerRow: alignedBytesPerRow,
        space: NSScreen.main()?.colorSpace?.cgColorSpace ?? CGColorSpaceCreateDeviceRGB(),
        bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue
    )!
    
    context.scaleBy(x: contentsScale, y: contentsScale)
    layer.draw(in: context)
    layer.contents = context.makeImage()
    

    Tips and recommendations for making it better/faster are welcome.