Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CATiledLayer drawLayer:inContext always being called on Main thread - MacOS El Capitan

I'm using a CATiledLayer backed NSView (Mac not iOS) and according to Apple docs https://developer.apple.com/reference/quartzcore/catiledlayer I expect this to be called asynchronously, on multiple threads to aid performance, however it only appears to ever get called on the main thread.

I'm doing the work in drawLayer(layer: CALayer, inContext ctx: CGContext)

I have enabled canDrawConcurrently on the NSView as well as ensuring the window has allowsConcurrentViewDrawing set as true (default), but it still always calls on the main thread for each tile rect.

I need to do some image manipulation prior to display dependant on the rect area needing display, and running on the main thread impacts performance.

Any ideas how I can either force it to call on a background thread?

I have tried marshalling the image a operation onto background thread and then recalling the main queue with the following but it displays a blank rect:

backgroundQueue.addOperationWithBlock({ [ weak self ] in            
    guard let strongSelf = self else { return }

    // ** This is the part I nee to do in background that can take some time
    guard let image = strongSelf.imageForTileRect(layerBounds, imageSize: imageSize) else { return }
    // ** End background bit

    var rect = layerBounds
    let rectImageRef = image.CGImageForProposedRect(&rect, context: nil, hints: nil)

    if (rectImageRef != nil) {
        NSOperationQueue.mainQueue().addOperationWithBlock({ 
            CGContextDrawImage(ctx, rect, rectImageRef)
        })
    }
})
like image 952
Herwr Avatar asked Sep 19 '16 02:09

Herwr


1 Answers

We never actually managed to get it working when the CATiledLayer was the primary layer, I'm not sure why it doesn't work and we never got an answer from the Apple bug raised.

However we got it working doing background rendering by making the primary layer a standard CALayer and then adding a CATiledLayer as the subLayer to this primary one, similar to code below.

We also noticed it worked as expected if hosting the CATiledLayer in an NSView

Hope this helps...

class HostingLayer : CALayer {

    var tiledLayer : CATiledLayer!

    override init() {
        super.init()

        self.tiledLayer = CATiledLayer.init()

        self.addSublayer(tiledLayer!)
    }
}
like image 107
Herwr Avatar answered Nov 02 '22 11:11

Herwr