Re: drawing in a separate thread
Re: drawing in a separate thread
- Subject: Re: drawing in a separate thread
- From: Jean-Daniel Dupas <email@hidden>
- Date: Sat, 3 May 2008 13:57:48 +0200
Le 3 mai 08 à 13:36, Duncan a écrit :
On May 3, 2008, at 5:00 AM, Graham Cox <email@hidden> wrote:
One thing I realised after the previous posting is that the
performance hit I'm seeing is because unlike the usual drawRect:
case, I wasn't doing any clipping to the update area, so the entire
view was getting repainted rather than just some small part of it -
adding a clipRect: call substantially improved things.
However it also made me realise that just doing the drawing on a
second thread is not enough - my graphics code makes quite a bit of
use of the view's -needsToDrawRect: method, which of course when
it's called by the thread is just not going to be valid, as
drawRect: has been and gone. I'm not sure how to tackle this - it
would seem I'd have to cache the result of -
getRectsBeingDrawn:count: each time I queue a draw from the main
thread and somehow make these rects available to clients of the
view when they are drawn from the second thread (by overriding
needsToDrawRect: for example). This seems complicated and somewhat
hackish - or I redesign the drawing code to have these rects passed
down as a parameter for every draw, which is equally awkward.
If you're going to do your drawing in a separate thread, you'll need
to remember WHAT to draw. I wouldn't call it "hackish", I'd call it
the cost of doing business that way.
If you implement a job queue, add the list of dirty rectangles to
each job object. -drawRect would be where you'd add your jobs to the
queue. It cold call getRectsBeingDrawn:count to get the list of
dirty rects, then add that list to the job object. Then when the
worker thread picks up a job, it would get the list of dirty
rectangles from the job object instead of calling
getRectsBeingDrawn:count. That should be pretty straightforward.
One thing you may face with rendering in a separate thread: At some
point, you may need to wait for rendering to complete before your
app can go on to it's next task. Say, for example, you need to show
the user the results of their changes, then ask them what to do
next. In that case, you'd need a way to wait until drawing
completes. You could add something like a flushRendering call (much
like glFlush in OpenGL) that wold block until all the rendering jobs
were completely, or waitUntilJobComplete, which could wait until a
specific rendering job was complet
In fact, glFlush() is asynchonous and do not block until the end of
the rendering. glFlush() only pushs the command on the renderer queue
and returns.
If you want to wait the end of the rendering, you must use glFinish().
( http://developer.apple.com/qa/qa2004/qa1158.html )
I'm not yet convinced that drawing on a second thread will really
give any benefit, so I'm reluctant to change things dramatically to
allow it when I may end up abandoning the whole idea.
Be useful to hear from anyone who's done something like this to a)
convince me it's worth it and b) hear about any solutions to the
update rects issue.
Using a separate thread for time-consuming drawing does make the
user experience much better. My app does OpenGL rendering of large,
complex 3D fractals, and I ended up pulling out the drawing code
into a separate thread. That's even hairier than what you're trying
to do, because I use NSOpenGLViews, and they are not particularly
well set up for multi-threaded use.
What I do is to display a progress bar at the bottom of my 3D view
window. As rendering progresses, I update the progress bar. I return
control to the user immediately, so I avoid the spinning wait
cursor. If the user then does something that invalidates the current
rendering task, I set a "terminate rendering" flag and wait for the
rendering thread to stop, then submit a new rendering job.
Duncan C
NSOpenGLViews is probably the only view that support multi-threading
out of the box. There is a lots of sample codes on ADC that draw in
OpenGL view from many threads. (All CoreVideo samples for example).
There is only two things you have to do. In your GLView subclass,
synchronize the -update message - (void)update { @synchronize(self)
{ [super update]; } } and in your drawing method lock your gl context
to be sure that only one thread access it to draw at a time.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden