2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 // http://floralicense.org/license/
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.
18 #include <dali/internal/update/queue/update-message-queue.h>
22 #pragma clang diagnostic push
23 #pragma clang diagnostic ignored "-Wall"
24 #include <boost/thread/mutex.hpp>
25 #pragma clang diagnostic pop
27 #include <boost/thread/mutex.hpp>
28 #endif // ifdef __clang
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>
38 using Dali::Integration::RenderController;
39 using Dali::Internal::SceneGraph::SceneGraphBuffers;
47 namespace // unnamed namespace
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
56 // A queue of message buffers
57 typedef vector< MessageBuffer* > MessageBufferQueue;
58 typedef MessageBufferQueue::iterator MessageBufferIter;
60 typedef boost::mutex MessageQueueMutex;
62 } // unnamed namespace
68 * Private MessageQueue data
70 struct MessageQueue::Impl
72 Impl( RenderController& controller, const SceneGraphBuffers& buffers )
73 : renderController(controller),
74 sceneGraphBuffers(buffers),
75 processingEvents(false),
77 sceneUpdateFlag( false ),
79 currentMessageBuffer(NULL)
85 // Delete the current buffer
86 delete currentMessageBuffer;
88 // Delete the unprocessed buffers
89 const MessageBufferIter processQueueEndIter = processQueue.end();
90 for ( MessageBufferIter iter = processQueue.begin(); iter != processQueueEndIter; ++iter )
92 MessageBuffer* unprocessedBuffer = *iter;
93 DeleteBufferContents( unprocessedBuffer );
94 delete unprocessedBuffer;
97 // Delete the recycled buffers
98 const MessageBufferIter recycleQueueEndIter = recycleQueue.end();
99 for ( MessageBufferIter iter = recycleQueue.begin(); iter != recycleQueueEndIter; ++iter )
101 MessageBuffer* recycledBuffer = *iter;
102 DeleteBufferContents( recycledBuffer );
103 delete recycledBuffer;
106 const MessageBufferIter freeQueueEndIter = freeQueue.end();
107 for ( MessageBufferIter iter = freeQueue.begin(); iter != freeQueueEndIter; ++iter )
109 MessageBuffer* freeBuffer = *iter;
110 DeleteBufferContents( freeBuffer );
115 void DeleteBufferContents( MessageBuffer* buffer )
117 for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
119 MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
121 // Call virtual destructor explictly; since delete will not be called after placement new
122 message->~MessageBase();
126 RenderController& renderController; ///< render controller
127 const SceneGraphBuffers& sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read.
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
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
138 MessageBuffer* currentMessageBuffer; ///< can be used without locking
139 MessageBufferQueue freeQueue; ///< buffers from the recycleQueue; can be used without locking
142 MessageQueue::MessageQueue( RenderController& controller, const SceneGraphBuffers& buffers )
145 mImpl = new Impl( controller, buffers );
148 MessageQueue::~MessageQueue()
153 void MessageQueue::EventProcessingStarted()
155 mImpl->processingEvents = true;
158 unsigned int* MessageQueue::ReserveMessageSlot( std::size_t requestedSize, bool updateScene )
160 DALI_ASSERT_DEBUG( 0 != requestedSize );
164 mImpl->sceneUpdateFlag = true;
167 if ( !mImpl->currentMessageBuffer )
169 const MessageBufferIter endIter = mImpl->freeQueue.end();
171 // Find the largest recycled buffer from freeQueue
172 MessageBufferIter nextBuffer = endIter;
173 for ( MessageBufferIter iter = mImpl->freeQueue.begin(); iter != endIter; ++iter )
175 if ( endIter == nextBuffer ||
176 (*nextBuffer)->GetCapacity() < (*iter)->GetCapacity() )
182 if ( endIter != nextBuffer )
184 // Reuse a recycled buffer from freeQueue
185 mImpl->currentMessageBuffer = *nextBuffer;
186 mImpl->freeQueue.erase( nextBuffer );
190 mImpl->currentMessageBuffer = new MessageBuffer( INITIAL_BUFFER_SIZE );
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 )
198 mImpl->renderController.RequestProcessEventsOnIdle();
201 return mImpl->currentMessageBuffer->ReserveMessageSlot( requestedSize );
204 BufferIndex MessageQueue::GetEventBufferIndex() const
206 return mImpl->sceneGraphBuffers.GetEventBufferIndex();
209 bool MessageQueue::FlushQueue()
211 const bool messagesToProcess = ( NULL != mImpl->currentMessageBuffer );
213 // If there're messages to flush
214 if ( messagesToProcess )
216 // queueMutex must be locked whilst accessing processQueue or recycleQueue
217 MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
219 mImpl->processQueue.push_back( mImpl->currentMessageBuffer );
220 mImpl->currentMessageBuffer = NULL;
222 // Grab any recycled MessageBuffers
223 while ( !mImpl->recycleQueue.empty() )
225 MessageBuffer* recycled = mImpl->recycleQueue.back();
226 mImpl->recycleQueue.pop_back();
228 // Guard against excessive message buffer growth
229 if ( MAX_FREE_BUFFER_COUNT < mImpl->freeQueue.size() ||
230 MAX_BUFFER_CAPACITY < recycled->GetCapacity() )
236 mImpl->freeQueue.push_back( recycled );
240 if( mImpl->sceneUpdateFlag )
242 mImpl->sceneUpdate |= 2;
243 mImpl->sceneUpdateFlag = false;
247 mImpl->processingEvents = false;
249 return messagesToProcess;
252 void MessageQueue::ProcessMessages()
254 PERF_MONITOR_START(PerformanceMonitor::PROCESS_MESSAGES);
256 // queueMutex must be locked whilst accessing queue
257 MessageQueueMutex::scoped_lock lock( mImpl->queueMutex );
259 const MessageBufferIter processQueueEndIter = mImpl->processQueue.end();
260 for ( MessageBufferIter iter = mImpl->processQueue.begin(); iter != processQueueEndIter ; ++iter )
262 MessageBuffer* buffer = *iter;
264 for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
266 MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
268 message->Process( mImpl->sceneGraphBuffers.GetUpdateBufferIndex() );
270 // Call virtual destructor explictly; since delete will not be called after placement new
271 message->~MessageBase();
275 // Pass back for use in the event-thread
276 mImpl->recycleQueue.push_back( buffer );
279 mImpl->sceneUpdate >>= 1;
281 mImpl->queueWasEmpty = mImpl->processQueue.empty(); // Flag whether we processed anything
283 mImpl->processQueue.clear();
285 PERF_MONITOR_END(PerformanceMonitor::PROCESS_MESSAGES);
288 bool MessageQueue::WasEmpty() const
290 return mImpl->queueWasEmpty;
293 bool MessageQueue::IsSceneUpdateRequired() const
295 return mImpl->sceneUpdate;
298 } // namespace Update
300 } // namespace Internal