Is there any way to draw to a NSView asynchronously on macOS?

I have read that as of macOS X 10.14 setting setAllowsConcurrentViewDrawing to true on a NSWindow and setCanDrawConcurrently to true on its view is no longer supported to perform drawing outside the main thread.

All the documentation that I find on the internet strongly advise programmers to cleanup their main loops to perform only drawing and user input handing there. What else is left to do when this means multiple programmer*years of work?

I used to draw a CGImage wrapped in a NSImage through a NSGraphicsContext on a separate looping thread calling NSView's needsDisplay then [display], to display smooth animations.

I also picked up that NSOpenGLView has been deprecated.

With all that said, what would be the best way to go to perform threaded drawing in a NSView?

Thanks

Where did you read it? Actually before 10.14 NSView setCanDrawConcurrently was broken and it run everything on the main-thread.

That seems unrelated to NSView setCanDrawConcurrently property. Either try to use setCanDrawConcurrently directly, it finally works on 10.14 and later, or do what was recommended in that stackoverflow answer.

I'm setting setCanDrawConcurrently to YES on my view. The graphics context calls executed from drawRect still act like noops when ran on a separate drawing thread. I can clearly see drawRect running on my drawing thread by dumping the thread ID, the current graphics context is not nil and seems valid, and I'm making sure to call flushGraphics at the end of drawRect, but still nothing appears on screen. This is very perplexing.

The StackOverflow solution is about rendering backbuffers on a thread (which I already do in my case), but then let the main thread still perform the drawing of the backbuffers to the screen. This is not tolerable in my case as our main thread has historically been busy, enough to drop 40 frames out of 60.

Could it be possible that setCanDrawConcurrently only gets AppKit to use background threads when it needs to refresh the view, and has nothing to do with spawning a separate drawing thread manually?

If I dispatch the display to the main thread from my drawing thread then the screen updates, but at a refresh rate way too low:

  dispatch_async(dispatch_get_main_queue(), ^{
  self.needsDisplay = YES;
 });

The drawing thread only pulls a backbuffer from a queue populated by a render thread. I basically loop around this code on my drawing thread:

  self.needsDisplay = YES;
  [self display];

My dev machine is on macOS 10.15.7

The way setCanDrawConcurrently works is that AppKit calls your drawRect method in another thread. And that's it, it doesn't mean you can safely draw things on yet another thread different from the calling thread.

Is there any way to draw to a NSView asynchronously on macOS?
 
 
Q