Stop heap allocating messages from UpdateManager for Animation and RenderTask complet...
[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 // EXTERNAL INCLUDES
22 #ifdef __clang__
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wall"
25
26 #include <boost/thread/mutex.hpp>
27
28 #pragma clang diagnostic pop
29 #else
30
31 #include <boost/thread/mutex.hpp>
32
33 #endif // __clang__
34
35 // INTERNAL INCLUDES
36 #include <dali/public-api/common/dali-common.h>
37 #include <dali/internal/common/owner-container.h>
38 #include <dali/internal/common/message.h>
39 #include <dali/internal/event/common/property-notification-impl.h>
40 #include <dali/internal/event/common/complete-notification-interface.h>
41
42 namespace Dali
43 {
44
45 namespace Internal
46 {
47
48 namespace
49 {
50 typedef Dali::Vector< CompleteNotificationInterface* > InterfaceContainer;
51
52 /**
53  * helper to move elements from one container to another
54  * @param from where to move
55  * @param to move target
56  */
57 void MoveElements( InterfaceContainer& from, InterfaceContainer& to )
58 {
59   // check if there's something in from
60   const InterfaceContainer::SizeType fromCount = from.Count();
61   if( fromCount > 0u )
62   {
63     // check if to has some elements
64     const InterfaceContainer::SizeType toCount = to.Count();
65     if( toCount == 0u )
66     {
67       // to is empty so we can swap with from
68       to.Swap( from );
69     }
70     else
71     {
72       to.Reserve( toCount + fromCount );
73       for( InterfaceContainer::SizeType i = 0; i < fromCount; ++i )
74       {
75         to.PushBack( from[ i ] );
76       }
77       from.Clear();
78     }
79   }
80 }
81 }
82
83 typedef boost::mutex MessageQueueMutex;
84 typedef OwnerContainer< MessageBase* > MessageContainer;
85
86 struct NotificationManager::Impl
87 {
88   Impl()
89   {
90     // reserve space on the vectors to avoid reallocs
91     // applications typically have up-to 20-30 notifications at startup
92     updateCompletedMessageQueue.Reserve( 32 );
93     updateWorkingMessageQueue.Reserve( 32 );
94     eventMessageQueue.Reserve( 32 );
95
96     // only a few manager objects get complete notifications (animation, render list, property notifications, ...)
97     updateCompletedInterfaceQueue.Reserve( 4 );
98     updateWorkingInterfaceQueue.Reserve( 4 );
99     eventInterfaceQueue.Reserve( 4 );
100   }
101
102   ~Impl()
103   {
104   }
105
106   // queueMutex must be locked whilst accessing queue
107   MessageQueueMutex queueMutex;
108   // three queues for objects owned by notification manager
109   MessageContainer updateCompletedMessageQueue;
110   MessageContainer updateWorkingMessageQueue;
111   MessageContainer eventMessageQueue;
112   // three queues for objects referenced by notification manager
113   InterfaceContainer updateCompletedInterfaceQueue;
114   InterfaceContainer updateWorkingInterfaceQueue;
115   InterfaceContainer eventInterfaceQueue;
116 };
117
118 NotificationManager::NotificationManager()
119 {
120   mImpl = new Impl();
121 }
122
123 NotificationManager::~NotificationManager()
124 {
125   delete mImpl;
126 }
127
128 void NotificationManager::QueueCompleteNotification( CompleteNotificationInterface* instance )
129 {
130   // queueMutex must be locked whilst accessing queues
131   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
132
133   mImpl->updateWorkingInterfaceQueue.PushBack( instance );
134 }
135
136 void NotificationManager::QueueMessage( MessageBase* message )
137 {
138   DALI_ASSERT_DEBUG( NULL != message );
139
140   // queueMutex must be locked whilst accessing queues
141   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
142
143   mImpl->updateWorkingMessageQueue.PushBack( message );
144 }
145
146 void NotificationManager::UpdateCompleted()
147 {
148   // queueMutex must be locked whilst accessing queues
149   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
150   // Move messages from update working queue to completed queue
151   // note that in theory its possible for update completed to have last frames
152   // events as well still hanging around. we need to keep them as well
153   mImpl->updateCompletedMessageQueue.MoveFrom( mImpl->updateWorkingMessageQueue );
154   // move pointers from interface queue
155   MoveElements( mImpl->updateWorkingInterfaceQueue, mImpl->updateCompletedInterfaceQueue );
156   // finally the lock is released
157 }
158
159 bool NotificationManager::MessagesToProcess()
160 {
161   // queueMutex must be locked whilst accessing queues
162   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
163
164   return ( 0u < mImpl->updateCompletedMessageQueue.Count() ||
165          ( 0u < mImpl->updateCompletedInterfaceQueue.Count() ) );
166 }
167
168 void NotificationManager::ProcessMessages()
169 {
170   // queueMutex must be locked whilst accessing queues
171   {
172     MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
173
174     // Move messages from update completed queue to event queue
175     // note that in theory its possible for event queue to have
176     // last frames events as well still hanging around so need to keep them
177     mImpl->eventMessageQueue.MoveFrom( mImpl->updateCompletedMessageQueue );
178     MoveElements( mImpl->updateCompletedInterfaceQueue, mImpl->eventInterfaceQueue );
179   }
180   // end of scope, lock is released
181
182   MessageContainer::Iterator iter = mImpl->eventMessageQueue.Begin();
183   const MessageContainer::Iterator end = mImpl->eventMessageQueue.End();
184   for( ; iter != end; ++iter )
185   {
186     (*iter)->Process( 0u/*ignored*/ );
187   }
188   // release the processed messages from event side queue
189   mImpl->eventMessageQueue.Clear();
190
191   InterfaceContainer::Iterator iter2 = mImpl->eventInterfaceQueue.Begin();
192   const InterfaceContainer::Iterator end2 = mImpl->eventInterfaceQueue.End();
193   for( ; iter2 != end2; ++iter2 )
194   {
195     CompleteNotificationInterface* interface = *iter2;
196     if( interface )
197     {
198       interface->NotifyCompleted();
199     }
200   }
201   // just clear the container, we dont own the objects
202   mImpl->eventInterfaceQueue.Clear();
203 }
204
205 } // namespace Internal
206
207 } // namespace Dali