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