Remove redundant Core::SendEvent() & NotificationEvent
[platform/core/uifw/dali-core.git] / dali / internal / update / queue / update-message-queue.cpp
1 //
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali/internal/update/queue/update-message-queue.h>
19
20 // EXTERNAL INCLUDES
21 #ifdef __clang__
22 #pragma clang diagnostic push
23 #pragma clang diagnostic ignored "-Wall"
24 #include <boost/thread/mutex.hpp>
25 #pragma clang diagnostic pop
26 #else
27 #include <boost/thread/mutex.hpp>
28 #endif // ifdef __clang
29
30 // INTERNAL INCLUDES
31 #include <dali/public-api/common/vector-wrapper.h>
32 #include <dali/integration-api/render-controller.h>
33 #include <dali/internal/common/message-buffer.h>
34 #include <dali/internal/render/common/performance-monitor.h>
35
36 using std::vector;
37
38 using Dali::Integration::RenderController;
39 using Dali::Internal::SceneGraph::SceneGraphBuffers;
40
41 namespace Dali
42 {
43
44 namespace Internal
45 {
46
47 namespace // unnamed namespace
48 {
49
50 // A message to set Actor::SIZE is 72 bytes on 32bit device
51 // A buffer of size 32768 would store (32768 - 4) / (72 + 4) = 431 of those messages
52 static const std::size_t INITIAL_BUFFER_SIZE =  32768;
53 static const std::size_t MAX_BUFFER_CAPACITY = 73728; // Avoid keeping buffers which exceed this
54 static const std::size_t MAX_FREE_BUFFER_COUNT = 3; // Allow this number of buffers to be recycled
55
56 // A queue of message buffers
57 typedef vector< MessageBuffer* > MessageBufferQueue;
58 typedef MessageBufferQueue::iterator MessageBufferIter;
59
60 typedef boost::mutex MessageQueueMutex;
61
62 } // unnamed namespace
63
64 namespace Update
65 {
66
67 /**
68  * Private MessageQueue data
69  */
70 struct MessageQueue::Impl
71 {
72   Impl( RenderController& controller, const SceneGraphBuffers& buffers )
73   : renderController(controller),
74     sceneGraphBuffers(buffers),
75     processingEvents(false),
76     queueWasEmpty(true),
77     sceneUpdateFlag( false ),
78     sceneUpdate( 0 ),
79     currentMessageBuffer(NULL)
80   {
81   }
82
83   ~Impl()
84   {
85     // Delete the current buffer
86     delete currentMessageBuffer;
87
88     // Delete the unprocessed buffers
89     const MessageBufferIter processQueueEndIter = processQueue.end();
90     for ( MessageBufferIter iter = processQueue.begin(); iter != processQueueEndIter; ++iter )
91     {
92       MessageBuffer* unprocessedBuffer = *iter;
93       DeleteBufferContents( unprocessedBuffer );
94       delete unprocessedBuffer;
95     }
96
97     // Delete the recycled buffers
98     const MessageBufferIter recycleQueueEndIter = recycleQueue.end();
99     for ( MessageBufferIter iter = recycleQueue.begin(); iter != recycleQueueEndIter; ++iter )
100     {
101       MessageBuffer* recycledBuffer = *iter;
102       DeleteBufferContents( recycledBuffer );
103       delete recycledBuffer;
104     }
105
106     const MessageBufferIter freeQueueEndIter = freeQueue.end();
107     for ( MessageBufferIter iter = freeQueue.begin(); iter != freeQueueEndIter; ++iter )
108     {
109       MessageBuffer* freeBuffer = *iter;
110       DeleteBufferContents( freeBuffer );
111       delete freeBuffer;
112     }
113   }
114
115   void DeleteBufferContents( MessageBuffer* buffer )
116   {
117     for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
118     {
119       MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
120
121       // Call virtual destructor explictly; since delete will not be called after placement new
122       message->~MessageBase();
123     }
124   }
125
126   RenderController&        renderController;     ///< render controller
127   const SceneGraphBuffers& sceneGraphBuffers;    ///< Used to keep track of which buffers are being written or read.
128
129   bool                     processingEvents;     ///< Whether messages queued will be flushed by core
130   bool                     queueWasEmpty;        ///< Flag whether the queue was empty during the Update()
131   bool                     sceneUpdateFlag;      ///< true when there is a new message that requires a scene-graph node tree update
132   int                      sceneUpdate;          ///< Non zero when there is a message in the queue requiring a scene-graph node tree update
133
134   MessageQueueMutex        queueMutex;           ///< queueMutex must be locked whilst accessing processQueue or recycleQueue
135   MessageBufferQueue       processQueue;         ///< to process in the next update
136   MessageBufferQueue       recycleQueue;         ///< to recycle MessageBuffers after the messages have been processed
137
138   MessageBuffer*           currentMessageBuffer; ///< can be used without locking
139   MessageBufferQueue       freeQueue;            ///< buffers from the recycleQueue; can be used without locking
140 };
141
142 MessageQueue::MessageQueue( RenderController& controller, const SceneGraphBuffers& buffers )
143 : mImpl(NULL)
144 {
145   mImpl = new Impl( controller, buffers );
146 }
147
148 MessageQueue::~MessageQueue()
149 {
150   delete mImpl;
151 }
152
153 void MessageQueue::EventProcessingStarted()
154 {
155   mImpl->processingEvents = true;
156 }
157
158 unsigned int* MessageQueue::ReserveMessageSlot( std::size_t requestedSize, bool updateScene )
159 {
160   DALI_ASSERT_DEBUG( 0 != requestedSize );
161
162   if( updateScene )
163   {
164     mImpl->sceneUpdateFlag = true;
165   }
166
167   if ( !mImpl->currentMessageBuffer )
168   {
169     const MessageBufferIter endIter = mImpl->freeQueue.end();
170
171     // Find the largest recycled buffer from freeQueue
172     MessageBufferIter nextBuffer = endIter;
173     for ( MessageBufferIter iter = mImpl->freeQueue.begin(); iter != endIter; ++iter )
174     {
175       if ( endIter == nextBuffer ||
176            (*nextBuffer)->GetCapacity() < (*iter)->GetCapacity() )
177       {
178         nextBuffer = iter;
179       }
180     }
181
182     if ( endIter != nextBuffer )
183     {
184       // Reuse a recycled buffer from freeQueue
185       mImpl->currentMessageBuffer = *nextBuffer;
186       mImpl->freeQueue.erase( nextBuffer );
187     }
188     else
189     {
190       mImpl->currentMessageBuffer = new MessageBuffer( INITIAL_BUFFER_SIZE );
191     }
192   }
193
194   // If we are inside Core::ProcessEvents(), core will automatically flush the queue.
195   // If we are outside, then we have to request a call to Core::ProcessEvents() on idle.
196   if ( false == mImpl->processingEvents )
197   {
198     mImpl->renderController.RequestProcessEventsOnIdle();
199   }
200
201   return mImpl->currentMessageBuffer->ReserveMessageSlot( requestedSize );
202 }
203
204 BufferIndex MessageQueue::GetEventBufferIndex() const
205 {
206   return mImpl->sceneGraphBuffers.GetEventBufferIndex();
207 }
208
209 bool MessageQueue::FlushQueue()
210 {
211   const bool messagesToProcess = ( NULL != mImpl->currentMessageBuffer );
212
213   // If there're messages to flush
214   if ( messagesToProcess )
215   {
216     // queueMutex must be locked whilst accessing processQueue or recycleQueue
217     MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
218
219     mImpl->processQueue.push_back( mImpl->currentMessageBuffer );
220     mImpl->currentMessageBuffer = NULL;
221
222     // Grab any recycled MessageBuffers
223     while ( !mImpl->recycleQueue.empty() )
224     {
225       MessageBuffer* recycled = mImpl->recycleQueue.back();
226       mImpl->recycleQueue.pop_back();
227
228       // Guard against excessive message buffer growth
229       if ( MAX_FREE_BUFFER_COUNT < mImpl->freeQueue.size() ||
230            MAX_BUFFER_CAPACITY   < recycled->GetCapacity() )
231       {
232         delete recycled;
233       }
234       else
235       {
236         mImpl->freeQueue.push_back( recycled );
237       }
238     }
239
240     if( mImpl->sceneUpdateFlag )
241     {
242       mImpl->sceneUpdate |= 2;
243       mImpl->sceneUpdateFlag = false;
244     }
245   }
246
247   mImpl->processingEvents = false;
248
249   return messagesToProcess;
250 }
251
252 void MessageQueue::ProcessMessages()
253 {
254   PERF_MONITOR_START(PerformanceMonitor::PROCESS_MESSAGES);
255
256   // queueMutex must be locked whilst accessing queue
257   MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
258
259   const MessageBufferIter processQueueEndIter = mImpl->processQueue.end();
260   for ( MessageBufferIter iter = mImpl->processQueue.begin(); iter != processQueueEndIter ; ++iter )
261   {
262     MessageBuffer* buffer = *iter;
263
264     for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
265     {
266       MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
267
268       message->Process( mImpl->sceneGraphBuffers.GetUpdateBufferIndex() );
269
270       // Call virtual destructor explictly; since delete will not be called after placement new
271       message->~MessageBase();
272     }
273     buffer->Reset();
274
275     // Pass back for use in the event-thread
276     mImpl->recycleQueue.push_back( buffer );
277
278     mImpl->sceneUpdate >>= 1;
279   }
280
281   mImpl->queueWasEmpty = mImpl->processQueue.empty(); // Flag whether we processed anything
282
283   mImpl->processQueue.clear();
284
285   PERF_MONITOR_END(PerformanceMonitor::PROCESS_MESSAGES);
286 }
287
288 bool MessageQueue::WasEmpty() const
289 {
290   return mImpl->queueWasEmpty;
291 }
292
293 bool MessageQueue::IsSceneUpdateRequired() const
294 {
295   return mImpl->sceneUpdate;
296 }
297
298 } // namespace Update
299
300 } // namespace Internal
301
302 } // namespace Dali