7

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)
        })
    }
})
Herwr
  • 494
  • 2
  • 7
  • Did you ever figure this out? I am seeing the same thing. I want to use a background thread to draw to my CATiledLayer for my NSView. – Stephen Johnson Jan 31 '17 at 19:00
  • Some more context here. If I add another CATiledLayer as an overlay to the one that is my backing overlay, it renders in the background. Just the main one that is the backing for my view renders on the main thread. I may end up making the main one be blank, and put my rendering to an overlay CATiledLayer. – Stephen Johnson Feb 01 '17 at 20:17

2 Answers2

2

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!)
    }
}
Herwr
  • 494
  • 2
  • 7
0

So here is what I did that is working, though it is not ideal. In the drawRect: for my CATiledLayer backed NSView I draw a simple background (in my case a simple grid). I created another CATiledLayer and added it my NSView's layer as a sublayer and set the NSView as its delegate. This second `CATiledLayer' is getting the delegate draw calls on a background thread.

Stephen Johnson
  • 5,293
  • 1
  • 23
  • 37