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