Append Stopped animation notify list at Update Animation time
[platform/core/uifw/dali-core.git] / dali / internal / update / manager / update-manager.cpp
index 1b5c1a3..7a971f5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
@@ -21,6 +21,8 @@
 // INTERNAL INCLUDES
 #include <dali/integration-api/core.h>
 
+#include <dali/internal/common/owner-key-container.h>
+
 #include <dali/internal/event/animation/animation-playlist.h>
 #include <dali/internal/event/common/notification-manager.h>
 #include <dali/internal/event/common/property-notifier.h>
@@ -31,6 +33,7 @@
 #include <dali/internal/update/controllers/scene-controller-impl.h>
 #include <dali/internal/update/manager/frame-callback-processor.h>
 #include <dali/internal/update/manager/render-task-processor.h>
+#include <dali/internal/update/manager/resetter-container.h>
 #include <dali/internal/update/manager/transform-manager.h>
 #include <dali/internal/update/manager/update-algorithms.h>
 #include <dali/internal/update/manager/update-manager-debug.h>
@@ -39,6 +42,7 @@
 
 #include <dali/internal/render/common/render-manager.h>
 #include <dali/internal/render/queue/render-queue.h>
+#include <dali/internal/render/renderers/render-vertex-buffer.h>
 
 // Un-comment to enable node tree debug logging
 //#define NODE_TREE_LOGGING 1
@@ -88,8 +92,8 @@ namespace
  * @param discardQueue to put the object to
  * @param updateBufferIndex to use
  */
-template<class T>
-inline void EraseUsingDiscardQueue(OwnerContainer<T*>& container, T* object, DiscardQueue& discardQueue, BufferIndex updateBufferIndex)
+template<class Type>
+inline void EraseUsingDiscardQueue(OwnerContainer<Type*>& container, Type* object, DiscardQueue<Type*, OwnerContainer<Type*>>& discardQueue, BufferIndex updateBufferIndex)
 {
   DALI_ASSERT_DEBUG(object && "NULL object not allowed");
 
@@ -106,18 +110,25 @@ inline void EraseUsingDiscardQueue(OwnerContainer<T*>& container, T* object, Dis
 }
 
 /**
- * Descends into node's hierarchy and sorts the children of each child according to their depth-index.
- * @param[in] node The node whose hierarchy to descend
+ * Helper to Erase an object from std::vector using discard queue
+ * @param container to remove from
+ * @param object to remove
+ * @param discardQueue to put the object to
+ * @param updateBufferIndex to use
  */
-void SortSiblingNodesRecursively(Node& node)
+template<class Type>
+inline void EraseUsingDiscardQueue(OwnerKeyContainer<Type>& container, const MemoryPoolKey<Type>& key, DiscardQueue<MemoryPoolKey<Type>, OwnerKeyContainer<Type>>& discardQueue, BufferIndex updateBufferIndex)
 {
-  NodeContainer& container = node.GetChildren();
-  std::sort(container.Begin(), container.End(), [](Node* a, Node* b) { return a->GetDepthIndex() < b->GetDepthIndex(); });
+  DALI_ASSERT_DEBUG(key && "INVALID Key not allowed");
 
-  // Descend tree and sort as well
-  for(auto&& iter : container)
+  for(auto iter = container.begin(), end = container.end(); iter != end; ++iter)
   {
-    SortSiblingNodesRecursively(*iter);
+    if(*iter == key)
+    {
+      // Transfer ownership to the discard queue, this keeps the object alive, until the render-thread has finished with it
+      discardQueue.Add(updateBufferIndex, container.Release(iter));
+      return; // return as we only ever remove one object. Iterators to container are now invalidated as well so cannot continue
+    }
   }
 }
 
@@ -151,7 +162,6 @@ struct UpdateManager::Impl
   Impl(NotificationManager&           notificationManager,
        CompleteNotificationInterface& animationPlaylist,
        PropertyNotifier&              propertyNotifier,
-       DiscardQueue&                  discardQueue,
        RenderController&              renderController,
        RenderManager&                 renderManager,
        RenderQueue&                   renderQueue,
@@ -163,7 +173,6 @@ struct UpdateManager::Impl
     animationPlaylist(animationPlaylist),
     propertyNotifier(propertyNotifier),
     shaderSaver(nullptr),
-    discardQueue(discardQueue),
     renderController(renderController),
     sceneController(nullptr),
     renderManager(renderManager),
@@ -176,7 +185,6 @@ struct UpdateManager::Impl
     panGestureProcessor(nullptr),
     messageQueue(renderController, sceneGraphBuffers),
     frameCallbackProcessor(nullptr),
-    keepRenderingSeconds(0.0f),
     nodeDirtyFlags(NodePropertyFlags::TRANSFORM), // set to TransformFlag to ensure full update the first time through Update()
     frameCounter(0),
     renderingBehavior(DevelStage::Rendering::IF_REQUIRED),
@@ -186,7 +194,7 @@ struct UpdateManager::Impl
     renderersAdded(false),
     renderingRequired(false)
   {
-    sceneController = new SceneControllerImpl(renderMessageDispatcher, renderQueue, discardQueue);
+    sceneController = new SceneControllerImpl(renderMessageDispatcher, renderQueue);
 
     // create first 'dummy' node
     nodes.PushBack(nullptr);
@@ -216,6 +224,7 @@ struct UpdateManager::Impl
       (*iter)->OnDestroy();
       Node::Delete(*iter);
     }
+    nodeIdMap.clear();
 
     for(auto&& scene : scenes)
     {
@@ -254,7 +263,6 @@ struct UpdateManager::Impl
   CompleteNotificationInterface& animationPlaylist;       ///< Holds handles to all the animations
   PropertyNotifier&              propertyNotifier;        ///< Provides notification to applications when properties are modified.
   ShaderSaver*                   shaderSaver;             ///< Saves shader binaries.
-  DiscardQueue&                  discardQueue;            ///< Nodes are added here when disconnected from the scene-graph.
   RenderController&              renderController;        ///< render controller
   SceneControllerImpl*           sceneController;         ///< scene controller
   RenderManager&                 renderManager;           ///< This is responsible for rendering the results of each "update"
@@ -268,18 +276,30 @@ struct UpdateManager::Impl
 
   Vector<Node*> nodes; ///< A container of all instantiated nodes
 
+  std::unordered_map<uint32_t, Node*> nodeIdMap; ///< A container of nodes map by id.
+
   Vector<Camera*> cameras; ///< A container of cameras. Note : these cameras are owned by Impl::nodes.
 
   OwnerContainer<PropertyOwner*> customObjects; ///< A container of owned objects (with custom properties)
 
-  OwnerContainer<PropertyResetterBase*> propertyResetters;     ///< A container of property resetters
-  OwnerContainer<NodeResetter*>         nodeResetters;         ///< A container of node resetters
+  ResetterContainer<PropertyResetterBase> propertyResetters; ///< A container of property resetters
+  ResetterContainer<NodeResetter>         nodeResetters;     ///< A container of node resetters
+  ResetterContainer<RendererResetter>     rendererResetters; ///< A container of renderer resetters
+
   OwnerContainer<Animation*>            animations;            ///< A container of owned animations
-  PropertyNotificationContainer         propertyNotifications; ///< A container of owner property notifications.
-  OwnerContainer<Renderer*>             renderers;             ///< A container of owned renderers
+  OwnerContainer<PropertyNotification*> propertyNotifications; ///< A container of owner property notifications.
+  OwnerKeyContainer<Renderer>           renderers;             ///< A container of owned renderers
   OwnerContainer<TextureSet*>           textureSets;           ///< A container of owned texture sets
   OwnerContainer<Shader*>               shaders;               ///< A container of owned shaders
-  OwnerPointer<PanGesture>              panGestureProcessor;   ///< Owned pan gesture processor; it lives for the lifecycle of UpdateManager
+
+  DiscardQueue<Node*, OwnerContainer<Node*>>                         nodeDiscardQueue; ///< Nodes are added here when disconnected from the scene-graph.
+  DiscardQueue<Shader*, OwnerContainer<Shader*>>                     shaderDiscardQueue;
+  DiscardQueue<MemoryPoolKey<Renderer>, OwnerKeyContainer<Renderer>> rendererDiscardQueue;
+  DiscardQueue<Scene*, OwnerContainer<Scene*>>                       sceneDiscardQueue;
+
+  CompleteNotificationInterface::ParameterList notifyRequiredAnimations; ///< A temperal container of complete notify required animations, like animation finished, stopped, or loop completed.
+
+  OwnerPointer<PanGesture> panGestureProcessor; ///< Owned pan gesture processor; it lives for the lifecycle of UpdateManager
 
   MessageQueue                         messageQueue;          ///< The messages queued from the event-thread
   std::vector<Internal::ShaderDataPtr> renderCompiledShaders; ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread.
@@ -288,11 +308,10 @@ struct UpdateManager::Impl
 
   OwnerPointer<FrameCallbackProcessor> frameCallbackProcessor; ///< Owned FrameCallbackProcessor, only created if required.
 
-  float             keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering
-  NodePropertyFlags nodeDirtyFlags;       ///< cumulative node dirty flags from previous frame
-  uint32_t          frameCounter;         ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
-
-  DevelStage::Rendering renderingBehavior; ///< Set via DevelStage::SetRenderingBehavior
+  std::atomic<std::size_t> renderInstructionCapacity{0u};
+  NodePropertyFlags        nodeDirtyFlags;    ///< cumulative node dirty flags from previous frame
+  uint32_t                 frameCounter;      ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
+  DevelStage::Rendering    renderingBehavior; ///< Set via DevelStage::SetRenderingBehavior
 
   bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
   bool previousUpdateScene;           ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
@@ -308,7 +327,6 @@ private:
 UpdateManager::UpdateManager(NotificationManager&           notificationManager,
                              CompleteNotificationInterface& animationFinishedNotifier,
                              PropertyNotifier&              propertyNotifier,
-                             DiscardQueue&                  discardQueue,
                              RenderController&              controller,
                              RenderManager&                 renderManager,
                              RenderQueue&                   renderQueue,
@@ -318,7 +336,6 @@ UpdateManager::UpdateManager(NotificationManager&           notificationManager,
   mImpl = new Impl(notificationManager,
                    animationFinishedNotifier,
                    propertyNotifier,
-                   discardQueue,
                    controller,
                    renderManager,
                    renderQueue,
@@ -338,15 +355,17 @@ void UpdateManager::InstallRoot(OwnerPointer<Layer>& layer)
 
   Layer* rootLayer = layer.Release();
 
-  DALI_ASSERT_DEBUG(std::find_if(mImpl->scenes.begin(), mImpl->scenes.end(), [rootLayer](Impl::SceneInfoPtr& scene) {
-                      return scene && scene->root == rootLayer;
-                    }) == mImpl->scenes.end() &&
+  DALI_ASSERT_DEBUG(std::find_if(mImpl->scenes.begin(), mImpl->scenes.end(), [rootLayer](Impl::SceneInfoPtr& scene) { return scene && scene->root == rootLayer; }) == mImpl->scenes.end() &&
                     "Root Node already installed");
 
   rootLayer->CreateTransform(&mImpl->transformManager);
   rootLayer->SetRoot(true);
 
-  AddNodeResetter(*rootLayer);
+  rootLayer->AddInitializeResetter(*this);
+
+  // Do not allow to insert duplicated nodes.
+  // It could be happened if node id is overflowed.
+  DALI_ASSERT_ALWAYS(mImpl->nodeIdMap.insert({rootLayer->GetId(), rootLayer}).second);
 
   mImpl->scenes.emplace_back(new Impl::SceneInfo(rootLayer));
 }
@@ -365,7 +384,9 @@ void UpdateManager::UninstallRoot(Layer* layer)
     }
   }
 
-  mImpl->discardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), layer);
+  mImpl->nodeIdMap.erase(layer->GetId());
+
+  mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), layer);
 
   // Notify the layer about impending destruction
   layer->OnDestroy();
@@ -384,7 +405,12 @@ void UpdateManager::AddNode(OwnerPointer<Node>& node)
     AddCamera(static_cast<Camera*>(rawNode));
   }
 
+  // Do not allow to insert duplicated nodes.
+  // It could be happened if node id is overflowed.
+  DALI_ASSERT_ALWAYS(mImpl->nodeIdMap.insert({rawNode->GetId(), rawNode}).second);
+
   mImpl->nodes.PushBack(rawNode);
+
   rawNode->CreateTransform(&mImpl->transformManager);
 }
 
@@ -396,9 +422,10 @@ void UpdateManager::ConnectNode(Node* parent, Node* node)
 
   DALI_LOG_INFO(gLogFilter, Debug::General, "[%x] ConnectNode\n", node);
 
+  parent->SetDirtyFlag(NodePropertyFlags::DESCENDENT_HIERARCHY_CHANGED); // make parent dirty so that render items dont get reused
   parent->ConnectChild(node);
 
-  AddNodeResetter(*node);
+  node->AddInitializeResetter(*this);
 
   // Inform the frame-callback-processor, if set, about the node-hierarchy changing
   if(mImpl->frameCallbackProcessor)
@@ -413,7 +440,7 @@ void UpdateManager::DisconnectNode(Node* node)
 
   Node* parent = node->GetParent();
   DALI_ASSERT_ALWAYS(nullptr != parent);
-  parent->SetDirtyFlag(NodePropertyFlags::CHILD_DELETED); // make parent dirty so that render items dont get reused
+  parent->SetDirtyFlag(NodePropertyFlags::CHILD_DELETED | NodePropertyFlags::DESCENDENT_HIERARCHY_CHANGED); // make parent dirty so that render items dont get reused
 
   parent->DisconnectChild(mSceneGraphBuffers.GetUpdateBufferIndex(), *node);
 
@@ -448,7 +475,9 @@ void UpdateManager::DestroyNode(Node* node)
     RemoveCamera(static_cast<Camera*>(node));
   }
 
-  mImpl->discardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), node);
+  mImpl->nodeIdMap.erase(node->GetId());
+
+  mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), node);
 
   // Notify the Node about impending destruction
   node->OnDestroy();
@@ -491,7 +520,7 @@ void UpdateManager::RemoveObject(PropertyOwner* object)
 void UpdateManager::AddRenderTaskList(OwnerPointer<RenderTaskList>& taskList)
 {
   RenderTaskList* taskListPointer = taskList.Release();
-  taskListPointer->SetRenderMessageDispatcher(&mImpl->renderMessageDispatcher);
+  taskListPointer->Initialize(*this, mImpl->renderMessageDispatcher);
 
   mImpl->scenes.back()->taskList = taskListPointer;
 }
@@ -538,11 +567,13 @@ void UpdateManager::RemoveScene(Scene* scene)
   // Construct message in the render queue memory; note that delete should not be called on the return value
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::UninitializeScene, scene);
 
+  scene->RemoveSurfaceRenderTarget();
+
   for(auto&& sceneInfo : mImpl->scenes)
   {
     if(sceneInfo && sceneInfo->scene && sceneInfo->scene.Get() == scene)
     {
-      mImpl->discardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), sceneInfo->scene.Release()); // take the address of the reference to a pointer
+      mImpl->sceneDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), sceneInfo->scene.Release()); // take the address of the reference to a pointer
       break;
     }
   }
@@ -562,6 +593,13 @@ void UpdateManager::StopAnimation(Animation* animation)
   mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || animationFinished;
 }
 
+void UpdateManager::ClearAnimation(Animation* animation)
+{
+  DALI_ASSERT_DEBUG(animation && "NULL animation called to clear");
+
+  animation->ClearAnimator(mSceneGraphBuffers.GetUpdateBufferIndex());
+}
+
 void UpdateManager::RemoveAnimation(Animation* animation)
 {
   DALI_ASSERT_DEBUG(animation && "NULL animation called to remove");
@@ -569,6 +607,8 @@ void UpdateManager::RemoveAnimation(Animation* animation)
   animation->OnDestroy(mSceneGraphBuffers.GetUpdateBufferIndex());
 
   DALI_ASSERT_DEBUG(animation->GetState() == Animation::Destroyed);
+
+  // Do not remove from container now. Destroyed animation will be removed at Animate.
 }
 
 bool UpdateManager::IsAnimationRunning() const
@@ -601,6 +641,13 @@ void UpdateManager::AddNodeResetter(const Node& node)
   mImpl->nodeResetters.PushBack(nodeResetter.Release());
 }
 
+void UpdateManager::AddRendererResetter(const Renderer& renderer)
+{
+  OwnerPointer<SceneGraph::RendererResetter> rendererResetter = SceneGraph::RendererResetter::New(renderer);
+  rendererResetter->Initialize();
+  mImpl->rendererResetters.PushBack(rendererResetter.Release());
+}
+
 void UpdateManager::AddPropertyNotification(OwnerPointer<PropertyNotification>& propertyNotification)
 {
   mImpl->propertyNotifications.PushBack(propertyNotification.Release());
@@ -608,7 +655,11 @@ void UpdateManager::AddPropertyNotification(OwnerPointer<PropertyNotification>&
 
 void UpdateManager::RemovePropertyNotification(PropertyNotification* propertyNotification)
 {
-  mImpl->propertyNotifications.EraseObject(propertyNotification);
+  auto iter = std::find(mImpl->propertyNotifications.Begin(), mImpl->propertyNotifications.End(), propertyNotification);
+  if(iter != mImpl->propertyNotifications.End())
+  {
+    mImpl->propertyNotifications.Erase(iter);
+  }
 }
 
 void UpdateManager::PropertyNotificationSetNotify(PropertyNotification* propertyNotification, PropertyNotification::NotifyMode notifyMode)
@@ -625,7 +676,7 @@ void UpdateManager::AddShader(OwnerPointer<Shader>& shader)
 void UpdateManager::RemoveShader(Shader* shader)
 {
   // Find the shader and destroy it
-  EraseUsingDiscardQueue(mImpl->shaders, shader, mImpl->discardQueue, mSceneGraphBuffers.GetUpdateBufferIndex());
+  EraseUsingDiscardQueue(mImpl->shaders, shader, mImpl->shaderDiscardQueue, mSceneGraphBuffers.GetUpdateBufferIndex());
 }
 
 void UpdateManager::SaveBinary(Internal::ShaderDataPtr shaderData)
@@ -644,27 +695,31 @@ void UpdateManager::SetShaderSaver(ShaderSaver& upstream)
   mImpl->shaderSaver = &upstream;
 }
 
-void UpdateManager::AddRenderer(OwnerPointer<Renderer>& renderer)
+void UpdateManager::AddRenderer(const RendererKey& rendererKey)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::General, "[%x] AddRenderer\n", renderer.Get());
+  SceneGraph::Renderer* renderer = rendererKey.Get();
+
+  DALI_LOG_INFO(gLogFilter, Debug::General, "[%x] AddRenderer\n", renderer);
 
   renderer->ConnectToSceneGraph(*mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex());
-  mImpl->renderers.PushBack(renderer.Release());
+  renderer->AddInitializeResetter(*this);
+
+  mImpl->renderers.PushBack(rendererKey);
 }
 
-void UpdateManager::RemoveRenderer(Renderer* renderer)
+void UpdateManager::RemoveRenderer(const RendererKey& rendererKey)
 {
-  DALI_LOG_INFO(gLogFilter, Debug::General, "[%x] RemoveRenderer\n", renderer);
+  DALI_LOG_INFO(gLogFilter, Debug::General, "[%x] RemoveRenderer\n", rendererKey.Get());
 
   // Find the renderer and destroy it
-  EraseUsingDiscardQueue(mImpl->renderers, renderer, mImpl->discardQueue, mSceneGraphBuffers.GetUpdateBufferIndex());
+  EraseUsingDiscardQueue(mImpl->renderers, rendererKey, mImpl->rendererDiscardQueue, mSceneGraphBuffers.GetUpdateBufferIndex());
   // Need to remove the render object as well
-  renderer->DisconnectFromSceneGraph(*mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex());
+  rendererKey->DisconnectFromSceneGraph(*mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex());
 }
 
 void UpdateManager::AttachRenderer(Node* node, Renderer* renderer)
 {
-  node->AddRenderer(renderer);
+  node->AddRenderer(Renderer::GetKey(renderer));
   mImpl->renderersAdded = true;
 }
 
@@ -677,6 +732,7 @@ void UpdateManager::SetPanGestureProcessor(PanGesture* panGestureProcessor)
 
 void UpdateManager::AddTextureSet(OwnerPointer<TextureSet>& textureSet)
 {
+  textureSet->SetRenderMessageDispatcher(&mImpl->renderMessageDispatcher);
   mImpl->textureSets.PushBack(textureSet.Release());
 }
 
@@ -690,11 +746,31 @@ uint32_t* UpdateManager::ReserveMessageSlot(uint32_t size, bool updateScene)
   return mImpl->messageQueue.ReserveMessageSlot(size, updateScene);
 }
 
+std::size_t UpdateManager::GetUpdateMessageQueueCapacity() const
+{
+  return mImpl->messageQueue.GetCapacity();
+}
+
+std::size_t UpdateManager::GetRenderMessageQueueCapacity() const
+{
+  return mImpl->renderQueue.GetCapacity();
+}
+
+std::size_t UpdateManager::GetRenderInstructionCapacity() const
+{
+  return mImpl->renderInstructionCapacity;
+}
+
 void UpdateManager::EventProcessingStarted()
 {
   mImpl->messageQueue.EventProcessingStarted();
 }
 
+void UpdateManager::EventProcessingFinished()
+{
+  mImpl->messageQueue.EventProcessingFinished();
+}
+
 bool UpdateManager::FlushQueue()
 {
   return mImpl->messageQueue.FlushQueue();
@@ -706,38 +782,13 @@ void UpdateManager::ResetProperties(BufferIndex bufferIndex)
   mImpl->animationFinishedDuringUpdate = false;
 
   // Reset node properties
-  std::vector<NodeResetter*> nodeResetterToDelete;
-  for(auto&& element : mImpl->nodeResetters)
-  {
-    element->ResetToBaseValue(bufferIndex);
-    if(element->IsFinished())
-    {
-      nodeResetterToDelete.push_back(element);
-    }
-  }
+  mImpl->nodeResetters.ResetToBaseValues(bufferIndex);
 
-  // If a node resetter is no longer required, delete it.
-  for(auto&& elementPtr : nodeResetterToDelete)
-  {
-    mImpl->nodeResetters.EraseObject(elementPtr);
-  }
+  // Reset renderer properties
+  mImpl->rendererResetters.ResetToBaseValues(bufferIndex);
 
   // Reset all animating / constrained properties
-  std::vector<PropertyResetterBase*> propertyResettertoDelete;
-  for(auto&& element : mImpl->propertyResetters)
-  {
-    element->ResetToBaseValue(bufferIndex);
-    if(element->IsFinished())
-    {
-      propertyResettertoDelete.push_back(element);
-    }
-  }
-
-  // If a property resetter is no longer required (the animator or constraint has been removed), delete it.
-  for(auto&& elementPtr : propertyResettertoDelete)
-  {
-    mImpl->propertyResetters.EraseObject(elementPtr);
-  }
+  mImpl->propertyResetters.ResetToBaseValues(bufferIndex);
 
   // Clear all root nodes dirty flags
   for(auto& scene : mImpl->scenes)
@@ -773,26 +824,30 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds)
 {
   bool animationActive = false;
 
-  auto&& iter            = mImpl->animations.Begin();
-  bool   animationLooped = false;
+  auto&& iter = mImpl->animations.Begin();
 
   while(iter != mImpl->animations.End())
   {
     Animation* animation             = *iter;
     bool       finished              = false;
-    bool       looped                = false;
+    bool       stopped               = false;
     bool       progressMarkerReached = false;
-    animation->Update(bufferIndex, elapsedSeconds, looped, finished, progressMarkerReached);
+    animation->Update(bufferIndex, elapsedSeconds, stopped, finished, progressMarkerReached);
 
     animationActive = animationActive || animation->IsActive();
 
     if(progressMarkerReached)
     {
-      mImpl->notificationManager.QueueMessage(Internal::NotifyProgressReachedMessage(mImpl->animationPlaylist, animation));
+      mImpl->notificationManager.QueueMessage(Internal::NotifyProgressReachedMessage(mImpl->animationPlaylist, animation->GetNotifyId()));
     }
 
     mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
-    animationLooped                      = animationLooped || looped;
+
+    // queue the notification on finished or stopped
+    if(finished || stopped)
+    {
+      mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId());
+    }
 
     // Remove animations that had been destroyed but were still waiting for an update
     if(animation->GetState() == Animation::Destroyed)
@@ -805,26 +860,29 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds)
     }
   }
 
-  // queue the notification on finished or looped (to update loop count)
-  if(mImpl->animationFinishedDuringUpdate || animationLooped)
+  // The application should be notified by NotificationManager, in another thread
+  if(!mImpl->notifyRequiredAnimations.Empty())
   {
-    // The application should be notified by NotificationManager, in another thread
-    mImpl->notificationManager.QueueCompleteNotification(&mImpl->animationPlaylist);
+    mImpl->notificationManager.QueueNotification(&mImpl->animationPlaylist, std::move(mImpl->notifyRequiredAnimations));
   }
 
   return animationActive;
 }
 
-void UpdateManager::ConstrainCustomObjects(BufferIndex bufferIndex)
+void UpdateManager::ConstrainCustomObjects(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
-  //Constrain custom objects (in construction order)
+  // Constrain custom objects (in construction order)
   for(auto&& object : mImpl->customObjects)
   {
     ConstrainPropertyOwner(*object, bufferIndex);
+    if(!object->GetPostConstraints().Empty())
+    {
+      postPropertyOwners.PushBack(object);
+    }
   }
 }
 
-void UpdateManager::ConstrainRenderTasks(BufferIndex bufferIndex)
+void UpdateManager::ConstrainRenderTasks(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   // Constrain render-tasks
   for(auto&& scene : mImpl->scenes)
@@ -835,17 +893,25 @@ void UpdateManager::ConstrainRenderTasks(BufferIndex bufferIndex)
       for(auto&& task : tasks)
       {
         ConstrainPropertyOwner(*task, bufferIndex);
+        if(!task->GetPostConstraints().Empty())
+        {
+          postPropertyOwners.PushBack(task);
+        }
       }
     }
   }
 }
 
-void UpdateManager::ConstrainShaders(BufferIndex bufferIndex)
+void UpdateManager::ConstrainShaders(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   // constrain shaders... (in construction order)
   for(auto&& shader : mImpl->shaders)
   {
     ConstrainPropertyOwner(*shader, bufferIndex);
+    if(!shader->GetPostConstraints().Empty())
+    {
+      postPropertyOwners.PushBack(shader);
+    }
   }
 }
 
@@ -856,7 +922,7 @@ void UpdateManager::ProcessPropertyNotifications(BufferIndex bufferIndex)
     bool valid = notification->Check(bufferIndex);
     if(valid)
     {
-      mImpl->notificationManager.QueueMessage(PropertyChangedMessage(mImpl->propertyNotifier, notification, notification->GetValidity()));
+      mImpl->notificationManager.QueueMessage(PropertyChangedMessage(mImpl->propertyNotifier, notification->GetNotifyId(), notification->GetValidity()));
     }
   }
 }
@@ -886,18 +952,23 @@ void UpdateManager::ForwardCompiledShadersToEventThread()
   }
 }
 
-void UpdateManager::UpdateRenderers(BufferIndex bufferIndex)
+void UpdateManager::UpdateRenderers(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
-  for(auto&& renderer : mImpl->renderers)
+  for(const auto& rendererKey : mImpl->renderers)
   {
-    //Apply constraints
+    // Apply constraints
+    auto renderer = rendererKey.Get();
     ConstrainPropertyOwner(*renderer, bufferIndex);
+    if(!renderer->GetPostConstraints().Empty())
+    {
+      postPropertyOwners.PushBack(renderer);
+    }
 
     mImpl->renderingRequired = renderer->PrepareRender(bufferIndex) || mImpl->renderingRequired;
   }
 }
 
-void UpdateManager::UpdateNodes(BufferIndex bufferIndex)
+void UpdateManager::UpdateNodes(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex)
 {
   mImpl->nodeDirtyFlags = NodePropertyFlags::NOTHING;
 
@@ -909,7 +980,8 @@ void UpdateManager::UpdateNodes(BufferIndex bufferIndex)
       // And add the renderers to the sorted layers. Start from root, which is also a layer
       mImpl->nodeDirtyFlags |= UpdateNodeTree(*scene->root,
                                               bufferIndex,
-                                              mImpl->renderQueue);
+                                              mImpl->renderQueue,
+                                              postPropertyOwners);
     }
   }
 }
@@ -934,12 +1006,15 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
 {
   const BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
 
-  //Clear nodes/resources which were previously discarded
-  mImpl->discardQueue.Clear(bufferIndex);
+  // Clear nodes/resources which were previously discarded
+  mImpl->nodeDiscardQueue.Clear(bufferIndex);
+  mImpl->shaderDiscardQueue.Clear(bufferIndex);
+  mImpl->rendererDiscardQueue.Clear(bufferIndex);
+  mImpl->sceneDiscardQueue.Clear(bufferIndex);
 
   bool isAnimationRunning = IsAnimationRunning();
 
-  //Process Touches & Gestures
+  // Process Touches & Gestures
   const bool gestureUpdated = ProcessGestures(bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds);
 
   bool updateScene =                                   // The scene-graph requires an update if..
@@ -949,14 +1024,15 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
     mImpl->frameCallbackProcessor ||                   // ..a frame callback processor is existed OR
     gestureUpdated;                                    // ..a gesture property was updated
 
-  bool keepRendererRendering = false;
-  mImpl->renderingRequired   = false;
+  uint32_t keepUpdating          = 0;
+  bool     keepRendererRendering = false;
+  mImpl->renderingRequired       = false;
 
   // Although the scene-graph may not require an update, we still need to synchronize double-buffered
   // values if the scene was updated in the previous frame.
   if(updateScene || mImpl->previousUpdateScene)
   {
-    //Reset properties from the previous update
+    // Reset properties from the previous update
     ResetProperties(bufferIndex);
     mImpl->transformManager.ResetToBaseValue();
   }
@@ -966,7 +1042,7 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
   // be set again
   updateScene |= mImpl->messageQueue.ProcessMessages(bufferIndex);
 
-  //Forward compiled shader programs to event thread for saving
+  // Forward compiled shader programs to event thread for saving
   ForwardCompiledShadersToEventThread();
 
   // Although the scene-graph may not require an update, we still need to synchronize double-buffered
@@ -974,13 +1050,14 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
   // We should not start skipping update steps or reusing lists until there has been two frames where nothing changes
   if(updateScene || mImpl->previousUpdateScene)
   {
-    //Animate
+    // Animate
     bool animationActive = Animate(bufferIndex, elapsedSeconds);
 
-    //Constraint custom objects
-    ConstrainCustomObjects(bufferIndex);
+    PropertyOwnerContainer postPropertyOwners;
+    // Constraint custom objects
+    ConstrainCustomObjects(postPropertyOwners, bufferIndex);
 
-    //Clear the lists of renderers from the previous update
+    // Clear the lists of renderers from the previous update
     for(auto&& scene : mImpl->scenes)
     {
       if(scene)
@@ -998,39 +1075,45 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
     // Call the frame-callback-processor if set
     if(mImpl->frameCallbackProcessor)
     {
-      mImpl->frameCallbackProcessor->Update(bufferIndex, elapsedSeconds);
+      keepRendererRendering |= mImpl->frameCallbackProcessor->Update(bufferIndex, elapsedSeconds);
     }
 
-    //Update node hierarchy, apply constraints,
-    UpdateNodes(bufferIndex);
+    // Update node hierarchy, apply constraints,
+    UpdateNodes(postPropertyOwners, bufferIndex);
 
-    //Apply constraints to RenderTasks, shaders
-    ConstrainRenderTasks(bufferIndex);
-    ConstrainShaders(bufferIndex);
+    // Apply constraints to RenderTasks, shaders
+    ConstrainRenderTasks(postPropertyOwners, bufferIndex);
+    ConstrainShaders(postPropertyOwners, bufferIndex);
 
-    //Update renderers and apply constraints
-    UpdateRenderers(bufferIndex);
+    // Update renderers and apply constraints
+    UpdateRenderers(postPropertyOwners, bufferIndex);
 
-    //Update the transformations of all the nodes
+    // Update the transformations of all the nodes
     if(mImpl->transformManager.Update())
     {
       mImpl->nodeDirtyFlags |= NodePropertyFlags::TRANSFORM;
     }
 
-    //Initialise layer renderable reuse
+    // Constraint applied after transform manager updated. Only required property owner processed.
+    for(auto&& propertyOwner : postPropertyOwners)
+    {
+      ConstrainPropertyOwner(*propertyOwner, bufferIndex, false);
+    }
+
+    // Initialise layer renderable reuse
     UpdateLayers(bufferIndex);
 
-    //Process Property Notifications
+    // Process Property Notifications
     ProcessPropertyNotifications(bufferIndex);
 
-    //Update cameras
+    // Update cameras
     for(auto&& cameraIterator : mImpl->cameras)
     {
       cameraIterator->Update(bufferIndex);
     }
 
-    //Process the RenderTasks if renderers exist. This creates the instructions for rendering the next frame.
-    //reset the update buffer index and make sure there is enough room in the instruction container
+    // Process the RenderTasks if renderers exist. This creates the instructions for rendering the next frame.
+    // reset the update buffer index and make sure there is enough room in the instruction container
     if(mImpl->renderersAdded)
     {
       // Calculate how many render tasks we have in total
@@ -1044,6 +1127,7 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
       }
 
       std::size_t numberOfRenderInstructions = 0;
+      mImpl->renderInstructionCapacity       = 0u;
       for(auto&& scene : mImpl->scenes)
       {
         if(scene && scene->root && scene->taskList && scene->scene)
@@ -1051,9 +1135,16 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
           scene->scene->GetRenderInstructions().ResetAndReserve(bufferIndex,
                                                                 static_cast<uint32_t>(scene->taskList->GetTasks().Count()));
 
+          bool sceneKeepUpdating = scene->scene->KeepRenderingCheck(elapsedSeconds);
+          if(sceneKeepUpdating)
+          {
+            keepUpdating |= KeepUpdating::STAGE_KEEP_RENDERING;
+          }
+
           // If there are animations running, only add render instruction if at least one animation is currently active (i.e. not delayed)
           // or the nodes are dirty
-          if(!isAnimationRunning || animationActive || mImpl->renderingRequired || (mImpl->nodeDirtyFlags & RenderableUpdateFlags))
+          // or keep rendering is requested
+          if(!isAnimationRunning || animationActive || mImpl->renderingRequired || (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || sceneKeepUpdating)
           {
             keepRendererRendering |= mImpl->renderTaskProcessor.Process(bufferIndex,
                                                                         *scene->taskList,
@@ -1063,6 +1154,7 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
                                                                         renderToFboEnabled,
                                                                         isRenderingToFbo);
 
+            mImpl->renderInstructionCapacity += scene->scene->GetRenderInstructions().GetCapacity();
             scene->scene->SetSkipRendering(false);
           }
           else
@@ -1080,15 +1172,17 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
 
   if(!uploadOnly)
   {
+    // check the countdown and notify
+    mImpl->renderTaskWaiting = false;
+
     for(auto&& scene : mImpl->scenes)
     {
       if(scene && scene->root && scene->taskList)
       {
         RenderTaskList::RenderTaskContainer& tasks = scene->taskList->GetTasks();
 
-        // check the countdown and notify
-        bool doRenderOnceNotify  = false;
-        mImpl->renderTaskWaiting = false;
+        CompleteNotificationInterface::ParameterList notifyRequiredRenderTasks;
+
         for(auto&& renderTask : tasks)
         {
           renderTask->UpdateState();
@@ -1101,14 +1195,14 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
 
           if(renderTask->HasRendered())
           {
-            doRenderOnceNotify = true;
+            notifyRequiredRenderTasks.PushBack(renderTask->GetNotifyId());
           }
         }
 
-        if(doRenderOnceNotify)
+        if(!notifyRequiredRenderTasks.Empty())
         {
           DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
-          mImpl->notificationManager.QueueCompleteNotification(scene->taskList->GetCompleteNotificationInterface());
+          mImpl->notificationManager.QueueNotification(scene->taskList->GetCompleteNotificationInterface(), std::move(notifyRequiredRenderTasks));
         }
       }
     }
@@ -1121,12 +1215,15 @@ uint32_t UpdateManager::Update(float    elapsedSeconds,
   mImpl->previousUpdateScene = updateScene;
 
   // Check whether further updates are required
-  uint32_t keepUpdating = KeepUpdatingCheck(elapsedSeconds);
+  keepUpdating |= KeepUpdatingCheck(elapsedSeconds);
 
   if(keepRendererRendering)
   {
     keepUpdating |= KeepUpdating::STAGE_KEEP_RENDERING;
+  }
 
+  if(keepUpdating & KeepUpdating::STAGE_KEEP_RENDERING)
+  {
     // Set dirty flags for next frame to continue rendering
     mImpl->nodeDirtyFlags |= RenderableUpdateFlags;
   }
@@ -1145,7 +1242,12 @@ void UpdateManager::PostRender()
   // Reset dirty flag
   for(auto&& renderer : mImpl->renderers)
   {
-    renderer->ResetDirtyFlag();
+    renderer->SetUpdated(false);
+  }
+
+  for(auto&& shader : mImpl->shaders)
+  {
+    shader->SetUpdated(false);
   }
 
   for(auto&& scene : mImpl->scenes)
@@ -1156,23 +1258,15 @@ void UpdateManager::PostRender()
 
 uint32_t UpdateManager::KeepUpdatingCheck(float elapsedSeconds) const
 {
-  // Update the duration set via Stage::KeepRendering()
-  if(mImpl->keepRenderingSeconds > 0.0f)
-  {
-    mImpl->keepRenderingSeconds -= elapsedSeconds;
-  }
-
   uint32_t keepUpdatingRequest = KeepUpdating::NOT_REQUESTED;
 
   // If the rendering behavior is set to continuously render, then continue to render.
-  // If Stage::KeepRendering() has been called, then continue until the duration has elapsed.
   // Keep updating until no messages are received and no animations are running.
   // If an animation has just finished, update at least once more for Discard end-actions.
   // No need to check for renderQueue as there is always a render after update and if that
   // render needs another update it will tell the adaptor to call update again
 
-  if((mImpl->renderingBehavior == DevelStage::Rendering::CONTINUOUSLY) ||
-     (mImpl->keepRenderingSeconds > 0.0f))
+  if(mImpl->renderingBehavior == DevelStage::Rendering::CONTINUOUSLY)
   {
     keepUpdatingRequest |= KeepUpdating::STAGE_KEEP_RENDERING;
   }
@@ -1204,7 +1298,13 @@ void UpdateManager::SurfaceReplaced(Scene* scene)
 
 void UpdateManager::KeepRendering(float durationSeconds)
 {
-  mImpl->keepRenderingSeconds = std::max(mImpl->keepRenderingSeconds, durationSeconds);
+  for(auto&& scene : mImpl->scenes)
+  {
+    if(scene->scene)
+    {
+      scene->scene->KeepRendering(durationSeconds);
+    }
+  }
 }
 
 void UpdateManager::SetRenderingBehavior(DevelStage::Rendering renderingBehavior)
@@ -1217,6 +1317,17 @@ void UpdateManager::RequestRendering()
   mImpl->renderingRequired = true;
 }
 
+Node* UpdateManager::GetNodePointerById(uint32_t nodeId) const
+{
+  Node* foundNodePointer = nullptr;
+  auto  iter             = mImpl->nodeIdMap.find(nodeId);
+  if(iter != mImpl->nodeIdMap.end())
+  {
+    foundNodePointer = iter->second;
+  }
+  return foundNodePointer;
+}
+
 void UpdateManager::SetLayerDepths(const SortedLayerPointers& layers, const Layer* rootLayer)
 {
   for(auto&& scene : mImpl->scenes)
@@ -1231,19 +1342,22 @@ void UpdateManager::SetLayerDepths(const SortedLayerPointers& layers, const Laye
 
 void UpdateManager::SetDepthIndices(OwnerPointer<NodeDepths>& nodeDepths)
 {
-  // note,this vector is already in depth order. It could be used as-is to
-  // remove sorting in update algorithm. However, it lacks layer boundary markers.
-  for(auto&& iter : nodeDepths->nodeDepths)
-  {
-    iter.node->SetDepthIndex(iter.sortedDepth);
-  }
+  // note, this vector is already in depth order.
+  // So if we reverse iterate, we can assume that
+  // my descendant node's depth index are updated.
 
-  for(auto&& scene : mImpl->scenes)
+  // And also, This API is the last flushed message.
+  // We can now setup the DESCENDENT_HIERARCHY_CHANGED flag here.
+  for(auto rIter = nodeDepths->nodeDepths.rbegin(), rEndIter = nodeDepths->nodeDepths.rend(); rIter != rEndIter; rIter++)
   {
-    if(scene)
+    auto* node = rIter->node;
+    node->PropagateDescendentFlags();
+    node->SetDepthIndex(rIter->sortedDepth);
+    if(node->IsChildrenReorderRequired())
     {
-      // Go through node hierarchy and rearrange siblings according to depth-index
-      SortSiblingNodesRecursively(*scene->root);
+      // Reorder children container only if sibiling order changed.
+      NodeContainer& container = node->GetChildren();
+      std::sort(container.Begin(), container.End(), [](Node* a, Node* b) { return a->GetDepthIndex() < b->GetDepthIndex(); });
     }
   }
 }
@@ -1258,10 +1372,15 @@ void UpdateManager::RemoveFrameCallback(FrameCallbackInterface* frameCallback)
   mImpl->GetFrameCallbackProcessor(*this).RemoveFrameCallback(frameCallback);
 }
 
+void UpdateManager::NotifyFrameCallback(FrameCallbackInterface* frameCallback, Dali::UpdateProxy::NotifySyncPoint syncPoint)
+{
+  mImpl->GetFrameCallbackProcessor(*this).NotifyFrameCallback(frameCallback, syncPoint);
+}
+
 void UpdateManager::AddSampler(OwnerPointer<Render::Sampler>& sampler)
 {
   // Message has ownership of Sampler while in transit from update to render
-  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::Sampler> >;
+  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::Sampler>>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1306,7 +1425,7 @@ void UpdateManager::SetWrapMode(Render::Sampler* sampler, uint32_t rWrapMode, ui
 void UpdateManager::AddVertexBuffer(OwnerPointer<Render::VertexBuffer>& vertexBuffer)
 {
   // Message has ownership of format while in transit from update -> render
-  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::VertexBuffer> >;
+  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::VertexBuffer>>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1329,7 +1448,7 @@ void UpdateManager::RemoveVertexBuffer(Render::VertexBuffer* vertexBuffer)
 void UpdateManager::SetVertexBufferFormat(Render::VertexBuffer* vertexBuffer, OwnerPointer<Render::VertexBuffer::Format>& format)
 {
   // Message has ownership of format while in transit from update -> render
-  using DerivedType = MessageValue2<RenderManager, Render::VertexBuffer*, OwnerPointer<Render::VertexBuffer::Format> >;
+  using DerivedType = MessageValue2<RenderManager, Render::VertexBuffer*, OwnerPointer<Render::VertexBuffer::Format>>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1338,10 +1457,10 @@ void UpdateManager::SetVertexBufferFormat(Render::VertexBuffer* vertexBuffer, Ow
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetVertexBufferFormat, vertexBuffer, format);
 }
 
-void UpdateManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer<Vector<uint8_t> >& data, uint32_t size)
+void UpdateManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer<Vector<uint8_t>>& data, uint32_t size)
 {
   // Message has ownership of format while in transit from update -> render
-  using DerivedType = MessageValue3<RenderManager, Render::VertexBuffer*, OwnerPointer<Dali::Vector<uint8_t> >, uint32_t>;
+  using DerivedType = MessageValue3<RenderManager, Render::VertexBuffer*, OwnerPointer<Dali::Vector<uint8_t>>, uint32_t>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1350,10 +1469,29 @@ void UpdateManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, Owne
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetVertexBufferData, vertexBuffer, data, size);
 }
 
+void UpdateManager::SetVertexBufferDivisor(Render::VertexBuffer* vertexBuffer, uint32_t divisor)
+{
+  using LocalType = MessageValue1<Render::VertexBuffer, uint32_t>;
+  uint32_t* slot  = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(LocalType));
+  new(slot) LocalType(vertexBuffer, &Render::VertexBuffer::SetDivisor, divisor);
+}
+
+void UpdateManager::SetVertexBufferUpdateCallback(Render::VertexBuffer* vertexBuffer, Dali::VertexBufferUpdateCallback* callback)
+{
+  // Message has ownership of format while in transit from update -> render
+  using DerivedType = MessageValue2<RenderManager, Render::VertexBuffer*, Dali::VertexBufferUpdateCallback*>;
+
+  // Reserve some memory inside the render queue
+  uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+  // Construct message in the render queue memory; note that delete should not be called on the return value
+  new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetVertexBufferUpdateCallback, vertexBuffer, callback);
+}
+
 void UpdateManager::AddGeometry(OwnerPointer<Render::Geometry>& geometry)
 {
   // Message has ownership of format while in transit from update -> render
-  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::Geometry> >;
+  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::Geometry>>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1384,9 +1522,20 @@ void UpdateManager::SetGeometryType(Render::Geometry* geometry, uint32_t geometr
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetGeometryType, geometry, geometryType);
 }
 
-void UpdateManager::SetIndexBuffer(Render::Geometry* geometry, Dali::Vector<uint16_t>& indices)
+void UpdateManager::SetIndexBuffer(Render::Geometry* geometry, Render::Geometry::Uint16ContainerType& indices)
 {
-  using DerivedType = IndexBufferMessage<RenderManager>;
+  using DerivedType = IndexBufferMessage<RenderManager, Render::Geometry::Uint16ContainerType>;
+
+  // Reserve some memory inside the render queue
+  uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+  // Construct message in the render queue memory; note that delete should not be called on the return value
+  new(slot) DerivedType(&mImpl->renderManager, geometry, indices);
+}
+
+void UpdateManager::SetIndexBuffer(Render::Geometry* geometry, Render::Geometry::Uint32ContainerType& indices)
+{
+  using DerivedType = IndexBufferMessage<RenderManager, Render::Geometry::Uint32ContainerType>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1417,10 +1566,9 @@ void UpdateManager::AttachVertexBuffer(Render::Geometry* geometry, Render::Verte
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::AttachVertexBuffer, geometry, vertexBuffer);
 }
 
-void UpdateManager::AddTexture(OwnerPointer<Render::Texture>& texture)
+void UpdateManager::AddTexture(const Render::TextureKey& texture)
 {
-  // Message has ownership of Texture while in transit from update -> render
-  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::Texture> >;
+  using DerivedType = MessageValue1<RenderManager, Render::TextureKey>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1429,9 +1577,9 @@ void UpdateManager::AddTexture(OwnerPointer<Render::Texture>& texture)
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::AddTexture, texture);
 }
 
-void UpdateManager::RemoveTexture(Render::Texture* texture)
+void UpdateManager::RemoveTexture(const Render::TextureKey& texture)
 {
-  using DerivedType = MessageValue1<RenderManager, Render::Texture*>;
+  using DerivedType = MessageValue1<RenderManager, Render::TextureKey>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1440,9 +1588,9 @@ void UpdateManager::RemoveTexture(Render::Texture* texture)
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::RemoveTexture, texture);
 }
 
-void UpdateManager::UploadTexture(Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params)
+void UpdateManager::UploadTexture(const Render::TextureKey& texture, PixelDataPtr pixelData, const Graphics::UploadParams& params)
 {
-  using DerivedType = MessageValue3<RenderManager, Render::Texture*, PixelDataPtr, Texture::UploadParams>;
+  using DerivedType = MessageValue3<RenderManager, Render::TextureKey, PixelDataPtr, Graphics::UploadParams>;
 
   // Reserve some memory inside the message queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1451,9 +1599,9 @@ void UpdateManager::UploadTexture(Render::Texture* texture, PixelDataPtr pixelDa
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::UploadTexture, texture, pixelData, params);
 }
 
-void UpdateManager::GenerateMipmaps(Render::Texture* texture)
+void UpdateManager::GenerateMipmaps(const Render::TextureKey& texture)
 {
-  using DerivedType = MessageValue1<RenderManager, Render::Texture*>;
+  using DerivedType = MessageValue1<RenderManager, Render::TextureKey>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
@@ -1462,9 +1610,31 @@ void UpdateManager::GenerateMipmaps(Render::Texture* texture)
   new(slot) DerivedType(&mImpl->renderManager, &RenderManager::GenerateMipmaps, texture);
 }
 
+void UpdateManager::SetTextureSize(const Render::TextureKey& texture, const Dali::ImageDimensions& size)
+{
+  using DerivedType = MessageValue2<RenderManager, Render::TextureKey, Dali::ImageDimensions>;
+
+  // Reserve some memory inside the render queue
+  uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+  // Construct message in the render queue memory; note that delete should not be called on the return value
+  new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetTextureSize, texture, size);
+}
+
+void UpdateManager::SetTextureFormat(const Render::TextureKey& texture, Dali::Pixel::Format pixelFormat)
+{
+  using DerivedType = MessageValue2<RenderManager, Render::TextureKey, Dali::Pixel::Format>;
+
+  // Reserve some memory inside the render queue
+  uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+  // Construct message in the render queue memory; note that delete should not be called on the return value
+  new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetTextureFormat, texture, pixelFormat);
+}
+
 void UpdateManager::AddFrameBuffer(OwnerPointer<Render::FrameBuffer>& frameBuffer)
 {
-  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::FrameBuffer> >;
+  using DerivedType = MessageValue1<RenderManager, OwnerPointer<Render::FrameBuffer>>;
 
   // Reserve some memory inside the render queue
   uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));