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