X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fupdate%2Fmanager%2Fupdate-manager.cpp;h=f462f75c631d4668bf74149abe0e4b9549def534;hb=refs%2Fheads%2Ftizen;hp=7e06c615606696997b63e97b8921be4d67798bdf;hpb=de692747190714a329245dad9e29836320c14eb7;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 7e06c61..2e329fa 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 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. @@ -18,8 +18,18 @@ // CLASS HEADER #include +// EXTERNAL INCLUDES +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) +#include +#include +#else +#include +#include +#endif + // INTERNAL INCLUDES #include +#include #include @@ -73,6 +83,10 @@ namespace Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_MANAGER"); } // unnamed namespace #endif +namespace +{ +DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_UPDATE_PROCESS, false); +} // namespace using namespace Dali::Integration; using Dali::Internal::Update::MessageQueue; @@ -85,6 +99,27 @@ namespace SceneGraph { namespace { +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) +/** + * Flag whether property has changed, during the Update phase. + */ +enum ContainerRemovedFlagBits +{ + NOTHING = 0x00, + NODE = 0x01, + RENDERER = 0x02, + SHADER = 0x04, + TEXTURE_SET = 0x08, + ANIMATION = 0x10, + PROPERTY_NOTIFICATION = 0x20, + CUSTOM_OBJECT = 0x40, +}; + +/** + * @brief ContainerRemovedFlags alters behaviour of implementation + */ +using ContainerRemovedFlags = uint8_t; +#endif /** * Helper to Erase an object from OwnerContainer using discard queue * @param container to remove from @@ -188,6 +223,10 @@ struct UpdateManager::Impl nodeDirtyFlags(NodePropertyFlags::TRANSFORM), // set to TransformFlag to ensure full update the first time through Update() frameCounter(0), renderingBehavior(DevelStage::Rendering::IF_REQUIRED), +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + containerRemovedFlags(ContainerRemovedFlagBits::NOTHING), +#endif + discardAnimationFinishedAge(0u), animationFinishedDuringUpdate(false), previousUpdateScene(false), renderTaskWaiting(false), @@ -224,6 +263,7 @@ struct UpdateManager::Impl (*iter)->OnDestroy(); Node::Delete(*iter); } + nodeIdMap.clear(); for(auto&& scene : scenes) { @@ -255,6 +295,34 @@ struct UpdateManager::Impl return *frameCallbackProcessor; } + /** + * @brief Remove all owned render context at scene. + * + * @note Should be called at ContextDestroyed case. + */ + void ContextDestroyed() + { + // Disconnect render tasks from nodes, before destroying the nodes + for(auto&& scene : scenes) + { + if(scene) + { + if(scene->scene) + { + scene->scene->ContextDestroyed(); + } + if(scene->taskList) + { + RenderTaskList::RenderTaskContainer& tasks = scene->taskList->GetTasks(); + for(auto&& task : tasks) + { + task->ContextDestroyed(); + } + } + } + } + } + SceneGraphBuffers sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read RenderMessageDispatcher renderMessageDispatcher; ///< Used for passing messages to the render-thread NotificationManager& notificationManager; ///< Queues notification messages for the event-thread. @@ -275,6 +343,17 @@ struct UpdateManager::Impl Vector nodes; ///< A container of all instantiated nodes +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + using NodeIdMap = std::map; + + using PropertyBaseResetRequestedContainer = std::set; +#else + using NodeIdMap = std::unordered_map; + + using PropertyBaseResetRequestedContainer = std::unordered_set; +#endif + NodeIdMap nodeIdMap; ///< A container of nodes map by id. + Vector cameras; ///< A container of cameras. Note : these cameras are owned by Impl::nodes. OwnerContainer customObjects; ///< A container of owned objects (with custom properties) @@ -283,6 +362,8 @@ struct UpdateManager::Impl ResetterContainer nodeResetters; ///< A container of node resetters ResetterContainer rendererResetters; ///< A container of renderer resetters + PropertyBaseResetRequestedContainer resetRequestedPropertyBases; ///< A container of property base to be resets + OwnerContainer animations; ///< A container of owned animations OwnerContainer propertyNotifications; ///< A container of owner property notifications. OwnerKeyContainer renderers; ///< A container of owned renderers @@ -310,11 +391,17 @@ struct UpdateManager::Impl 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) - bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered - bool renderersAdded; ///< Flag to keep track when renderers have been added to avoid unnecessary processing - bool renderingRequired; ///< True if required to render the current frame +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + ContainerRemovedFlags containerRemovedFlags; ///< cumulative container removed flags during current frame +#endif + + uint8_t discardAnimationFinishedAge : 2; ///< Age of EndAction::Discard animation Stop/Finished. It will make we call ResetToBaseValue at least 2 frames. + + bool animationFinishedDuringUpdate : 1; ///< Flag whether any animations finished during the Update() + bool previousUpdateScene : 1; ///< True if the scene was updated in the previous frame (otherwise it was optimized out) + bool renderTaskWaiting : 1; ///< A REFRESH_ONCE render task is waiting to be rendered + bool renderersAdded : 1; ///< Flag to keep track when renderers have been added to avoid unnecessary processing + bool renderingRequired : 1; ///< True if required to render the current frame private: Impl(const Impl&); ///< Undefined @@ -330,6 +417,8 @@ UpdateManager::UpdateManager(NotificationManager& notificationManager, RenderTaskProcessor& renderTaskProcessor) : mImpl(nullptr) { + PropertyBase::RegisterResetterManager(*this); + mImpl = new Impl(notificationManager, animationFinishedNotifier, propertyNotifier, @@ -343,6 +432,22 @@ UpdateManager::UpdateManager(NotificationManager& notificationManager, UpdateManager::~UpdateManager() { delete mImpl; + PropertyBase::UnregisterResetterManager(); + + // Ensure to release memory pool + Animation::ResetMemoryPool(); + Camera::ResetMemoryPool(); + Node::ResetMemoryPool(); + Renderer::ResetMemoryPool(); + RenderItem::ResetMemoryPool(); + RenderTaskList::ResetMemoryPool(); + TextureSet::ResetMemoryPool(); +} + +void UpdateManager::ContextDestroyed() +{ + // Remove owned update context + mImpl->ContextDestroyed(); } void UpdateManager::InstallRoot(OwnerPointer& layer) @@ -360,6 +465,10 @@ void UpdateManager::InstallRoot(OwnerPointer& layer) 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)); } @@ -377,6 +486,8 @@ void UpdateManager::UninstallRoot(Layer* layer) } } + mImpl->nodeIdMap.erase(layer->GetId()); + mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), layer); // Notify the layer about impending destruction @@ -396,7 +507,12 @@ void UpdateManager::AddNode(OwnerPointer& node) AddCamera(static_cast(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); } @@ -408,6 +524,7 @@ 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); node->AddInitializeResetter(*this); @@ -425,7 +542,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); @@ -450,6 +567,9 @@ void UpdateManager::DestroyNode(Node* node) if((*iter) == node) { mImpl->nodes.Erase(iter); +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::NODE; +#endif break; } } @@ -460,6 +580,8 @@ void UpdateManager::DestroyNode(Node* node) RemoveCamera(static_cast(node)); } + mImpl->nodeIdMap.erase(node->GetId()); + mImpl->nodeDiscardQueue.Add(mSceneGraphBuffers.GetUpdateBufferIndex(), node); // Notify the Node about impending destruction @@ -498,6 +620,9 @@ void UpdateManager::AddObject(OwnerPointer& object) void UpdateManager::RemoveObject(PropertyOwner* object) { mImpl->customObjects.EraseObject(object); +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::CUSTOM_OBJECT; +#endif } void UpdateManager::AddRenderTaskList(OwnerPointer& taskList) @@ -573,12 +698,16 @@ void UpdateManager::StopAnimation(Animation* animation) bool animationFinished = animation->Stop(mSceneGraphBuffers.GetUpdateBufferIndex()); - // Queue this animation into notify required animations. Since we need to send Finished signal - mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId()); - 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"); @@ -627,6 +756,11 @@ void UpdateManager::AddRendererResetter(const Renderer& renderer) mImpl->rendererResetters.PushBack(rendererResetter.Release()); } +void UpdateManager::RequestPropertyBaseResetToBaseValue(PropertyBase* propertyBase) +{ + mImpl->resetRequestedPropertyBases.insert(propertyBase); +} + void UpdateManager::AddPropertyNotification(OwnerPointer& propertyNotification) { mImpl->propertyNotifications.PushBack(propertyNotification.Release()); @@ -638,6 +772,9 @@ void UpdateManager::RemovePropertyNotification(PropertyNotification* propertyNot if(iter != mImpl->propertyNotifications.End()) { mImpl->propertyNotifications.Erase(iter); +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::PROPERTY_NOTIFICATION; +#endif } } @@ -656,6 +793,9 @@ void UpdateManager::RemoveShader(Shader* shader) { // Find the shader and destroy it EraseUsingDiscardQueue(mImpl->shaders, shader, mImpl->shaderDiscardQueue, mSceneGraphBuffers.GetUpdateBufferIndex()); +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::SHADER; +#endif } void UpdateManager::SaveBinary(Internal::ShaderDataPtr shaderData) @@ -694,6 +834,10 @@ void UpdateManager::RemoveRenderer(const RendererKey& rendererKey) EraseUsingDiscardQueue(mImpl->renderers, rendererKey, mImpl->rendererDiscardQueue, mSceneGraphBuffers.GetUpdateBufferIndex()); // Need to remove the render object as well rendererKey->DisconnectFromSceneGraph(*mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex()); + +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::RENDERER; +#endif } void UpdateManager::AttachRenderer(Node* node, Renderer* renderer) @@ -718,6 +862,9 @@ void UpdateManager::AddTextureSet(OwnerPointer& textureSet) void UpdateManager::RemoveTextureSet(TextureSet* textureSet) { mImpl->textureSets.EraseObject(textureSet); +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::TEXTURE_SET; +#endif } uint32_t* UpdateManager::ReserveMessageSlot(uint32_t size, bool updateScene) @@ -745,6 +892,11 @@ void UpdateManager::EventProcessingStarted() mImpl->messageQueue.EventProcessingStarted(); } +void UpdateManager::EventProcessingFinished() +{ + mImpl->messageQueue.EventProcessingFinished(); +} + bool UpdateManager::FlushQueue() { return mImpl->messageQueue.FlushQueue(); @@ -755,14 +907,30 @@ void UpdateManager::ResetProperties(BufferIndex bufferIndex) // Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped mImpl->animationFinishedDuringUpdate = false; + // Age down discard animations. + mImpl->discardAnimationFinishedAge >>= 1; + + // Ensure that their was no request to reset to base values during the previous update + // (Since requested property base doesn't consider the lifecycle of PropertyBase, + // It might be invalid after the previous update finished) + DALI_ASSERT_DEBUG(mImpl->resetRequestedPropertyBases.empty() && "Reset to base values requested during the previous update!"); + mImpl->resetRequestedPropertyBases.clear(); + // Reset node properties - mImpl->nodeResetters.ResetToBaseValues(bufferIndex); + mImpl->nodeResetters.RequestResetToBaseValues(); // Reset renderer properties - mImpl->rendererResetters.ResetToBaseValues(bufferIndex); + mImpl->rendererResetters.RequestResetToBaseValues(); // Reset all animating / constrained properties - mImpl->propertyResetters.ResetToBaseValues(bufferIndex); + mImpl->propertyResetters.RequestResetToBaseValues(); + + // Actual reset to base values here + for(auto&& propertyBase : mImpl->resetRequestedPropertyBases) + { + propertyBase->ResetToBaseValue(bufferIndex); + } + mImpl->resetRequestedPropertyBases.clear(); // Clear all root nodes dirty flags for(auto& scene : mImpl->scenes) @@ -797,17 +965,25 @@ bool UpdateManager::ProcessGestures(BufferIndex bufferIndex, uint32_t lastVSyncT bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) { bool animationActive = false; - bool animationLooped = false; + + if(mImpl->animations.Empty()) + { + return animationActive; + } auto&& iter = mImpl->animations.Begin(); + DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_ANIMATION_ANIMATE", [&](std::ostringstream& oss) { + oss << "[" << mImpl->animations.Count() << "]"; + }); + 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(); @@ -817,10 +993,15 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) } mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished; - animationLooped = animationLooped || looped; - // queue the notification on finished or stoped or looped (to update loop count) - if(finished || looped) + // Check whether finished animation is Discard type. If then, we should update scene at least 2 frames. + if(finished && animation->GetEndAction() == Animation::EndAction::DISCARD) + { + mImpl->discardAnimationFinishedAge |= 2u; + } + + // queue the notification on finished or stopped + if(finished || stopped) { mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId()); } @@ -829,6 +1010,9 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) if(animation->GetState() == Animation::Destroyed) { iter = mImpl->animations.Erase(iter); +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + mImpl->containerRemovedFlags |= ContainerRemovedFlagBits::ANIMATION; +#endif } else { @@ -842,6 +1026,10 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) mImpl->notificationManager.QueueNotification(&mImpl->animationPlaylist, std::move(mImpl->notifyRequiredAnimations)); } + DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_ANIMATION_ANIMATE", [&](std::ostringstream& oss) { + oss << "[" << mImpl->animations.Count() << "]"; + }); + return animationActive; } @@ -930,6 +1118,15 @@ void UpdateManager::ForwardCompiledShadersToEventThread() void UpdateManager::UpdateRenderers(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex) { + if(mImpl->renderers.Empty()) + { + return; + } + + DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_UPDATE_RENDERERS", [&](std::ostringstream& oss) { + oss << "[" << mImpl->renderers.Count() << "]"; + }); + for(const auto& rendererKey : mImpl->renderers) { // Apply constraints @@ -942,6 +1139,8 @@ void UpdateManager::UpdateRenderers(PropertyOwnerContainer& postPropertyOwners, mImpl->renderingRequired = renderer->PrepareRender(bufferIndex) || mImpl->renderingRequired; } + + DALI_TRACE_END(gTraceFilter, "DALI_UPDATE_RENDERERS"); } void UpdateManager::UpdateNodes(PropertyOwnerContainer& postPropertyOwners, BufferIndex bufferIndex) @@ -998,11 +1197,11 @@ uint32_t UpdateManager::Update(float elapsedSeconds, isAnimationRunning || // ..at least one animation is running OR mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR mImpl->frameCallbackProcessor || // ..a frame callback processor is existed OR + mImpl->discardAnimationFinishedAge > 0u || // ..at least one animation with EndAction::DISCARD finished gestureUpdated; // ..a gesture property was updated - uint32_t keepUpdating = 0; - bool keepRendererRendering = false; - mImpl->renderingRequired = false; + uint32_t keepUpdating = 0; + 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. @@ -1026,6 +1225,15 @@ 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) { + DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_UPDATE_INTERNAL", [&](std::ostringstream& oss) { + oss << "[n:" << mImpl->nodes.Size() << ","; + oss << "c:" << mImpl->customObjects.Size() << ","; + oss << "a:" << mImpl->animations.Size() << ","; + oss << "r:" << mImpl->renderers.Size() << ","; + oss << "t:" << mImpl->textureSets.Size() << ","; + oss << "s:" << mImpl->shaders.Size() << "]"; + }); + // Animate bool animationActive = Animate(bufferIndex, elapsedSeconds); @@ -1051,7 +1259,10 @@ uint32_t UpdateManager::Update(float elapsedSeconds, // Call the frame-callback-processor if set if(mImpl->frameCallbackProcessor) { - keepRendererRendering |= mImpl->frameCallbackProcessor->Update(bufferIndex, elapsedSeconds); + if(mImpl->frameCallbackProcessor->Update(bufferIndex, elapsedSeconds)) + { + keepUpdating |= KeepUpdating::FRAME_UPDATE_CALLBACK; + } } // Update node hierarchy, apply constraints, @@ -1093,7 +1304,9 @@ uint32_t UpdateManager::Update(float elapsedSeconds, if(mImpl->renderersAdded) { // Calculate how many render tasks we have in total - std::size_t numberOfRenderTasks = 0; + std::size_t numberOfRenderTasks = 0; + std::size_t numberOfRenderInstructions = 0; + bool renderContinuously = false; for(auto&& scene : mImpl->scenes) { if(scene && scene->taskList) @@ -1102,8 +1315,7 @@ uint32_t UpdateManager::Update(float elapsedSeconds, } } - std::size_t numberOfRenderInstructions = 0; - mImpl->renderInstructionCapacity = 0u; + mImpl->renderInstructionCapacity = 0u; for(auto&& scene : mImpl->scenes) { if(scene && scene->root && scene->taskList && scene->scene) @@ -1122,13 +1334,12 @@ uint32_t UpdateManager::Update(float elapsedSeconds, // or keep rendering is requested if(!isAnimationRunning || animationActive || mImpl->renderingRequired || (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || sceneKeepUpdating) { - keepRendererRendering |= mImpl->renderTaskProcessor.Process(bufferIndex, - *scene->taskList, - *scene->root, - scene->sortedLayerList, - scene->scene->GetRenderInstructions(), - renderToFboEnabled, - isRenderingToFbo); + renderContinuously |= mImpl->renderTaskProcessor.Process(bufferIndex, + *scene->taskList, + scene->sortedLayerList, + scene->scene->GetRenderInstructions(), + renderToFboEnabled, + isRenderingToFbo); mImpl->renderInstructionCapacity += scene->scene->GetRenderInstructions().GetCapacity(); scene->scene->SetSkipRendering(false); @@ -1142,8 +1353,15 @@ uint32_t UpdateManager::Update(float elapsedSeconds, } } + if(renderContinuously) + { + keepUpdating |= KeepUpdating::RENDERER_CONTINUOUSLY; + } + DALI_LOG_INFO(gLogFilter, Debug::General, "Update: numberOfRenderTasks(%d), Render Instructions(%d)\n", numberOfRenderTasks, numberOfRenderInstructions); } + + DALI_TRACE_END(gTraceFilter, "DALI_UPDATE_INTERNAL"); } if(!uploadOnly) @@ -1187,18 +1405,48 @@ uint32_t UpdateManager::Update(float elapsedSeconds, // Macro is undefined in release build. SNAPSHOT_NODE_LOGGING; +#if defined(LOW_SPEC_MEMORY_MANAGEMENT_ENABLED) + // Shrink relevant containers if required. + if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::NODE) + { + mImpl->nodes.ShrinkToFitIfNeeded(); + } + if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::RENDERER) + { + mImpl->renderers.ShrinkToFitIfNeeded(); + } + if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::SHADER) + { + mImpl->shaders.ShrinkToFitIfNeeded(); + } + if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::TEXTURE_SET) + { + mImpl->textureSets.ShrinkToFitIfNeeded(); + } + if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::ANIMATION) + { + mImpl->animations.ShrinkToFitIfNeeded(); + } + if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::PROPERTY_NOTIFICATION) + { + mImpl->propertyNotifications.ShrinkToFitIfNeeded(); + } + if(mImpl->containerRemovedFlags & ContainerRemovedFlagBits::CUSTOM_OBJECT) + { + mImpl->customObjects.ShrinkToFitIfNeeded(); + } + + // Reset flag + mImpl->containerRemovedFlags = ContainerRemovedFlagBits::NOTHING; +#endif + // A ResetProperties() may be required in the next frame mImpl->previousUpdateScene = updateScene; // Check whether further updates are required keepUpdating |= KeepUpdatingCheck(elapsedSeconds); - if(keepRendererRendering) - { - keepUpdating |= KeepUpdating::STAGE_KEEP_RENDERING; - } - - if(keepUpdating & KeepUpdating::STAGE_KEEP_RENDERING) + if(keepUpdating & (KeepUpdating::STAGE_KEEP_RENDERING | KeepUpdating::FRAME_UPDATE_CALLBACK | KeepUpdating::RENDERER_CONTINUOUSLY)) { // Set dirty flags for next frame to continue rendering mImpl->nodeDirtyFlags |= RenderableUpdateFlags; @@ -1218,7 +1466,7 @@ void UpdateManager::PostRender() // Reset dirty flag for(auto&& renderer : mImpl->renderers) { - renderer->ResetDirtyFlag(); + renderer->SetUpdated(false); } for(auto&& shader : mImpl->shaders) @@ -1238,7 +1486,7 @@ uint32_t UpdateManager::KeepUpdatingCheck(float elapsedSeconds) const // If the rendering behavior is set to continuously render, then continue to render. // 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. + // If an animation has just finished, update at least two frames 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 @@ -1248,7 +1496,8 @@ uint32_t UpdateManager::KeepUpdatingCheck(float elapsedSeconds) const } if(IsAnimationRunning() || - mImpl->animationFinishedDuringUpdate) + mImpl->animationFinishedDuringUpdate || + mImpl->discardAnimationFinishedAge > 0u) { keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING; } @@ -1276,7 +1525,10 @@ void UpdateManager::KeepRendering(float durationSeconds) { for(auto&& scene : mImpl->scenes) { - scene->scene->KeepRendering(durationSeconds); + if(scene->scene) + { + scene->scene->KeepRendering(durationSeconds); + } } } @@ -1290,6 +1542,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) @@ -1307,9 +1570,13 @@ void UpdateManager::SetDepthIndices(OwnerPointer& nodeDepths) // 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. + + // 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++) { auto* node = rIter->node; + node->PropagateDescendentFlags(); node->SetDepthIndex(rIter->sortedDepth); if(node->IsChildrenReorderRequired()) { @@ -1546,9 +1813,9 @@ void UpdateManager::RemoveTexture(const Render::TextureKey& texture) new(slot) DerivedType(&mImpl->renderManager, &RenderManager::RemoveTexture, texture); } -void UpdateManager::UploadTexture(const Render::TextureKey& texture, PixelDataPtr pixelData, const Texture::UploadParams& params) +void UpdateManager::UploadTexture(const Render::TextureKey& texture, PixelDataPtr pixelData, const Graphics::UploadParams& params) { - using DerivedType = MessageValue3; + using DerivedType = MessageValue3; // Reserve some memory inside the message queue uint32_t* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType)); @@ -1568,6 +1835,28 @@ void UpdateManager::GenerateMipmaps(const Render::TextureKey& texture) new(slot) DerivedType(&mImpl->renderManager, &RenderManager::GenerateMipmaps, texture); } +void UpdateManager::SetTextureSize(const Render::TextureKey& texture, const Dali::ImageDimensions& size) +{ + using DerivedType = MessageValue2; + + // 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; + + // 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& frameBuffer) { using DerivedType = MessageValue1>;