Reordering CALayer sublayers without raping my performance?
-
Jonathan del Strother Reordering CALayer sublayers without raping my performance? Nov 16 2007, 19:41I have a root CALayer with around 250 child layers. Only 50 or so are
visible at a time, the rest have their opacity set to 0 (which I've
found to be far more performant that continuously removing and adding
child layers).
Every 0.2 seconds, I want to move one of these child layers to be
drawn on the top of everything else. I'm doing this by altering the
order of the root layer's sub layers. I haven't been able to find an
acceptable way of doing this. Everything I've tried will continuously
increase my virtual memory usage to ~3.5GB, before dropping back to
1.1GB every 10 seconds or so. While that drop happens, my application
performance drops massively, displaying a frame a second at best, on a
Mac Pro with 3GB RAM.
The obvious way of moving a sublayer to the front would appear to be :
[rootLayer insertSublayer:child above:[[rootLayer sublayers]
lastObject]];
where 'child' already exists within in the rootLayer's sublayers.
I've also tried variants along the lines of :
NSMutableArray* sublayers = [[rootLayer sublayers] mutableCopy];
[sublayers removeObject:child];
[sublayers addObject:child];
rootLayer.sublayers = sublayers;
[sublayers release];
Everything I've tried results in the excessive virtual memory usage
and a huge drop in performance.
If I give up on moving the child to the front, it runs perfectly : my
app sits happily at 120MB real / 1.1GB virtual memory, and updates
smoothly. It's only when trying to alter the sublayers array that
these problems kick in.
Any suggestions on getting around this?
Jon -
On Nov 16, 2007, at 10:41 AM, Jonathan del Strother wrote:
> I have a root CALayer with around 250 child layers. Only 50 or so
> are visible at a time, the rest have their opacity set to 0 (which
> I've found to be far more performant that continuously removing and
> adding child layers).
>
> Every 0.2 seconds, I want to move one of these child layers to be
> drawn on the top of everything else. I'm doing this by altering the
> order of the root layer's sub layers. I haven't been able to find
> an acceptable way of doing this. Everything I've tried will
> continuously increase my virtual memory usage to ~3.5GB, before
> dropping back to 1.1GB every 10 seconds or so. While that drop
> happens, my application performance drops massively, displaying a
> frame a second at best, on a Mac Pro with 3GB RAM.
Use the zPosition property. All layers with a larger zPosition will be
placed in front of those with a smaller one. The default value is 0.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...> -
On 16 Nov 2007, at 18:48, David Duncan wrote:
> On Nov 16, 2007, at 10:41 AM, Jonathan del Strother wrote:
>
>> I have a root CALayer with around 250 child layers. Only 50 or so
>> are visible at a time, the rest have their opacity set to 0 (which
>> I've found to be far more performant that continuously removing and
>> adding child layers).
>>
>> Every 0.2 seconds, I want to move one of these child layers to be
>> drawn on the top of everything else. I'm doing this by altering
>> the order of the root layer's sub layers. I haven't been able to
>> find an acceptable way of doing this. Everything I've tried will
>> continuously increase my virtual memory usage to ~3.5GB, before
>> dropping back to 1.1GB every 10 seconds or so. While that drop
>> happens, my application performance drops massively, displaying a
>> frame a second at best, on a Mac Pro with 3GB RAM.
>
>
> Use the zPosition property. All layers with a larger zPosition will
> be placed in front of those with a smaller one. The default value is
> 0.
Hmm, you're right.
Am I misreading this, or does the "Layer Geometry and Transforms" page
tell me something completely different :
"The zPosition is intended to be used to set the visual position of
the layer relative to its sibling layers. It should not be used to
specify the order of layer siblings, instead reorder the layer in the
sublayer array." -
On Nov 16, 2007, at 10:54 AM, Jonathan del Strother wrote:
> Hmm, you're right.
>
> Am I misreading this, or does the "Layer Geometry and Transforms"
> page tell me something completely different :
> "The zPosition is intended to be used to set the visual position of
> the layer relative to its sibling layers. It should not be used to
> specify the order of layer siblings, instead reorder the layer in
> the sublayer array."
Well, it is performing a sort when you set zPosition :). So it can be
more expensive than just reordering the sublayers array, certainly so
if you only have a 2D presentation. An alternative to try is disabling
transactions while your rearranging the sublayers array, like this
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
// do your sublayer rearrangement here
[CATransaction commit];
Of course, if you ever plan to go for a 2.5D scene (ala Coverflow)
then you will need to deal with zPosition, as the layer order isn't
enough to get the correct appearance in that situation.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...> -
On 16 Nov 2007, at 19:08, David Duncan wrote:
> On Nov 16, 2007, at 10:54 AM, Jonathan del Strother wrote:
>
>> Hmm, you're right.
>>
>> Am I misreading this, or does the "Layer Geometry and Transforms"
>> page tell me something completely different :
>> "The zPosition is intended to be used to set the visual position of
>> the layer relative to its sibling layers. It should not be used to
>> specify the order of layer siblings, instead reorder the layer in
>> the sublayer array."
>
>
> Well, it is performing a sort when you set zPosition :). So it can
> be more expensive than just reordering the sublayers array,
> certainly so if you only have a 2D presentation.
Would you run that past me again? Changing the zPosition re-sorts the
sibling layers? In which case, is there any point in re-sorting the
child array to specify render order?
I'll test it out later, but I assume that CA is using a depth buffer
to make sure that higher zPositioned objects appear in front of
others, in which case the only time you need to worry about the order
of the child array ought to be if you're dealing with transparent
elements.
Is there any way of re-sorting the child element array that doesn't
incur a huge performance & memory hit?
Jonathan del Strother -
On Nov 19, 2007, at 1:09 AM, Jonathan del Strother wrote:
> Would you run that past me again? Changing the zPosition re-sorts
> the sibling layers? In which case, is there any point in re-sorting
> the child array to specify render order?
Whenever the zPosition of a layer changes, you have to sort the layers
(internally) for presentation, otherwise you wouldn't get the correct
visual effect. It doesn't sort the sublayers array, just the visual
order that the layers are rendered in (which if all layers have the
same zPosition is just the order in the sublayers array).
> I'll test it out later, but I assume that CA is using a depth buffer
> to make sure that higher zPositioned objects appear in front of
> others, in which case the only time you need to worry about the
> order of the child array ought to be if you're dealing with
> transparent elements.
CA has no guarantees of having or not having transparent content. In
fact, the most common use for it (Appkit's layer based views) involves
considerable amounts of transparency (mostly for antialiasing, but
since the entire drawing model is supported arbitrary transparency has
to be supported as well).
> Is there any way of re-sorting the child element array that doesn't
> incur a huge performance & memory hit?
The alternative is what I said last time, to use the current
transaction to disable creating implicit animations.
--
David Duncan
Apple DTS Animation and Printing
<david.duncan...> -
On 19 Nov 2007, at 09:49, David Duncan wrote:
> On Nov 19, 2007, at 1:09 AM, Jonathan del Strother wrote:
>
>> Would you run that past me again? Changing the zPosition re-sorts
>> the sibling layers? In which case, is there any point in re-
>> sorting the child array to specify render order?
>
> Whenever the zPosition of a layer changes, you have to sort the
> layers (internally) for presentation, otherwise you wouldn't get the
> correct visual effect. It doesn't sort the sublayers array, just the
> visual order that the layers are rendered in (which if all layers
> have the same zPosition is just the order in the sublayers array).
>
>> I'll test it out later, but I assume that CA is using a depth
>> buffer to make sure that higher zPositioned objects appear in front
>> of others, in which case the only time you need to worry about the
>> order of the child array ought to be if you're dealing with
>> transparent elements.
>
> CA has no guarantees of having or not having transparent content. In
> fact, the most common use for it (Appkit's layer based views)
> involves considerable amounts of transparency (mostly for
> antialiasing, but since the entire drawing model is supported
> arbitrary transparency has to be supported as well).
>
>> Is there any way of re-sorting the child element array that doesn't
>> incur a huge performance & memory hit?
>
>
> The alternative is what I said last time, to use the current
> transaction to disable creating implicit animations.
Oooh, it's finally clicked that re-sorting the sublayers is an
animated process. That would explain the memory usage pattern I was
seeing, since I would have been created a lot of overlapping
animations...
Thanks for clarifying that
Jon -
So, just to clarify for posterity, if you had turned off animation by
using a transaction, it would have mostly or completely removed your
slowdown?
On Nov 19, 2007, at 5:02 AM, Jonathan del Strother wrote:
> On 19 Nov 2007, at 09:49, David Duncan wrote:
>
>> On Nov 19, 2007, at 1:09 AM, Jonathan del Strother wrote:
>>
>>> Would you run that past me again? Changing the zPosition re-sorts
>>> the sibling layers? In which case, is there any point in re-
>>> sorting the child array to specify render order?
>>
>> Whenever the zPosition of a layer changes, you have to sort the
>> layers (internally) for presentation, otherwise you wouldn't get
>> the correct visual effect. It doesn't sort the sublayers array,
>> just the visual order that the layers are rendered in (which if all
>> layers have the same zPosition is just the order in the sublayers
>> array).
>>
>>> I'll test it out later, but I assume that CA is using a depth
>>> buffer to make sure that higher zPositioned objects appear in
>>> front of others, in which case the only time you need to worry
>>> about the order of the child array ought to be if you're dealing
>>> with transparent elements.
>>
>> CA has no guarantees of having or not having transparent content.
>> In fact, the most common use for it (Appkit's layer based views)
>> involves considerable amounts of transparency (mostly for
>> antialiasing, but since the entire drawing model is supported
>> arbitrary transparency has to be supported as well).
>>
>>> Is there any way of re-sorting the child element array that
>>> doesn't incur a huge performance & memory hit?
>>
>>
>> The alternative is what I said last time, to use the current
>> transaction to disable creating implicit animations.
>
> Oooh, it's finally clicked that re-sorting the sublayers is an
> animated process. That would explain the memory usage pattern I was
> seeing, since I would have been created a lot of overlapping
> animations...
>
> Thanks for clarifying that
>
> Jon
>
Cheers!
--Chris Ryland / Em Software, Inc. / www.emsoftware.com -
On 19 Nov 2007, at 18:56, Chris Ryland wrote:
> So, just to clarify for posterity, if you had turned off animation
> by using a transaction, it would have mostly or completely removed
> your slowdown?
Correct. After disabling actions, adding/removing/reordering
sublayers has negligible performance hit on what we're trying to do.



