X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=dali%2Finternal%2Fupdate%2Fmanager%2Fupdate-manager.cpp;h=f462f75c631d4668bf74149abe0e4b9549def534;hb=refs%2Fheads%2Ftizen;hp=7a971f5e9758f4163cbf86fbb6ff5f017246de85;hpb=aeba901745cad05623bbd1e877c722672c89505d;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 7a971f5..3c2a422 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -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,12 @@ namespace Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_MANAGER"); } // unnamed namespace #endif +namespace +{ +// TODO : The name of trace marker is from VD specific. +// We might need to change it as DALI_TRACE_UPDATE_PROCESS. +DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_COMBINED, false); +} // namespace using namespace Dali::Integration; using Dali::Internal::Update::MessageQueue; @@ -85,6 +101,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 +225,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), @@ -276,7 +317,16 @@ struct UpdateManager::Impl Vector nodes; ///< A container of all instantiated nodes - std::unordered_map nodeIdMap; ///< A container of nodes map by id. +#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. @@ -286,6 +336,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 @@ -313,11 +365,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 @@ -333,6 +391,8 @@ UpdateManager::UpdateManager(NotificationManager& notificationManager, RenderTaskProcessor& renderTaskProcessor) : mImpl(nullptr) { + PropertyBase::RegisterResetterManager(*this); + mImpl = new Impl(notificationManager, animationFinishedNotifier, propertyNotifier, @@ -346,6 +406,7 @@ UpdateManager::UpdateManager(NotificationManager& notificationManager, UpdateManager::~UpdateManager() { delete mImpl; + PropertyBase::UnregisterResetterManager(); } void UpdateManager::InstallRoot(OwnerPointer& layer) @@ -465,6 +526,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; } } @@ -515,6 +579,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) @@ -648,6 +715,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()); @@ -659,6 +731,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 } } @@ -677,6 +752,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) @@ -715,6 +793,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) @@ -739,6 +821,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) @@ -781,14 +866,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) @@ -824,8 +925,17 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) { bool animationActive = 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; @@ -843,6 +953,12 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished; + // 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) { @@ -853,6 +969,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 { @@ -866,6 +985,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; } @@ -954,6 +1077,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 @@ -966,6 +1098,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) @@ -1022,11 +1156,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. @@ -1050,6 +1184,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); @@ -1075,7 +1218,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, @@ -1117,7 +1263,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) @@ -1126,8 +1274,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) @@ -1146,13 +1293,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); @@ -1166,8 +1312,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) @@ -1211,18 +1364,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; @@ -1262,7 +1445,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 @@ -1272,7 +1455,8 @@ uint32_t UpdateManager::KeepUpdatingCheck(float elapsedSeconds) const } if(IsAnimationRunning() || - mImpl->animationFinishedDuringUpdate) + mImpl->animationFinishedDuringUpdate || + mImpl->discardAnimationFinishedAge > 0u) { keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING; }