2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/common/notification-manager.h>
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>
39 typedef std::vector<std::pair<CompleteNotificationInterface*, CompleteNotificationInterface::ParameterList>> InterfaceContainer;
41 DALI_INIT_TRACE_FILTER(gTraceFilter, DALI_TRACE_PERFORMANCE_MARKER, false);
44 * helper to move elements from one container to another
45 * @param from where to move
46 * @param to move target
48 void MoveElements(InterfaceContainer& from, InterfaceContainer& to)
51 std::make_move_iterator(from.begin()),
52 std::make_move_iterator(from.end()));
57 using MessageQueueMutex = Dali::Mutex;
58 using MessageContainer = OwnerContainer<MessageBase*>;
60 struct NotificationManager::Impl
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);
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);
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;
90 NotificationManager::NotificationManager()
95 NotificationManager::~NotificationManager()
100 void NotificationManager::QueueNotification(CompleteNotificationInterface* instance, NotificationParameterList&& parameter)
102 // queueMutex must be locked whilst accessing queues
103 MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
105 mImpl->updateWorkingInterfaceQueue.emplace_back(instance, std::move(parameter));
108 void NotificationManager::QueueMessage(MessageBase* message)
110 DALI_ASSERT_DEBUG(NULL != message);
112 // queueMutex must be locked whilst accessing queues
113 MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
115 mImpl->updateWorkingMessageQueue.PushBack(message);
118 void NotificationManager::UpdateCompleted()
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);
127 // move pointers from interface queue
128 MoveElements(mImpl->updateWorkingInterfaceQueue, mImpl->updateCompletedInterfaceQueue);
130 // finally the lock is released
133 bool NotificationManager::MessagesToProcess()
135 // queueMutex must be locked whilst accessing queues
136 MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
138 return ((0u < mImpl->updateCompletedMessageQueue.Count()) ||
139 (0u < mImpl->updateCompletedInterfaceQueue.size()));
142 void NotificationManager::ProcessMessages()
144 // queueMutex must be locked whilst accessing queues
146 MessageQueueMutex::ScopedLock lock(mImpl->queueMutex);
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);
154 // end of scope, lock is released
156 MessageContainer::Iterator iter = mImpl->eventMessageQueue.Begin();
157 const MessageContainer::Iterator end = mImpl->eventMessageQueue.End();
160 DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_PROCESS_MESSAGE", [&](std::ostringstream& oss) {
161 oss << "[" << mImpl->eventMessageQueue.Count() << "]";
163 for(; iter != end; ++iter)
165 (*iter)->Process(0u /*ignored*/);
167 DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_PROCESS_MESSAGE", [&](std::ostringstream& oss) {
168 oss << "[" << mImpl->eventMessageQueue.Count() << "]";
171 // release the processed messages from event side queue
172 mImpl->eventMessageQueue.Clear();
174 InterfaceContainer::iterator iter2 = mImpl->eventInterfaceQueue.begin();
175 const InterfaceContainer::iterator end2 = mImpl->eventInterfaceQueue.end();
178 DALI_TRACE_BEGIN_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_NOTIFY_COMPLETED", [&](std::ostringstream& oss) {
179 oss << "[" << mImpl->eventInterfaceQueue.size() << "]";
181 for(; iter2 != end2; ++iter2)
183 CompleteNotificationInterface* interface = iter2->first;
186 interface->NotifyCompleted(std::move(iter2->second));
189 DALI_TRACE_END_WITH_MESSAGE_GENERATOR(gTraceFilter, "DALI_NOTIFICATION_NOTIFY_COMPLETED", [&](std::ostringstream& oss) {
190 oss << "[" << mImpl->eventInterfaceQueue.size() << "]";
193 // just clear the container, we dont own the objects
194 mImpl->eventInterfaceQueue.clear();
197 } // namespace Internal