From a47be8c9c52483c21ea56367e0129dc88de2a31f Mon Sep 17 00:00:00 2001 From: Eunki Hong Date: Tue, 21 Mar 2023 01:19:21 +0900 Subject: [PATCH] Reduce overhead of notification (like AnimationFinished, PropertyNotify) Previously, we check existed all animations are finished, and send signal. We can reduce this kind of iteration. Now, send specific scenegraph notify id, and send signal for this. It will reduce NotificationManager::ProcessMessage running time on event side. And, refactorize notifier-interface. Previously, we use scene-graph object's pointer to check whether this object is valid or not. But it has some logical problem when we destroy and create continously. Now we define NotifyId to specify the notify required item. So we can expect SceneGraph items to excute notify process. TODO : Make RenderTaskList also keep hashing... or just ignore this case Change-Id: Ied35d018d1da854ef0e61343710230461d76c67a Signed-off-by: Eunki Hong --- automated-tests/src/dali/utc-Dali-Animation.cpp | 187 ++++++++++++++++++++- dali/internal/common/core-impl.h | 3 +- dali/internal/common/ordered-set.h | 1 + dali/internal/event/animation/animation-impl.cpp | 6 + .../event/animation/animation-playlist.cpp | 60 ++++--- dali/internal/event/animation/animation-playlist.h | 16 +- .../event/common/complete-notification-interface.h | 8 +- .../internal/event/common/notification-manager.cpp | 55 +++--- dali/internal/event/common/notification-manager.h | 11 +- .../notifier-interface.cpp} | 35 ++-- dali/internal/event/common/notifier-interface.h | 66 ++++++++ .../event/common/property-notification-impl.cpp | 8 +- .../event/common/property-notification-impl.h | 11 +- .../event/common/property-notification-manager.cpp | 35 ++-- .../event/common/property-notification-manager.h | 17 +- dali/internal/event/common/property-notifier.h | 17 +- .../common/scene-graph-notifier-interface-mapper.h | 109 ++++++++++++ .../event/render-tasks/render-task-list-impl.cpp | 14 +- .../event/render-tasks/render-task-list-impl.h | 7 +- dali/internal/file.list | 1 + .../update/animation/scene-graph-animation.cpp | 7 +- .../update/animation/scene-graph-animation.h | 3 +- .../common/scene-graph-property-notification.h | 3 +- dali/internal/update/manager/update-manager.cpp | 48 ++++-- .../update/render-tasks/scene-graph-render-task.h | 3 +- 25 files changed, 552 insertions(+), 179 deletions(-) rename dali/internal/event/{animation/animation-playlist-declarations.h => common/notifier-interface.cpp} (53%) create mode 100644 dali/internal/event/common/notifier-interface.h create mode 100644 dali/internal/event/common/scene-graph-notifier-interface-mapper.h diff --git a/automated-tests/src/dali/utc-Dali-Animation.cpp b/automated-tests/src/dali/utc-Dali-Animation.cpp index 1ee61ec..22ae7f4 100644 --- a/automated-tests/src/dali/utc-Dali-Animation.cpp +++ b/automated-tests/src/dali/utc-Dali-Animation.cpp @@ -3171,6 +3171,174 @@ int UtcDaliAnimationStopSetPositionP(void) END_TEST; } +int UtcDaliAnimationStopEmitFinishedSignalImmediateP(void) +{ + TestApplication application; + + Actor actor = Actor::New(); + application.GetScene().Add(actor); + + // Build the animation + float durationSeconds(1.0f); + Animation animation = Animation::New(durationSeconds); + Vector3 targetPosition(100.0f, 100.0f, 100.0f); + animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR); + + bool signalReceived(false); + AnimationFinishCheck finishCheck(signalReceived); + animation.FinishedSignal().Connect(&application, finishCheck); + + // Play + { + tet_printf("Play and Stop immediately\n"); + // Start the animation, and stop immediately. + animation.Play(); + animation.Stop(); + + finishCheck.CheckSignalNotReceived(); + + application.SendNotification(); + application.Render(0); + + // expect finished signal recieved due to Stop API. + application.SendNotification(); + finishCheck.CheckSignalReceived(); + finishCheck.Reset(); + + application.SendNotification(); + application.Render(0); + } + // Play multiple times + { + tet_printf("Play and Stop immediately 2\n"); + // Start the animation, and stop immediately. + animation.Play(); + animation.Stop(); + animation.Play(); + animation.Stop(); + animation.Play(); + animation.Play(); + animation.Stop(); + + finishCheck.CheckSignalNotReceived(); + + application.SendNotification(); + application.Render(0); + + // expect finished signal recieved due to Stop API. + application.SendNotification(); + finishCheck.CheckSignalReceived(); + finishCheck.Reset(); + + application.SendNotification(); + application.Render(0); + } + // PlayAfter + { + tet_printf("PlayAfter and Stop immediately\n"); + // Start the animation, and stop immediately. + animation.PlayAfter(1.0f); + animation.Stop(); + + finishCheck.CheckSignalNotReceived(); + + application.SendNotification(); + application.Render(0); + + // expect finished signal recieved due to Stop API. + application.SendNotification(); + finishCheck.CheckSignalReceived(); + finishCheck.Reset(); + + application.SendNotification(); + application.Render(0); + } + // PlayFrom + { + tet_printf("PlayFrom and Stop immediately\n"); + // Start the animation, and stop immediately. + animation.PlayFrom(0.5f); + animation.Stop(); + + finishCheck.CheckSignalNotReceived(); + + application.SendNotification(); + application.Render(0); + + // expect finished signal recieved due to Stop API. + application.SendNotification(); + finishCheck.CheckSignalReceived(); + finishCheck.Reset(); + + application.SendNotification(); + application.Render(0); + } + // Play and Pause + { + tet_printf("Play and Pause and Stop immediately\n"); + // Pause the animation, and stop immediately. + animation.Play(); + animation.Pause(); + animation.Stop(); + + finishCheck.CheckSignalNotReceived(); + + application.SendNotification(); + application.Render(0); + + // expect finished signal recieved due to Stop API. + application.SendNotification(); + finishCheck.CheckSignalReceived(); + finishCheck.Reset(); + + application.SendNotification(); + application.Render(0); + } + + // Check finished signal not emmited if animation was not play state. + { + tet_printf("Check whether stop-only case didnt send finished signal\n"); + // Stop only. + animation.Stop(); + animation.Stop(); + animation.Stop(); + + finishCheck.CheckSignalNotReceived(); + + application.SendNotification(); + application.Render(0); + + // expect finished signal recieved due to Stop API. + application.SendNotification(); + finishCheck.CheckSignalNotReceived(); + finishCheck.Reset(); + + application.SendNotification(); + application.Render(0); + } + { + tet_printf("Check whether pause-stop case didnt send finished signal\n"); + // Pause and Stop. + animation.Pause(); + animation.Stop(); + + finishCheck.CheckSignalNotReceived(); + + application.SendNotification(); + application.Render(0); + + // expect finished signal recieved due to Stop API. + application.SendNotification(); + finishCheck.CheckSignalNotReceived(); + finishCheck.Reset(); + + application.SendNotification(); + application.Render(0); + } + + END_TEST; +} + int UtcDaliAnimationClearP(void) { TestApplication application; @@ -12639,6 +12807,7 @@ int UtcDaliAnimationProgressSignalConnectionWithoutProgressMarkerP(void) application.SendNotification(); tet_infoline("Ensure after animation has started playing that ProgressReachedSignal not emitted"); + finishCheck.CheckSignalNotReceived(); progressCheck.CheckSignalNotReceived(); application.Render(static_cast(durationSeconds * 900.0f) + 1u /*just beyond the animation duration*/); @@ -13031,7 +13200,9 @@ int UtcDaliAnimationProgressCallbackWithLoopingP(void) for(int count = 0; count < loopCount; count++) { application.SendNotification(); - application.Render(0); // start animation + application.Render(0); // start animation + finishCheck.CheckSignalNotReceived(); + application.Render(durationSeconds * 0.25 * 1000.0f); // 25% progress DALI_TEST_EQUALS(0.25f, animation.GetCurrentProgress(), TEST_LOCATION); @@ -13258,14 +13429,19 @@ int UtcDaliAnimationProgressCallbackNegativeSpeed(void) animation.SetLooping(false); animation.SetLoopCount(4); animation.Play(); - application.Render(0u); - application.SendNotification(); + application.SendNotification(); // Send Stop event into update thread + application.Render(0u); // Send Notification into event thread + application.SendNotification(); // Execute finished signal. + + finishCheck.CheckSignalReceived(); // Due to stop called. + finishCheck.Reset(); for(int count = 0; count < 4; count++) { application.SendNotification(); application.Render(0); // start animation progressCheck.CheckSignalNotReceived(); + finishCheck.CheckSignalNotReceived(); application.SendNotification(); application.Render(durationSeconds * 0.25 * 1000.0f); // 25% progress @@ -14926,7 +15102,6 @@ int UtcDaliAnimationSetGetBlendPoint(void) { TestApplication application; - Animation animation = Animation::New(1.0f); DALI_TEST_EQUALS(animation.GetBlendPoint(), 0.0f, 0.01f, TEST_LOCATION); @@ -15337,8 +15512,8 @@ int UtcDaliAnimationPlayBlendQuaternion(void) application.SendNotification(); application.Render(250); - Quaternion value = actor.GetCurrentProperty(index); - Vector3 axis; + Quaternion value = actor.GetCurrentProperty(index); + Vector3 axis; Dali::Radian angle; DALI_TEST_EQUALS(value.ToAxisAngle(axis, angle), true, TEST_LOCATION); DALI_TEST_EQUALS(angle.radian, 1.0f, 0.05f, TEST_LOCATION); diff --git a/dali/internal/common/core-impl.h b/dali/internal/common/core-impl.h index 3aea733..ff8940e 100644 --- a/dali/internal/common/core-impl.h +++ b/dali/internal/common/core-impl.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -330,7 +329,7 @@ private: Integration::PlatformAbstraction& mPlatform; ///< The interface providing platform specific services. IntrusivePtr mStage; ///< The current stage - AnimationPlaylistOwner mAnimationPlaylist; ///< For 'Fire and forget' animation support + OwnerPointer mAnimationPlaylist; ///< For 'Fire and forget' animation support OwnerPointer mPropertyNotificationManager; ///< For safe signal emmision of property changed notifications IntrusivePtr mRelayoutController; ///< Size negotiation relayout controller diff --git a/dali/internal/common/ordered-set.h b/dali/internal/common/ordered-set.h index 7c76310..65b798b 100644 --- a/dali/internal/common/ordered-set.h +++ b/dali/internal/common/ordered-set.h @@ -259,6 +259,7 @@ public: * @brief Release and move ownership of object. * This API do not remove memory. * + * @post iterators are invalidated by this method. * @param[in] iter The iterator what we want to release. */ T* Release(Iterator iter) diff --git a/dali/internal/event/animation/animation-impl.cpp b/dali/internal/event/animation/animation-impl.cpp index 59a77db..4547efa 100644 --- a/dali/internal/event/animation/animation-impl.cpp +++ b/dali/internal/event/animation/animation-impl.cpp @@ -193,12 +193,18 @@ void Animation::CreateSceneObject() mAnimation = SceneGraph::Animation::New(mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction); OwnerPointer transferOwnership(const_cast(mAnimation)); AddAnimationMessage(mEventThreadServices.GetUpdateManager(), transferOwnership); + + // Setup mapping infomations between scenegraph animation + mPlaylist.MapNotifier(mAnimation, *this); } void Animation::DestroySceneObject() { if(mAnimation != nullptr) { + // Remove mapping infomations + mPlaylist.UnmapNotifier(mAnimation); + // Remove animation using a message to the update manager RemoveAnimationMessage(mEventThreadServices.GetUpdateManager(), *mAnimation); mAnimation = nullptr; diff --git a/dali/internal/event/animation/animation-playlist.cpp b/dali/internal/event/animation/animation-playlist.cpp index a2edbd1..60521d4 100644 --- a/dali/internal/event/animation/animation-playlist.cpp +++ b/dali/internal/event/animation/animation-playlist.cpp @@ -21,6 +21,7 @@ // INTERNAL INCLUDES #include #include +#include #include namespace Dali @@ -80,52 +81,49 @@ void AnimationPlaylist::OnClear(Animation& animation) } } -void AnimationPlaylist::NotifyCompleted() +void AnimationPlaylist::NotifyProgressReached(NotifierInterface::NotifyId notifyId) { - std::vector finishedAnimations; + Dali::Animation handle; // Will own handle until all emits have been done. - // Since animations can be unreferenced during the signal emissions, iterators into animationPointers may be invalidated. - // First copy and reference the finished animations, then emit signals - for(auto* animation : mAnimations) + auto* animation = GetEventObject(notifyId); + if(DALI_LIKELY(animation)) { - if(animation->HasFinished()) - { - Dali::Animation handle = Dali::Animation(animation); - finishedAnimations.push_back(handle); + // Check if this animation hold inputed scenegraph animation. + DALI_ASSERT_DEBUG(animation->GetSceneObject()->GetNotifyId() == notifyId); - // The animation may be present in mPlaylist - remove if necessary - // Note that the animation "Finish" signal is emitted after Stop() has been called - OnClear(*animation); - } - } - - // Now it's safe to emit the signals - for(auto iter = finishedAnimations.begin(); iter != finishedAnimations.end(); ++iter) - { - Dali::Animation& handle = *iter; - - GetImplementation(handle).EmitSignalFinish(); + handle = Dali::Animation(animation); + animation->EmitSignalProgressReached(); } } -void AnimationPlaylist::NotifyProgressReached(const SceneGraph::Animation* sceneGraphAnimation) +void AnimationPlaylist::NotifyCompleted(CompleteNotificationInterface::ParameterList notifierIdList) { - std::vector notifyProgressAnimations; // Will own animations until all emits have been done + std::vector finishedAnimations; // Will own handle until all emits have been done. - for(auto* animation : mAnimations) + for(const auto& notifierId : notifierIdList) { - if((animation->GetSceneObject()) == sceneGraphAnimation) + auto* animation = GetEventObject(notifierId); + if(DALI_LIKELY(animation)) { - // Store handles to animations that need signals emitted in the case of an animation being cleared in-between emits - notifyProgressAnimations.push_back(Dali::Animation(animation)); + // Check if this animation hold inputed scenegraph animation. + DALI_ASSERT_DEBUG(animation->GetSceneObject()->GetNotifyId() == notifierId); + + // Update loop count. And check whether animation was finished or not. + if(animation->HasFinished()) + { + finishedAnimations.push_back(Dali::Animation(animation)); + + // The animation may be present in mPlaylist - remove if necessary + // Note that the animation "Finish" signal is emitted after Stop() has been called + OnClear(*animation); + } } } - for(std::vector::iterator iter = notifyProgressAnimations.begin(); iter != notifyProgressAnimations.end(); ++iter) + // Now it's safe to emit the signals + for(auto& animation : finishedAnimations) { - Dali::Animation& handle = *iter; - - GetImplementation(handle).EmitSignalProgressReached(); + GetImplementation(animation).EmitSignalFinish(); } } diff --git a/dali/internal/event/animation/animation-playlist.h b/dali/internal/event/animation/animation-playlist.h index 5b0a8b4..ddecbd0 100644 --- a/dali/internal/event/animation/animation-playlist.h +++ b/dali/internal/event/animation/animation-playlist.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ class Animation; * AnimationPlaylist provides notifications to applications when animations are finished. * It reference-counts playing animations, to allow "fire and forget" behaviour. */ -class AnimationPlaylist : public CompleteNotificationInterface +class AnimationPlaylist : public CompleteNotificationInterface, public SceneGraphNotifierInterfaceMapper { public: /** @@ -80,9 +81,9 @@ public: /** * @brief Notify that an animation has reached a progress marker - * @param[in] sceneGraphAnimation scene graph animation that has reached progress + * @param[in] notifyId scene graph animation's notifyId that has reached progress */ - void NotifyProgressReached(const SceneGraph::Animation* sceneGraphAnimation); + void NotifyProgressReached(NotifierInterface::NotifyId notifyId); /** * @brief Retrive the number of Animations. @@ -115,11 +116,12 @@ private: // from CompleteNotificationInterface /** * @copydoc CompleteNotificationInterface::NotifyCompleted() */ - void NotifyCompleted() override; + void NotifyCompleted(CompleteNotificationInterface::ParameterList notifierList) override; private: OrderedSet mAnimations; ///< All existing animations (not owned) - std::map mPlaylist; ///< The currently playing animations (owned through handle). Note we can hold same handles multiple. + std::map mPlaylist; ///< The currently playing animations (owned through handle). + ///< Note we can hold same handles multiple, since OnClear can be called after NotifyCompleted. }; /** @@ -127,9 +129,9 @@ private: * * Note animationPlaylist is of type CompleteNotificationInterface because of updateManager only knowing about the interface not actual playlist */ -inline MessageBase* NotifyProgressReachedMessage(CompleteNotificationInterface& animationPlaylist, const SceneGraph::Animation* animation) +inline MessageBase* NotifyProgressReachedMessage(CompleteNotificationInterface& animationPlaylist, NotifierInterface::NotifyId notifyId) { - return new MessageValue1(static_cast(&animationPlaylist), &AnimationPlaylist::NotifyProgressReached, animation); + return new MessageValue1(static_cast(&animationPlaylist), &AnimationPlaylist::NotifyProgressReached, notifyId); } } // namespace Internal diff --git a/dali/internal/event/common/complete-notification-interface.h b/dali/internal/event/common/complete-notification-interface.h index ca287d6..4eed850 100644 --- a/dali/internal/event/common/complete-notification-interface.h +++ b/dali/internal/event/common/complete-notification-interface.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_COMPLETE_NOTIFICATION_INTERFACE_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -19,6 +19,8 @@ */ // INTERNAL INCLUDES +#include +#include namespace Dali { @@ -42,10 +44,12 @@ protected: virtual ~CompleteNotificationInterface() = default; public: + using ParameterList = typename Dali::Vector; + /** * This method is called by Notification Manager */ - virtual void NotifyCompleted() = 0; + virtual void NotifyCompleted(ParameterList notifierList) = 0; }; } // namespace Internal diff --git a/dali/internal/event/common/notification-manager.cpp b/dali/internal/event/common/notification-manager.cpp index d20ec05..127fe57 100644 --- a/dali/internal/event/common/notification-manager.cpp +++ b/dali/internal/event/common/notification-manager.cpp @@ -25,8 +25,10 @@ #include #include #include +#include #include #include +#include namespace Dali { @@ -34,7 +36,7 @@ namespace Internal { namespace { -typedef Dali::Vector InterfaceContainer; +typedef std::vector> InterfaceContainer; DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false); @@ -45,27 +47,10 @@ DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false); */ void MoveElements(InterfaceContainer& from, InterfaceContainer& to) { - // check if there's something in from - const InterfaceContainer::SizeType fromCount = from.Count(); - if(fromCount > 0u) - { - // check if to has some elements - const InterfaceContainer::SizeType toCount = to.Count(); - if(toCount == 0u) - { - // to is empty so we can swap with from - to.Swap(from); - } - else - { - to.Reserve(toCount + fromCount); - for(InterfaceContainer::SizeType i = 0; i < fromCount; ++i) - { - to.PushBack(from[i]); - } - from.Clear(); - } - } + to.insert(to.end(), + std::make_move_iterator(from.begin()), + std::make_move_iterator(from.end())); + from.clear(); } } // namespace @@ -83,9 +68,9 @@ struct NotificationManager::Impl eventMessageQueue.Reserve(32); // only a few manager objects get complete notifications (animation, render list, property notifications, ...) - updateCompletedInterfaceQueue.Reserve(4); - updateWorkingInterfaceQueue.Reserve(4); - eventInterfaceQueue.Reserve(4); + updateCompletedInterfaceQueue.reserve(4); + updateWorkingInterfaceQueue.reserve(4); + eventInterfaceQueue.reserve(4); } ~Impl() = default; @@ -112,12 +97,12 @@ NotificationManager::~NotificationManager() delete mImpl; } -void NotificationManager::QueueCompleteNotification(CompleteNotificationInterface* instance) +void NotificationManager::QueueNotification(CompleteNotificationInterface* instance, NotificationParameterList&& parameter) { // queueMutex must be locked whilst accessing queues MessageQueueMutex::ScopedLock lock(mImpl->queueMutex); - mImpl->updateWorkingInterfaceQueue.PushBack(instance); + mImpl->updateWorkingInterfaceQueue.emplace_back(instance, std::move(parameter)); } void NotificationManager::QueueMessage(MessageBase* message) @@ -138,8 +123,10 @@ void NotificationManager::UpdateCompleted() // note that in theory its possible for update completed to have last frames // events as well still hanging around. we need to keep them as well mImpl->updateCompletedMessageQueue.MoveFrom(mImpl->updateWorkingMessageQueue); + // move pointers from interface queue MoveElements(mImpl->updateWorkingInterfaceQueue, mImpl->updateCompletedInterfaceQueue); + // finally the lock is released } @@ -148,8 +135,8 @@ bool NotificationManager::MessagesToProcess() // queueMutex must be locked whilst accessing queues MessageQueueMutex::ScopedLock lock(mImpl->queueMutex); - return (0u < mImpl->updateCompletedMessageQueue.Count() || - (0u < mImpl->updateCompletedInterfaceQueue.Count())); + return ((0u < mImpl->updateCompletedMessageQueue.Count()) || + (0u < mImpl->updateCompletedInterfaceQueue.size())); } void NotificationManager::ProcessMessages() @@ -179,22 +166,22 @@ void NotificationManager::ProcessMessages() // release the processed messages from event side queue mImpl->eventMessageQueue.Clear(); - InterfaceContainer::Iterator iter2 = mImpl->eventInterfaceQueue.Begin(); - const InterfaceContainer::Iterator end2 = mImpl->eventInterfaceQueue.End(); + InterfaceContainer::iterator iter2 = mImpl->eventInterfaceQueue.begin(); + const InterfaceContainer::iterator end2 = mImpl->eventInterfaceQueue.end(); if(iter2 != end2) { DALI_TRACE_SCOPE(gTraceFilter, "DALI_NOTIFICATION_NOTIFY_COMPLETED"); for(; iter2 != end2; ++iter2) { - CompleteNotificationInterface* interface = *iter2; + CompleteNotificationInterface* interface = iter2->first; if(interface) { - interface->NotifyCompleted(); + interface->NotifyCompleted(std::move(iter2->second)); } } } // just clear the container, we dont own the objects - mImpl->eventInterfaceQueue.Clear(); + mImpl->eventInterfaceQueue.clear(); } } // namespace Internal diff --git a/dali/internal/event/common/notification-manager.h b/dali/internal/event/common/notification-manager.h index a967eba..18aed73 100644 --- a/dali/internal/event/common/notification-manager.h +++ b/dali/internal/event/common/notification-manager.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_NOTIFICATION_MANAGER_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -19,6 +19,9 @@ */ // INTERNAL INCLUDES +#include +#include ///< for NotifierInterface::NotifyId +#include namespace Dali { @@ -34,6 +37,9 @@ class MessageBase; class NotificationManager { public: + // TODO : Can we get this typename from complete-notification-interface.h? + using NotificationParameterList = typename Dali::Vector; + /** * Create an NotificationManager. Owned by Core in event thread side. */ @@ -49,8 +55,9 @@ public: /** * Queue a scene message to an interface. This method is thread-safe. * @param[in] instance to be notified about completion of the Update side event. + * @param[in] parameter list of notifiers as input. */ - void QueueCompleteNotification(CompleteNotificationInterface* instance); + void QueueNotification(CompleteNotificationInterface* instance, NotificationParameterList&& parameter); /** * Queue a scene message. This method is thread-safe. diff --git a/dali/internal/event/animation/animation-playlist-declarations.h b/dali/internal/event/common/notifier-interface.cpp similarity index 53% rename from dali/internal/event/animation/animation-playlist-declarations.h rename to dali/internal/event/common/notifier-interface.cpp index 710fde4..053d391 100644 --- a/dali/internal/event/animation/animation-playlist-declarations.h +++ b/dali/internal/event/common/notifier-interface.cpp @@ -1,8 +1,5 @@ -#ifndef DALI_INTERNAL_ANIMATION_PLAYLIST_DECLARATIONS_H -#define DALI_INTERNAL_ANIMATION_PLAYLIST_DECLARATIONS_H - /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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,19 +15,27 @@ * */ -// INTERNAL INCLUDES -#include +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include +#include // uint32_t -namespace Dali +namespace { -namespace Internal +Dali::Internal::NotifierInterface::NotifyId GetNextNotifyId() { -class AnimationPlaylist; - -using AnimationPlaylistOwner = OwnerPointer; + static std::atomic_uint32_t gNotifyCount{0u}; + return ++gNotifyCount; +} +} // namespace -} // namespace Internal - -} // namespace Dali +namespace Dali::Internal +{ +NotifierInterface::NotifierInterface() +: mNotifyId(GetNextNotifyId()) +{ +} -#endif // DALI_INTERNAL_ANIMATION_PLAYLIST_DECLARATIONS_H +} // namespace Dali::Internal diff --git a/dali/internal/event/common/notifier-interface.h b/dali/internal/event/common/notifier-interface.h new file mode 100644 index 0000000..96b3e19 --- /dev/null +++ b/dali/internal/event/common/notifier-interface.h @@ -0,0 +1,66 @@ +#ifndef DALI_INTERNAL_NOTIFIER_INTERFACE_H +#define DALI_INTERNAL_NOTIFIER_INTERFACE_H + +/* + * Copyright (c) 2023 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include // uint32_t + +namespace Dali +{ +namespace Internal +{ +/** + * Abstract interface to notifier to the event-thread regarding the changes in previous update(s). + * For example an property notificatoin. + */ +class NotifierInterface +{ +public: + using NotifyId = uint32_t; + +public: + /** + * Constructor. + */ + NotifierInterface(); + + /** + * Virtual destructor as this is an interface. + */ + virtual ~NotifierInterface() = default; + + /** + * @brief Get the Id of this notifier interface. + * + * @return The NotifyId. + */ + NotifyId GetNotifyId() const + { + return mNotifyId; + } + +private: + NotifyId mNotifyId{0u}; +}; + +} // namespace Internal + +} // namespace Dali + +#endif // DALI_INTERNAL_NOTIFIER_INTERFACE_H diff --git a/dali/internal/event/common/property-notification-impl.cpp b/dali/internal/event/common/property-notification-impl.cpp index 2585bae..2a93442 100644 --- a/dali/internal/event/common/property-notification-impl.cpp +++ b/dali/internal/event/common/property-notification-impl.cpp @@ -196,9 +196,9 @@ bool PropertyNotification::GetNotifyResult() const return mNotifyResult; } -bool PropertyNotification::CompareSceneObject(const SceneGraph::PropertyNotification* sceneObject) +bool PropertyNotification::CompareSceneObjectNotifyId(NotifierInterface::NotifyId notifyId) const { - return sceneObject && sceneObject == mPropertyNotification; + return mPropertyNotification && mPropertyNotification->GetNotifyId() == notifyId; } void PropertyNotification::CreateSceneObject() @@ -221,7 +221,7 @@ void PropertyNotification::CreateSceneObject() AddPropertyNotificationMessage(mUpdateManager, transferOwnership); // Setup mapping infomations between scenegraph property notification - mPropertyNotificationManager.PropertyNotificationSceneObjectMapping(mPropertyNotification, *this); + mPropertyNotificationManager.MapNotifier(mPropertyNotification, *this); } } @@ -232,7 +232,7 @@ void PropertyNotification::DestroySceneObject() DALI_ASSERT_ALWAYS(EventThreadServices::IsCoreRunning()); // Remove mapping infomations - mPropertyNotificationManager.PropertyNotificationSceneObjectUnmapping(mPropertyNotification); + mPropertyNotificationManager.UnmapNotifier(mPropertyNotification); // Remove PropertyNotification using a message to the update manager RemovePropertyNotificationMessage(mUpdateManager, *mPropertyNotification); diff --git a/dali/internal/event/common/property-notification-impl.h b/dali/internal/event/common/property-notification-impl.h index 613cc8e..5d77031 100644 --- a/dali/internal/event/common/property-notification-impl.h +++ b/dali/internal/event/common/property-notification-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_PROPERTY_NOTIFICATION_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -19,6 +19,7 @@ */ // INTERNAL INCLUDES +#include ///< for NotifierInterface::NotifyId #include #include #include @@ -129,11 +130,11 @@ public: bool GetNotifyResult() const; /** - * Compare the passed sceneObject to the one created by this instance - * @param[in] sceneObject The SceneGraph::PropertyNotification pointer to compare - * @return true if sceneObject is the same as the one created by this instance + * Compare the passed NotifyId to the one created by this instance + * @param[in] notifyId The SceneGraph::PropertyNotification's notify id to compare + * @return true if notifyId is the same as the one created by this instance */ - bool CompareSceneObject(const SceneGraph::PropertyNotification* sceneObject); + bool CompareSceneObjectNotifyId(NotifierInterface::NotifyId notifyId) const; protected: /** diff --git a/dali/internal/event/common/property-notification-manager.cpp b/dali/internal/event/common/property-notification-manager.cpp index 873e940..807d448 100644 --- a/dali/internal/event/common/property-notification-manager.cpp +++ b/dali/internal/event/common/property-notification-manager.cpp @@ -46,33 +46,22 @@ void PropertyNotificationManager::PropertyNotificationDestroyed(PropertyNotifica mPropertyNotifications.Erase(iter); } -void PropertyNotificationManager::PropertyNotificationSceneObjectMapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification, PropertyNotification& propertyNotification) +void PropertyNotificationManager::NotifyProperty(NotifierInterface::NotifyId notifyId, bool validity) { - mSceneGraphObjectMap.insert({sceneGraphPropertyNotification, &propertyNotification}); -} - -void PropertyNotificationManager::PropertyNotificationSceneObjectUnmapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification) -{ - auto iter = mSceneGraphObjectMap.find(sceneGraphPropertyNotification); - DALI_ASSERT_DEBUG(iter != mSceneGraphObjectMap.end()); - - mSceneGraphObjectMap.erase(iter); -} + Dali::PropertyNotification handle; // Will own handle until all emits have been done. -void PropertyNotificationManager::NotifyProperty(SceneGraph::PropertyNotification* sceneGraphPropertyNotification, bool validity) -{ - const auto iter = mSceneGraphObjectMap.find(sceneGraphPropertyNotification); - if(iter != mSceneGraphObjectMap.end()) + auto* propertyNotification = GetEventObject(notifyId); + if(DALI_LIKELY(propertyNotification)) { // Check if this notification hold inputed scenegraph property notification. - auto* propertyNotification = iter->second; - if(propertyNotification->CompareSceneObject(sceneGraphPropertyNotification)) - { - // allow application to access the value that triggered this emit incase of NOTIFY_ON_CHANGED mode - propertyNotification->SetNotifyResult(validity); - // yes..emit signal - propertyNotification->EmitSignalNotify(); - } + DALI_ASSERT_DEBUG(propertyNotification->CompareSceneObjectNotifyId(notifyId)); + + handle = Dali::PropertyNotification(propertyNotification); + + // allow application to access the value that triggered this emit incase of NOTIFY_ON_CHANGED mode + propertyNotification->SetNotifyResult(validity); + // yes..emit signal + propertyNotification->EmitSignalNotify(); } } diff --git a/dali/internal/event/common/property-notification-manager.h b/dali/internal/event/common/property-notification-manager.h index 4229be2..58a87d8 100644 --- a/dali/internal/event/common/property-notification-manager.h +++ b/dali/internal/event/common/property-notification-manager.h @@ -24,6 +24,7 @@ // INTERNAL INCLUDES #include #include +#include #include namespace Dali @@ -38,7 +39,7 @@ class PropertyNotification; * It also monitors the lifetime of PropertyNotification objects and will * only emit signals for PropertyNotification objects which are still valid. */ -class PropertyNotificationManager : public PropertyNotifier +class PropertyNotificationManager : public PropertyNotifier, public SceneGraphNotifierInterfaceMapper { public: /** @@ -62,21 +63,11 @@ public: */ void PropertyNotificationDestroyed(PropertyNotification& propertyNotification); - /** - * Called when a SceneGraph::PropertyNotification is mapping by PropertyNotification. - */ - void PropertyNotificationSceneObjectMapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification, PropertyNotification& propertyNotification); - - /** - * Called when a SceneGraph::PropertyNotification is unmaped from PropertyNotification. - */ - void PropertyNotificationSceneObjectUnmapping(const SceneGraph::PropertyNotification* sceneGraphPropertyNotification); - private: // private virtual overrides /** * @copydoc PropertyNotifier::NotifyProperty */ - void NotifyProperty(SceneGraph::PropertyNotification* sceneGraphPropertyNotification, bool validity) override; + void NotifyProperty(NotifierInterface::NotifyId notifyId, bool validity) override; private: /** @@ -92,8 +83,6 @@ private: private: OrderedSet mPropertyNotifications; ///< All existing PropertyNotifications (not owned) - - std::unordered_map mSceneGraphObjectMap; ///< Converter from SceneGraph object pointer to Event object. }; } // namespace Internal diff --git a/dali/internal/event/common/property-notifier.h b/dali/internal/event/common/property-notifier.h index df17870..810fbf9 100644 --- a/dali/internal/event/common/property-notifier.h +++ b/dali/internal/event/common/property-notifier.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_PROPERTY_NOTIFIER_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include ///< for NotifierInterface::NotifyId namespace Dali { @@ -45,22 +46,22 @@ public: /** * Provide notification signals for a changed property. * This method should be called in the event-thread; the update-thread must use PropertyChangedMessage. - * @param[in] propertyNotification A pointer to the SceneGraph::PropertyNotification that has been mnodified. + * @param[in] notifyId A notifyId to the SceneGraph::PropertyNotification that has been mnodified. * @param[in] validity Passes in whether the notification was triggered by a true or false condition result */ - virtual void NotifyProperty(SceneGraph::PropertyNotification* propertyNotification, bool validity) = 0; + virtual void NotifyProperty(NotifierInterface::NotifyId notifyId, bool validity) = 0; }; /** * Notification message for when a property has been modified * @param[in] notifier This will provide the notification signal. */ -inline MessageBase* PropertyChangedMessage(PropertyNotifier& notifier, SceneGraph::PropertyNotification* propertyNotification, bool validity) +inline MessageBase* PropertyChangedMessage(PropertyNotifier& notifier, NotifierInterface::NotifyId notifyId, bool validity) { - return new MessageValue2(¬ifier, - &PropertyNotifier::NotifyProperty, - propertyNotification, - validity); + return new MessageValue2(¬ifier, + &PropertyNotifier::NotifyProperty, + notifyId, + validity); } } // namespace Internal diff --git a/dali/internal/event/common/scene-graph-notifier-interface-mapper.h b/dali/internal/event/common/scene-graph-notifier-interface-mapper.h new file mode 100644 index 0000000..714b703 --- /dev/null +++ b/dali/internal/event/common/scene-graph-notifier-interface-mapper.h @@ -0,0 +1,109 @@ +#ifndef DALI_INTERNAL_SCENE_GRAPH_NOTIFIER_INTERFACE_MAPPER_H +#define DALI_INTERNAL_SCENE_GRAPH_NOTIFIER_INTERFACE_MAPPER_H + +/* + * Copyright (c) 2023 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include // for std::unique_ptr +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ +namespace Internal +{ +/** + * @brief Abstract object mapper between event object and scenegraph notifier interface object. + * @note This class is not thread safe. Please call API only for event thread. + * + * @tparam EventObject Mainly controlled object. Usually in Dali::Internal namespace. + */ +template +class SceneGraphNotifierInterfaceMapper +{ +protected: + /** + * Constructor, not to be directly instantiated. + */ + SceneGraphNotifierInterfaceMapper() = default; + + /** + * Virtual destructor. + */ + virtual ~SceneGraphNotifierInterfaceMapper() = default; + +public: + /** + * Called when a NotifierInterface is mapping by EventObject. + */ + void MapNotifier(const NotifierInterface* notifierInterface, EventObject& eventObject) + { + auto id = notifierInterface->GetNotifyId(); + + auto iter = mNotifierMap.find(id); + DALI_ASSERT_DEBUG(iter == mNotifierMap.end()); + + mNotifierMap.insert(iter, {id, &eventObject}); + } + + /** + * Called when a NotifierInterface is unmaped from EventObject. + */ + void UnmapNotifier(const NotifierInterface* notifierInterface) + { + auto id = notifierInterface->GetNotifyId(); + + auto iter = mNotifierMap.find(id); + DALI_ASSERT_DEBUG(iter != mNotifierMap.end()); + + mNotifierMap.erase(iter); + } + +protected: + /** + * @brief Get EventObject pointer by NotifierInterface notifyId. + * + * @return Mapped EventObject pointer, or nullptr if not exist. + */ + EventObject* GetEventObject(const NotifierInterface::NotifyId notifyId) + { + EventObject* result = nullptr; + + const auto iter = mNotifierMap.find(notifyId); + if(iter != mNotifierMap.end()) + { + result = iter->second; + } + + return result; + } + +private: + using NotifyIdConverter = std::unordered_map; + + NotifyIdConverter mNotifierMap{}; ///< Converter from NotifyId to EventObject pointer. +}; + +} // namespace Internal + +} // namespace Dali + +#endif // DALI_INTERNAL_SCENE_GRAPH_OBJECT_MAPPER_H diff --git a/dali/internal/event/render-tasks/render-task-list-impl.cpp b/dali/internal/event/render-tasks/render-task-list-impl.cpp index 2c0fffe..70cb524 100644 --- a/dali/internal/event/render-tasks/render-task-list-impl.cpp +++ b/dali/internal/event/render-tasks/render-task-list-impl.cpp @@ -68,6 +68,9 @@ RenderTaskPtr RenderTaskList::CreateTask(Actor* sourceActor, CameraActor* camera mTasks.push_back(task); } + // Setup mapping infomations between scenegraph rendertask + this->MapNotifier(task->GetRenderTaskSceneObject(), *task); + return task; } @@ -77,6 +80,9 @@ RenderTaskPtr RenderTaskList::CreateOverlayTask(Actor* sourceActor, CameraActor* { mOverlayRenderTask = RenderTask::New(sourceActor, cameraActor, *this, true); mTasks.push_back(mOverlayRenderTask); + + // Setup mapping infomations between scenegraph rendertask + this->MapNotifier(mOverlayRenderTask->GetRenderTaskSceneObject(), *mOverlayRenderTask); } return mOverlayRenderTask; } @@ -94,6 +100,9 @@ void RenderTaskList::RemoveTask(Internal::RenderTask& task) mOverlayRenderTask.Reset(); } + // Remove mapping infomations + this->UnmapNotifier(task.GetRenderTaskSceneObject()); + // delete the task mTasks.erase(iter); @@ -189,12 +198,15 @@ void RenderTaskList::Initialize() mSceneObject->SetCompleteNotificationInterface(this); } -void RenderTaskList::NotifyCompleted() +void RenderTaskList::NotifyCompleted(CompleteNotificationInterface::ParameterList notifierList) { DALI_LOG_TRACE_METHOD(gLogRenderList); RenderTaskContainer finishedRenderTasks; + // TODO : Optimize here if required. + // Note : Actually, Total number of RenderTask should be small enough so full search might not overhead for now. + // Since render tasks can be unreferenced during the signal emissions, iterators into render tasks pointers may be invalidated. // First copy the finished render tasks, then emit signals for(RenderTaskContainer::iterator iter = mTasks.begin(), endIt = mTasks.end(); iter != endIt; ++iter) diff --git a/dali/internal/event/render-tasks/render-task-list-impl.h b/dali/internal/event/render-tasks/render-task-list-impl.h index c01b981..2be8177 100644 --- a/dali/internal/event/render-tasks/render-task-list-impl.h +++ b/dali/internal/event/render-tasks/render-task-list-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_RENDER_TASK_LIST_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -50,7 +51,7 @@ class UpdateManager; * A proxy for the scene-graph RenderTaskList. * A separate LayerList is maintained for actors added via the SystemLevel::Add(). */ -class RenderTaskList : public BaseObject, public CompleteNotificationInterface +class RenderTaskList : public BaseObject, public CompleteNotificationInterface, public SceneGraphNotifierInterfaceMapper { public: using RenderTaskContainer = std::vector; @@ -188,7 +189,7 @@ private: // from CompleteNotificationInterface /** * @copydoc CompleteNotificationInterface::NotifyCompleted() */ - void NotifyCompleted() override; + void NotifyCompleted(CompleteNotificationInterface::ParameterList notifierList) override; private: EventThreadServices& mEventThreadServices; diff --git a/dali/internal/file.list b/dali/internal/file.list index f96636a..efa4c8b 100644 --- a/dali/internal/file.list +++ b/dali/internal/file.list @@ -36,6 +36,7 @@ SET( internal_src_files ${internal_src_dir}/event/common/base-object-impl.cpp ${internal_src_dir}/event/common/event-thread-services.cpp ${internal_src_dir}/event/common/notification-manager.cpp + ${internal_src_dir}/event/common/notifier-interface.cpp ${internal_src_dir}/event/common/object-impl.cpp ${internal_src_dir}/event/common/object-registry-impl.cpp ${internal_src_dir}/event/common/projection.cpp diff --git a/dali/internal/update/animation/scene-graph-animation.cpp b/dali/internal/update/animation/scene-graph-animation.cpp index 2359154..31a3e0a 100644 --- a/dali/internal/update/animation/scene-graph-animation.cpp +++ b/dali/internal/update/animation/scene-graph-animation.cpp @@ -82,7 +82,7 @@ Animation::Animation(float durationSeconds, float speedFactor, const Vector2& pl mProgressReachedSignalRequired(false), mAutoReverseEnabled(false), mAnimatorSortRequired(false), - mIsActive{false}, + mIsActive{false, false}, mIsFirstLoop{true} { } @@ -330,9 +330,9 @@ void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& loop looped = false; finished = false; + // Short circuit when animation isn't running if(mState == Stopped || mState == Destroyed) { - // Short circuit when animation isn't running return; } @@ -509,8 +509,7 @@ void Animation::UpdateAnimators(BufferIndex bufferIndex, bool bake, bool animati if(cleanup) { // Remove animators whose PropertyOwner has been destroyed - mAnimators.EraseIf([](auto& animator) - { return animator->Orphan(); }); + mAnimators.EraseIf([](auto& animator) { return animator->Orphan(); }); // Need to be re-sort if remained animators size is bigger than one. // Note that if animator contains only zero or one items, It is already sorted case. diff --git a/dali/internal/update/animation/scene-graph-animation.h b/dali/internal/update/animation/scene-graph-animation.h index 7c2be77..a1bb347 100644 --- a/dali/internal/update/animation/scene-graph-animation.h +++ b/dali/internal/update/animation/scene-graph-animation.h @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace Dali @@ -37,7 +38,7 @@ namespace SceneGraph * managers "update" phase. An animation is a container of Animator objects; the actual setting * of object values is done by the animators. */ -class Animation +class Animation : public NotifierInterface { public: using EndAction = Dali::Animation::EndAction; diff --git a/dali/internal/update/common/scene-graph-property-notification.h b/dali/internal/update/common/scene-graph-property-notification.h index 4c4474b..2c4c22c 100644 --- a/dali/internal/update/common/scene-graph-property-notification.h +++ b/dali/internal/update/common/scene-graph-property-notification.h @@ -19,6 +19,7 @@ */ // INTERNAL INCLUDES +#include #include #include #include @@ -40,7 +41,7 @@ using ConditionFunction = bool (*)(const Dali::PropertyInput&, Dali::Internal::P * PropertyNotifications are used to inspect properties of scene graph objects, as part of a scene * managers "update" phase. When a condition has been met the application receives a notification signal. */ -class PropertyNotification +class PropertyNotification : public NotifierInterface { public: using NotifyMode = Dali::PropertyNotification::NotifyMode; diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 2723a7b..808c8fd 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -294,6 +294,8 @@ struct UpdateManager::Impl DiscardQueue, OwnerKeyContainer> rendererDiscardQueue; DiscardQueue> sceneDiscardQueue; + CompleteNotificationInterface::ParameterList notifyRequiredAnimations; ///< A temperal container of complete notify required animations, like animation finished, stopped, or loop completed. + OwnerPointer panGestureProcessor; ///< Owned pan gesture processor; it lives for the lifecycle of UpdateManager MessageQueue messageQueue; ///< The messages queued from the event-thread @@ -571,6 +573,9 @@ 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; } @@ -581,6 +586,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 @@ -627,7 +634,11 @@ void UpdateManager::AddPropertyNotification(OwnerPointer& 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) @@ -786,9 +797,9 @@ bool UpdateManager::ProcessGestures(BufferIndex bufferIndex, uint32_t lastVSyncT bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) { bool animationActive = false; + bool animationLooped = false; - auto&& iter = mImpl->animations.Begin(); - bool animationLooped = false; + auto&& iter = mImpl->animations.Begin(); while(iter != mImpl->animations.End()) { @@ -802,12 +813,18 @@ bool UpdateManager::Animate(BufferIndex bufferIndex, float elapsedSeconds) 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 stoped or looped (to update loop count) + if(finished || looped) + { + mImpl->notifyRequiredAnimations.PushBack(animation->GetNotifyId()); + } + // Remove animations that had been destroyed but were still waiting for an update if(animation->GetState() == Animation::Destroyed) { @@ -819,11 +836,10 @@ 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; @@ -882,7 +898,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())); } } } @@ -1132,15 +1148,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(); @@ -1153,14 +1171,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)); } } } diff --git a/dali/internal/update/render-tasks/scene-graph-render-task.h b/dali/internal/update/render-tasks/scene-graph-render-task.h index 60b03ae..b54ffe1 100644 --- a/dali/internal/update/render-tasks/scene-graph-render-task.h +++ b/dali/internal/update/render-tasks/scene-graph-render-task.h @@ -19,6 +19,7 @@ */ // INTERNAL INCLUDES +#include #include #include #include @@ -46,7 +47,7 @@ class ResetterManager; /** * RenderTasks describe how the Dali scene should be rendered. */ -class RenderTask : public PropertyOwner, public PropertyOwner::Observer +class RenderTask : public PropertyOwner, public PropertyOwner::Observer, public NotifierInterface { public: enum State : uint8_t -- 2.7.4