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