Skip navigation.
 
mlRe: drawing in a separate thread
FROM : Graham Cox
DATE : Fri May 02 13:07:26 2008

On 2 May 2008, at 6:13 pm, Kyle Sluder wrote:

> On Fri, May 2, 2008 at 3:13 AM, Graham Cox <graham.<email_removed>> 
> wrote:

>> I realise these questions must sound rather fundamental, but 
>> nothing in the
>> Cocoa Drawing Guide or Thread Guide really addresses them. I have 
>> used
>> threads before to perform tasks not involving drawing, so I'm not 
>> completely
>> unfamiliar with them, but I haven't tried drawing on a secondary 
>> thread
>> before.

>
> The reason these questions aren't addressed in the guide is because
> they are highly dependent on just what you are doing.  Only you can
> determine when something needs to be updated.



Well the current single-threaded app already does all of that, and so 
I end up with setNeedsDisplayInRect: calls being made to the view as 
usual. Then I get a drawRect: to draw whatever accumulated on the 
previous loop. It's the actual rendering that I'm hoping to offload 
onto another thread - and so use a separate core, leaving the main 
thread to continue handling user input which *should* make the app 
feel faster even though the amount of drawing going on is the same 
(Corollary question: does Quartz thread any of its drawing anyway? 
Maybe there's no advantage in this if it does).

I found this old posting by John C Randolph:

> "In a multithreaded application, the main thread is still responsible
> for redisplaying dirty views through the same process as a
> single-threaded application. The drawRect: method of every dirty view
> is called in the main thread. If the drawing needs to be done in
> another thread, the drawRect: method for the view should arrange for
> the secondary thread to do the drawing and not do any drawing in
> drawRect:."



So what I guess needs to happen is that when the view gets a drawRect: 
call it needs to flag to the secondary thread that it should go ahead 
and perform the redraw, instead of doing it synchronously itself, so 
something like:


- (void)    drawRect:(NSRect) updateRect
{
    if( threaded )
   [thread doDrawingWithRect:updateRect inView:self]; // thread wakes up 
and calls [view doDrawingWithRect:] then sleeps
    else
   [self doDrawingWithRect:updateRect]; // standard synchronous drawing
}


All of my drawing is completely within the rules, in that it's 
performed within drawRect:, and any updates needed end up in 
setNeedsDisplayInRect:, so it seems to me that the drawing in the 
second thread should be straightforward enough (and also easy to 
switch between the two "modes" of operation). At this stage I consider 
it an experiment to see what the benefits or difficulties might be.

>
> As for spawning multiple threads, you want your drawing to be
> performed really quickly.  I would strongly advocate keeping a thread
> around for the life of your view and having it sit an a loop that ends
> with it performing a blocking read on some IPC port.  That way it gets
> scheduled off the processor but you don't suffer the thread-creation
> or -destruction penalty every time you perform a draw.


From what you're saying, I should have a worker thread that waits for 
a request to draw, do the drawing, then go back to sleep until next 
time. What isn't clear is if this thread should be per-view, or used 
by all views that work this way, and how exactly it should be flagged 
to do the drawing (and all the sleep issues, etc). I'm not sure what 
an IPC port is (I will look it up) but I get the general idea. If you 
can point me in the right direction to answer some of these, I'm happy 
to experiment with what's needed on the drawing side of things (and 
I'm hoping it's relatively little different from the single-threaded 
case).

So my question at this stage isn't about drawing but about setting up 
and controlling the worker thread, (I think).
>
> Drawing from a secondary thread isn't an easy task, so perhaps you
> might want to consider whether it's possible to avoid doing so.  Maybe
> you can draw into an image on the secondary thread, and then when
> necessary use -performSelectorOnMainThread:withObject:waitUntilDone:
> to send the view a -setNeedsDisplay: message when after your thread
> has completed its drawing.  Then the view can overwrite its own buffer
> with it.  Be careful of synchronization issues, of course.
>
> HTH,
> --Kyle Sluder

Related mailsAuthorDate
mldrawing in a separate thread Graham Cox May 2, 09:13
mlRe: drawing in a separate thread Kyle Sluder May 2, 10:13
mlRe: drawing in a separate thread Graham Cox May 2, 13:07
mlRe: drawing in a separate thread Jean-Daniel Dupas May 2, 13:20
mlRe: drawing in a separate thread Jens Alfke May 2, 17:27
mlRe: drawing in a separate thread Graham Cox May 2, 17:30
mlRe: drawing in a separate thread Jean-Daniel Dupas May 2, 18:04
mlRe: drawing in a separate thread Duncan May 3, 05:40
mlRe: drawing in a separate thread Graham Cox May 3, 06:51
mlRe: drawing in a separate thread Duncan May 3, 13:36
mlRe: drawing in a separate thread Jean-Daniel Dupas May 3, 13:57
mlRe: drawing in a separate thread Graham Cox May 3, 14:52
mlRe: drawing in a separate thread Jean-Daniel Dupas May 3, 15:22
mlRe: drawing in a separate thread Graham Cox May 3, 15:30
mlRe: drawing in a separate thread Ricky Sharp May 3, 15:44
mlRe: drawing in a separate thread Jean-Daniel Dupas May 3, 15:55
mlRe: drawing in a separate thread Graham Cox May 3, 16:11