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