2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/update/queue/update-message-queue.h>
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>
31 using Dali::Integration::RenderController;
32 using Dali::Internal::SceneGraph::SceneGraphBuffers;
40 namespace // unnamed namespace
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
49 // A queue of message buffers
50 typedef vector< MessageBuffer* > MessageBufferQueue;
51 using MessageBufferIter = MessageBufferQueue::iterator;
53 using MessageQueueMutex = Dali::Mutex;
55 } // unnamed namespace
61 * Private MessageQueue data
63 struct MessageQueue::Impl
65 Impl( RenderController& controller, const SceneGraphBuffers& buffers )
66 : renderController(controller),
67 sceneGraphBuffers(buffers),
68 processingEvents(false),
70 sceneUpdateFlag( false ),
72 currentMessageBuffer(nullptr)
78 // Delete the current buffer
79 if( currentMessageBuffer )
81 DeleteBufferContents( currentMessageBuffer );
82 delete currentMessageBuffer;
85 // Delete the unprocessed buffers
86 const MessageBufferIter processQueueEndIter = processQueue.end();
87 for ( MessageBufferIter iter = processQueue.begin(); iter != processQueueEndIter; ++iter )
89 MessageBuffer* unprocessedBuffer = *iter;
90 DeleteBufferContents( unprocessedBuffer );
91 delete unprocessedBuffer;
94 // Delete the recycled buffers
95 const MessageBufferIter recycleQueueEndIter = recycleQueue.end();
96 for ( MessageBufferIter iter = recycleQueue.begin(); iter != recycleQueueEndIter; ++iter )
98 MessageBuffer* recycledBuffer = *iter;
99 DeleteBufferContents( recycledBuffer );
100 delete recycledBuffer;
103 const MessageBufferIter freeQueueEndIter = freeQueue.end();
104 for ( MessageBufferIter iter = freeQueue.begin(); iter != freeQueueEndIter; ++iter )
106 MessageBuffer* freeBuffer = *iter;
107 DeleteBufferContents( freeBuffer );
112 void DeleteBufferContents( MessageBuffer* buffer )
114 for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
116 MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
118 // Call virtual destructor explictly; since delete will not be called after placement new
119 message->~MessageBase();
123 RenderController& renderController; ///< render controller
124 const SceneGraphBuffers& sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read.
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
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
135 MessageBuffer* currentMessageBuffer; ///< can be used without locking
136 MessageBufferQueue freeQueue; ///< buffers from the recycleQueue; can be used without locking
139 MessageQueue::MessageQueue( Integration::RenderController& controller, const SceneGraph::SceneGraphBuffers& buffers )
142 mImpl = new Impl( controller, buffers );
145 MessageQueue::~MessageQueue()
150 void MessageQueue::EventProcessingStarted()
152 mImpl->processingEvents = true; // called from event thread
155 // Called from event thread
156 uint32_t* MessageQueue::ReserveMessageSlot( uint32_t requestedSize, bool updateScene )
158 DALI_ASSERT_DEBUG( 0 != requestedSize );
162 mImpl->sceneUpdateFlag = true;
165 if ( !mImpl->currentMessageBuffer )
167 const MessageBufferIter endIter = mImpl->freeQueue.end();
169 // Find the largest recycled buffer from freeQueue
170 MessageBufferIter nextBuffer = endIter;
171 for ( MessageBufferIter iter = mImpl->freeQueue.begin(); iter != endIter; ++iter )
173 if ( endIter == nextBuffer ||
174 (*nextBuffer)->GetCapacity() < (*iter)->GetCapacity() )
180 if ( endIter != nextBuffer )
182 // Reuse a recycled buffer from freeQueue
183 mImpl->currentMessageBuffer = *nextBuffer;
184 mImpl->freeQueue.erase( nextBuffer );
188 mImpl->currentMessageBuffer = new MessageBuffer( INITIAL_BUFFER_SIZE );
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 )
196 mImpl->renderController.RequestProcessEventsOnIdle( false );
199 return mImpl->currentMessageBuffer->ReserveMessageSlot( requestedSize );
202 // Called from event thread
203 bool MessageQueue::FlushQueue()
205 const bool messagesToProcess = ( nullptr != mImpl->currentMessageBuffer );
207 // If there're messages to flush
208 if ( messagesToProcess )
210 // queueMutex must be locked whilst accessing processQueue or recycleQueue
211 MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
213 mImpl->processQueue.push_back( mImpl->currentMessageBuffer );
214 mImpl->currentMessageBuffer = nullptr;
216 // Grab any recycled MessageBuffers
217 while ( !mImpl->recycleQueue.empty() )
219 MessageBuffer* recycled = mImpl->recycleQueue.back();
220 mImpl->recycleQueue.pop_back();
222 // Guard against excessive message buffer growth
223 if ( MAX_FREE_BUFFER_COUNT < mImpl->freeQueue.size() ||
224 MAX_BUFFER_CAPACITY < recycled->GetCapacity() )
230 mImpl->freeQueue.push_back( recycled );
234 if( mImpl->sceneUpdateFlag )
236 mImpl->sceneUpdate |= 2;
237 mImpl->sceneUpdateFlag = false;
241 mImpl->processingEvents = false;
243 return messagesToProcess;
246 bool MessageQueue::ProcessMessages( BufferIndex updateBufferIndex )
248 PERF_MONITOR_START(PerformanceMonitor::PROCESS_MESSAGES);
250 // queueMutex must be locked whilst accessing queue
251 MessageQueueMutex::ScopedLock lock( mImpl->queueMutex );
253 const MessageBufferIter processQueueEndIter = mImpl->processQueue.end();
254 for ( MessageBufferIter iter = mImpl->processQueue.begin(); iter != processQueueEndIter ; ++iter )
256 MessageBuffer* buffer = *iter;
258 for( MessageBuffer::Iterator iter = buffer->Begin(); iter.IsValid(); iter.Next() )
260 MessageBase* message = reinterpret_cast< MessageBase* >( iter.Get() );
262 message->Process( updateBufferIndex );
264 // Call virtual destructor explictly; since delete will not be called after placement new
265 message->~MessageBase();
269 // Pass back for use in the event-thread
270 mImpl->recycleQueue.push_back( buffer );
273 mImpl->sceneUpdate >>= 1;
275 mImpl->queueWasEmpty = mImpl->processQueue.empty(); // Flag whether we processed anything
277 mImpl->processQueue.clear();
279 PERF_MONITOR_END(PerformanceMonitor::PROCESS_MESSAGES);
281 return ( mImpl->sceneUpdate & 0x01 ); // if it was previously 2, scene graph was updated.
284 bool MessageQueue::WasEmpty() const
286 return mImpl->queueWasEmpty;
289 bool MessageQueue::IsSceneUpdateRequired() const
291 return mImpl->sceneUpdate;
294 } // namespace Update
296 } // namespace Internal