Fix some more of size_t and unsigned ints in DALi API
[platform/core/uifw/dali-core.git] / dali / internal / update / queue / update-message-queue.cpp
1 /*
2  * Copyright (c) 2018 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/internal/common/message.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 Dali::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     if( currentMessageBuffer )
80     {
81       DeleteBufferContents( currentMessageBuffer );
82       delete currentMessageBuffer;
83     }
84
85     // Delete the unprocessed buffers
86     const MessageBufferIter processQueueEndIter = processQueue.end();
87     for ( MessageBufferIter iter = processQueue.begin(); iter != processQueueEndIter; ++iter )
88     {
89       MessageBuffer* unprocessedBuffer = *iter;
90       DeleteBufferContents( unprocessedBuffer );
91       delete unprocessedBuffer;
92     }
93
94     // Delete the recycled buffers
95     const MessageBufferIter recycleQueueEndIter = recycleQueue.end();
96     for ( MessageBufferIter iter = recycleQueue.begin(); iter != recycleQueueEndIter; ++iter )
97     {
98       MessageBuffer* recycledBuffer = *iter;
99       DeleteBufferContents( recycledBuffer );
100       delete recycledBuffer;
101     }
102
103     const MessageBufferIter freeQueueEndIter = freeQueue.end();
104     for ( MessageBufferIter iter = freeQueue.begin(); iter != freeQueueEndIter; ++iter )
105     {
106       MessageBuffer* freeBuffer = *iter;
107       DeleteBufferContents( freeBuffer );
108       delete freeBuffer;
109     }
110   }
111
112   void DeleteBufferContents( MessageBuffer* buffer )
113   {
114     for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
115     {
116       MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
117
118       // Call virtual destructor explictly; since delete will not be called after placement new
119       message->~MessageBase();
120     }
121   }
122
123   RenderController&        renderController;     ///< render controller
124   const SceneGraphBuffers& sceneGraphBuffers;    ///< Used to keep track of which buffers are being written or read.
125
126   bool                     processingEvents;     ///< Whether messages queued will be flushed by core
127   bool                     queueWasEmpty;        ///< Flag whether the queue was empty during the Update()
128   bool                     sceneUpdateFlag;      ///< true when there is a new message that requires a scene-graph node tree update
129   int                      sceneUpdate;          ///< Non zero when there is a message in the queue requiring a scene-graph node tree update
130
131   MessageQueueMutex        queueMutex;           ///< queueMutex must be locked whilst accessing processQueue or recycleQueue
132   MessageBufferQueue       processQueue;         ///< to process in the next update
133   MessageBufferQueue       recycleQueue;         ///< to recycle MessageBuffers after the messages have been processed
134
135   MessageBuffer*           currentMessageBuffer; ///< can be used without locking
136   MessageBufferQueue       freeQueue;            ///< buffers from the recycleQueue; can be used without locking
137 };
138
139 MessageQueue::MessageQueue( Integration::RenderController& controller, const SceneGraph::SceneGraphBuffers& buffers )
140 : mImpl(NULL)
141 {
142   mImpl = new Impl( controller, buffers );
143 }
144
145 MessageQueue::~MessageQueue()
146 {
147   delete mImpl;
148 }
149
150 void MessageQueue::EventProcessingStarted()
151 {
152   mImpl->processingEvents = true; // called from event thread
153 }
154
155 // Called from event thread
156 uint32_t* MessageQueue::ReserveMessageSlot( uint32_t requestedSize, bool updateScene )
157 {
158   DALI_ASSERT_DEBUG( 0 != requestedSize );
159
160   if( updateScene )
161   {
162     mImpl->sceneUpdateFlag = true;
163   }
164
165   if ( !mImpl->currentMessageBuffer )
166   {
167     const MessageBufferIter endIter = mImpl->freeQueue.end();
168
169     // Find the largest recycled buffer from freeQueue
170     MessageBufferIter nextBuffer = endIter;
171     for ( MessageBufferIter iter = mImpl->freeQueue.begin(); iter != endIter; ++iter )
172     {
173       if ( endIter == nextBuffer ||
174            (*nextBuffer)->GetCapacity() < (*iter)->GetCapacity() )
175       {
176         nextBuffer = iter;
177       }
178     }
179
180     if ( endIter != nextBuffer )
181     {
182       // Reuse a recycled buffer from freeQueue
183       mImpl->currentMessageBuffer = *nextBuffer;
184       mImpl->freeQueue.erase( nextBuffer );
185     }
186     else
187     {
188       mImpl->currentMessageBuffer = new MessageBuffer( INITIAL_BUFFER_SIZE );
189     }
190   }
191
192   // If we are inside Core::ProcessEvents(), core will automatically flush the queue.
193   // If we are outside, then we have to request a call to Core::ProcessEvents() on idle.
194   if ( false == mImpl->processingEvents )
195   {
196     mImpl->renderController.RequestProcessEventsOnIdle( false );
197   }
198
199   return mImpl->currentMessageBuffer->ReserveMessageSlot( requestedSize );
200 }
201
202 // Called from event thread
203 bool MessageQueue::FlushQueue()
204 {
205   const bool messagesToProcess = ( NULL != mImpl->currentMessageBuffer );
206
207   // If there're messages to flush
208   if ( messagesToProcess )
209   {
210     // queueMutex must be locked whilst accessing processQueue or recycleQueue
211     MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
212
213     mImpl->processQueue.push_back( mImpl->currentMessageBuffer );
214     mImpl->currentMessageBuffer = NULL;
215
216     // Grab any recycled MessageBuffers
217     while ( !mImpl->recycleQueue.empty() )
218     {
219       MessageBuffer* recycled = mImpl->recycleQueue.back();
220       mImpl->recycleQueue.pop_back();
221
222       // Guard against excessive message buffer growth
223       if ( MAX_FREE_BUFFER_COUNT < mImpl->freeQueue.size() ||
224            MAX_BUFFER_CAPACITY   < recycled->GetCapacity() )
225       {
226         delete recycled;
227       }
228       else
229       {
230         mImpl->freeQueue.push_back( recycled );
231       }
232     }
233
234     if( mImpl->sceneUpdateFlag )
235     {
236       mImpl->sceneUpdate |= 2;
237       mImpl->sceneUpdateFlag = false;
238     }
239   }
240
241   mImpl->processingEvents = false;
242
243   return messagesToProcess;
244 }
245
246 bool MessageQueue::ProcessMessages( BufferIndex updateBufferIndex )
247 {
248   PERF_MONITOR_START(PerformanceMonitor::PROCESS_MESSAGES);
249
250   // queueMutex must be locked whilst accessing queue
251   MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
252
253   const MessageBufferIter processQueueEndIter = mImpl->processQueue.end();
254   for ( MessageBufferIter iter = mImpl->processQueue.begin(); iter != processQueueEndIter ; ++iter )
255   {
256     MessageBuffer* buffer = *iter;
257
258     for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
259     {
260       MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
261
262       message->Process( updateBufferIndex  );
263
264       // Call virtual destructor explictly; since delete will not be called after placement new
265       message->~MessageBase();
266     }
267     buffer->Reset();
268
269     // Pass back for use in the event-thread
270     mImpl->recycleQueue.push_back( buffer );
271   }
272
273   mImpl->sceneUpdate >>= 1;
274
275   mImpl->queueWasEmpty = mImpl->processQueue.empty(); // Flag whether we processed anything
276
277   mImpl->processQueue.clear();
278
279   PERF_MONITOR_END(PerformanceMonitor::PROCESS_MESSAGES);
280
281   return ( mImpl->sceneUpdate & 0x01 ); // if it was previously 2, scene graph was updated.
282 }
283
284 bool MessageQueue::WasEmpty() const
285 {
286   return mImpl->queueWasEmpty;
287 }
288
289 bool MessageQueue::IsSceneUpdateRequired() const
290 {
291   return mImpl->sceneUpdate;
292 }
293
294 } // namespace Update
295
296 } // namespace Internal
297
298 } // namespace Dali