Add trace log to NotificationManager::ProcessMessages
[platform/core/uifw/dali-core.git] / dali / internal / event / common / notification-manager.cpp
index dbebbec..828586a 100644 (file)
 // CLASS HEADER
 #include <dali/internal/event/common/notification-manager.h>
 
-// EXTERNAL INCLUDES
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wall"
-
-#include <boost/thread/mutex.hpp>
-
-#pragma clang diagnostic pop
-#else
-
-#include <boost/thread/mutex.hpp>
-
-#endif // __clang__
-
 // INTERNAL INCLUDES
-#include <dali/public-api/common/dali-common.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/trace.h>
+#include <dali/internal/common/message.h>
+#include <dali/internal/event/common/complete-notification-interface.h>
 #include <dali/internal/event/common/property-notification-impl.h>
-#include <dali/internal/common/message-container.h>
-
-using namespace std;
+#include <dali/public-api/common/dali-common.h>
 
 namespace Dali
 {
-
 namespace Internal
 {
+namespace
+{
+typedef Dali::Vector<CompleteNotificationInterface*> InterfaceContainer;
 
-typedef boost::mutex MessageQueueMutex;
+DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
 
-struct NotificationManager::Impl
+/**
+ * helper to move elements from one container to another
+ * @param from where to move
+ * @param to move target
+ */
+void MoveElements(InterfaceContainer& from, InterfaceContainer& to)
 {
-  Impl()
-  : notificationCount(0)
+  // 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();
+    }
   }
+}
+} // namespace
 
-  ~Impl()
+using MessageQueueMutex = Dali::Mutex;
+using MessageContainer  = OwnerContainer<MessageBase*>;
+
+struct NotificationManager::Impl
+{
+  Impl()
   {
+    // reserve space on the vectors to avoid reallocs
+    // applications typically have up-to 20-30 notifications at startup
+    updateCompletedMessageQueue.Reserve(32);
+    updateWorkingMessageQueue.Reserve(32);
+    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);
   }
 
-  // Used to skip duplicate operations during Notify()
-  unsigned int notificationCount;
+  ~Impl() = default;
 
   // queueMutex must be locked whilst accessing queue
   MessageQueueMutex queueMutex;
-  MessageContainer updateCompletedQueue;
-  MessageContainer updateWorkingQueue;
-  MessageContainer eventQueue;
+  // three queues for objects owned by notification manager
+  MessageContainer updateCompletedMessageQueue;
+  MessageContainer updateWorkingMessageQueue;
+  MessageContainer eventMessageQueue;
+  // three queues for objects referenced by notification manager
+  InterfaceContainer updateCompletedInterfaceQueue;
+  InterfaceContainer updateWorkingInterfaceQueue;
+  InterfaceContainer eventInterfaceQueue;
 };
 
 NotificationManager::NotificationManager()
@@ -78,60 +112,91 @@ NotificationManager::~NotificationManager()
   delete mImpl;
 }
 
-void NotificationManager::QueueMessage( MessageBase* message )
+void NotificationManager::QueueCompleteNotification(CompleteNotificationInterface* instance)
 {
-  DALI_ASSERT_DEBUG( NULL != message );
+  // queueMutex must be locked whilst accessing queues
+  MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
 
-  // queueMutex must be locked whilst accessing queue
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+  mImpl->updateWorkingInterfaceQueue.PushBack(instance);
+}
 
-  mImpl->updateWorkingQueue.PushBack( message );
+void NotificationManager::QueueMessage(MessageBase* message)
+{
+  DALI_ASSERT_DEBUG(NULL != message);
+
+  // queueMutex must be locked whilst accessing queues
+  MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
+
+  mImpl->updateWorkingMessageQueue.PushBack(message);
 }
 
 void NotificationManager::UpdateCompleted()
 {
-  // queueMutex must be locked whilst accessing queue
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
-  // Swap the queue, original queue ends up empty, then release the lock
-  mImpl->updateCompletedQueue.Swap( mImpl->updateWorkingQueue );
+  // queueMutex must be locked whilst accessing queues
+  MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
+  // Move messages from update working queue to completed queue
+  // 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
 }
 
 bool NotificationManager::MessagesToProcess()
 {
-  // queueMutex must be locked whilst accessing queue
-  MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+  // queueMutex must be locked whilst accessing queues
+  MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
 
-  return ( false == mImpl->updateCompletedQueue.IsEmpty() );
+  return (0u < mImpl->updateCompletedMessageQueue.Count() ||
+          (0u < mImpl->updateCompletedInterfaceQueue.Count()));
 }
 
 void NotificationManager::ProcessMessages()
 {
-  // Done before messages are processed, for notification count comparisons
-  ++mImpl->notificationCount;
-
-  // queueMutex must be locked whilst accessing queue
+  // queueMutex must be locked whilst accessing queues
   {
-    MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
+    MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
 
-    // Swap the queue, original queue ends up empty, then release the lock
-    mImpl->updateCompletedQueue.Swap( mImpl->eventQueue );
+    // Move messages from update completed queue to event queue
+    // note that in theory its possible for event queue to have
+    // last frames events as well still hanging around so need to keep them
+    mImpl->eventMessageQueue.MoveFrom(mImpl->updateCompletedMessageQueue);
+    MoveElements(mImpl->updateCompletedInterfaceQueue, mImpl->eventInterfaceQueue);
   }
   // end of scope, lock is released
 
-  MessageContainer::Iterator iter = mImpl->eventQueue.Begin();
-  MessageContainer::Iterator end = mImpl->eventQueue.End();
-  for( ; iter != end; ++iter )
+  MessageContainer::Iterator       iter = mImpl->eventMessageQueue.Begin();
+  const MessageContainer::Iterator end  = mImpl->eventMessageQueue.End();
+  if(iter != end)
   {
-    (*iter)->Process( 0u/*ignored*/ );
+    DALI_TRACE_BEGIN(gTraceFilter, "DALI_NOTIFICATION_PROCESS_MESSAGE");
+    for(; iter != end; ++iter)
+    {
+      (*iter)->Process(0u /*ignored*/);
+    }
+    DALI_TRACE_END(gTraceFilter, "DALI_NOTIFICATION_PROCESS_MESSAGE");
   }
-
   // release the processed messages from event side queue
-  mImpl->eventQueue.Clear();
-}
+  mImpl->eventMessageQueue.Clear();
 
-unsigned int NotificationManager::GetNotificationCount() const
-{
-  return mImpl->notificationCount;
+  InterfaceContainer::Iterator       iter2 = mImpl->eventInterfaceQueue.Begin();
+  const InterfaceContainer::Iterator end2  = mImpl->eventInterfaceQueue.End();
+  if(iter2 != end2)
+  {
+    DALI_TRACE_BEGIN(gTraceFilter, "DALI_NOTIFICATION_NOTIFY_COMPLETED");
+    for(; iter2 != end2; ++iter2)
+    {
+      CompleteNotificationInterface* interface = *iter2;
+      if(interface)
+      {
+        interface->NotifyCompleted();
+      }
+    }
+    DALI_TRACE_END(gTraceFilter, "DALI_NOTIFICATION_NOTIFY_COMPLETED");
+  }
+  // just clear the container, we dont own the objects
+  mImpl->eventInterfaceQueue.Clear();
 }
 
 } // namespace Internal