Re: Threaded drawing

2013-12-12 Thread Uli Kusterer
On 11 Dec 2013, at 16:01, Jens Alfke j...@mooseyard.com wrote:
 On Dec 11, 2013, at 4:39 AM, 2551 2551p...@gmail.com wrote:
 It’s certainly seemed the case to me that I would have probably spent less 
 time just writing my own code from scratch than I spend trying to figure out 
 how half the methods I’m trying to use should be implemented. 
 
 That’s probably not actually true; our experience of time is pretty 
 subjective, and time goes by faster when you’re in a ‘flow’ state than when 
 you’re trying to figure out something new.
 
 Even if it’s a bit faster to write your own code, using the system APIs is 
 probably still a win because
 (a) their implementations are almost certainly better debugged and more 
 performant than your brand-new unused code;
 (b) they will be improved and maintained by other people over time, saving 
 you the trouble;
 (c) they’ve been designed to be reusable, so you’ll be able to use them 
 quickly in your next project;
 (d) you can later hang out here explaining the APIs to noobs and make 
 yourself look like a guru (or better yet, write books) ;-)


Let's preface that with the statement that I agree with your conclusion.

Using Apple's code generally saves a lot of hassle and work because your code 
has only you doing QA. Apple's code has all of Apple, plus you, plus everyone 
else outside Apple who uses this API doing QA. It's bound to be more solid. 
That said, Apple's code still has only whatever team at Apple is responsible 
for that code fixing it. Only they have the source code.

So occasionally, when a piece of code isn't or stops being a priority for 
Apple, item (b) above can actually be a liability. Still, we've seen how people 
circumvent that with sync code and CoreData. People first use Apple's code, 
getting a leg up and a release out the door and money in their coffers, and can 
then afford to fund their own version.

-- Uli Kusterer
The Witnesses of TeachText are everywhere...




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing - JPEG

2013-12-12 Thread Uli Kusterer
On 11 Dec 2013, at 18:53, Steve Sisak sgs-li...@codewell.com wrote:
 At 10:25 AM -0800 12/10/13, Seth Willits wrote:
 On Dec 10, 2013, at 1:32 AM, Graham Cox graham@bigpond.com wrote:
  But my situation is that I need to draw VECTOR objects up to 25,000% zoom 
  with no pixelization.
 
 You're given a CGContext to draw into; What's the difference? The tiled 
 drawing is async, so if the drawing doesn't occur fast enough it'll scale up 
 the low-scale bitmap, but what's evil about that? It's like Apple or Google 
 maps.
 
 Not to hijack the thread, but I'm just getting head into optimizing some code 
 which displays live preview for a number of JPEG streams simultaneously.
 
 Most implementations I've tried result in being CPU bound in JPEG code on the 
 main thread with the 7 other cores idle.
 
 I've tried variants of NSImageView, CGImage and CIImage and all that's needed 
 to render them on alternate threads but Cocoa appears to so good at delaying 
 evaluation as long as possible that it seems to end up calling the JPEG 
 decoder synchronously from -drawRect of whatever view subclass I've chosen on 
 the main thread.
 
 Any suggestions for what technologies to use to run a JPEG through, say 
 CIImage w/o blocking the main thread.
 
 This has turned out to be way more complicated than I thought.


 If you want previews, I think ImageIO has dedicated methods for generating 
previews (MacOS definitely has some somewhere, even if I mis-remember them 
being in ImageIO). Particularly in the case of JPEG these can be much more 
efficient because of the way JPEGs are stored. Essentially, JPEGs often contain 
a few small DCTs at the start that can give you a vague, blurry version of the 
image, then draw more DCTs on top to add in the detail (I'm criminally 
simplifying here). So the preview calls can actually just draw the blurry 
version into a smaller destination and stop there, and don't have to calculate 
or even load the rest of the image.

-- Uli Kusterer
The Witnesses of TeachText are everywhere...




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing - JPEG

2013-12-12 Thread Mike Abdullah

On 12 Dec 2013, at 11:55, Uli Kusterer witness.of.teacht...@gmx.net wrote:

 On 11 Dec 2013, at 18:53, Steve Sisak sgs-li...@codewell.com wrote:
 At 10:25 AM -0800 12/10/13, Seth Willits wrote:
 On Dec 10, 2013, at 1:32 AM, Graham Cox graham@bigpond.com wrote:
 But my situation is that I need to draw VECTOR objects up to 25,000% zoom 
 with no pixelization.
 
 You're given a CGContext to draw into; What's the difference? The tiled 
 drawing is async, so if the drawing doesn't occur fast enough it'll scale 
 up the low-scale bitmap, but what's evil about that? It's like Apple or 
 Google maps.
 
 Not to hijack the thread, but I'm just getting head into optimizing some 
 code which displays live preview for a number of JPEG streams simultaneously.
 
 Most implementations I've tried result in being CPU bound in JPEG code on 
 the main thread with the 7 other cores idle.
 
 I've tried variants of NSImageView, CGImage and CIImage and all that's 
 needed to render them on alternate threads but Cocoa appears to so good at 
 delaying evaluation as long as possible that it seems to end up calling the 
 JPEG decoder synchronously from -drawRect of whatever view subclass I've 
 chosen on the main thread.
 
 Any suggestions for what technologies to use to run a JPEG through, say 
 CIImage w/o blocking the main thread.
 
 This has turned out to be way more complicated than I thought.
 
 
 If you want previews, I think ImageIO has dedicated methods for generating 
 previews (MacOS definitely has some somewhere, even if I mis-remember them 
 being in ImageIO). Particularly in the case of JPEG these can be much more 
 efficient because of the way JPEGs are stored. Essentially, JPEGs often 
 contain a few small DCTs at the start that can give you a vague, blurry 
 version of the image, then draw more DCTs on top to add in the detail (I'm 
 criminally simplifying here). So the preview calls can actually just draw the 
 blurry version into a smaller destination and stop there, and don't have to 
 calculate or even load the rest of the image.

Yes, ImageIO has highly optimised routines for generating thumbnails. (Which 
seems a slight misnomer seeing as you can use them to pull out some seriously 
large images).

By default, ImageIO holds off decoding JPEGs etc. until actually needed. iOS 
devs have run up against this for years, where the decoding kicks in on the 
main thread at the first draw, and gets in the way. The standard solution most 
seem to have arrived at is to first — on a worker thread — draw a single pixel 
of the image into a 1x1 pixel bitmap context. This forces the decoding to kick 
in, and is now cached ready for drawing on the main thread.

As of 10.9, ImageIO adds the option: kCGImageSourceShouldCacheImmediately. 
Sadly this hasn’t made its way through to the full docs yet, but it should 
solve the problem you have without the need to faff about with a bitmap context 
in the background.

If you use the thumbnail routines instead, in my experience they perform the 
decoding upfront for you anyway, so there’s no need for the workaround there.
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-12 Thread 2551
OK, OK, point taken. 

I think I'll print that list (and Uli’s caveat) and hang it on the wall, right 
next to the space I use for banging my head when struggling with Cocoa… :p


On 12 Dec 2013, at 18:46, Uli Kusterer witness.of.teacht...@gmx.net wrote:

 On 11 Dec 2013, at 16:01, Jens Alfke j...@mooseyard.com wrote:
 On Dec 11, 2013, at 4:39 AM, 2551 2551p...@gmail.com wrote:
 It’s certainly seemed the case to me that I would have probably spent less 
 time just writing my own code from scratch than I spend trying to figure 
 out how half the methods I’m trying to use should be implemented. 
 
 That’s probably not actually true; our experience of time is pretty 
 subjective, and time goes by faster when you’re in a ‘flow’ state than when 
 you’re trying to figure out something new.
 
 Even if it’s a bit faster to write your own code, using the system APIs is 
 probably still a win because
 (a) their implementations are almost certainly better debugged and more 
 performant than your brand-new unused code;
 (b) they will be improved and maintained by other people over time, saving 
 you the trouble;
 (c) they’ve been designed to be reusable, so you’ll be able to use them 
 quickly in your next project;
 (d) you can later hang out here explaining the APIs to noobs and make 
 yourself look like a guru (or better yet, write books) ;-)
 
 
 Let's preface that with the statement that I agree with your conclusion.
 
 Using Apple's code generally saves a lot of hassle and work because your code 
 has only you doing QA. Apple's code has all of Apple, plus you, plus everyone 
 else outside Apple who uses this API doing QA. It's bound to be more solid. 
 That said, Apple's code still has only whatever team at Apple is responsible 
 for that code fixing it. Only they have the source code.
 
 So occasionally, when a piece of code isn't or stops being a priority for 
 Apple, item (b) above can actually be a liability. Still, we've seen how 
 people circumvent that with sync code and CoreData. People first use Apple's 
 code, getting a leg up and a release out the door and money in their coffers, 
 and can then afford to fund their own version.
 
 -- Uli Kusterer
 The Witnesses of TeachText are everywhere...
 
 
 


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Graham Cox

On 10 Dec 2013, at 7:39 pm, Kyle Sluder k...@ksluder.com wrote:

 but more directly, by using CATiledLayer you don't have to handle the tiling 
 and threading yourself, and it avoids the final blit of your buffer into the 
 view because you're (presumably) drawing directly into the layer backing.
 
 Yup, these two points are exactly why I suggested it.


Well, looks like we have a winner :)

Thanks to all that suggested CATiledLayer, I guess I shouldn’t be surprised, 
but it does actually work, and as well as performing excellently is very easy 
to set up as well. Seems to do the job without any kinks in the road - just set 
it as the view’s layer and away it goes.

The documentation is sparse though, I’m not quite sure what I should be using 
for -levelsOfDetail and -levelsOfDetailBias. It’s clear I do need to set these 
to something other than their defaults to get the behaviour I need, which is 
not to pixelize my vector drawing as I zoom in. The defaults do show 
pixelization.

My understanding is that -levelsOfDetail pertains to zooming OUT, and how many 
images get cached. So I have a fairly small number here, as zooming out isn’t a 
huge deal. -levelsOfDetailBias*, on the other hand, appears to pertain to 
zooming IN, and at what point the content is redrawn at a higher resolution. 
Since I need to attain up to 250x zoom, I’ve set this to 8, as each level is 
double the res of the last one, and 2^8 is 256. That’s my somewhat limited 
understanding, not particularly well-informed by the docs, but appears to work 
by experimentation. If anyone knows more than this, I’d love to know if I’m 
off-track.

*who comes up with these names? Are they self-describing?

Performance wise, It’s very hard to come up with a number as to whether this is 
showing any benefit in my test case (which isn’t very ‘heavy’ on drawing). 
Instruments shows a very different profile, with no one stack really 
dominating, which I suppose is good. The CPU Usage graph also shows 
considerably less overall work being done with no peaks hitting the max level. 
But the overall milliseconds appears to be very slightly more than straight 
drawing in the test case. *Shrugs*, I guess I have to throw it at my ‘heavy’ 
drawing and just see if it is noticeably better.

—Graham




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Ken Thomases
On Dec 11, 2013, at 4:20 AM, Graham Cox wrote:

 The documentation is sparse though, I’m not quite sure what I should be using 
 for -levelsOfDetail and -levelsOfDetailBias. It’s clear I do need to set 
 these to something other than their defaults to get the behaviour I need, 
 which is not to pixelize my vector drawing as I zoom in. The defaults do show 
 pixelization.

By searching the docs for levelsOfDetailBias, I found Apple's 
CALayerEssentials sample code.  A section of the AppController.m sets these 
properties and has a comment which explains them fairly well:

// To provide multiple levels of content, you need to set the 
levelsOfDetail property.
// For this sample, we have 5 levels of detail (1/4x - 4x).
// By setting the value to 5, we establish that we have levels of 1/16x - 
1x (2^-4 - 2^0)
// we use the levelsOfDetailBias property we shift this up by 2 raised to 
the power
// of the bias, changing the range to 1/4-4x (2^-2 - 2^2).
exampleCATiledLayer.levelsOfDetail = 5;
exampleCATiledLayer.levelsOfDetailBias = 2;

Why such a clear explanation isn't in the class reference, I couldn't tell you.

Regards,
Ken


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread 2551

On 11 Dec 2013, at 17:20, Graham Cox graham@bigpond.com wrote:
 The documentation is sparse though SNIP...That’s my somewhat limited 
 understanding, not particularly well-informed by the docs, but appears to 
 work by experimentation. 

The commonality of this experience makes me wonder almost with everything I try 
to do in Cocoa whether it really IS true as advertised that the pre-written 
APIs make it easier than writing your own raw code all the way down in C and 
Obj-C or whether the whole Cocoa edifice has turned into such a monster that 
for anyone except the seasoned expert, quite the reverse is true.

It’s certainly seemed the case to me that I would have probably spent less time 
just writing my own code from scratch than I spend trying to figure out how 
half the methods I’m trying to use should be implemented. Of course, I always 
give in to Cocoa on the grounds that I figure I must be being stupid and 
missing the obvious and/or it’s inevitable that I’ll have to learn how to do it 
‘the Cocoa way’ in the end. 

Still, you can’t help wondering… ;)
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Graham Cox

On 11 Dec 2013, at 1:39 pm, 2551 2551p...@gmail.com wrote:

 The commonality of this experience makes me wonder almost with everything I 
 try to do in Cocoa whether it really IS true as advertised that the 
 pre-written APIs make it easier than writing your own raw code all the way 
 down in C and Obj-C or whether the whole Cocoa edifice has turned into such a 
 monster that for anyone except the seasoned expert, quite the reverse is true.


Actually I think my experiences illustrated in this thread show the opposite. I 
started by attempting to write my own code (still in Obj-C) and it got 
moderately complicated before I gave up without showing any performance benefit 
(in fact the opposite).

Using CATiledLayer, as badly documented as it is, was about 5 lines of code and 
actually worked in doing what I had been attempting to do all along. The 
problem for me was one of even realising that the class was a good fit for my 
situation.

On the whole, using Cocoa is a huge benefit. Of course it’ll have some bugs, 
bad documentation, etc - in other words the same problems all projects have. 
The difference I suppose is that it has many knowledgable engineers working on 
it, it is extremely well-funded (in theory) and is more thoroughly debugged 
than pretty much anything you could write on your own of its size and scope. We 
do complain sometimes, and frustration isn’t uncommon, but let’s keep things in 
perspective.

File radars, maybe we’ll get better documentation.

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Graham Cox

On 11 Dec 2013, at 12:40 pm, Ken Thomases k...@codeweavers.com wrote:

 By searching the docs for levelsOfDetailBias, I found Apple's 
 CALayerEssentials sample code.  A section of the AppController.m sets these 
 properties and has a comment which explains them fairly well:

Ah, thanks! That makes more sense and explains the method names better as well.

 Why such a clear explanation isn't in the class reference, I couldn't tell 
 you.


Indeed ;-)

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Jens Alfke

On Dec 11, 2013, at 4:39 AM, 2551 2551p...@gmail.com wrote:

 It’s certainly seemed the case to me that I would have probably spent less 
 time just writing my own code from scratch than I spend trying to figure out 
 how half the methods I’m trying to use should be implemented. 

That’s probably not actually true; our experience of time is pretty subjective, 
and time goes by faster when you’re in a ‘flow’ state than when you’re trying 
to figure out something new.

Even if it’s a bit faster to write your own code, using the system APIs is 
probably still a win because
(a) their implementations are almost certainly better debugged and more 
performant than your brand-new unused code;
(b) they will be improved and maintained by other people over time, saving you 
the trouble;
(c) they’ve been designed to be reusable, so you’ll be able to use them quickly 
in your next project;
(d) you can later hang out here explaining the APIs to noobs and make yourself 
look like a guru (or better yet, write books) ;-)

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Jeffrey Oleander



On 2013 Dec 11, at 10:01, Jens Alfke wrote:

On 2013 Dec 11, at 04:39, 2551 2551p...@gmail.com wrote:
It’s certainly seemed the case to me that I would have probably 
spent less time just writing my own code from scratch than I spend 
trying to figure out how half the methods I’m trying to use should 
be implemented.


That’s probably not actually true; our experience of time is pretty 
subjective, and time goes by faster when you’re in a flow state 
than when you're trying to figure out something new...


When a software developer is figuring out something new is exactly when 
he is in a flow state.  Flow state requires a challenge which can be 
met.  In this case, at some level, we're weighing trying to figure out 
from the cryptic docs and experiments how the frame-work works*, vs. 
building something that works as you think of it and as you want it to 
work from simpler components.  Sometimes the frame-works are 
easier/better, and sometimes designing and developing your own is 
better.


* (The posted snippet from sample code was as clear as mud to me.  Why 
powers of 4 (and -4) instead of 5 when we're talking about 5 levels of 
detail?
1/(2^2) - 2^2 = (1/4) - 4  means ...levelsOfDetail should be set to 
5?!?

It needs more words, more context.)

Leave comments on the docs, file radars, maybe we’ll get better 
documentation... some day.  dum spiro spero


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Mike Abdullah

On 11 Dec 2013, at 13:10, Graham Cox graham@bigpond.com wrote:

 
 On 11 Dec 2013, at 1:39 pm, 2551 2551p...@gmail.com wrote:
 
 The commonality of this experience makes me wonder almost with everything I 
 try to do in Cocoa whether it really IS true as advertised that the 
 pre-written APIs make it easier than writing your own raw code all the way 
 down in C and Obj-C or whether the whole Cocoa edifice has turned into such 
 a monster that for anyone except the seasoned expert, quite the reverse is 
 true.
 
 
 Actually I think my experiences illustrated in this thread show the opposite. 
 I started by attempting to write my own code (still in Obj-C) and it got 
 moderately complicated before I gave up without showing any performance 
 benefit (in fact the opposite).
 
 Using CATiledLayer, as badly documented as it is, was about 5 lines of code 
 and actually worked in doing what I had been attempting to do all along. The 
 problem for me was one of even realising that the class was a good fit for my 
 situation.
 
 On the whole, using Cocoa is a huge benefit. Of course it’ll have some bugs, 
 bad documentation, etc - in other words the same problems all projects have. 
 The difference I suppose is that it has many knowledgable engineers working 
 on it, it is extremely well-funded (in theory) and is more thoroughly 
 debugged than pretty much anything you could write on your own of its size 
 and scope. We do complain sometimes, and frustration isn’t uncommon, but 
 let’s keep things in perspective.
 
 File radars, maybe we’ll get better documentation.

Even better, use the “Provide Feedback” links in the documentation. They’re 
quicker to fill out, and preferred by Apple’s engineers as give them more 
context as to what you’re complaining about.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing - JPEG

2013-12-11 Thread Steve Sisak

At 10:25 AM -0800 12/10/13, Seth Willits wrote:

On Dec 10, 2013, at 1:32 AM, Graham Cox graham@bigpond.com wrote:
  But my situation is that I need to draw VECTOR objects up to 
25,000% zoom with no pixelization.


You're given a CGContext to draw into; What's the difference? The 
tiled drawing is async, so if the drawing doesn't occur fast enough 
it'll scale up the low-scale bitmap, but what's evil about that? 
It's like Apple or Google maps.


Not to hijack the thread, but I'm just getting head into optimizing 
some code which displays live preview for a number of JPEG streams 
simultaneously.


Most implementations I've tried result in being CPU bound in JPEG 
code on the main thread with the 7 other cores idle.


I've tried variants of NSImageView, CGImage and CIImage and all 
that's needed to render them on alternate threads but Cocoa appears 
to so good at delaying evaluation as long as possible that it seems 
to end up calling the JPEG decoder synchronously from -drawRect of 
whatever view subclass I've chosen on the main thread.


Any suggestions for what technologies to use to run a JPEG through, 
say CIImage w/o blocking the main thread.


This has turned out to be way more complicated than I thought.

Thanks,

-Steve
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing - JPEG

2013-12-11 Thread Greg Parker
On Dec 11, 2013, at 9:53 AM, Steve Sisak sgs-li...@codewell.com wrote:
 Not to hijack the thread, but I'm just getting head into optimizing some code 
 which displays live preview for a number of JPEG streams simultaneously.
 
 Most implementations I've tried result in being CPU bound in JPEG code on the 
 main thread with the 7 other cores idle.
 
 I've tried variants of NSImageView, CGImage and CIImage and all that's needed 
 to render them on alternate threads but Cocoa appears to so good at delaying 
 evaluation as long as possible that it seems to end up calling the JPEG 
 decoder synchronously from -drawRect of whatever view subclass I've chosen on 
 the main thread.

Simple attempt: when you get the JPEG, create a CGBitmapContext on a background 
thread and draw the JPEG into it. Then use the CGBitmapContext to draw on the 
main thread.


-- 
Greg Parker gpar...@apple.com Runtime Wrangler



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread David Duncan
On Dec 11, 2013, at 8:05 AM, Jeffrey Oleander jgo...@yahoo.com wrote:

 * (The posted snippet from sample code was as clear as mud to me.  Why powers 
 of 4 (and -4) instead of 5 when we're talking about 5 levels of detail?
 1/(2^2) - 2^2 = (1/4) - 4  means ...levelsOfDetail should be set to 5?!? It 
 needs more words, more context.)


The base level of detail is a zoom level of 2^0 (1 level of detail only allows 
for a single representation like that). Each additional level of detail is a 
zoom level half that size smaller (thus a 2nd level if 2^-1x or 1/2x, then 
2^-2x or 1/4x, etc). The bias adds to the base level’s exponent, thus a bias of 
2 means the base level if 2^2x (4x) zoom instead of 2^0x zoom.

There are no powers of 4, (or 5 or any other except for 2). The level of detail 
is range of the exponent, not the base.
--
David Duncan

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing - JPEG

2013-12-11 Thread Kevin Meaney
On 11 Dec 2013, at 22:43, Greg Parker gpar...@apple.com wrote:

 On Dec 11, 2013, at 9:53 AM, Steve Sisak sgs-li...@codewell.com wrote:
 Not to hijack the thread, but I'm just getting head into optimizing some 
 code which displays live preview for a number of JPEG streams simultaneously.
 
 Most implementations I've tried result in being CPU bound in JPEG code on 
 the main thread with the 7 other cores idle.
 
 I've tried variants of NSImageView, CGImage and CIImage and all that's 
 needed to render them on alternate threads but Cocoa appears to so good at 
 delaying evaluation as long as possible that it seems to end up calling the 
 JPEG decoder synchronously from -drawRect of whatever view subclass I've 
 chosen on the main thread.
 
 Simple attempt: when you get the JPEG, create a CGBitmapContext on a 
 background thread and draw the JPEG into it. Then use the CGBitmapContext to 
 draw on the main thread.

I think I must have missed something, because when drawing from the context 
created using CGBitmapContext don't you have to create a CGImage from the 
bitmap first and then draw that. Plus didn't part of the previous discussion in 
this thread suggest that you can't get the details of the window context that 
you'll be drawing into so that the image will have to be drawn again rather 
than just a bunch of memory copies. See Graham Cox's e-mail 9 December at 19:02 
(GMT). So that's a jpeg decompress and draw, the CGImage creation, and then a 
draw into a context that you don't know what it is. I haven't profiled this but 
it doesn't seem efficient though the main thread might be a little more 
responsive.

Kevin






___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread Dave Fernandes
Is there any way to zoom in just one dimension?

On Dec 11, 2013, at 6:05 PM, David Duncan david.dun...@apple.com wrote:

 On Dec 11, 2013, at 8:05 AM, Jeffrey Oleander jgo...@yahoo.com wrote:
 
 * (The posted snippet from sample code was as clear as mud to me.  Why 
 powers of 4 (and -4) instead of 5 when we're talking about 5 levels of 
 detail?
 1/(2^2) - 2^2 = (1/4) - 4  means ...levelsOfDetail should be set to 5?!? 
 It needs more words, more context.)
 
 
 The base level of detail is a zoom level of 2^0 (1 level of detail only 
 allows for a single representation like that). Each additional level of 
 detail is a zoom level half that size smaller (thus a 2nd level if 2^-1x or 
 1/2x, then 2^-2x or 1/4x, etc). The bias adds to the base level’s exponent, 
 thus a bias of 2 means the base level if 2^2x (4x) zoom instead of 2^0x zoom.
 
 There are no powers of 4, (or 5 or any other except for 2). The level of 
 detail is range of the exponent, not the base.
 --
 David Duncan
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 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:
 https://lists.apple.com/mailman/options/cocoa-dev/dave.fernandes%40utoronto.ca
 
 This email sent to dave.fernan...@utoronto.ca


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-11 Thread David Duncan

On Dec 11, 2013, at 4:17 PM, Dave Fernandes dave.fernan...@utoronto.ca wrote:

 Is there any way to zoom in just one dimension?

Not really. You could put a counter transform before drawing that eliminates 
the opposite direction (and the aforementioned sample should show how to find 
out the current zoom level) but thats not really a satisfying solution...

 
 On Dec 11, 2013, at 6:05 PM, David Duncan david.dun...@apple.com wrote:
 
 On Dec 11, 2013, at 8:05 AM, Jeffrey Oleander jgo...@yahoo.com wrote:
 
 * (The posted snippet from sample code was as clear as mud to me.  Why 
 powers of 4 (and -4) instead of 5 when we're talking about 5 levels of 
 detail?
 1/(2^2) - 2^2 = (1/4) - 4  means ...levelsOfDetail should be set to 5?!? 
 It needs more words, more context.)
 
 
 The base level of detail is a zoom level of 2^0 (1 level of detail only 
 allows for a single representation like that). Each additional level of 
 detail is a zoom level half that size smaller (thus a 2nd level if 2^-1x or 
 1/2x, then 2^-2x or 1/4x, etc). The bias adds to the base level’s exponent, 
 thus a bias of 2 means the base level if 2^2x (4x) zoom instead of 2^0x zoom.
 
 There are no powers of 4, (or 5 or any other except for 2). The level of 
 detail is range of the exponent, not the base.
 --
 David Duncan
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 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:
 https://lists.apple.com/mailman/options/cocoa-dev/dave.fernandes%40utoronto.ca
 
 This email sent to dave.fernan...@utoronto.ca

--
David Duncan

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Graham Cox

On 9 Dec 2013, at 11:12 pm, Kyle Sluder k...@ksluder.com wrote:

 Which is another reason to seriously consider CATiledLayer


I”ll consider it, and revisit it…

But my situation is that I need to draw VECTOR objects up to 25,000% zoom with 
no pixelization. That means the CATileLayer needs to remain firmly “stuck to 
the window”, and not to the view. Without more comprehensive documentation 
and/or a reasonably similar example code to work from, it’s an uphill struggle.

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Graham Cox

On 10 Dec 2013, at 12:39 am, Seth Willits sli...@araelium.com wrote:

 There’s NSView’s bitmapImageRepForCachingDisplayInRect: and you can grab a 
 colorspace from the rep. I would certainly imagine that has the ideal space 
 and you can confirm it’s one or another. You can use that method to create 
 your presumably ideal backing and then create multiple contexts that share 
 the same buffer as that original bitmap rep on your background threads.


Interesting idea, I’ll certainly give it a shot.

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Mike Abdullah

On 10 Dec 2013, at 09:32, Graham Cox graham@bigpond.com wrote:

 
 On 9 Dec 2013, at 11:12 pm, Kyle Sluder k...@ksluder.com wrote:
 
 Which is another reason to seriously consider CATiledLayer
 
 
 I”ll consider it, and revisit it…
 
 But my situation is that I need to draw VECTOR objects up to 25,000% zoom 
 with no pixelization. That means the CATileLayer needs to remain firmly 
 “stuck to the window”, and not to the view. Without more comprehensive 
 documentation and/or a reasonably similar example code to work from, it’s an 
 uphill struggle.

Another option to consider is using CAShapeLayer to render individual objects 
where reasonable. This should allow Core Animation to efficiently render such 
vectors without a dedicated backing store.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Graham Cox

On 10 Dec 2013, at 10:52 am, Mike Abdullah mabdul...@karelia.com wrote:

 Another option to consider is using CAShapeLayer to render individual objects 
 where reasonable. This should allow Core Animation to efficiently render such 
 vectors without a dedicated backing store.


CAShapeLayers really don’t scale much at all before OpenGL falls over. Consider 
a simple shape with a bounds of about 100 x 100 points. At my maximum zoom 
level that becomes 2,500,000 points in terms of the screen. Of course, the vast 
majority is clipped and does not represent any actual pixels, but seemingly the 
CA system doesn’t know that and such a size can’t be set. In practical terms 
the most zoom I could reliably get from CAShapeLayer was about 4x.

The other problem is that CA.. anything must live in a view. My vector data 
model doesn’t really care about views. The same model can be rendered into 
multiple views if you want. At the very top level, a view’s drawRect: method 
calls into the model to tell it to draw a region into a context - much like 
CALayers - but the model is otherwise self-contained. While Apple claim CA *is* 
a model, it’s one firmly welded to a single view somewhere. Architecturally, CA 
doesn’t fit. Where it might be useful is to manage backing store issues at the 
top, view level. So possibly CATileLayer may help, but I can’t see CAShapeLayer 
practically fitting in anywhere. My reading of the CA system may be wrong, but 
again I’m constrained by what documentation there is, which is only barely 
adequate.

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Kevin Meaney
I'm probably teaching my grandmother to suck eggs by suggesting this. Have you 
looked at using CGLayers?

Kevin

On 10 Dec 2013, at 10:08, Graham Cox graham@bigpond.com wrote:

 
 On 10 Dec 2013, at 10:52 am, Mike Abdullah mabdul...@karelia.com wrote:
 
 Another option to consider is using CAShapeLayer to render individual 
 objects where reasonable. This should allow Core Animation to efficiently 
 render such vectors without a dedicated backing store.
 
 
 CAShapeLayers really don’t scale much at all before OpenGL falls over. 
 Consider a simple shape with a bounds of about 100 x 100 points. At my 
 maximum zoom level that becomes 2,500,000 points in terms of the screen. Of 
 course, the vast majority is clipped and does not represent any actual 
 pixels, but seemingly the CA system doesn’t know that and such a size can’t 
 be set. In practical terms the most zoom I could reliably get from 
 CAShapeLayer was about 4x.
 
 The other problem is that CA.. anything must live in a view. My vector data 
 model doesn’t really care about views. The same model can be rendered into 
 multiple views if you want. At the very top level, a view’s drawRect: method 
 calls into the model to tell it to draw a region into a context - much like 
 CALayers - but the model is otherwise self-contained. While Apple claim CA 
 *is* a model, it’s one firmly welded to a single view somewhere. 
 Architecturally, CA doesn’t fit. Where it might be useful is to manage 
 backing store issues at the top, view level. So possibly CATileLayer may 
 help, but I can’t see CAShapeLayer practically fitting in anywhere. My 
 reading of the CA system may be wrong, but again I’m constrained by what 
 documentation there is, which is only barely adequate.
 
 —Graham
 
 
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 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:
 https://lists.apple.com/mailman/options/cocoa-dev/ktam%40yvs.eu.com
 
 This email sent to k...@yvs.eu.com


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Seth Willits
On Dec 10, 2013, at 2:47 AM, Kevin Meaney k...@yvs.eu.com wrote:

 I'm probably teaching my grandmother to suck eggs by suggesting this. Have 
 you looked at using CGLayers?

They're extremely heavy. You definitely don't want them around if performance 
is a consideration.


--
Seth Willits



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Seth Willits
On Dec 10, 2013, at 1:32 AM, Graham Cox graham@bigpond.com wrote:

 Which is another reason to seriously consider CATiledLayer
 
 I”ll consider it, and revisit it…
 
 But my situation is that I need to draw VECTOR objects up to 25,000% zoom 
 with no pixelization.

You're given a CGContext to draw into; What's the difference? The tiled drawing 
is async, so if the drawing doesn't occur fast enough it'll scale up the 
low-scale bitmap, but what's evil about that? It's like Apple or Google maps. 



 The other problem is that CA.. anything must live in a view. My vector data 
 model doesn’t really care about views. The same model can be rendered into 
 multiple views if you want.

Ok, two things:

1) I don't think anyone (so far) suggesting that you use CATiledLayer was also 
suggesting you switch *everything* over to layers. Just use a single (tiling) 
layer and draw into the CGContext you're handed. CATiledLayer simply does what 
you're trying to do: section the visible area into tiles and draw them in 
parallel. The idea is that by using it you push drawing commands into the ether 
which may end up being drawn on the GPU via QE (I don't know that anyone said 
that, but it's something that occurred to me, I'm just not sure on how that's 
done internally), but more directly, by using CATiledLayer you don't have to 
handle the tiling and threading yourself, and it avoids the final blit of your 
buffer into the view because you're (presumably) drawing directly into the 
layer backing.

2) Even if you *were* going to make everything a layer, you don't need to 
intermingle your models and layers in the same hierarchy. The layers can become 
their own hierarchy and you can traverse, inspect, and manipulate them in the 
same way you would your model hierarchy (with the addition of some helpful 
methods of your own). You can also add any arbitrary k/v pairs to a layer, 
which gives you convenient property/reference storage. It's certainly not 
trivial, but when you get it all setup it's not bad.



--
Seth Willits




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-10 Thread Kyle Sluder
On Dec 10, 2013, at 10:25 AM, Seth Willits sli...@araelium.com wrote:
 
 The idea is that by using it you push drawing commands into the ether which 
 may end up being drawn on the GPU via QE (I don't know that anyone said that, 
 but it's something that occurred to me, I'm just not sure on how that's done 
 internally)

This isn't the case. QuartzGL is not enabled on any Mac—it turns out that 
building the pixmap on the CPU and shoving it over the bus once was more 
performant than sending a bunch of draw calls to the video card. (Which strikes 
me as likely to be particularly true for relatively-underpowered integrated 
GPUs with shared memory.)


 but more directly, by using CATiledLayer you don't have to handle the tiling 
 and threading yourself, and it avoids the final blit of your buffer into the 
 view because you're (presumably) drawing directly into the layer backing.

Yup, these two points are exactly why I suggested it.

--Kyle Sluder

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Graham Cox

On 6 Dec 2013, at 5:46 pm, Graham Cox graham@bigpond.com wrote:

 OK, I’ve now tried this approach, and it’s much cleaner in that it works with 
 scrollers, with and without “responsive” scrolling (which appears to buffer 
 its contents) and also zooming. Code follows. In this case, drawing overall 
 is slower than the normal case, because the simple drawing I’m doing doesn’t 
 tax things much, so the set up and tear down of the bitmaps is dominating, 
 but I would expect for very complex drawing it would show a win.



I think I’ve explored this as far as I can go. Here’s my wrap-up, for what it’s 
worth to anyone. Not a lot, I expect.

The conclusion is, I don’t think it can be done with the current graphics APIs 
with any worthwhile performance. Here’s my summary of why that is. I really 
hope someone who knows the graphics innards could take a look and see if I’ve 
overlooked anything, because in principle this *could* dramatically improve 
drawing performance *if* there were some support for doing it.

GOAL: to improve drawing performance in a ‘heavy' view by tiling the visible 
rect of the view and rendering each tile on a separate thread. By ‘heavy’ I 
mean the view has thousands of objects to draw, which ultimately make a huge 
number of Core Graphics calls.

(n.b. in my previously posted code, I tiled the bounds of the view, which is 
not quite the same as what I’m talking about here, which is tiling the visible 
rect of the view in such a way that each tile renders the scaled, translated 
view content into a fixed backing store region. Having solved that problem, I 
don’t think it’s worth posting the code because overall this technique doesn’t 
gain any performance).

APPROACH: Each tile is used to construct an offscreen bitmap and a context that 
wraps it. The context is set up so that normal drawing (just as if it were done 
by -drawRect:) will render into the tile context. Because each tile has its own 
context, each one can be executed on a separate thread. In principle this 
should show a drawing performance boost because different non-overlapping parts 
of the view are drawn in parallel.

After capturing the tile content, the resulting image is copied back into the 
original current context as part of -drawRect:

This last step is where it all falls down, because this one call, to 
CGContextDrawImage, takes a whopping 67% of the overall time for drawRect: to 
run, and normal drawing doesn’t need this call (this is testing in a ‘light’ 
view, but nevertheless, it makes the view very noticeably laggy).

However, it’s the only workable approach I’ve managed to discover, so that’s 
why I’m stuck.

ALTERNATIVES THAT WOULD WORK, IF ONLY:

Because the final drawing of the image takes so long, if that could be avoided 
then the threaded drawing would probably be a win. Here’s what I tried:

1. Make one big bitmap instead and create a context for each tile that 
represents just a portion of it. This doesn’t work because the tile width and 
the bytesPerRow are not consistent with an image that has an exclusive context 
for the entire bitmap. Attempting to create the context fails because of this, 
even though the byte offset between rows is actually correct. Essentially, 
CGBitmapContextCreate() does not trust your bytesPerRow calculation, even when 
it’s right. (I say crash and be damned rather than assert here). Even if this 
worked, it would still require an image draw, but at least it would be just 
one, not one per tile.

2. Make one big bitmap + context and set each tile to focus on one portion of 
this at a time. This doesn’t work because each thread must have its own context 
so that context state is exclusive per thread.

3. Make a copy of the current context and focus it per tile. This doesn’t work 
because there is no API to copy a context, and/or to share the backing store of 
an existing context.

4. Create a tile context from the window’s underlying backing store. This works 
for simple views, but does not work with scrollers or other more complex views 
that use some intermediate buffering.

I’ll bet there’s some private API that would help here (NSScrollView appears to 
be doing something along these lines for ‘responsive’ scrolling) but as usual 
Apple are keeping it out of the hands of us plebs. Even back in the old days of 
GWorlds on Mac OS 7.x and later you could do this sort of thing much more 
easily than now.

BOTTOM LINE:

Creating multiple contexts that draw into a single shared backing store is 
currently not possible. This precludes drawing on multiple threads and so 
ultimate drawing performance is unattainable.

—Graham




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail

Re: Threaded drawing

2013-12-09 Thread Mike Abdullah

On 9 Dec 2013, at 15:47, Graham Cox graham@bigpond.com wrote:

 
 On 6 Dec 2013, at 5:46 pm, Graham Cox graham@bigpond.com wrote:
 
 OK, I’ve now tried this approach, and it’s much cleaner in that it works 
 with scrollers, with and without “responsive” scrolling (which appears to 
 buffer its contents) and also zooming. Code follows. In this case, drawing 
 overall is slower than the normal case, because the simple drawing I’m doing 
 doesn’t tax things much, so the set up and tear down of the bitmaps is 
 dominating, but I would expect for very complex drawing it would show a win.
 
 
 
 I think I’ve explored this as far as I can go. Here’s my wrap-up, for what 
 it’s worth to anyone. Not a lot, I expect.
 
 The conclusion is, I don’t think it can be done with the current graphics 
 APIs with any worthwhile performance. Here’s my summary of why that is. I 
 really hope someone who knows the graphics innards could take a look and see 
 if I’ve overlooked anything, because in principle this *could* dramatically 
 improve drawing performance *if* there were some support for doing it.
 
 GOAL: to improve drawing performance in a ‘heavy' view by tiling the visible 
 rect of the view and rendering each tile on a separate thread. By ‘heavy’ I 
 mean the view has thousands of objects to draw, which ultimately make a huge 
 number of Core Graphics calls.
 
 (n.b. in my previously posted code, I tiled the bounds of the view, which is 
 not quite the same as what I’m talking about here, which is tiling the 
 visible rect of the view in such a way that each tile renders the scaled, 
 translated view content into a fixed backing store region. Having solved that 
 problem, I don’t think it’s worth posting the code because overall this 
 technique doesn’t gain any performance).
 
 APPROACH: Each tile is used to construct an offscreen bitmap and a context 
 that wraps it. The context is set up so that normal drawing (just as if it 
 were done by -drawRect:) will render into the tile context. Because each tile 
 has its own context, each one can be executed on a separate thread. In 
 principle this should show a drawing performance boost because different 
 non-overlapping parts of the view are drawn in parallel.
 
 After capturing the tile content, the resulting image is copied back into the 
 original current context as part of -drawRect:
 
 This last step is where it all falls down, because this one call, to 
 CGContextDrawImage, takes a whopping 67% of the overall time for drawRect: to 
 run, and normal drawing doesn’t need this call (this is testing in a ‘light’ 
 view, but nevertheless, it makes the view very noticeably laggy).
 
 However, it’s the only workable approach I’ve managed to discover, so that’s 
 why I’m stuck.
 
 ALTERNATIVES THAT WOULD WORK, IF ONLY:
 
 Because the final drawing of the image takes so long, if that could be 
 avoided then the threaded drawing would probably be a win. Here’s what I 
 tried:
 
 1. Make one big bitmap instead and create a context for each tile that 
 represents just a portion of it. This doesn’t work because the tile width and 
 the bytesPerRow are not consistent with an image that has an exclusive 
 context for the entire bitmap. Attempting to create the context fails because 
 of this, even though the byte offset between rows is actually correct. 
 Essentially, CGBitmapContextCreate() does not trust your bytesPerRow 
 calculation, even when it’s right. (I say crash and be damned rather than 
 assert here). Even if this worked, it would still require an image draw, but 
 at least it would be just one, not one per tile.
 
 2. Make one big bitmap + context and set each tile to focus on one portion of 
 this at a time. This doesn’t work because each thread must have its own 
 context so that context state is exclusive per thread.
 
 3. Make a copy of the current context and focus it per tile. This doesn’t 
 work because there is no API to copy a context, and/or to share the backing 
 store of an existing context.
 
 4. Create a tile context from the window’s underlying backing store. This 
 works for simple views, but does not work with scrollers or other more 
 complex views that use some intermediate buffering.
 
 I’ll bet there’s some private API that would help here (NSScrollView appears 
 to be doing something along these lines for ‘responsive’ scrolling) but as 
 usual Apple are keeping it out of the hands of us plebs. Even back in the old 
 days of GWorlds on Mac OS 7.x and later you could do this sort of thing much 
 more easily than now.
 
 BOTTOM LINE:
 
 Creating multiple contexts that draw into a single shared backing store is 
 currently not possible. This precludes drawing on multiple threads and so 
 ultimate drawing performance is unattainable.

Maybe a dumb question: How about using CATiledLayer?


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator

Re: Threaded drawing

2013-12-09 Thread Graham Cox

On 9 Dec 2013, at 5:01 pm, Mike Abdullah mabdul...@karelia.com wrote:

 Maybe a dumb question: How about using CATiledLayer?


Well, I haven’t explored it very much, and certainly not in this context, but 
it seems to me that it’s solving a different problem. It sounds similar, but 
it’s not actually useful for buffering vector drawing in the way I’m trying to. 
The tiles are relative to the view’s bounds, so as you zoom in, they get larger 
- so large that they soon hit hard limits in OpenGL for texture sizes. What I 
need are tiles that never change size as you zoom in and out, and are relative 
to the window’s backing store. (As the window size changes, you have more or 
fewer tiles, but they never change size). 

If CATiledLayer can be made to work that way (perhaps in some layer-backed 
subclass of NSClipView) it might be worth exploring, though for now this 
exercise has me feeling pretty exhausted. The lack of decent documentation 
isn’t much help either.

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Kevin Meaney
I've been impressed with the thought you've put into this.

Probably a question you don't want at this point, because by now your looking 
for closure, but did you try different blend modes when calling DrawImage, 
specifically the copy blend mode. I'm wondering if that might be faster as 
hopefully then it's just moving memory not doing any calculations. That 67% is 
a real killer.

Kevin

On 9 Dec 2013, at 15:47, Graham Cox graham@bigpond.com wrote:

 
 On 6 Dec 2013, at 5:46 pm, Graham Cox graham@bigpond.com wrote:
 
 OK, I’ve now tried this approach, and it’s much cleaner in that it works 
 with scrollers, with and without “responsive” scrolling (which appears to 
 buffer its contents) and also zooming. Code follows. In this case, drawing 
 overall is slower than the normal case, because the simple drawing I’m doing 
 doesn’t tax things much, so the set up and tear down of the bitmaps is 
 dominating, but I would expect for very complex drawing it would show a win.
 
 
 
 I think I’ve explored this as far as I can go. Here’s my wrap-up, for what 
 it’s worth to anyone. Not a lot, I expect.
 
 The conclusion is, I don’t think it can be done with the current graphics 
 APIs with any worthwhile performance. Here’s my summary of why that is. I 
 really hope someone who knows the graphics innards could take a look and see 
 if I’ve overlooked anything, because in principle this *could* dramatically 
 improve drawing performance *if* there were some support for doing it.
 
 GOAL: to improve drawing performance in a ‘heavy' view by tiling the visible 
 rect of the view and rendering each tile on a separate thread. By ‘heavy’ I 
 mean the view has thousands of objects to draw, which ultimately make a huge 
 number of Core Graphics calls.
 
 (n.b. in my previously posted code, I tiled the bounds of the view, which is 
 not quite the same as what I’m talking about here, which is tiling the 
 visible rect of the view in such a way that each tile renders the scaled, 
 translated view content into a fixed backing store region. Having solved that 
 problem, I don’t think it’s worth posting the code because overall this 
 technique doesn’t gain any performance).
 
 APPROACH: Each tile is used to construct an offscreen bitmap and a context 
 that wraps it. The context is set up so that normal drawing (just as if it 
 were done by -drawRect:) will render into the tile context. Because each tile 
 has its own context, each one can be executed on a separate thread. In 
 principle this should show a drawing performance boost because different 
 non-overlapping parts of the view are drawn in parallel.
 
 After capturing the tile content, the resulting image is copied back into the 
 original current context as part of -drawRect:
 
 This last step is where it all falls down, because this one call, to 
 CGContextDrawImage, takes a whopping 67% of the overall time for drawRect: to 
 run, and normal drawing doesn’t need this call (this is testing in a ‘light’ 
 view, but nevertheless, it makes the view very noticeably laggy).
 
 However, it’s the only workable approach I’ve managed to discover, so that’s 
 why I’m stuck.
 
 ALTERNATIVES THAT WOULD WORK, IF ONLY:
 
 Because the final drawing of the image takes so long, if that could be 
 avoided then the threaded drawing would probably be a win. Here’s what I 
 tried:
 
 1. Make one big bitmap instead and create a context for each tile that 
 represents just a portion of it. This doesn’t work because the tile width and 
 the bytesPerRow are not consistent with an image that has an exclusive 
 context for the entire bitmap. Attempting to create the context fails because 
 of this, even though the byte offset between rows is actually correct. 
 Essentially, CGBitmapContextCreate() does not trust your bytesPerRow 
 calculation, even when it’s right. (I say crash and be damned rather than 
 assert here). Even if this worked, it would still require an image draw, but 
 at least it would be just one, not one per tile.
 
 2. Make one big bitmap + context and set each tile to focus on one portion of 
 this at a time. This doesn’t work because each thread must have its own 
 context so that context state is exclusive per thread.
 
 3. Make a copy of the current context and focus it per tile. This doesn’t 
 work because there is no API to copy a context, and/or to share the backing 
 store of an existing context.
 
 4. Create a tile context from the window’s underlying backing store. This 
 works for simple views, but does not work with scrollers or other more 
 complex views that use some intermediate buffering.
 
 I’ll bet there’s some private API that would help here (NSScrollView appears 
 to be doing something along these lines for ‘responsive’ scrolling) but as 
 usual Apple are keeping it out of the hands of us plebs. Even back in the old 
 days of GWorlds on Mac OS 7.x and later you could do this sort of thing much 
 more easily than now.
 
 BOTTOM LINE:
 
 Creating

Re: Threaded drawing

2013-12-09 Thread Jens Alfke

On Dec 9, 2013, at 7:47 AM, Graham Cox graham@bigpond.com wrote:

 This last step is where it all falls down, because this one call, to 
 CGContextDrawImage, takes a whopping 67% of the overall time for drawRect: to 
 run, and normal drawing doesn’t need this call (this is testing in a ‘light’ 
 view, but nevertheless, it makes the view very noticeably laggy).

A few months ago I saw a great presentation given by Apple engineer Andy 
Matuschak about the way rendering works on iOS, the whole pipeline all the way 
from the app’s API calls to the pixels appearing onscreen. Its purpose was to 
teach some intuition about what rendering techniques will perform better than 
others. [This specific talk doesn’t seem to be online, but he has a WWDC talk* 
that I think covers similar topics.]

The big picture is that the actual rendering pipeline is
[your app] — [graphics server process] — [OpenGL] — [GPU] — [Screen]
and the earlier the graphics calls get converted into pixels, the less 
efficient the drawing will be, because it’s more expensive to push pixmaps 
through the pipeline than lists of drawing commands.

So if you can avoid it, you shouldn’t be doing your own rendering into images. 
I haven’t been following the details of this thread, but my guess is you’ll get 
better performance by drawing the tiles directly to the view, just setting a 
clipping rect beforehand so the drawing is limited to the tile your thread is 
working on.

—Jens

* “Understanding UIKit Rendering”: 
https://developer.apple.com/itunes/?destination=adc.apple.com.8270634034.08270634040.8367260927?i=1122536585
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread David Duncan

On Dec 9, 2013, at 8:36 AM, Jens Alfke j...@mooseyard.com wrote:

 
 On Dec 9, 2013, at 7:47 AM, Graham Cox graham@bigpond.com wrote:
 
 This last step is where it all falls down, because this one call, to 
 CGContextDrawImage, takes a whopping 67% of the overall time for drawRect: 
 to run, and normal drawing doesn’t need this call (this is testing in a 
 ‘light’ view, but nevertheless, it makes the view very noticeably laggy).
 
 A few months ago I saw a great presentation given by Apple engineer Andy 
 Matuschak about the way rendering works on iOS, the whole pipeline all the 
 way from the app’s API calls to the pixels appearing onscreen. Its purpose 
 was to teach some intuition about what rendering techniques will perform 
 better than others. [This specific talk doesn’t seem to be online, but he has 
 a WWDC talk* that I think covers similar topics.]
 
 The big picture is that the actual rendering pipeline is
   [your app] — [graphics server process] — [OpenGL] — [GPU] — [Screen]
 and the earlier the graphics calls get converted into pixels, the less 
 efficient the drawing will be, because it’s more expensive to push pixmaps 
 through the pipeline than lists of drawing commands.
 
 So if you can avoid it, you shouldn’t be doing your own rendering into 
 images. I haven’t been following the details of this thread, but my guess is 
 you’ll get better performance by drawing the tiles directly to the view, just 
 setting a clipping rect beforehand so the drawing is limited to the tile your 
 thread is working on.

One major impediment to this is that you cannot use the same graphics context 
between multiple threads, and as such using the graphics context that AppKit 
gives you forces you into a single threaded model.

If you have a buffer to draw into, then you can easily slice that buffer to use 
between multiple graphics contexts, but you will fundamentally have to draw 
them all into the source context at the end.

 
 —Jens
 
 * “Understanding UIKit Rendering”: 
 https://developer.apple.com/itunes/?destination=adc.apple.com.8270634034.08270634040.8367260927?i=1122536585
 ___
 
 Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)
 
 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:
 https://lists.apple.com/mailman/options/cocoa-dev/david.duncan%40apple.com
 
 This email sent to david.dun...@apple.com

--
David Duncan


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Graham Cox

On 9 Dec 2013, at 5:36 pm, Jens Alfke j...@mooseyard.com wrote:

 So if you can avoid it, you shouldn’t be doing your own rendering into 
 images. I haven’t been following the details of this thread, but my guess is 
 you’ll get better performance by drawing the tiles directly to the view, just 
 setting a clipping rect beforehand so the drawing is limited to the tile your 
 thread is working on.
 

Indeed, that’s certainly my intuition too, if only there were a way to do it.

Trouble is, each thread needs its own context in order to draw into the view 
without a lock on every set of context drawing calls, and there’s no way to 
create such a context that doesn’t have its own bitmap image. The image is only 
there because it’s the only way to make a context (that I could see - maybe 
using a PDF context might work, I’ll try that).

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Graham Cox

On 9 Dec 2013, at 5:17 pm, Kevin Meaney k...@yvs.eu.com wrote:

 Probably a question you don't want at this point, because by now your looking 
 for closure, but did you try different blend modes when calling DrawImage, 
 specifically the copy blend mode. I'm wondering if that might be faster as 
 hopefully then it's just moving memory not doing any calculations. That 67% 
 is a real killer.


Yep, that’s with using the copy mode :(

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Graham Cox

On 9 Dec 2013, at 5:45 pm, David Duncan david.dun...@apple.com wrote:

 If you have a buffer to draw into, then you can easily slice that buffer to 
 use between multiple graphics contexts, but you will fundamentally have to 
 draw them all into the source context at the end.


I wasn’t able to figure out how to do this, so I haven’t tested to see if it’s 
any faster.

By “slice the buffer”, I assume you mean set up a context on some region of 
that buffer, but when I tried to do that, CGBitmapContextCreate[WithData] would 
not accept my bytesPerRow value because it was inconsistent with the ‘width’ 
value, even though I had calculated the bytesPerRow to be the correct offset 
anyway.

So if you know of a practical way to “slice the buffer”, please do share!

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Scott Ribe
On Dec 9, 2013, at 9:50 AM, Graham Cox graham@bigpond.com wrote:

 By “slice the buffer”, I assume you mean set up a context on some region of 
 that buffer, but when I tried to do that, CGBitmapContextCreate[WithData] 
 would not accept my bytesPerRow value because it was inconsistent with the 
 ‘width’ value, even though I had calculated the bytesPerRow to be the correct 
 offset anyway.

What were your actual values and what was the assertion?

-- 
Scott Ribe
scott_r...@elevated-dev.com
http://www.elevated-dev.com/
(303) 722-0567 voice





___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Jens Alfke

On Dec 9, 2013, at 8:45 AM, David Duncan david.dun...@apple.com wrote:

 One major impediment to this is that you cannot use the same graphics context 
 between multiple threads, and as such using the graphics context that AppKit 
 gives you forces you into a single threaded model.

Ah, interesting.

What’s the slow part of the drawing, Graham? Is it the CG calls themselves, or 
your own computations that lead up to them? If the latter, you could farm out 
those computations to multiple threads, and schedule the actual rendering calls 
on the single thread that has the graphics context.

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Kyle Sluder
 On Dec 9, 2013, at 8:50 AM, Graham Cox graham@bigpond.com wrote:

 
 
 On 9 Dec 2013, at 5:45 pm, David Duncan david.dun...@apple.com wrote:
 
 If you have a buffer to draw into, then you can easily slice that buffer to 
 use between multiple graphics contexts, but you will fundamentally have to 
 draw them all into the source context at the end.
 
 
 I wasn’t able to figure out how to do this, so I haven’t tested to see if 
 it’s any faster.
 
 By “slice the buffer”, I assume you mean set up a context on some region of 
 that buffer, but when I tried to do that, CGBitmapContextCreate[WithData] 
 would not accept my bytesPerRow value because it was inconsistent with the 
 ‘width’ value, even though I had calculated the bytesPerRow to be the correct 
 offset anyway.
 
 So if you know of a practical way to “slice the buffer”, please do share!

What if all your contexts used the same backing bitmap, but you were extremely 
careful to set up their clipping regions such that they never touched the same 
pixels?

But I'd seriously consider Mike Abdullah's suggestion. It sounds like 
CATiledLayer does most if not all of this work already.

--Kyle Sluder

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread David Duncan

On Dec 9, 2013, at 9:23 AM, Kyle Sluder k...@ksluder.com wrote:

 On Dec 9, 2013, at 8:50 AM, Graham Cox graham@bigpond.com wrote:
 
 
 
 On 9 Dec 2013, at 5:45 pm, David Duncan david.dun...@apple.com wrote:
 
 If you have a buffer to draw into, then you can easily slice that buffer to 
 use between multiple graphics contexts, but you will fundamentally have to 
 draw them all into the source context at the end.
 
 
 I wasn’t able to figure out how to do this, so I haven’t tested to see if 
 it’s any faster.
 
 By “slice the buffer”, I assume you mean set up a context on some region of 
 that buffer, but when I tried to do that, CGBitmapContextCreate[WithData] 
 would not accept my bytesPerRow value because it was inconsistent with the 
 ‘width’ value, even though I had calculated the bytesPerRow to be the 
 correct offset anyway.
 
 So if you know of a practical way to “slice the buffer”, please do share!
 
 What if all your contexts used the same backing bitmap, but you were 
 extremely careful to set up their clipping regions such that they never 
 touched the same pixels?

That should at least mostly work. I might have some concern for effects that 
should read outside of the clipping region (antialiasing for example), but that 
may not be an issue. You’d notice immediately if it was.

As far as slicing, if CGBitmapContextCreate doesn’t let you use columns  rows, 
it should at least let you use rows, although I would have expected columns  
rows to work.

 
 But I'd seriously consider Mike Abdullah's suggestion. It sounds like 
 CATiledLayer does most if not all of this work already.
 
 --Kyle Sluder

--
David Duncan

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Seth Willits

 I think I’ve explored this as far as I can go. Here’s my wrap-up, for what 
 it’s worth to anyone. Not a lot, I expect.
 
 The conclusion is, I don’t think it can be done with the current graphics 
 APIs with any worthwhile performance. Here’s my summary of why that is…


 … This last step is where it all falls down, because this one call, to 
 CGContextDrawImage, takes a whopping 67% of the overall time for drawRect: to 
 run, and normal drawing doesn’t need this call (this is testing in a ‘light’ 
 view, but nevertheless, it makes the view very noticeably laggy).


If all the drawRect is doing is making a single call to CGContextDrawImage then 
it should rightly be 100% of the time, so that measure isn’t interesting on its 
own. :)



 1. Make one big bitmap instead and create a context for each tile... Even if 
 this worked, it would still require an image draw, but at least it would be 
 just one, not one per tile.


You must be passing in incorrect values. It will work. I’ve done this before 
and I just tested it now and I’m not getting any assertions like you are.

If your backing is 1600 x 800, and you want a context for the left half and 
another for the right half both have bytesPerRow values of 1600 * 4, a width of 
800, and heigh of 800. The only thing that is different is the buffer offset. 
The first one is at 0 and the second at 800 * 4. It may feel odd because the 
second context specifies that the last row is 1600 * 4 bytes wide, but thanks 
to initial offset and real buffer size is only 800 * 4 wide, but CG won't try 
to read or write to those bytes in rows that are after width * bytesPerPixel, 
so it really is safe. 


The single CGContextDrawImage in drawRect: should end up essentially being a 
memcpy which will be ridiculously fast, as long as your contexts/backing all 
use the same color space and bitmap layout as the view’s context’s backing. 
Definitely make sure they’re using the same color space because converting is 
really slow.




And as a general note separate to the threading, are you sure you can’t cache 
individual objects’ images? (And this just gets into trying to replicate 
layers, really, though, and with or without layers you’d have a memory usage 
concern to analyze.)


--
Seth Willits


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Graham Cox

On 9 Dec 2013, at 7:03 pm, Seth Willits sli...@araelium.com wrote:

 If all the drawRect is doing is making a single call to CGContextDrawImage 
 then it should rightly be 100% of the time, so that measure isn’t interesting 
 on its own. :)


Yes, that’s true. It’s hard to be totally objective, because running 
Instruments against the app involves some manual input like scrolling, which is 
hard to reproduce accurately each time without writing a complicated test, but 
it looks as if it’s roughly 4 times slower when I enable the threaded code (and 
there I was hoping it would be 4x faster, being the number of cores I have ;-).

 You must be passing in incorrect values. It will work. I’ve done this before 
 and I just tested it now and I’m not getting any assertions like you are.
 
 If your backing is 1600 x 800, and you want a context for the left half and 
 another for the right half both have bytesPerRow values of 1600 * 4, a width 
 of 800, and heigh of 800. The only thing that is different is the buffer 
 offset. The first one is at 0 and the second at 800 * 4. It may feel odd 
 because the second context specifies that the last row is 1600 * 4 bytes 
 wide, but thanks to initial offset and real buffer size is only 800 * 4 wide, 
 but CG won't try to read or write to those bytes in rows that are after width 
 * bytesPerPixel, so it really is safe. 

This sounds like what I was doing, so I’ll check again and make sure my values 
are really correct - I may well have made a mistake.

 The single CGContextDrawImage in drawRect: should end up essentially being a 
 memcpy which will be ridiculously fast, as long as your contexts/backing all 
 use the same color space and bitmap layout as the view’s context’s backing. 
 Definitely make sure they’re using the same color space because converting is 
 really slow.

But how can you do that? There’s no CGContextGetColorspace function, except for 
a bitmap context, and the context that’s current when drawRect: is entered does 
not seem to be a bitmap context. I would have expected it to be, but it returns 
nil for all of the CGBitmapContextxxx functions, so my assumption is it’s a 
private variant. Same goes for the format, even if it has one. I’m using the 
genericRGB colourspace and premultiplied alpha first for my own contexts.

—Graham



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Jens Alfke

 The single CGContextDrawImage in drawRect: should end up essentially being a 
 memcpy which will be ridiculously fast

The bottleneck for image blitting is copying the pixels from CPU RAM to GPU 
texture RAM. This is often a bottleneck in high-speed image drawing, and I know 
that Quartz goes through contortions to try to eliminate it whenever possible.

—Jens

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Kyle Sluder
On Mon, Dec 9, 2013, at 02:04 PM, Jens Alfke wrote:
 
  The single CGContextDrawImage in drawRect: should end up essentially being 
  a memcpy which will be ridiculously fast
 
 The bottleneck for image blitting is copying the pixels from CPU RAM to
 GPU texture RAM. This is often a bottleneck in high-speed image drawing,
 and I know that Quartz goes through contortions to try to eliminate it
 whenever possible.

Which is another reason to seriously consider CATiledLayer… it's
plausible that the context it uses is located in shared memory on
machines with onboard graphics.

--Kyle Sluder

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-09 Thread Seth Willits
 The single CGContextDrawImage in drawRect: should end up essentially being a 
 memcpy which will be ridiculously fast, as long as your contexts/backing all 
 use the same color space and bitmap layout as the view’s context’s backing. 
 Definitely make sure they’re using the same color space because converting 
 is really slow.
 
 But how can you do that? There’s no CGContextGetColorspace function, except 
 for a bitmap context, and the context that’s current when drawRect: is 
 entered does not seem to be a bitmap context. I would have expected it to be, 
 but it returns nil for all of the CGBitmapContextxxx functions, so my 
 assumption is it’s a private variant. Same goes for the format, even if it 
 has one. I’m using the genericRGB colourspace and premultiplied alpha first 
 for my own contexts.

Offhand I couldn’t tell you. The main thing is to look at the profile and 
inspect what’s happening within the draw call. It’ll be obvious if it’s doing 
colorspace conversion. 

Just thinking out loud: There’s NSView’s bitmapImageRepForCachingDisplayInRect: 
and you can grab a colorspace from the rep. I would certainly imagine that has 
the ideal space and you can confirm it’s one or another. You can use that 
method to create your presumably ideal backing and then create multiple 
contexts that share the same buffer as that original bitmap rep on your 
background threads. I can’t say whether it’s better or not, but it’s something 
that comes to mind. 


(CATiledLayer still sounds like a good idea to me as well.)


--
Seth Willits

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-07 Thread Graham Cox

On 7 Dec 2013, at 1:05 am, Roland King r...@rols.org wrote:

 And reminded of the comment about how hard block syntax can be to remember, I 
 didn't make this page, I'm not a fan of the name, but it's awfully useful and 
 I keep it bookmarked,  I tinyURLed it to avoid tripping up swear checkers, 
 http://tinyurl.com/m6lukyg. 


Ha yes, thanks. Glad I’m not the only one ;-)

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-07 Thread Clark Smith Cox III

On Dec 6, 2013, at 7:27, Graham Cox graham@bigpond.com wrote:

 
 On 6 Dec 2013, at 11:26 am, Graham Cox graham@bigpond.com wrote:
 
  NSBlockOperation* op = [NSBlockOperation 
 blockOperationWithBlock:^
  {
  CGContextClipToRect( ncx, tileRect );
 
  [self drawTile:tileRect inContext:ncx];
  }];
 
 
 A question for blocks experts:
 
 Is the value of tileRect here captured when the block is created,or when it 
 is run?

It is captured when the block is created.

-- 
Clark Smith Cox III
clark@apple.com
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Graham Cox

On 4 Dec 2013, at 9:33 pm, Graham Cox graham@bigpond.com wrote:

 But that leaves those annoying cases when you have the whole view to redraw. 
 I wondered if it would be worth dividing up the view into rects and rendering 
 each one on a separate thread. The problem seems to me to be that they’d all 
 be drawing into the same CGContext, and I wonder how well that could work - 
 e.g. one thread could set a clip ready for its next drawing operation and 
 another could then change that clip so they’d all be tripping over each 
 other, even though they were all drawing into a different part of the 
 context. If access to the context were synchronised, then that would end up 
 serialising all the drawing so there wouldn’t be any gain.
 
 Has anyone trod this path? It would be useful to know whether there’s 
 anything that can be done along these lines, because rendering 10,000 or more 
 objects is just taking too darn long!


OK, after some thought and a bit of experimentation, I think I’ve got a handle 
on this. I just thought I’d share with the list in case anyone is remotely 
interested, or has anything to suggest/add/criticise…

Obviously, you cannot share a graphics context across multiple threads for the 
reasons I mentioned - a single context cannot be thread safe, by design. But 
that doesn’t mean you can’t have a separate context per thread, all drawing 
into the same backing store. That was my breakthrough insight I guess, for what 
it’s worth.

So proceeding on that basis, I wrote a test view that uses a NSOperationQueue 
to dispatch chunks of drawing work by dividing up the view into tiles, creating 
a context for each tile (but all drawing into the same window backing store). 
As long as you wait for the tiles to all finish, everything works just 
tickety-boo.

Here’s the code, which is the -drawRect: method of a view. The view creates an 
NSOperationQueue called mDrawingQueue in its -initWithFrame: method.

#define TILE_SIZE   NSMakeSize( 100, 100 )
#define DRAW_THREADED   1


- (void)drawRect:(NSRect) dirtyRect
{
[[NSColor whiteColor] set];
NSRectFill( dirtyRect );

// get current context:

CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];

// divide into tiles

NSSize  tileSize = TILE_SIZE;
NSRect  br = self.bounds;
NSUInteger  tx, ty;

tx = ceil(NSWidth( br ) / tileSize.width);
ty = ceil(NSHeight( br ) / tileSize.height);

NSRect tileRect;

tileRect.size = tileSize;

for( NSInteger i = 0; i  ty; ++i )
{
for( NSInteger j = 0; j  tx; ++j )
{
tileRect.origin.x = br.origin.x + tileSize.width * j;
tileRect.origin.y = br.origin.y + tileSize.height * i;

if([self needsToDrawRect:tileRect])
{
#if DRAW_THREADED
NSBlockOperation* op = [NSBlockOperation 
blockOperationWithBlock:^
{
NSGraphicsContext* context = 
[NSGraphicsContext graphicsContextWithWindow:[self window]];
CGContextRefncx = [context 
graphicsPort];

// align and clip this new context to 
the view

CGAffineTransform ctm = 
CGContextGetCTM( ctx );

CGContextConcatCTM( ncx, ctm );
CGContextClipToRect( ncx, br );

// also clip to the tile (not strictly 
necessary)

CGContextClipToRect( ncx, tileRect );

[self drawTile:tileRect inContext:ncx];
}];

[mDrawingQueue addOperation:op];
#else
[self drawTile:tileRect inContext:ctx];
#endif

}
}
}

#if DRAW_THREADED
// need to wait until tiles all drawn before flushing
[mDrawingQueue waitUntilAllOperationsAreFinished];
#endif
}



- (void)drawTile:(NSRect) tile inContext:(CGContextRef) ctx
{
// draw something in the tile. Not very challenging at the moment

NSRect tr = NSInsetRect( tile, 10, 10 );

CGContextSetFillColorWithColor( ctx, [[NSColor redColor] CGColor]);
CGContextFillRect( ctx, tr );

CGContextSetStrokeColorWithColor(ctx, CGColorGetConstantColor( 
kCGColorBlack ));
CGContextStrokeRect( ctx, tile );
}



Re: Threaded drawing

2013-12-06 Thread Roland King
That's very ingenious. Not an OSX expert myself but it does bother me that 
you're not drawing into the context you are given but one you construct 
yourself from a piece of the window. That's not something I think iOS would 
even let you get at. 

For a start does that work layer backed? 

Is there always a guaranteed correspondence between the context passed to 
drawrect and the window like that? Does OSX never choose to render to a bitmap 
and then blend to the window store later? 

That might be another way, by the way, render to your own tiled small bitmaps 
on background threads then blit them into the real context. 

Perhaps that code is fine on OSX, I'd certainly be happier if there was a 
create context from context call you could use to relate your small contexts to 
the draw rect one. That code would keep me up nights. 

 On 6 Dec, 2013, at 18:26, Graham Cox graham@bigpond.com wrote:
 
 
 On 4 Dec 2013, at 9:33 pm, Graham Cox graham@bigpond.com wrote:
 
 But that leaves those annoying cases when you have the whole view to redraw. 
 I wondered if it would be worth dividing up the view into rects and 
 rendering each one on a separate thread. The problem seems to me to be that 
 they’d all be drawing into the same CGContext, and I wonder how well that 
 could work - e.g. one thread could set a clip ready for its next drawing 
 operation and another could then change that clip so they’d all be tripping 
 over each other, even though they were all drawing into a different part of 
 the context. If access to the context were synchronised, then that would end 
 up serialising all the drawing so there wouldn’t be any gain.
 
 Has anyone trod this path? It would be useful to know whether there’s 
 anything that can be done along these lines, because rendering 10,000 or 
 more objects is just taking too darn long!
 
 
 OK, after some thought and a bit of experimentation, I think I’ve got a 
 handle on this. I just thought I’d share with the list in case anyone is 
 remotely interested, or has anything to suggest/add/criticise…
 
 Obviously, you cannot share a graphics context across multiple threads for 
 the reasons I mentioned - a single context cannot be thread safe, by design. 
 But that doesn’t mean you can’t have a separate context per thread, all 
 drawing into the same backing store. That was my breakthrough insight I 
 guess, for what it’s worth.
 
 So proceeding on that basis, I wrote a test view that uses a NSOperationQueue 
 to dispatch chunks of drawing work by dividing up the view into tiles, 
 creating a context for each tile (but all drawing into the same window 
 backing store). As long as you wait for the tiles to all finish, everything 
 works just tickety-boo.
 
 Here’s the code, which is the -drawRect: method of a view. The view creates 
 an NSOperationQueue called mDrawingQueue in its -initWithFrame: method.
 
 #defineTILE_SIZENSMakeSize( 100, 100 )
 #defineDRAW_THREADED1
 
 
 - (void)drawRect:(NSRect) dirtyRect
 {
[[NSColor whiteColor] set];
NSRectFill( dirtyRect );

// get current context:

CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];

// divide into tiles

NSSizetileSize = TILE_SIZE;
NSRectbr = self.bounds;
NSUIntegertx, ty;

tx = ceil(NSWidth( br ) / tileSize.width);
ty = ceil(NSHeight( br ) / tileSize.height);

NSRect tileRect;

tileRect.size = tileSize;

for( NSInteger i = 0; i  ty; ++i )
{
for( NSInteger j = 0; j  tx; ++j )
{
tileRect.origin.x = br.origin.x + tileSize.width * j;
tileRect.origin.y = br.origin.y + tileSize.height * i;

if([self needsToDrawRect:tileRect])
{
 #if DRAW_THREADED
NSBlockOperation* op = [NSBlockOperation 
 blockOperationWithBlock:^
{
NSGraphicsContext* context = [NSGraphicsContext 
 graphicsContextWithWindow:[self window]];
CGContextRefncx = [context graphicsPort];

// align and clip this new context to the view
 
CGAffineTransform ctm = CGContextGetCTM( ctx );

CGContextConcatCTM( ncx, ctm );
CGContextClipToRect( ncx, br );
 
// also clip to the tile (not strictly necessary)
 
CGContextClipToRect( ncx, tileRect );
 
[self drawTile:tileRect inContext:ncx];
}];

[mDrawingQueue addOperation:op];
 #else
[self drawTile:tileRect inContext:ctx];
 #endif

}
}
}

 #if DRAW_THREADED
// need to wait until tiles all drawn before flushing
[mDrawingQueue waitUntilAllOperationsAreFinished];
 #endif
 }
 
 
 
 - (void)drawTile:(NSRect) tile 

Re: Threaded drawing

2013-12-06 Thread Graham Cox

On 6 Dec 2013, at 12:14 pm, Roland King r...@rols.org wrote:

 That's very ingenious. Not an OSX expert myself but it does bother me that 
 you're not drawing into the context you are given but one you construct 
 yourself from a piece of the window. That's not something I think iOS would 
 even let you get at. 
 
 For a start does that work layer backed? 

Not tried it, but...
 
 Is there always a guaranteed correspondence between the context passed to 
 drawrect and the window like that? Does OSX never choose to render to a 
 bitmap and then blend to the window store later? 


I don’t know, but my next step was to embed the view in a scroller. Doesn’t 
work, so either the scroller is buffering its content somehow and there is a 
discrepancy in the contexts, or else I’m not doing the right thing with the 
CTM. (I suspect the former, more experiments to come).


 That might be another way, by the way, render to your own tiled small bitmaps 
 on background threads then blit them into the real context. 

Yep, that was also on my list to try, but for top performance it would make 
sense not to do that if it can be avoided.


 Perhaps that code is fine on OSX, I'd certainly be happier if there was a 
 create context from context call you could use to relate your small contexts 
 to the draw rect one.

That was what I looked for at first as well, but there doesn’t appear to be 
such a call, such as CGContextCreateCopy. Pity, hence the veering into hackery 
territory. But there may be a cleaner way, I just haven’t discovered it yet.

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Roland King

 
 That might be another way, by the way, render to your own tiled small 
 bitmaps on background threads then blit them into the real context. 
 
 Yep, that was also on my list to try, but for top performance it would make 
 sense not to do that if it can be avoided.
 

My WAG would be that works well enough. Heavy lifting on the threads, then toss 
a bitmap/CGImage copy to the main thread where I'd hope it was just a bitblt 
into the context. I've seen similar recommended for iOS but only with a 
fullsize bitmap, not with bits and pieces. In most of those cases the view was 
an image and the contents was constructed on a background thread and then set 
into the image outside the drawrect call. 

 
 Perhaps that code is fine on OSX, I'd certainly be happier if there was a 
 create context from context call you could use to relate your small contexts 
 to the draw rect one.
 
 That was what I looked for at first as well, but there doesn’t appear to be 
 such a call, such as CGContextCreateCopy. Pity, hence the veering into 
 hackery territory. But there may be a cleaner way, I just haven’t discovered 
 it yet.

You and I looked for the same API point. If it existed it would probably 
require the contexts would be used on the same thread and thus be useless. 
 

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Graham Cox

On 6 Dec 2013, at 11:26 am, Graham Cox graham@bigpond.com wrote:

   NSBlockOperation* op = [NSBlockOperation 
 blockOperationWithBlock:^
   {
   CGContextClipToRect( ncx, tileRect );
 
   [self drawTile:tileRect inContext:ncx];
   }];


A question for blocks experts:

Is the value of tileRect here captured when the block is created,or when it 
is run?

If the latter, it’s going to be probably wrong most of the time, so how can I 
make sure it is captured when the block is created?

—Graham


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread dangerwillrobinsondanger


Sent from my iPhone

 On 2013/12/07, at 0:27, Graham Cox graham@bigpond.com wrote:
 
 
 On 6 Dec 2013, at 11:26 am, Graham Cox graham@bigpond.com wrote:
 
NSBlockOperation* op = [NSBlockOperation 
 blockOperationWithBlock:^
{
CGContextClipToRect( ncx, tileRect );
 
[self drawTile:tileRect inContext:ncx];
}];
 
 
 A question for blocks experts:
 
 Is the value of tileRect here captured when the block is created,or when it 
 is run?
 
 If the latter, it’s going to be probably wrong most of the time, so how can I 
 make sure it is captured when the block is created?
 
 ―Graham
 
 
 _
It's the latter IIRC
You'll want to capture it outside and prefix it to be block scoped. 
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Graham Cox

On 6 Dec 2013, at 2:42 pm, Roland King r...@rols.org wrote:

 
 
 That might be another way, by the way, render to your own tiled small 
 bitmaps on background threads then blit them into the real context. 
 
 Yep, that was also on my list to try, but for top performance it would make 
 sense not to do that if it can be avoided.
 
 
 My WAG would be that works well enough. Heavy lifting on the threads, then 
 toss a bitmap/CGImage copy to the main thread where I'd hope it was just a 
 bitblt into the context. I've seen similar recommended for iOS but only with 
 a fullsize bitmap, not with bits and pieces. In most of those cases the view 
 was an image and the contents was constructed on a background thread and then 
 set into the image outside the drawrect call. 


OK, I’ve now tried this approach, and it’s much cleaner in that it works with 
scrollers, with and without “responsive” scrolling (which appears to buffer its 
contents) and also zooming. Code follows. In this case, drawing overall is 
slower than the normal case, because the simple drawing I’m doing doesn’t tax 
things much, so the set up and tear down of the bitmaps is dominating, but I 
would expect for very complex drawing it would show a win.

I also tried to create one big bitmap into which all the different contexts 
drew. That worked to a degree, but it seems that when you create a context that 
wraps a block of memory, the first thing it does it to clear it to some 
background colour. That’s annoying, because you end up with some blank areas 
where a later thread cleared the bitmap that an earlier thread had already 
drawn. If just creating the context didn’t do this clearing, it would probably 
work fine and be a lot more performant, because the bitmap and image would not 
need to be created on the fly, and afterwards you can just blit the update 
rects back to the main context. It would be useful if some graphics gurus (Ken 
Ferry??) could chip in and comment on whether this conclusion is correct, and 
if there’s a workaround.

Also, to answer my earlier question, blocks capture the values of variables 
when they’re created, not when they’re run, so that makes life much easier as 
well.

The next step will be to make the tiles themselves represent the visible rect 
of the view, and the context factor in the zoom scale in such a way that 
drawing paths and so on always rasterizes to the native resolution of the 
screen. At the moment zooming in shows pixelization because the tile bitmaps 
are scaling with the view frame. Need some more thought on how to do that.




- (void)drawRect:(NSRect) dirtyRect
{
NSTimeInterval  time = [NSDate timeIntervalSinceReferenceDate];

// get current context:

CGContextRef ctx = [[NSGraphicsContext currentContext] graphicsPort];

CGContextSaveGState( ctx );

const CGRect* rects;
NSInteger count;

[self getRectsBeingDrawn:rects count:count];

CGContextClipToRects( ctx, rects, count );

// divide into tiles

NSSize  tileSize = TILE_SIZE;
NSRect  br = self.bounds;
NSUInteger  tx, ty;

tx = ceil(NSWidth( br ) / tileSize.width);
ty = ceil(NSHeight( br ) / tileSize.height);

NSRect tileRect;

tileRect.size = tileSize;

for( NSInteger i = 0; i  ty; ++i )
{
for( NSInteger j = 0; j  tx; ++j )
{
tileRect.origin.x = br.origin.x + tileSize.width * j;
tileRect.origin.y = br.origin.y + tileSize.height * i;

if([self needsToDrawRect:tileRect])
{
#if DRAW_THREADED
NSBlockOperation* op = [NSBlockOperation 
blockOperationWithBlock:^
{
// make sure retina screens taken into 
account

NSRect backing = [[self window] 
convertRectToBacking:tileRect];

// create a bitmap image for the tile

CGColorSpaceRef cspace = 
CGColorSpaceCreateWithName( kCGColorSpaceGenericRGB );

NSUInteger  bytesPerRow = NSWidth( 
backing ) * 4;
size_t bytes = bytesPerRow * NSHeight( 
backing );

void* bitsPtr = malloc( bytes );

CGDataProviderRef provider = 
CGDataProviderCreateWithData( NULL, bitsPtr, bytes, NULL );
   

Re: Threaded drawing

2013-12-06 Thread Seth Willits
On Dec 6, 2013, at 8:05 AM, dangerwillrobinsondan...@gmail.com wrote:

 On 6 Dec 2013, at 11:26 am, Graham Cox graham@bigpond.com wrote:
 
   NSBlockOperation* op = [NSBlockOperation 
 blockOperationWithBlock:^
   {
   CGContextClipToRect( ncx, tileRect );
 
   [self drawTile:tileRect inContext:ncx];
   }];
 
 
 A question for blocks experts:
 
 Is the value of tileRect here captured when the block is created,or when 
 it is run?
 
 If the latter, it’s going to be probably wrong most of the time, so how can 
 I make sure it is captured when the block is created?
 
 
 
 It's the latter IIRC
 You'll want to capture it outside and prefix it to be block scoped. 


No it’s not and no you don’t. 


int x = 3;
void (^block)(void) = ^{ NSLog(@%d, x); };
x = 5;
block();

The result is 3 not 5.


--
Seth Willits




___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread John McCall
On Dec 6, 2013, at 9:24 AM, Seth Willits sli...@araelium.com wrote:
 On Dec 6, 2013, at 8:05 AM, dangerwillrobinsondan...@gmail.com wrote:
 On 6 Dec 2013, at 11:26 am, Graham Cox graham@bigpond.com wrote:
 
  NSBlockOperation* op = [NSBlockOperation 
 blockOperationWithBlock:^
  {
  CGContextClipToRect( ncx, tileRect );
 
  [self drawTile:tileRect inContext:ncx];
  }];
 
 
 A question for blocks experts:
 
 Is the value of tileRect here captured when the block is created,or when 
 it is run?
 
 If the latter, it’s going to be probably wrong most of the time, so how can 
 I make sure it is captured when the block is created?
 
 
 
 It's the latter IIRC
 You'll want to capture it outside and prefix it to be block scoped. 
 
 No it’s not and no you don’t.

To expand on this, whenever you evaluate a block literal expression that uses 
one or more normal local variables, those variables are immediately copied into 
the block, essentially as if the block literal were a struct with a field that 
looks exactly like the local variable.  When you copy the block and it has to 
“move to the heap, the exact same structure gets allocated there and 
member-by-member copied from the stack version.  Any subsequent changes to the 
variable aren’t tracked, because how could they be?

A __block variable is special; when you capture a __block variable, what’s 
actually captured is a pointer to the __block variable’s byref struct.  I’ve 
seen a lot of confusion and over-use of __block variables, which can probably 
be traced back to the name being somewhat misleading.  You don’t need to make a 
__block variable just to capture something in a block.  You need to make a 
__block variable only if it’s important to you that the block and the enclosing 
function are working on the same variable, not just the same value; that is, if 
you’re going to modify the variable in one place and need those modifications 
to be seen by the other.  The usual use case is a block that’s supposed to set 
some variable in the enclosing scope, but you could also imagine a function 
running a state machine and a long-lived block that’s supposed to react to 
state changes.

John.
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Jens Alfke

On Dec 6, 2013, at 7:27 AM, Graham Cox graham@bigpond.com wrote:

 Is the value of tileRect here captured when the block is created,or when it 
 is run?

It depends on whether tileRect is an instance variable.
* If it isn’t (i.e. it’s local/static/global), it gets captured when the block 
is created.
* If it _is_ an ivar, then “tileRect” is just syntactic sugar for 
“self-tileRect”, which means that ‘self’ gets captured at create time, and the 
‘-tileRect’ part is evaluated at runtime.

(This is one of many reasons why I believe ivar names should be distinguished, 
e.g. by prefixing them with “_”. Their behavior is different enough from other 
variables that it’s important to be aware of them when reading code.)

—Jens
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Graham Cox

On 6 Dec 2013, at 8:37 pm, Jens Alfke j...@mooseyard.com wrote:

 It depends on whether tileRect is an instance variable.

It’s not

 (This is one of many reasons why I believe ivar names should be 
 distinguished, e.g. by prefixing them with “_”. Their behavior is different 
 enough from other variables that it’s important to be aware of them when 
 reading code.)

I completely concur, which is why I use mIvarName for mEmbers (a C++ habit, 
rather than the Cocoa one of _ivarName), also gLobals, sTatics, fIelds, and 
probably others that escape me for the moment. Only locals have no special 
naming.

But I found out the answer to my question regarding blocks a few moments after 
posting, as is usual ;)

—Graham



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Roland King

On 7 Dec, 2013, at 12:46 am, Graham Cox graham@bigpond.com wrote:

 
   
   @synchronized( self )
   {
   CGContextDrawImage( ctx, 
 tileRect, tileImage );
   }
   CGImageRelease( tileImage );
   
   free( bitsPtr );
   }];
   
   [mDrawingQueue addOperation:op];
 #else
   [self drawTile:tileRect inContext:ctx];
 #endif
   
   }
   }
   }
   
 #if DRAW_THREADED
   [mDrawingQueue waitUntilAllOperationsAreFinished];
 #endif
   

You could also, instead of synchronizing the CGContextDrawImage(), which may 
make your threads wait for each other for some infinitessimal time, use

dispatch_async( dispatch_get_main_queue(), {
CGContextDrawImage( ctx, tileRect, tileImage );
CGImageRelease( tileImage );
free( bitsPtr );
}

which serializes them. And I doubt it would make a sod of difference. 

For completeness, if you wanted a dispatch queue as opposed to NSOperationQueue 
based approach, setting up a dispatch queue, concurrent one, and using 
dispatch_apply() with iterations = tx * ty would do that, and wait for 
completion, so you don't need the waitUntilAllOperationsAreFinished.  But 
that's just preference, I use dispatch queues when I can most of the time. 

And reminded of the comment about how hard block syntax can be to remember, I 
didn't make this page, I'm not a fan of the name, but it's awfully useful and I 
keep it bookmarked,  I tinyURLed it to avoid tripping up swear checkers, 
http://tinyurl.com/m6lukyg. 


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Greg Parker
On Dec 6, 2013, at 11:37 AM, Jens Alfke j...@mooseyard.com wrote:
 On Dec 6, 2013, at 7:27 AM, Graham Cox graham@bigpond.com wrote:
 Is the value of tileRect here captured when the block is created,or when 
 it is run?
 
 It depends on whether tileRect is an instance variable.
 * If it isn’t (i.e. it’s local/static/global), it gets captured when the 
 block is created.
 * If it _is_ an ivar, then “tileRect” is just syntactic sugar for 
 “self-tileRect”, which means that ‘self’ gets captured at create time, and 
 the ‘-tileRect’ part is evaluated at runtime.

*Only* ordinary local variables are captured when the block is constructed. 
Globals, static locals, __block locals, and ivars are not captured.


% clang test.m -framework Foundation  ./a.out
local 0, static_local 1, block_local 1, global 1, ivar 1

% cat test.m
#include Foundation/Foundation.h

@interface Test : NSObject @end

int global;

@implementation Test {
int ivar;
}

-(void)method 
{
int local;
static int static_local;
__block int block_local;

local = 0;
static_local = 0;
block_local = 0;
global = 0;
ivar = 0;

void (^block)(void) = ^{ 
printf(local %d, static_local %d, block_local %d, global %d, ivar 
%d\n, 
   local, static_local, block_local, global, ivar);
};

local = 1;
static_local = 1;
block_local = 1;
global = 1;
ivar = 1;

block();
}

@end

int main()
{
[[Test new] method];
}


-- 
Greg Parker gpar...@apple.com Runtime Wrangler



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-06 Thread Ken Thomases
On Dec 6, 2013, at 6:05 PM, Roland King wrote:

 On 7 Dec, 2013, at 12:46 am, Graham Cox graham@bigpond.com wrote:
 
 
  
  @synchronized( self )
  {
  CGContextDrawImage( ctx, 
 tileRect, tileImage );
  }
  CGImageRelease( tileImage );

 You could also, instead of synchronizing the CGContextDrawImage(), which may 
 make your threads wait for each other for some infinitessimal time, use
 
 dispatch_async( dispatch_get_main_queue(), {
   CGContextDrawImage( ctx, tileRect, tileImage );
   CGImageRelease( tileImage );
   free( bitsPtr );
 }
 
 which serializes them. And I doubt it would make a sod of difference. 

It would make a difference in that it wouldn't work.  The draw operations will 
not be performed before the CGContextRestoreGState() call nor before the 
NSGraphicsContext that the CGContext was obtained from has had a chance to, for 
example, release the CGContext.  Or, if not that, then change its state values.

Regards,
Ken


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Threaded drawing

2013-12-04 Thread Graham Cox
Another question of a general nature.

NSView has -setCanDrawConcurrently, which, when you also permit this at the 
window level, will handle its -drawRect refreshes on a background thread. I’ve 
been experimenting with this to see if it yields any worthwhile gains, but it 
doesn’t appear so - there seems to be a lock on the main thread that waits 
until the drawing thread has finished, presumably to synchronise the final 
window update. That being the case, it doesn’t improve responsiveness over 
drawing on the main thread, so I wonder whether there’s much point to this?

But anyway, it got me thinking how threads *could* be used to draw more quickly.

First, only drawing the refresh rects helps a lot, because I do a lot of work 
to not only avoid drawing what doesn’t need to be refreshed, but there’s a 
spatial hash to rapidly exclude objects that fall outside of these update rects 
without having to iterate over the whole lot testing for intersection. This 
shows a massive benefit when you’re zoomed well into a view, where most of the 
objects aren’t visible.

But that leaves those annoying cases when you have the whole view to redraw. I 
wondered if it would be worth dividing up the view into rects and rendering 
each one on a separate thread. The problem seems to me to be that they’d all be 
drawing into the same CGContext, and I wonder how well that could work - e.g. 
one thread could set a clip ready for its next drawing operation and another 
could then change that clip so they’d all be tripping over each other, even 
though they were all drawing into a different part of the context. If access to 
the context were synchronised, then that would end up serialising all the 
drawing so there wouldn’t be any gain.

Has anyone trod this path? It would be useful to know whether there’s anything 
that can be done along these lines, because rendering 10,000 or more objects is 
just taking too darn long!

—Graham



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Threaded drawing

2013-12-04 Thread Sean McBride
On Wed, 4 Dec 2013 21:33:16 +0100, Graham Cox said:

NSView has -setCanDrawConcurrently, which, when you also permit this at
the window level, will handle its -drawRect refreshes on a background
thread. I’ve been experimenting with this to see if it yields any
worthwhile gains,

I looked into to few years ago, but gave up when I discovered it doesn't 
(didn't?) support layer-backed views.

but it doesn’t appear so - there seems to be a lock on
the main thread that waits until the drawing thread has finished,
presumably to synchronise the final window update. That being the case,
it doesn’t improve responsiveness over drawing on the main thread, so I
wonder whether there’s much point to this?

I think the idea is that several views can do their drawing independently on 
different threads, but the main thread waits for them all to be done.  That 
limits you to the speed of your slowest view, but can help if you have several 
views that are all pretty slow.

I haven't seen concurrent drawing talked about in recent WWDC videos, so wonder 
about it really...

Cheers,

-- 

Sean McBride, B. Eng s...@rogue-research.com
Rogue Researchwww.rogue-research.com 
Mac Software Developer  Montréal, Québec, Canada

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com