[dali_2.3.25] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / dali / internal / event / common / notification-manager.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/common/notification-manager.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/devel-api/common/owner-container.h>
23 #include <dali/devel-api/threading/mutex.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/integration-api/trace.h>
26 #include <dali/internal/common/message.h>
27 #include <dali/internal/event/common/complete-notification-interface.h>
28 #include <dali/internal/event/common/notifier-interface.h>
29 #include <dali/internal/event/common/property-notification-impl.h>
30 #include <dali/public-api/common/dali-common.h>
31 #include <dali/public-api/common/vector-wrapper.h>
32
33 namespace Dali
34 {
35 namespace Internal
36 {
37 namespace
38 {
39 typedef std::vector<std::pair<CompleteNotificationInterface*, CompleteNotificationInterface::ParameterList>> InterfaceContainer;
40
41 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
42
43 /**
44  * helper to move elements from one container to another
45  * @param from where to move
46  * @param to move target
47  */
48 void MoveElements(InterfaceContainer& from, InterfaceContainer& to)
49 {
50   to.insert(to.end(),
51             std::make_move_iterator(from.begin()),
52             std::make_move_iterator(from.end()));
53   from.clear();
54 }
55 } // namespace
56
57 using MessageQueueMutex = Dali::Mutex;
58 using MessageContainer  = OwnerContainer<MessageBase*>;
59
60 struct NotificationManager::Impl
61 {
62   Impl()
63   {
64     // reserve space on the vectors to avoid reallocs
65     // applications typically have up-to 20-30 notifications at startup
66     updateCompletedMessageQueue.Reserve(32);
67     updateWorkingMessageQueue.Reserve(32);
68     eventMessageQueue.Reserve(32);
69
70     // only a few manager objects get complete notifications (animation, render list, property notifications, ...)
71     updateCompletedInterfaceQueue.reserve(4);
72     updateWorkingInterfaceQueue.reserve(4);
73     eventInterfaceQueue.reserve(4);
74   }
75
76   ~Impl() = default;
77
78   // queueMutex must be locked whilst accessing queue
79   MessageQueueMutex queueMutex;
80   // three queues for objects owned by notification manager
81   MessageContainer updateCompletedMessageQueue;
82   MessageContainer updateWorkingMessageQueue;
83   MessageContainer eventMessageQueue;
84   // three queues for objects referenced by notification manager
85   InterfaceContainer updateCompletedInterfaceQueue;
86   InterfaceContainer updateWorkingInterfaceQueue;
87   InterfaceContainer eventInterfaceQueue;
88 };
89
90 NotificationManager::NotificationManager()
91 {
92   mImpl = new Impl();
93 }
94
95 NotificationManager::~NotificationManager()
96 {
97   delete mImpl;
98 }
99
100 void NotificationManager::QueueNotification(CompleteNotificationInterface* instance, NotificationParameterList&& parameter)
101 {
102   // queueMutex must be locked whilst accessing queues
103   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
104
105   mImpl->updateWorkingInterfaceQueue.emplace_back(instance, std::move(parameter));
106 }
107
108 void NotificationManager::QueueMessage(MessageBase* message)
109 {
110   DALI_ASSERT_DEBUG(NULL != message);
111
112   // queueMutex must be locked whilst accessing queues
113   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
114
115   mImpl->updateWorkingMessageQueue.PushBack(message);
116 }
117
118 void NotificationManager::UpdateCompleted()
119 {
120   // queueMutex must be locked whilst accessing queues
121   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
122   // Move messages from update working queue to completed queue
123   // note that in theory its possible for update completed to have last frames
124   // events as well still hanging around. we need to keep them as well
125   mImpl->updateCompletedMessageQueue.MoveFrom(mImpl->updateWorkingMessageQueue);
126
127   // move pointers from interface queue
128   MoveElements(mImpl->updateWorkingInterfaceQueue, mImpl->updateCompletedInterfaceQueue);
129
130   // finally the lock is released
131 }
132
133 bool NotificationManager::MessagesToProcess()
134 {
135   // queueMutex must be locked whilst accessing queues
136   MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
137
138   return ((0u < mImpl->updateCompletedMessageQueue.Count()) ||
139           (0u < mImpl->updateCompletedInterfaceQueue.size()));
140 }
141
142 void NotificationManager::ProcessMessages()
143 {
144   // queueMutex must be locked whilst accessing queues
145   {
146     MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
147
148     // Move messages from update completed queue to event queue
149     // note that in theory its possible for event queue to have
150     // last frames events as well still hanging around so need to keep them
151     mImpl->eventMessageQueue.MoveFrom(mImpl->updateCompletedMessageQueue);
152     MoveElements(mImpl->updateCompletedInterfaceQueue, mImpl->eventInterfaceQueue);
153   }
154   // end of scope, lock is released
155
156   MessageContainer::Iterator       iter = mImpl->eventMessageQueue.Begin();
157   const MessageContainer::Iterator end  = mImpl->eventMessageQueue.End();
158   if(iter != end)
159   {
160     DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_PROCESS_MESSAGE", [&](std::ostringstream& oss) {
161       oss << "[" << mImpl->eventMessageQueue.Count() << "]";
162     });
163     for(; iter != end; ++iter)
164     {
165       (*iter)->Process(0u /*ignored*/);
166     }
167     DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_PROCESS_MESSAGE", [&](std::ostringstream& oss) {
168       oss << "[" << mImpl->eventMessageQueue.Count() << "]";
169     });
170   }
171   // release the processed messages from event side queue
172   mImpl->eventMessageQueue.Clear();
173
174   InterfaceContainer::iterator       iter2 = mImpl->eventInterfaceQueue.begin();
175   const InterfaceContainer::iterator end2  = mImpl->eventInterfaceQueue.end();
176   if(iter2 != end2)
177   {
178     DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_NOTIFY_COMPLETED", [&](std::ostringstream& oss) {
179       oss << "[" << mImpl->eventInterfaceQueue.size() << "]";
180     });
181     for(; iter2 != end2; ++iter2)
182     {
183       CompleteNotificationInterface* interface = iter2->first;
184       if(interface)
185       {
186         interface->NotifyCompleted(std::move(iter2->second));
187       }
188     }
189     DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_NOTIFY_COMPLETED", [&](std::ostringstream& oss) {
190       oss << "[" << mImpl->eventInterfaceQueue.size() << "]";
191     });
192   }
193   // just clear the container, we dont own the objects
194   mImpl->eventInterfaceQueue.clear();
195 }
196
197 } // namespace Internal
198
199 } // namespace Dali