2 * Copyright (c) 2015 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/manager/update-manager.h>
22 #include <dali/public-api/common/stage.h>
23 #include <dali/devel-api/common/set-wrapper.h>
24 #include <dali/devel-api/common/owner-container.h>
25 #include <dali/devel-api/threading/mutex.h>
27 #include <dali/integration-api/core.h>
28 #include <dali/integration-api/render-controller.h>
29 #include <dali/internal/common/shader-data.h>
30 #include <dali/integration-api/debug.h>
32 #include <dali/internal/common/core-impl.h>
33 #include <dali/internal/common/message.h>
35 #include <dali/internal/event/common/notification-manager.h>
36 #include <dali/internal/event/common/property-notification-impl.h>
37 #include <dali/internal/event/common/property-notifier.h>
38 #include <dali/internal/event/effects/shader-factory.h>
40 #include <dali/internal/update/animation/scene-graph-animator.h>
41 #include <dali/internal/update/animation/scene-graph-animation.h>
42 #include <dali/internal/update/common/discard-queue.h>
43 #include <dali/internal/update/common/scene-graph-buffers.h>
44 #include <dali/internal/update/controllers/render-message-dispatcher.h>
45 #include <dali/internal/update/controllers/scene-controller-impl.h>
46 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
47 #include <dali/internal/update/manager/object-owner-container.h>
48 #include <dali/internal/update/manager/prepare-render-algorithms.h>
49 #include <dali/internal/update/manager/process-render-tasks.h>
50 #include <dali/internal/update/manager/sorted-layers.h>
51 #include <dali/internal/update/manager/update-algorithms.h>
52 #include <dali/internal/update/manager/update-manager-debug.h>
53 #include <dali/internal/update/node-attachments/scene-graph-camera-attachment.h>
54 #include <dali/internal/update/node-attachments/scene-graph-image-attachment.h>
55 #include <dali/internal/update/nodes/node.h>
56 #include <dali/internal/update/nodes/scene-graph-layer.h>
57 #include <dali/internal/update/queue/update-message-queue.h>
58 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
59 #include <dali/internal/update/render-tasks/scene-graph-render-task-list.h>
60 #include <dali/internal/update/rendering/scene-graph-material.h>
61 #include <dali/internal/update/rendering/scene-graph-geometry.h>
62 #include <dali/internal/update/resources/resource-manager.h>
63 #include <dali/internal/update/resources/complete-status-manager.h>
64 #include <dali/internal/update/touch/touch-resampler.h>
66 #include <dali/internal/render/common/render-instruction-container.h>
67 #include <dali/internal/render/common/render-manager.h>
68 #include <dali/internal/render/queue/render-queue.h>
69 #include <dali/internal/render/common/performance-monitor.h>
70 #include <dali/internal/render/gl-resources/texture-cache.h>
71 #include <dali/internal/render/shaders/scene-graph-shader.h>
72 #include <dali/internal/render/renderers/render-sampler.h>
74 // Un-comment to enable node tree debug logging
75 //#define NODE_TREE_LOGGING 1
77 #if ( defined( DEBUG_ENABLED ) && defined( NODE_TREE_LOGGING ) )
78 #define SNAPSHOT_NODE_LOGGING \
79 const int FRAME_COUNT_TRIGGER = 16;\
80 if( mImpl->frameCounter >= FRAME_COUNT_TRIGGER )\
82 if ( NULL != mImpl->root )\
84 mImpl->frameCounter = 0;\
85 PrintNodeTree( *mImpl->root, mSceneGraphBuffers.GetUpdateBufferIndex(), "" );\
88 mImpl->frameCounter++;
90 #define SNAPSHOT_NODE_LOGGING
93 #if defined(DEBUG_ENABLED)
94 extern Debug::Filter* gRenderTaskLogFilter;
98 using namespace Dali::Integration;
99 using Dali::Internal::Update::MessageQueue;
113 void DestroyNodeSet( std::set<Node*>& nodeSet )
115 for( std::set<Node*>::iterator iter = nodeSet.begin(); iter != nodeSet.end(); ++iter )
119 // Call Node::OnDestroy as each node is destroyed
129 typedef OwnerContainer< Shader* > ShaderContainer;
130 typedef ShaderContainer::Iterator ShaderIter;
131 typedef ShaderContainer::ConstIterator ShaderConstIter;
133 typedef std::vector<Internal::ShaderDataPtr> ShaderDataBinaryQueue;
135 typedef OwnerContainer<PanGesture*> GestureContainer;
136 typedef GestureContainer::Iterator GestureIter;
137 typedef GestureContainer::ConstIterator GestureConstIter;
141 * Structure to contain UpdateManager internal data
143 struct UpdateManager::Impl
145 Impl( NotificationManager& notificationManager,
146 GlSyncAbstraction& glSyncAbstraction,
147 CompleteNotificationInterface& animationFinishedNotifier,
148 PropertyNotifier& propertyNotifier,
149 ResourceManager& resourceManager,
150 DiscardQueue& discardQueue,
151 RenderController& renderController,
152 RenderManager& renderManager,
153 RenderQueue& renderQueue,
154 TextureCache& textureCache,
155 TouchResampler& touchResampler,
156 SceneGraphBuffers& sceneGraphBuffers )
158 renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
159 notificationManager( notificationManager ),
160 animationFinishedNotifier( animationFinishedNotifier ),
161 propertyNotifier( propertyNotifier ),
163 resourceManager( resourceManager ),
164 discardQueue( discardQueue ),
165 renderController( renderController ),
166 sceneController( NULL ),
167 renderManager( renderManager ),
168 renderQueue( renderQueue ),
169 renderInstructions( renderManager.GetRenderInstructionContainer() ),
170 completeStatusManager( glSyncAbstraction, renderMessageDispatcher, resourceManager ),
171 touchResampler( touchResampler ),
172 backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
173 taskList ( completeStatusManager ),
174 systemLevelTaskList ( completeStatusManager ),
176 systemLevelRoot( NULL ),
177 renderers( sceneGraphBuffers, discardQueue ),
178 geometries( sceneGraphBuffers, discardQueue ),
179 materials( sceneGraphBuffers, discardQueue ),
180 messageQueue( renderController, sceneGraphBuffers ),
181 keepRenderingSeconds( 0.0f ),
182 animationFinishedDuringUpdate( false ),
183 nodeDirtyFlags( TransformFlag ), // set to TransformFlag to ensure full update the first time through Update()
184 previousUpdateScene( false ),
186 renderSortingHelper(),
187 renderTaskWaiting( false )
189 sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue, textureCache, completeStatusManager );
191 renderers.SetSceneController( *sceneController );
192 geometries.SetSceneController( *sceneController );
193 materials.SetSceneController( *sceneController );
198 // Disconnect render tasks from nodes, before destroying the nodes
199 RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
200 for (RenderTaskList::RenderTaskContainer::Iterator iter = tasks.Begin(); iter != tasks.End(); ++iter)
202 (*iter)->SetSourceNode( NULL );
204 // ..repeat for system level RenderTasks
205 RenderTaskList::RenderTaskContainer& systemLevelTasks = systemLevelTaskList.GetTasks();
206 for (RenderTaskList::RenderTaskContainer::Iterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter)
208 (*iter)->SetSourceNode( NULL );
211 // UpdateManager owns the Nodes
212 DestroyNodeSet( activeDisconnectedNodes );
213 DestroyNodeSet( connectedNodes );
214 DestroyNodeSet( disconnectedNodes );
216 // If there is root, reset it, otherwise do nothing as rendering was never started
225 if( systemLevelRoot )
227 systemLevelRoot->OnDestroy();
229 delete systemLevelRoot;
230 systemLevelRoot = NULL;
233 sceneController->GetTextureCache().SetBufferIndices(NULL); // TODO - Remove
234 delete sceneController;
237 SceneGraphBuffers sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read
238 RenderMessageDispatcher renderMessageDispatcher; ///< Used for passing messages to the render-thread
239 NotificationManager& notificationManager; ///< Queues notification messages for the event-thread.
240 CompleteNotificationInterface& animationFinishedNotifier; ///< Provides notification to applications when animations are finished.
241 PropertyNotifier& propertyNotifier; ///< Provides notification to applications when properties are modified.
242 ShaderSaver* shaderSaver; ///< Saves shader binaries.
243 ResourceManager& resourceManager; ///< resource manager
244 DiscardQueue& discardQueue; ///< Nodes are added here when disconnected from the scene-graph.
245 RenderController& renderController; ///< render controller
246 SceneControllerImpl* sceneController; ///< scene controller
247 RenderManager& renderManager; ///< This is responsible for rendering the results of each "update"
248 RenderQueue& renderQueue; ///< Used to queue messages for the next render
249 RenderInstructionContainer& renderInstructions; ///< Used to prepare the render instructions
250 CompleteStatusManager completeStatusManager; ///< Complete Status Manager
251 TouchResampler& touchResampler; ///< Used to resample touch events on every update.
253 Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
255 RenderTaskList taskList; ///< The list of scene graph render-tasks
256 RenderTaskList systemLevelTaskList; ///< Separate render-tasks for system-level content
258 Layer* root; ///< The root node (root is a layer)
259 Layer* systemLevelRoot; ///< A separate root-node for system-level content
260 std::set< Node* > activeDisconnectedNodes; ///< A container of new or modified nodes (without parent) owned by UpdateManager
261 std::set< Node* > connectedNodes; ///< A container of connected (with parent) nodes owned by UpdateManager
262 std::set< Node* > disconnectedNodes; ///< A container of inactive disconnected nodes (without parent) owned by UpdateManager
264 SortedLayerPointers sortedLayers; ///< A container of Layer pointers sorted by depth
265 SortedLayerPointers systemLevelSortedLayers; ///< A separate container of system-level Layers
267 OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties)
269 AnimationContainer animations; ///< A container of owned animations
270 PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
272 ObjectOwnerContainer<Renderer> renderers;
273 ObjectOwnerContainer<Geometry> geometries; ///< A container of geometries
274 ObjectOwnerContainer<Material> materials; ///< A container of materials
276 ShaderContainer shaders; ///< A container of owned shaders
278 MessageQueue messageQueue; ///< The messages queued from the event-thread
279 ShaderDataBinaryQueue renderCompiledShaders; ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread.
280 ShaderDataBinaryQueue updateCompiledShaders; ///< Shaders to be sent from Update to Event
281 Mutex compiledShaderMutex; ///< lock to ensure no corruption on the renderCompiledShaders
283 float keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering
284 bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
286 int nodeDirtyFlags; ///< cumulative node dirty flags from previous frame
287 bool previousUpdateScene; ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
289 int frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
290 RendererSortingHelper renderSortingHelper; ///< helper used to sort transparent renderers
292 GestureContainer gestures; ///< A container of owned gesture detectors
293 bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered
296 UpdateManager::UpdateManager( NotificationManager& notificationManager,
297 GlSyncAbstraction& glSyncAbstraction,
298 CompleteNotificationInterface& animationFinishedNotifier,
299 PropertyNotifier& propertyNotifier,
300 ResourceManager& resourceManager,
301 DiscardQueue& discardQueue,
302 RenderController& controller,
303 RenderManager& renderManager,
304 RenderQueue& renderQueue,
305 TextureCache& textureCache,
306 TouchResampler& touchResampler )
309 mImpl = new Impl( notificationManager,
311 animationFinishedNotifier,
320 mSceneGraphBuffers );
322 textureCache.SetBufferIndices( &mSceneGraphBuffers );
325 UpdateManager::~UpdateManager()
330 void UpdateManager::InstallRoot( SceneGraph::Layer* layer, bool systemLevel )
332 DALI_ASSERT_DEBUG( layer->IsLayer() );
333 DALI_ASSERT_DEBUG( layer->GetParent() == NULL);
337 DALI_ASSERT_DEBUG( mImpl->root == NULL && "Root Node already installed" );
342 DALI_ASSERT_DEBUG( mImpl->systemLevelRoot == NULL && "System-level Root Node already installed" );
343 mImpl->systemLevelRoot = layer;
346 layer->SetRoot(true);
349 void UpdateManager::AddNode( Node* node )
351 DALI_ASSERT_ALWAYS( NULL != node );
352 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
354 mImpl->activeDisconnectedNodes.insert( node ); // Takes ownership of node
357 void UpdateManager::ConnectNode( Node* parent, Node* node )
359 DALI_ASSERT_ALWAYS( NULL != parent );
360 DALI_ASSERT_ALWAYS( NULL != node );
361 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
363 // Move from active/disconnectedNodes to connectedNodes
364 std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
367 removed = mImpl->disconnectedNodes.erase( node );
368 DALI_ASSERT_ALWAYS( removed );
370 mImpl->connectedNodes.insert( node );
372 node->SetActive( true );
374 parent->ConnectChild( node );
377 void UpdateManager::DisconnectNode( Node* node )
379 Node* parent = node->GetParent();
380 DALI_ASSERT_ALWAYS( NULL != parent );
381 parent->SetDirtyFlag( ChildDeletedFlag ); // make parent dirty so that render items dont get reused
383 // Move from connectedNodes to activeDisconnectedNodes (reset properties next frame)
384 parent->DisconnectChild( mSceneGraphBuffers.GetUpdateBufferIndex(), *node, mImpl->connectedNodes, mImpl->activeDisconnectedNodes );
387 void UpdateManager::SetNodeActive( Node* node )
389 DALI_ASSERT_ALWAYS( NULL != node );
390 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
392 // Move from disconnectedNodes to activeDisconnectedNodes (reset properties next frame)
393 std::set<Node*>::size_type removed = mImpl->disconnectedNodes.erase( node );
394 DALI_ASSERT_ALWAYS( removed );
395 mImpl->activeDisconnectedNodes.insert( node );
397 node->SetActive( true );
400 void UpdateManager::DestroyNode( Node* node )
402 DALI_ASSERT_ALWAYS( NULL != node );
403 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should have been disconnected
405 // Transfer ownership from new/disconnectedNodes to the discard queue
406 // This keeps the nodes alive, until the render-thread has finished with them
407 std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
410 removed = mImpl->disconnectedNodes.erase( node );
411 DALI_ASSERT_ALWAYS( removed );
413 mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), node );
415 // Notify the Node about impending destruction
419 //@todo MESH_REWORK Extend to allow arbitrary scene objects to connect to each other
420 void UpdateManager::AttachToNode( Node* node, NodeAttachment* attachment )
422 DALI_ASSERT_DEBUG( node != NULL );
423 DALI_ASSERT_DEBUG( attachment != NULL );
425 // attach node to attachment first so that parent is known by the time attachment is connected
426 node->Attach( *attachment ); // node takes ownership
428 // @todo MESH_REWORK Remove after merge of SceneGraph::RenderableAttachment and SceneGraph::RendererAttachment
429 if( dynamic_cast<SceneGraph::ImageAttachment*>( attachment ) != NULL )
431 attachment->Initialize( *mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex() );
435 void UpdateManager::AddObject( PropertyOwner* object )
437 DALI_ASSERT_DEBUG( NULL != object );
439 mImpl->customObjects.PushBack( object );
442 void UpdateManager::RemoveObject( PropertyOwner* object )
444 DALI_ASSERT_DEBUG( NULL != object );
446 OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
448 // Find the object and destroy it
449 for ( OwnerContainer< PropertyOwner* >::Iterator iter = customObjects.Begin(); iter != customObjects.End(); ++iter )
451 PropertyOwner* current = *iter;
452 if ( current == object )
454 customObjects.Erase( iter );
459 // Should not reach here
460 DALI_ASSERT_DEBUG(false);
463 void UpdateManager::AddAnimation( Animation* animation )
465 mImpl->animations.PushBack( animation );
468 void UpdateManager::StopAnimation( Animation* animation )
470 DALI_ASSERT_DEBUG( animation && "NULL animation called to stop" );
472 bool animationFinished = animation->Stop( mSceneGraphBuffers.GetUpdateBufferIndex() );
474 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || animationFinished;
477 void UpdateManager::RemoveAnimation( Animation* animation )
479 DALI_ASSERT_DEBUG( animation && "NULL animation called to remove" );
481 animation->OnDestroy( mSceneGraphBuffers.GetUpdateBufferIndex() );
483 DALI_ASSERT_DEBUG( animation->GetState() == Animation::Destroyed );
486 bool UpdateManager::IsAnimationRunning() const
488 bool isRunning(false);
489 AnimationContainer& animations = mImpl->animations;
491 // Find any animation that isn't stopped or paused
493 const AnimationIter endIter = animations.End();
494 for ( AnimationIter iter = animations.Begin(); !isRunning && iter != endIter; ++iter )
496 const Animation::State state = (*iter)->GetState();
498 if (state != Animation::Stopped &&
499 state != Animation::Paused)
508 void UpdateManager::AddPropertyNotification( PropertyNotification* propertyNotification )
510 mImpl->propertyNotifications.PushBack( propertyNotification );
513 void UpdateManager::RemovePropertyNotification( PropertyNotification* propertyNotification )
515 PropertyNotificationContainer &propertyNotifications = mImpl->propertyNotifications;
516 PropertyNotificationIter iter = propertyNotifications.Begin();
518 while ( iter != propertyNotifications.End() )
520 if( *iter == propertyNotification )
522 propertyNotifications.Erase(iter);
529 void UpdateManager::PropertyNotificationSetNotify( PropertyNotification* propertyNotification, PropertyNotification::NotifyMode notifyMode )
531 DALI_ASSERT_DEBUG( propertyNotification && "propertyNotification scene graph object missing" );
532 propertyNotification->SetNotifyMode( notifyMode );
535 ObjectOwnerContainer<Geometry>& UpdateManager::GetGeometryOwner()
537 return mImpl->geometries;
540 ObjectOwnerContainer<Renderer>& UpdateManager::GetRendererOwner()
542 return mImpl->renderers;
546 ObjectOwnerContainer<Material>& UpdateManager::GetMaterialOwner()
548 return mImpl->materials;
551 void UpdateManager::AddShader( Shader* shader )
553 DALI_ASSERT_DEBUG( NULL != shader );
555 if( mImpl->shaders.Count() == 0 )
557 // the first added shader becomes our default shader
558 // Construct message in the render queue memory; note that delete should not be called on the return value
559 typedef MessageValue1< RenderManager, Shader* > DerivedType;
561 // Reserve some memory inside the render queue
562 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
564 // Construct message in the render queue memory; note that delete should not be called on the return value
565 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetDefaultShader, shader );
568 mImpl->shaders.PushBack( shader );
570 // Allows the shader to dispatch texture requests to the cache
571 shader->Initialize( mImpl->renderQueue, mImpl->sceneController->GetTextureCache() );
574 void UpdateManager::RemoveShader( Shader* shader )
576 DALI_ASSERT_DEBUG(shader != NULL);
578 ShaderContainer& shaders = mImpl->shaders;
580 // Find the shader and destroy it
581 for ( ShaderIter iter = shaders.Begin(); iter != shaders.End(); ++iter )
583 Shader& current = **iter;
584 if ( ¤t == shader )
586 // Transfer ownership to the discard queue
587 // This keeps the shader alive, until the render-thread has finished with it
588 mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), shaders.Release( iter ) );
593 // Should not reach here
594 DALI_ASSERT_DEBUG(false);
597 void UpdateManager::SetShaderProgram( Shader* shader,
598 Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
603 typedef MessageValue3< Shader, Internal::ShaderDataPtr, ProgramCache*, bool> DerivedType;
605 // Reserve some memory inside the render queue
606 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
608 // Construct message in the render queue memory; note that delete should not be called on the return value
609 new (slot) DerivedType( shader, &Shader::SetProgram, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
613 void UpdateManager::SaveBinary( Internal::ShaderDataPtr shaderData )
615 DALI_ASSERT_DEBUG( shaderData && "No NULL shader data pointers please." );
616 DALI_ASSERT_DEBUG( shaderData->GetBufferSize() > 0 && "Shader binary empty so nothing to save." );
618 // lock as update might be sending previously compiled shaders to event thread
619 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
620 mImpl->renderCompiledShaders.push_back( shaderData );
624 RenderTaskList* UpdateManager::GetRenderTaskList( bool systemLevel )
628 // copy the list, this is only likely to happen once in application life cycle
629 return &(mImpl->taskList);
633 // copy the list, this is only likely to happen once in application life cycle
634 return &(mImpl->systemLevelTaskList);
638 void UpdateManager::AddGesture( PanGesture* gesture )
640 DALI_ASSERT_DEBUG( NULL != gesture );
642 mImpl->gestures.PushBack( gesture );
645 void UpdateManager::RemoveGesture( PanGesture* gesture )
647 DALI_ASSERT_DEBUG( gesture != NULL );
649 GestureContainer& gestures = mImpl->gestures;
651 // Find the gesture and destroy it
652 for ( GestureIter iter = gestures.Begin(), endIter = gestures.End(); iter != endIter; ++iter )
654 PanGesture& current = **iter;
655 if ( ¤t == gesture )
657 mImpl->gestures.Erase( iter );
661 // Should not reach here
662 DALI_ASSERT_DEBUG(false);
665 unsigned int* UpdateManager::ReserveMessageSlot( std::size_t size, bool updateScene )
667 return mImpl->messageQueue.ReserveMessageSlot( size, updateScene );
670 void UpdateManager::EventProcessingStarted()
672 mImpl->messageQueue.EventProcessingStarted();
675 bool UpdateManager::FlushQueue()
677 return mImpl->messageQueue.FlushQueue();
680 void UpdateManager::ResetProperties( BufferIndex bufferIndex )
682 PERF_MONITOR_START(PerformanceMonitor::RESET_PROPERTIES);
684 // Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped
685 mImpl->animationFinishedDuringUpdate = false;
687 // Animated properties have to be reset to their original value each frame
689 // Reset root properties
692 mImpl->root->ResetToBaseValues( bufferIndex );
694 if ( mImpl->systemLevelRoot )
696 mImpl->systemLevelRoot->ResetToBaseValues( bufferIndex );
699 // Reset the Connected Nodes
700 const std::set<Node*>::iterator endIter = mImpl->connectedNodes.end();
701 for( std::set<Node*>::iterator iter = mImpl->connectedNodes.begin(); endIter != iter; ++iter )
703 (*iter)->ResetToBaseValues( bufferIndex );
706 // If a Node is disconnected, it may still be "active" (requires a reset in next frame)
707 for( std::set<Node*>::iterator iter = mImpl->activeDisconnectedNodes.begin(); mImpl->activeDisconnectedNodes.end() != iter; iter = mImpl->activeDisconnectedNodes.begin() )
710 node->ResetToBaseValues( bufferIndex );
711 node->SetActive( false );
713 // Move everything from activeDisconnectedNodes to disconnectedNodes (no need to reset again)
714 mImpl->activeDisconnectedNodes.erase( iter );
715 mImpl->disconnectedNodes.insert( node );
718 // Reset system-level render-task list properties to base values
719 const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
721 for (RenderTaskList::RenderTaskContainer::ConstIterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter)
723 (*iter)->ResetToBaseValues( bufferIndex );
726 // Reset render-task list properties to base values.
727 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
729 for (RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(); iter != tasks.End(); ++iter)
731 (*iter)->ResetToBaseValues( bufferIndex );
734 // Reset custom object properties to base values
735 for (OwnerContainer<PropertyOwner*>::Iterator iter = mImpl->customObjects.Begin(); iter != mImpl->customObjects.End(); ++iter)
737 (*iter)->ResetToBaseValues( bufferIndex );
740 mImpl->materials.ResetToBaseValues( bufferIndex );
741 mImpl->geometries.ResetToBaseValues( bufferIndex );
742 mImpl->renderers.ResetToBaseValues( bufferIndex );
745 // Reset animatable shader properties to base values
746 for (ShaderIter iter = mImpl->shaders.Begin(); iter != mImpl->shaders.End(); ++iter)
748 (*iter)->ResetToBaseValues( bufferIndex );
751 PERF_MONITOR_END(PerformanceMonitor::RESET_PROPERTIES);
754 bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
756 bool gestureUpdated( false );
758 // constrain gestures... (in construction order)
759 GestureContainer& gestures = mImpl->gestures;
761 for ( GestureIter iter = gestures.Begin(), endIter = gestures.End(); iter != endIter; ++iter )
763 PanGesture& gesture = **iter;
764 gesture.ResetToBaseValues( bufferIndex ); // Needs to be done every time as gesture data is written directly to an update-buffer rather than via a message
765 gestureUpdated |= gesture.UpdateProperties( lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
768 return gestureUpdated;
771 void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
773 PERF_MONITOR_START(PerformanceMonitor::ANIMATE_NODES);
775 AnimationContainer &animations = mImpl->animations;
776 AnimationIter iter = animations.Begin();
777 while ( iter != animations.End() )
779 Animation* animation = *iter;
780 bool finished = animation->Update( bufferIndex, elapsedSeconds );
782 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
784 // Remove animations that had been destroyed but were still waiting for an update
785 if (animation->GetState() == Animation::Destroyed)
787 iter = animations.Erase(iter);
795 if ( mImpl->animationFinishedDuringUpdate )
797 // The application should be notified by NotificationManager, in another thread
798 mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationFinishedNotifier );
801 PERF_MONITOR_END(PerformanceMonitor::ANIMATE_NODES);
804 void UpdateManager::ApplyConstraints( BufferIndex bufferIndex )
806 PERF_MONITOR_START(PerformanceMonitor::APPLY_CONSTRAINTS);
808 // constrain custom objects... (in construction order)
809 OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
811 const OwnerContainer< PropertyOwner* >::Iterator endIter = customObjects.End();
812 for ( OwnerContainer< PropertyOwner* >::Iterator iter = customObjects.Begin(); endIter != iter; ++iter )
814 PropertyOwner& object = **iter;
815 ConstrainPropertyOwner( object, bufferIndex );
818 // constrain nodes... (in Depth First traversal order)
821 ConstrainNodes( *(mImpl->root), bufferIndex );
824 if ( mImpl->systemLevelRoot )
826 ConstrainNodes( *(mImpl->systemLevelRoot), bufferIndex );
829 // constrain other property-owners after nodes as they are more likely to depend on a node's
830 // current frame property than vice versa. They tend to be final constraints (no further
831 // constraints depend on their properties)
832 // e.g. ShaderEffect uniform a function of Actor's position.
833 // Mesh vertex a function of Actor's position or world position.
835 // TODO: refactor this code (and reset nodes) as these are all just lists of property-owners
836 // they can be all processed in a super-list of property-owners.
838 // Constrain system-level render-tasks
839 const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
841 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter )
843 RenderTask& task = **iter;
844 ConstrainPropertyOwner( task, bufferIndex );
847 // Constrain render-tasks
848 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
850 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(); iter != tasks.End(); ++iter )
852 RenderTask& task = **iter;
853 ConstrainPropertyOwner( task, bufferIndex );
856 // Constrain Materials and geometries
857 mImpl->materials.ConstrainObjects( bufferIndex );
858 mImpl->geometries.ConstrainObjects( bufferIndex );
859 mImpl->renderers.ConstrainObjects( bufferIndex );
861 // constrain shaders... (in construction order)
862 ShaderContainer& shaders = mImpl->shaders;
864 for ( ShaderIter iter = shaders.Begin(); iter != shaders.End(); ++iter )
866 Shader& shader = **iter;
867 ConstrainPropertyOwner( shader, bufferIndex );
870 PERF_MONITOR_END(PerformanceMonitor::APPLY_CONSTRAINTS);
873 void UpdateManager::ProcessPropertyNotifications( BufferIndex bufferIndex )
875 PropertyNotificationContainer ¬ifications = mImpl->propertyNotifications;
876 PropertyNotificationIter iter = notifications.Begin();
878 while ( iter != notifications.End() )
880 PropertyNotification* notification = *iter;
881 bool valid = notification->Check( bufferIndex );
884 mImpl->notificationManager.QueueMessage( PropertyChangedMessage( mImpl->propertyNotifier, notification, notification->GetValidity() ) );
890 void UpdateManager::ForwardCompiledShadersToEventThread()
892 DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." );
893 if( mImpl->shaderSaver )
895 // lock and swap the queues
897 // render might be attempting to send us more binaries at the same time
898 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
899 mImpl->renderCompiledShaders.swap( mImpl->updateCompiledShaders );
902 if( mImpl->updateCompiledShaders.size() > 0 )
904 ShaderSaver& factory = *mImpl->shaderSaver;
905 ShaderDataBinaryQueue::iterator i = mImpl->updateCompiledShaders.begin();
906 ShaderDataBinaryQueue::iterator end = mImpl->updateCompiledShaders.end();
907 for( ; i != end; ++i )
909 mImpl->notificationManager.QueueMessage( ShaderCompiledMessage( factory, *i ) );
911 // we don't need them in update anymore
912 mImpl->updateCompiledShaders.clear();
917 void UpdateManager::UpdateRenderers( BufferIndex bufferIndex )
919 const OwnerContainer<Renderer*>& rendererContainer( mImpl->renderers.GetObjectContainer() );
920 unsigned int rendererCount( rendererContainer.Size() );
921 for( unsigned int i(0); i<rendererCount; ++i )
923 if( rendererContainer[i]->IsReferenced() )
925 rendererContainer[i]->PrepareResources(bufferIndex, mImpl->resourceManager);
926 rendererContainer[i]->PrepareRender( bufferIndex );
931 void UpdateManager::UpdateNodes( BufferIndex bufferIndex )
933 mImpl->nodeDirtyFlags = NothingFlag;
940 PERF_MONITOR_START( PerformanceMonitor::UPDATE_NODES );
942 // Prepare resources, update shaders, update attachments, for each node
943 // And add the renderers to the sorted layers. Start from root, which is also a layer
944 mImpl->nodeDirtyFlags = UpdateNodesAndAttachments( *( mImpl->root ),
946 mImpl->resourceManager,
947 mImpl->renderQueue );
949 if ( mImpl->systemLevelRoot )
951 mImpl->nodeDirtyFlags |= UpdateNodesAndAttachments( *( mImpl->systemLevelRoot ),
953 mImpl->resourceManager,
954 mImpl->renderQueue );
957 PERF_MONITOR_END( PerformanceMonitor::UPDATE_NODES );
960 unsigned int UpdateManager::Update( float elapsedSeconds,
961 unsigned int lastVSyncTimeMilliseconds,
962 unsigned int nextVSyncTimeMilliseconds )
964 PERF_MONITOR_END(PerformanceMonitor::FRAME_RATE); // Mark the End of the last frame
965 PERF_MONITOR_NEXT_FRAME(); // Prints out performance info for the last frame (if enabled)
966 PERF_MONITOR_START(PerformanceMonitor::FRAME_RATE); // Mark the start of this current frame
968 // Measure the time spent in UpdateManager::Update
969 PERF_MONITOR_START(PerformanceMonitor::UPDATE);
971 const BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
973 // 1) Clear nodes/resources which were previously discarded
974 mImpl->discardQueue.Clear( bufferIndex );
976 // 2) Grab any loaded resources
977 bool resourceChanged = mImpl->resourceManager.UpdateCache( bufferIndex );
979 // 3) Process Touches & Gestures
980 mImpl->touchResampler.Update();
981 const bool gestureUpdated = ProcessGestures( bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
983 const bool updateScene = // The scene-graph requires an update if..
984 (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || // ..nodes were dirty in previous frame OR
985 IsAnimationRunning() || // ..at least one animation is running OR
986 mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR
987 resourceChanged || // ..one or more resources were updated/changed OR
988 gestureUpdated; // ..a gesture property was updated
991 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
992 // values if the scene was updated in the previous frame.
993 if( updateScene || mImpl->previousUpdateScene )
995 // 4) Reset properties from the previous update
996 ResetProperties( bufferIndex );
999 // 5) Process the queued scene messages
1000 mImpl->messageQueue.ProcessMessages( bufferIndex );
1002 // 6) Post Process Ids of resources updated by renderer
1003 mImpl->resourceManager.PostProcessResources( bufferIndex );
1005 // 6.1) Forward compiled shader programs to event thread for saving
1006 ForwardCompiledShadersToEventThread();
1008 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
1009 // renderer lists if the scene was updated in the previous frame.
1010 // We should not start skipping update steps or reusing lists until there has been two frames where nothing changes
1011 if( updateScene || mImpl->previousUpdateScene )
1014 Animate( bufferIndex, elapsedSeconds );
1016 // 8) Apply Constraints
1017 ApplyConstraints( bufferIndex );
1019 // 9) Check Property Notifications
1020 ProcessPropertyNotifications( bufferIndex );
1022 // 10) Clear the lists of renderable-attachments from the previous update
1023 ClearRenderables( mImpl->sortedLayers );
1024 ClearRenderables( mImpl->systemLevelSortedLayers );
1026 // 11) Update node hierarchy and perform sorting / culling.
1027 // This will populate each Layer with a list of renderers which are ready.
1028 UpdateNodes( bufferIndex );
1029 UpdateRenderers( bufferIndex );
1032 // 12) Prepare for the next render
1033 PERF_MONITOR_START(PerformanceMonitor::PREPARE_RENDERABLES);
1035 PrepareRenderables( bufferIndex, mImpl->sortedLayers );
1036 PrepareRenderables( bufferIndex, mImpl->systemLevelSortedLayers );
1037 PERF_MONITOR_END(PerformanceMonitor::PREPARE_RENDERABLES);
1039 PERF_MONITOR_START(PerformanceMonitor::PROCESS_RENDER_TASKS);
1041 // 14) Process the RenderTasks; this creates the instructions for rendering the next frame.
1042 // reset the update buffer index and make sure there is enough room in the instruction container
1043 mImpl->renderInstructions.ResetAndReserve( bufferIndex,
1044 mImpl->taskList.GetTasks().Count() + mImpl->systemLevelTaskList.GetTasks().Count() );
1046 if ( NULL != mImpl->root )
1048 ProcessRenderTasks( bufferIndex,
1049 mImpl->completeStatusManager,
1052 mImpl->sortedLayers,
1053 mImpl->renderSortingHelper,
1054 mImpl->renderInstructions );
1056 // Process the system-level RenderTasks last
1057 if ( NULL != mImpl->systemLevelRoot )
1059 ProcessRenderTasks( bufferIndex,
1060 mImpl->completeStatusManager,
1061 mImpl->systemLevelTaskList,
1062 *mImpl->systemLevelRoot,
1063 mImpl->systemLevelSortedLayers,
1064 mImpl->renderSortingHelper,
1065 mImpl->renderInstructions );
1070 // check the countdown and notify (note, at the moment this is only done for normal tasks, not for systemlevel tasks)
1071 bool doRenderOnceNotify = false;
1072 mImpl->renderTaskWaiting = false;
1073 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
1074 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(), endIter = tasks.End();
1075 endIter != iter; ++iter )
1077 RenderTask& renderTask(*(*iter));
1079 renderTask.UpdateState();
1081 if( renderTask.IsWaitingToRender() &&
1082 renderTask.ReadyToRender( bufferIndex ) /*avoid updating forever when source actor is off-stage*/ )
1084 mImpl->renderTaskWaiting = true; // keep update/render threads alive
1087 if( renderTask.HasRendered() )
1089 doRenderOnceNotify = true;
1093 if( doRenderOnceNotify )
1095 DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
1096 mImpl->notificationManager.QueueCompleteNotification( mImpl->taskList.GetCompleteNotificationInterface() );
1099 PERF_MONITOR_END(PerformanceMonitor::PROCESS_RENDER_TASKS);
1101 // Macro is undefined in release build.
1102 SNAPSHOT_NODE_LOGGING;
1104 // A ResetProperties() may be required in the next frame
1105 mImpl->previousUpdateScene = updateScene;
1107 // Check whether further updates are required
1108 unsigned int keepUpdating = KeepUpdatingCheck( elapsedSeconds );
1110 #ifdef PERFORMANCE_MONITOR_ENABLED
1111 // Always keep rendering when measuring FPS
1112 keepUpdating |= KeepUpdating::MONITORING_PERFORMANCE;
1115 // tell the update manager that we're done so the queue can be given to event thread
1116 mImpl->notificationManager.UpdateCompleted();
1118 // The update has finished; swap the double-buffering indices
1119 mSceneGraphBuffers.Swap();
1121 PERF_MONITOR_END(PerformanceMonitor::UPDATE);
1123 return keepUpdating;
1126 unsigned int UpdateManager::KeepUpdatingCheck( float elapsedSeconds ) const
1128 // Update the duration set via Stage::KeepRendering()
1129 if ( mImpl->keepRenderingSeconds > 0.0f )
1131 mImpl->keepRenderingSeconds -= elapsedSeconds;
1134 unsigned int keepUpdatingRequest = KeepUpdating::NOT_REQUESTED;
1136 // If Stage::KeepRendering() has been called, then continue until the duration has elapsed.
1137 // Keep updating until no messages are received and no animations are running.
1138 // If an animation has just finished, update at least once more for Discard end-actions.
1139 // No need to check for renderQueue as there is always a render after update and if that
1140 // render needs another update it will tell the adaptor to call update again
1142 if ( mImpl->keepRenderingSeconds > 0.0f )
1144 keepUpdatingRequest |= KeepUpdating::STAGE_KEEP_RENDERING;
1147 if ( IsAnimationRunning() ||
1148 mImpl->animationFinishedDuringUpdate )
1150 keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING;
1153 if ( mImpl->renderTaskWaiting )
1155 keepUpdatingRequest |= KeepUpdating::RENDER_TASK_SYNC;
1158 return keepUpdatingRequest;
1161 void UpdateManager::SetBackgroundColor( const Vector4& color )
1163 typedef MessageValue1< RenderManager, Vector4 > DerivedType;
1165 // Reserve some memory inside the render queue
1166 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1168 // Construct message in the render queue memory; note that delete should not be called on the return value
1169 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetBackgroundColor, color );
1172 void UpdateManager::SetDefaultSurfaceRect( const Rect<int>& rect )
1174 typedef MessageValue1< RenderManager, Rect<int> > DerivedType;
1176 // Reserve some memory inside the render queue
1177 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1179 // Construct message in the render queue memory; note that delete should not be called on the return value
1180 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetDefaultSurfaceRect, rect );
1183 void UpdateManager::KeepRendering( float durationSeconds )
1185 mImpl->keepRenderingSeconds = std::max( mImpl->keepRenderingSeconds, durationSeconds );
1188 void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, bool systemLevel )
1192 // just copy the vector of pointers
1193 mImpl->sortedLayers = layers;
1197 mImpl->systemLevelSortedLayers = layers;
1201 void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
1203 mImpl->shaderSaver = &upstream;
1206 void UpdateManager::AddSampler( Render::Sampler* sampler )
1208 typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
1210 // Reserve some memory inside the render queue
1211 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1213 // Construct message in the render queue memory; note that delete should not be called on the return value
1214 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddSampler, sampler );
1217 void UpdateManager::RemoveSampler( Render::Sampler* sampler )
1219 typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
1221 // Reserve some memory inside the render queue
1222 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1224 // Construct message in the render queue memory; note that delete should not be called on the return value
1225 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveSampler, sampler );
1228 void UpdateManager::SetFilterMode( Render::Sampler* sampler, unsigned int minFilterMode, unsigned int magFilterMode )
1230 typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
1232 // Reserve some memory inside the render queue
1233 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1235 // Construct message in the render queue memory; note that delete should not be called on the return value
1236 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetFilterMode, sampler, minFilterMode, magFilterMode );
1239 void UpdateManager::SetWrapMode( Render::Sampler* sampler, unsigned int uWrapMode, unsigned int vWrapMode )
1241 typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
1243 // Reserve some memory inside the render queue
1244 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1246 // Construct message in the render queue memory; note that delete should not be called on the return value
1247 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetWrapMode, sampler, uWrapMode, vWrapMode );
1250 void UpdateManager::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer )
1252 typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
1254 // Reserve some memory inside the render queue
1255 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1257 // Construct message in the render queue memory; note that delete should not be called on the return value
1258 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddPropertyBuffer, propertyBuffer );
1261 void UpdateManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
1263 typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
1265 // Reserve some memory inside the render queue
1266 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1268 // Construct message in the render queue memory; note that delete should not be called on the return value
1269 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemovePropertyBuffer, propertyBuffer );
1272 void UpdateManager::SetPropertyBufferFormat(Render::PropertyBuffer* propertyBuffer, Render::PropertyBuffer::Format* format )
1274 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, Render::PropertyBuffer::Format* > DerivedType;
1276 // Reserve some memory inside the render queue
1277 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1279 // Construct message in the render queue memory; note that delete should not be called on the return value
1280 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferFormat, propertyBuffer, format );
1283 void UpdateManager::SetPropertyBufferData(Render::PropertyBuffer* propertyBuffer, Dali::Vector<char>* data)
1285 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, Dali::Vector<char>* > DerivedType;
1287 // Reserve some memory inside the render queue
1288 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1290 // Construct message in the render queue memory; note that delete should not be called on the return value
1291 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferData, propertyBuffer, data );
1294 void UpdateManager::SetPropertyBufferSize(Render::PropertyBuffer* propertyBuffer, size_t size )
1296 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, size_t > DerivedType;
1298 // Reserve some memory inside the render queue
1299 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1301 // Construct message in the render queue memory; note that delete should not be called on the return value
1302 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferSize, propertyBuffer, size );
1305 } // namespace SceneGraph
1307 } // namespace Internal