Reordering CALayer sublayers without raping my performance?

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

    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.
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today