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 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/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

Reply via email to