Re: Threaded drawing
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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