Reduce IntrusivePtr<ActorPtr> reference change during PropagateAll 03/319603/5
authorEunki, Hong <eunkiki.hong@samsung.com>
Thu, 13 Feb 2025 10:12:36 +0000 (19:12 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Fri, 14 Feb 2025 09:58:59 +0000 (18:58 +0900)
std::atomic value changeness might gave overhead if we call it
very frequencly.

To reduce it's overhead, let we use Interal::Actor& instead Actor handle
if we can.

Note that we cannot remove Dali::Actor handle at RelayoutInfo,
since we need to guard case that Actor itself destruct during
Relayout callback at application side.

Change-Id: I5f058be4706c8c2be77f1677e1f5624f37d50478
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
dali/internal/event/actors/actor-sizer.cpp
dali/internal/event/size-negotiation/memory-pool-relayout-container.cpp
dali/internal/event/size-negotiation/memory-pool-relayout-container.h
dali/internal/event/size-negotiation/relayout-controller-impl.cpp
dali/internal/event/size-negotiation/relayout-controller-impl.h

index cd6116752c8277adfd8ea47ac4fbc001e7d2c7d1..be37cc084c1af5ba03a4b42524c0b62c6cf6503a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -686,7 +686,7 @@ float ActorSizer::GetMaximumSize(Dimension::Type dimension) const
 void ActorSizer::OnAnimateSize(Animation& animation, Vector3 targetSize, bool relative)
 {
   Vector3 originalTargetSize = mTargetSize;
-  mTargetSize      = targetSize + mTargetSize * float(relative);
+  mTargetSize                = targetSize + mTargetSize * float(relative);
   if(originalTargetSize != mTargetSize)
   {
     mTargetSizeDirtyFlag = true;
@@ -708,8 +708,8 @@ void ActorSizer::OnAnimateSize(Animation& animation, Vector3 targetSize, bool re
 void ActorSizer::OnAnimateWidth(Animation& animation, float width, bool relative)
 {
   const float originalWidth = mTargetSize.width;
-  mTargetSize.width   = width + float(relative) * mTargetSize.width;
-  if(!Equals(originalWidth,mTargetSize.width))
+  mTargetSize.width         = width + float(relative) * mTargetSize.width;
+  if(!Equals(originalWidth, mTargetSize.width))
   {
     mTargetSizeDirtyFlag = true;
   }
@@ -728,7 +728,7 @@ void ActorSizer::OnAnimateWidth(Animation& animation, float width, bool relative
 void ActorSizer::OnAnimateHeight(Animation& animation, float height, bool relative)
 {
   const float originalHeight = mTargetSize.height;
-  mTargetSize.height   = height + float(relative) * mTargetSize.height;
+  mTargetSize.height         = height + float(relative) * mTargetSize.height;
   if(!Equals(originalHeight, mTargetSize.height))
   {
     mTargetSizeDirtyFlag = true;
@@ -748,7 +748,7 @@ void ActorSizer::OnAnimateHeight(Animation& animation, float height, bool relati
 void ActorSizer::OnAnimateDepth(Animation& animation, float depth, bool relative)
 {
   const float originalDepth = mTargetSize.depth;
-  mTargetSize.depth   = depth + float(relative) * mTargetSize.depth;
+  mTargetSize.depth         = depth + float(relative) * mTargetSize.depth;
   if(!Equals(originalDepth, mTargetSize.depth))
   {
     mTargetSizeDirtyFlag = true;
index 901d5b10a8124678f5d6fee9a6335437cc3cdb93..a1ee16943f2366c3b7281d5c5ea0fb0916ff4778 100644 (file)
@@ -30,56 +30,45 @@ MemoryPoolRelayoutContainer::MemoryPoolRelayoutContainer(MemoryPoolObjectAllocat
 
 MemoryPoolRelayoutContainer::~MemoryPoolRelayoutContainer() = default;
 
-bool MemoryPoolRelayoutContainer::Contains(const Dali::Actor& actor)
+void MemoryPoolRelayoutContainer::Add(const Dali::Actor& actor, const Vector2& size)
 {
   // Store actor into dummy info.
   // It will be used for check comparision.
+  // TODO : Can't we remove this handle copying, to avoid useless IntrusivePtr ref count?
   mDummyRelayoutInfo->actor = actor;
 
-  bool ret = (mRelayoutInfos.Find(mDummyRelayoutInfo.get()) != mRelayoutInfos.End());
-
-  // Reset empty handle for deference.
-  mDummyRelayoutInfo->actor = Dali::Actor();
-  return ret;
-}
-
-void MemoryPoolRelayoutContainer::Add(const Dali::Actor& actor, const Vector2& size)
-{
-  if(!Contains(actor))
+  if(mRelayoutInfos.Find(mDummyRelayoutInfo.get()) == mRelayoutInfos.End())
   {
     void*         ptr  = mAllocator.AllocateRaw();
     RelayoutInfo* info = new(ptr) RelayoutInfo();
-    info->actor        = actor;
-    info->size         = size;
+
+    info->actor = std::move(mDummyRelayoutInfo->actor);
+    info->size  = size;
 
     mRelayoutInfos.PushBack(info);
   }
-}
-
-void MemoryPoolRelayoutContainer::PopBack()
-{
-  if(mRelayoutInfos.Count() > 0)
+  else
   {
-    RelayoutInfoContainer::Iterator back = mRelayoutInfos.End();
-    back--;
-    RelayoutInfo* info = *back;
-    mRelayoutInfos.Erase(back);
-
-    // Need to be destroyed after mRelayoutInfos erased.
-    mAllocator.Destroy(info);
+    // Reset empty handle for deference.
+    mDummyRelayoutInfo->actor = Dali::Actor();
   }
 }
 
-void MemoryPoolRelayoutContainer::GetBack(Dali::Actor& actorOut, Vector2& sizeOut) const
+void MemoryPoolRelayoutContainer::PopBack(Dali::Actor& actorOut, Vector2& sizeOut)
 {
-  if(mRelayoutInfos.Count() > 0)
-  {
-    RelayoutInfoContainer::ConstIterator back = mRelayoutInfos.End();
-    back--;
-    RelayoutInfo* info = *back;
-    actorOut           = info->actor;
-    sizeOut            = info->size;
-  }
+  DALI_ASSERT_ALWAYS(mRelayoutInfos.Count() > 0 && "Try to pop from empty relayout container!");
+
+  RelayoutInfoContainer::ConstIterator back = mRelayoutInfos.End();
+  back--;
+  RelayoutInfo* info = *back;
+
+  mRelayoutInfos.Erase(back);
+
+  actorOut = std::move(info->actor);
+  sizeOut  = std::move(info->size);
+
+  // Need to be destroyed after mRelayoutInfos erased.
+  mAllocator.Destroy(info);
 }
 
 size_t MemoryPoolRelayoutContainer::Size() const
index 38e76015478558a5e0fb93acc2e86c99ab47ef3f..f7846d4117f983193a07f52eb5455f6b5f5fb1b0 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_MEMORY_POOL_RELAYOUT_CONTAINER_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ public:
    */
   struct RelayoutInfo
   {
-    Dali::Actor actor; ///< The actor to relayout
+    Dali::Actor actor; ///< The actor to relayout (Keep reference, to guard destruct case during Relayout)
     Vector2     size;  ///< The desired size of the actor
 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
     struct RelayoutInfoCompareLess
@@ -95,17 +95,12 @@ public:
   void Add(const Dali::Actor& actor, const Vector2& size) override;
 
   /**
-   * @brief Remove information from the container
-   */
-  void PopBack();
-
-  /**
-   * @brief Retrieve relayout information for the latest added
+   * @brief Retrieve relayout information for the latest added, and remove from the container
    *
    * @param[out] actorOut Latest added actor
    * @param[out] sizeOt Latest added size
    */
-  void GetBack(Dali::Actor& actorOut, Vector2& sizeOut) const;
+  void PopBack(Dali::Actor& actorOut, Vector2& sizeOut);
 
   /**
    * @brief The count of information in the container
@@ -124,15 +119,6 @@ public:
    */
   void Clear();
 
-private:
-  /**
-   * @brief Returns if the container contains the actor or not
-   *
-   * @param actor The actor to search for
-   * @return Return if the actor was found or not
-   */
-  bool Contains(const Dali::Actor& actor);
-
 private:
 #if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED)
   using RelayoutInfoContainer = Dali::Integration::OrderedSet<RelayoutInfo, false, RelayoutInfo::RelayoutInfoCompareLess>;
index 09407387357aea3f4d739cc51260f2cc29c4723d..1ca993eb5fc609f8728c1fe978ac2aa2ef32d1f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -138,12 +138,11 @@ RelayoutController* RelayoutController::Get()
   return nullptr;
 }
 
-void RelayoutController::QueueActor(Internal::Actor* actor, RelayoutContainer& actors, Vector2 size)
+void RelayoutController::QueueActor(Internal::Actor& actorImpl, RelayoutContainer& actors, Vector2 size)
 {
-  if(actor && actor->RelayoutRequired())
+  if(actorImpl.RelayoutRequired())
   {
-    Dali::Actor actorHandle = Dali::Actor(actor);
-    actors.Add(actorHandle, size);
+    actors.Add(Dali::Actor(&actorImpl), size);
   }
 }
 
@@ -154,49 +153,53 @@ void RelayoutController::RequestRelayout(Dali::Actor& actor, Dimension::Type dim
     return;
   }
 
-  std::vector<Dali::Actor>& potentialRedundantSubRoots = mPotentialRedundantSubRoots;
-  std::vector<Dali::Actor>& topOfSubTreeStack          = mTopOfSubTreeStack;
+  RawActorList& potentialRedundantSubRoots = mPotentialRedundantSubRoots;
+  RawActorList& topOfSubTreeStack          = mTopOfSubTreeStack;
 
   DALI_ASSERT_ALWAYS(potentialRedundantSubRoots.empty() && "potentialRedundantSubRoots must be empty before RequestRelayout!");
   DALI_ASSERT_ALWAYS(topOfSubTreeStack.empty() && "topOfSubTreeStack must be empty before RequestRelayout!");
 
-  topOfSubTreeStack.push_back(actor);
-
-  // Propagate on all dimensions
-  for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
   {
-    if(dimension & (1 << i))
+    Dali::Internal::Actor& actorImpl = GetImplementation(actor);
+
+    topOfSubTreeStack.push_back(&actorImpl);
+
+    // Propagate on all dimensions
+    for(uint32_t i = 0; i < Dimension::DIMENSION_COUNT; ++i)
     {
-      // Do the propagation
-      PropagateAll(actor, static_cast<Dimension::Type>(1 << i), topOfSubTreeStack, potentialRedundantSubRoots);
+      if(dimension & (1 << i))
+      {
+        // Do the propagation
+        PropagateAll(actorImpl, static_cast<Dimension::Type>(1 << i), topOfSubTreeStack, potentialRedundantSubRoots);
+      }
     }
   }
 
   while(!topOfSubTreeStack.empty())
   {
     // Request this actor as head of sub-tree if it is not dependent on a parent that is dirty
-    Dali::Actor subTreeActor = topOfSubTreeStack.back();
+    Dali::Internal::Actor& subTreeActorImpl = *topOfSubTreeStack.back();
     topOfSubTreeStack.pop_back();
 
-    Dali::Actor parent = subTreeActor.GetParent();
-    if(!parent || !(GetImplementation(subTreeActor).RelayoutDependentOnParent() && GetImplementation(parent).RelayoutRequired()))
+    Dali::Internal::Actor* parentImplPtr = subTreeActorImpl.GetParent();
+    if(!parentImplPtr || !(subTreeActorImpl.RelayoutDependentOnParent() && (*parentImplPtr).RelayoutRequired()))
     {
       // Add sub tree root to relayout list
-      AddRequest(subTreeActor);
+      AddRequest(subTreeActorImpl);
 
       // Flag request for end of frame
       Request();
     }
     else
     {
-      potentialRedundantSubRoots.push_back(subTreeActor);
+      potentialRedundantSubRoots.push_back(&subTreeActorImpl);
     }
   }
 
   // Remove any redundant sub-tree heads
-  for(auto& subRoot : potentialRedundantSubRoots)
+  for(const auto& subRoot : potentialRedundantSubRoots)
   {
-    RemoveRequest(subRoot);
+    RemoveRequest(*subRoot);
   }
 
   potentialRedundantSubRoots.clear();
@@ -218,22 +221,16 @@ void RelayoutController::OnApplicationSceneCreated()
   Request();
 }
 
-void RelayoutController::RequestRelayoutTree(Dali::Actor& actor)
+void RelayoutController::RequestRelayoutRecursively(Dali::Internal::Actor& actorImpl)
 {
-  if(!mEnabled)
-  {
-    return;
-  }
-
   // Only set dirty flag if doing relayout and not already marked as dirty
-  Actor& actorImpl = GetImplementation(actor);
   if(actorImpl.RelayoutPossible())
   {
     // If parent is not in relayout we are at the top of a new sub-tree
-    Dali::Actor parent = actor.GetParent();
-    if(!parent || !GetImplementation(parent).IsRelayoutEnabled())
+    Dali::Internal::Actor* parentImplPtr = actorImpl.GetParent();
+    if(!parentImplPtr || !(*parentImplPtr).IsRelayoutEnabled())
     {
-      AddRequest(actor);
+      AddRequest(actorImpl);
     }
 
     // Set dirty flag on actors that are enabled
@@ -242,18 +239,20 @@ void RelayoutController::RequestRelayoutTree(Dali::Actor& actor)
   }
 
   // Propagate down to children
-  for(uint32_t i = 0; i < actor.GetChildCount(); ++i)
+  if(actorImpl.GetChildCount())
   {
-    Dali::Actor child = actor.GetChildAt(i);
-
-    RequestRelayoutTree(child);
+    // Get reference of children container, to avoid useless reference count changing
+    auto& children = actorImpl.GetChildrenInternal();
+    for(auto& childImplPtr : children)
+    {
+      RequestRelayoutRecursively(*childImplPtr);
+    }
   }
 }
 
-void RelayoutController::PropagateAll(Dali::Actor& actor, Dimension::Type dimension, std::vector<Dali::Actor>& topOfSubTreeStack, std::vector<Dali::Actor>& potentialRedundantSubRoots)
+void RelayoutController::PropagateAll(Dali::Internal::Actor& actorImpl, Dimension::Type dimension, RawActorList& topOfSubTreeStack, RawActorList& potentialRedundantSubRoots)
 {
   // Only set dirty flag if doing relayout and not already marked as dirty
-  Actor& actorImpl = GetImplementation(actor);
   if(actorImpl.RelayoutPossible(dimension))
   {
     // Set dirty and negotiated flags
@@ -269,60 +268,76 @@ void RelayoutController::PropagateAll(Dali::Actor& actor, Dimension::Type dimens
       if(actorImpl.RelayoutDependentOnDimension(dimension, dimensionToCheck) &&
          !actorImpl.IsLayoutDirty(dimensionToCheck))
       {
-        PropagateAll(actor, dimensionToCheck, topOfSubTreeStack, potentialRedundantSubRoots);
+        PropagateAll(actorImpl, dimensionToCheck, topOfSubTreeStack, potentialRedundantSubRoots);
       }
     }
 
     // Propagate up to parent
-    Dali::Actor parent = actor.GetParent();
-    if(parent)
     {
-      Actor& parentImpl = GetImplementation(parent);
-      if(parentImpl.RelayoutDependentOnChildren(dimension) && !parentImpl.IsLayoutDirty(dimension))
+      Dali::Internal::Actor* parentImplPtr = actorImpl.GetParent();
+      if(parentImplPtr)
       {
-        // Store the highest parent reached
-        bool found = false;
-        for(auto&& element : topOfSubTreeStack)
+        Actor& parentImpl = *parentImplPtr;
+        if(parentImpl.RelayoutDependentOnChildren(dimension) && !parentImpl.IsLayoutDirty(dimension))
         {
-          if(element == parent)
+          // Store the highest parent reached
+          bool found = false;
+          for(auto&& element : topOfSubTreeStack)
           {
-            found = true;
-            break;
+            if(element == &parentImpl)
+            {
+              found = true;
+              break;
+            }
           }
-        }
 
-        if(!found)
-        {
-          topOfSubTreeStack.push_back(parent);
-        }
+          if(!found)
+          {
+            topOfSubTreeStack.push_back(&parentImpl);
+          }
 
-        // Propagate up
-        PropagateAll(parent, dimension, topOfSubTreeStack, potentialRedundantSubRoots);
+          // Propagate up
+          PropagateAll(parentImpl, dimension, topOfSubTreeStack, potentialRedundantSubRoots);
+        }
       }
     }
 
     // Propagate down to children
-    for(unsigned int i = 0, childCount = actor.GetChildCount(); i < childCount; ++i)
+    if(actorImpl.GetChildCount())
     {
-      Dali::Actor child     = actor.GetChildAt(i);
-      Actor&      childImpl = GetImplementation(child);
-
-      if(childImpl.IsRelayoutEnabled() && childImpl.RelayoutDependentOnParent(dimension))
+      // Get reference of children container, to avoid useless reference count changing
+      auto& children = actorImpl.GetChildrenInternal();
+      for(auto& childImplPtr : children)
       {
-        if(childImpl.IsLayoutDirty(dimension))
-        {
-          // We have found a child that could potentially have already been collected for relayout
-          potentialRedundantSubRoots.push_back(child);
-        }
-        else
+        Internal::Actor& childImpl = *childImplPtr;
+
+        if(childImpl.IsRelayoutEnabled() && childImpl.RelayoutDependentOnParent(dimension))
         {
-          PropagateAll(child, dimension, topOfSubTreeStack, potentialRedundantSubRoots);
+          if(childImpl.IsLayoutDirty(dimension))
+          {
+            // We have found a child that could potentially have already been collected for relayout
+            potentialRedundantSubRoots.push_back(&childImpl);
+          }
+          else
+          {
+            PropagateAll(childImpl, dimension, topOfSubTreeStack, potentialRedundantSubRoots);
+          }
         }
       }
     }
   }
 }
 
+void RelayoutController::RequestRelayoutTree(Dali::Actor& actor)
+{
+  if(!mEnabled)
+  {
+    return;
+  }
+
+  RequestRelayoutRecursively(GetImplementation(actor));
+}
+
 void RelayoutController::PropagateFlags(Dali::Actor& actor, Dimension::Type dimension)
 {
   // Only set dirty flag if doing relayout and not already marked as dirty
@@ -371,23 +386,20 @@ void RelayoutController::PropagateFlags(Dali::Actor& actor, Dimension::Type dime
   }
 }
 
-void RelayoutController::AddRequest(Dali::Actor& actor)
+void RelayoutController::AddRequest(Internal::Actor& actorImpl)
 {
-  Internal::Actor* actorPtr = &GetImplementation(actor);
-
   // Only add the rootActor if it is not already recorded
-  auto iter = mDirtyLayoutSubTrees.Find(actorPtr);
+  auto iter = mDirtyLayoutSubTrees.Find(&actorImpl);
 
   if(iter == mDirtyLayoutSubTrees.End())
   {
-    mDirtyLayoutSubTrees.PushBack(actorPtr);
+    mDirtyLayoutSubTrees.PushBack(&actorImpl);
   }
 }
 
-void RelayoutController::RemoveRequest(Dali::Actor& actor)
+void RelayoutController::RemoveRequest(const Internal::Actor& actorImpl)
 {
-  Internal::Actor* actorPtr = &GetImplementation(actor);
-  mDirtyLayoutSubTrees.EraseObject(actorPtr);
+  mDirtyLayoutSubTrees.EraseObject(&actorImpl);
 }
 
 void RelayoutController::Request()
@@ -419,22 +431,23 @@ void RelayoutController::Relayout()
 
     // 1. Finds all top-level controls from the dirty list and allocate them the size of the scene
     //    These controls are paired with the parent/scene size and added to the stack.
-    for(auto& dirtyActor : mDirtyLayoutSubTrees)
+    for(auto iter = mDirtyLayoutSubTrees.Begin(); iter != mDirtyLayoutSubTrees.End();)
     {
+      Internal::Actor* dirtyActorImplPtr = *iter;
       // Need to test if actor is valid (could have been deleted and had the pointer cleared)
-      if(dirtyActor)
+      if(dirtyActorImplPtr)
       {
+        auto& dirtyActorImpl = *dirtyActorImplPtr;
         // Only negotiate actors that are on the scene
-        if(dirtyActor->OnScene())
+        if(dirtyActorImpl.OnScene())
         {
-          Internal::Actor* parent = dirtyActor->GetParent();
-          QueueActor(dirtyActor, *mRelayoutStack, (parent) ? Vector2(parent->GetTargetSize()) : dirtyActor->GetScene().GetSize());
+          Internal::Actor* parent = dirtyActorImpl.GetParent();
+          QueueActor(dirtyActorImpl, *mRelayoutStack, (parent) ? Vector2(parent->GetTargetSize()) : dirtyActorImpl.GetScene().GetSize());
         }
       }
+      iter = mDirtyLayoutSubTrees.Erase(iter);
     }
 
-    mDirtyLayoutSubTrees.Clear();
-
     // 2. Iterate through the stack until it's empty.
     if(mRelayoutStack->Size() > 0)
     {
@@ -447,23 +460,22 @@ void RelayoutController::Relayout()
 
       while(mRelayoutStack->Size() > 0)
       {
-        Dali::Actor actor;
-        Vector2     size;
-
 #ifdef TRACE_ENABLED
         ++relayoutActorCount;
 #endif
+        Dali::Actor actor;
+        Vector2     size;
+
+        mRelayoutStack->PopBack(actor, size);
 
-        mRelayoutStack->GetBack(actor, size);
-        Actor& actorImpl = GetImplementation(actor);
-        mRelayoutStack->PopBack();
+        Internal::Actor& actorImpl = GetImplementation(actor);
 
         if(actorImpl.RelayoutRequired() && actorImpl.OnScene())
         {
 #ifdef TRACE_ENABLED
           ++negotiatedActorCount;
 #endif
-          DALI_LOG_INFO(gLogFilter, Debug::General, "[Internal::RelayoutController::Relayout] Negotiating %p %s %s (%.2f, %.2f)\n", &actorImpl, actor.GetTypeName().c_str(), actor.GetProperty<std::string>(Dali::Actor::Property::NAME).c_str(), size.width, size.height);
+          DALI_LOG_INFO(gLogFilter, Debug::General, "[Internal::RelayoutController::Relayout] Negotiating %p %s %s (%.2f, %.2f)\n", &actorImpl, actorImpl.GetTypeName().c_str(), std::string(actorImpl.GetName()).c_str(), size.width, size.height);
 
           // 3. Negotiate the size with the current actor. Pass it an empty container which the actor
           //    has to fill with all the actors it has not done any size negotiation for.
index d0045dd4df812c549cdd1795fa54857e0d2bfd6f..c359706ae0ca9bbce20bc1abf9ee2012bf6db373 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_RELAYOUT_CONTROLLER_IMPL_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -146,7 +146,8 @@ public: // CALLBACKS
   void OnObjectDestroyed(const Dali::RefObject* object);
 
 private:
-  using RawActorList = Dali::Integration::OrderedSet<Dali::Internal::Actor, false>;
+  using RawActorOrderedSet = Dali::Integration::OrderedSet<Dali::Internal::Actor, false>; ///< Specialised container to find duplication list, and order
+  using RawActorList       = std::vector<Dali::Internal::Actor*>;
 
   /**
    * @brief Request for relayout. Relays out whole scene.
@@ -156,16 +157,16 @@ private:
   /**
    * @brief Add actor to request list
    *
-   * @param[in] actor The root of the sub tree to add
+   * @param[in] actorImpl The root of the sub tree to add
    */
-  void AddRequest(Dali::Actor& actor);
+  void AddRequest(Dali::Internal::Actor& actorImpl);
 
   /**
    * @brief Remove actor from request list
    *
-   * @param[in] actor The root of the sub tree to remove
+   * @param[in] actorImpl The root of the sub tree to remove
    */
-  void RemoveRequest(Dali::Actor& actor);
+  void RemoveRequest(const Dali::Internal::Actor& actorImpl);
 
   /**
    * @brief Disconnect the Relayout() method from the Stage::EventProcessingFinishedSignal().
@@ -176,12 +177,12 @@ private:
    * @brief Propagate dirty layout flags to actor and all sub-actors. This will stop propagating when a dirty actor
    * is found.
    *
-   * @param[in] actor The actor to propagate on
+   * @param[in] actorImpl The actor to propagate on
    * @param[in] dimension The dimension to propagate on
    * @param[in] topOfSubTreeStack The top of the sub tree that this actor is in
    * @param[in] potentialRedundantSubRoots Actors collected as potentially already being included in relayout
    */
-  void PropagateAll(Dali::Actor& actor, Dimension::Type dimension, std::vector<Dali::Actor>& topOfSubTreeStack, std::vector<Dali::Actor>& potentialRedundantSubRoots);
+  void PropagateAll(Dali::Internal::Actor& actorImpl, Dimension::Type dimension, RawActorList& topOfSubTreeStack, RawActorList& potentialRedundantSubRoots);
 
   /**
    * Queue an actor on the relayout container
@@ -190,7 +191,14 @@ private:
    * @param[in] actors The container to add the actor to
    * @param[in] size The size that this actor should be
    */
-  void QueueActor(Internal::Actor* actor, RelayoutContainer& actors, Vector2 size);
+  void QueueActor(Internal::Actor& actor, RelayoutContainer& actors, Vector2 size);
+
+  /**
+   * Internal recursive logic for relayout tree
+   *
+   * @param[in] actorImpl The root of the sub tree to request relayout
+   */
+  void RequestRelayoutRecursively(Internal::Actor& actorImpl);
 
   // Undefined
   RelayoutController(const RelayoutController&) = delete;
@@ -202,12 +210,12 @@ private:
 
   SlotDelegate<RelayoutController> mSlotDelegate;
 
-  RawActorList mDirtyLayoutSubTrees; ///< List of roots of sub trees that are dirty
+  RawActorOrderedSet mDirtyLayoutSubTrees; ///< List of roots of sub trees that are dirty
 
   std::unique_ptr<MemoryPoolRelayoutContainer> mRelayoutStack; ///< Stack for relayouting
 
-  std::vector<Dali::Actor> mPotentialRedundantSubRoots; ///< Stack of Actor when RequestLayout comes. Keep it as member to avoid vector size reserving.
-  std::vector<Dali::Actor> mTopOfSubTreeStack;
+  RawActorList mPotentialRedundantSubRoots; ///< Stack of Actor when RequestLayout comes. Keep it as member to avoid vector size reserving.
+  RawActorList mTopOfSubTreeStack;
 
   bool mRelayoutConnection : 1;   ///< Whether EventProcessingFinishedSignal signal is connected.
   bool mRelayoutFlag : 1;         ///< Relayout flag to avoid unnecessary calls