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/process-render-tasks.h>
49 #include <dali/internal/update/manager/sorted-layers.h>
50 #include <dali/internal/update/manager/update-algorithms.h>
51 #include <dali/internal/update/manager/update-manager-debug.h>
52 #include <dali/internal/update/node-attachments/scene-graph-camera-attachment.h>
53 #include <dali/internal/update/nodes/node.h>
54 #include <dali/internal/update/nodes/scene-graph-layer.h>
55 #include <dali/internal/update/queue/update-message-queue.h>
56 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
57 #include <dali/internal/update/render-tasks/scene-graph-render-task-list.h>
58 #include <dali/internal/update/rendering/scene-graph-material.h>
59 #include <dali/internal/update/rendering/scene-graph-geometry.h>
60 #include <dali/internal/update/resources/resource-manager.h>
61 #include <dali/internal/update/resources/complete-status-manager.h>
62 #include <dali/internal/update/touch/touch-resampler.h>
64 #include <dali/internal/render/common/render-instruction-container.h>
65 #include <dali/internal/render/common/render-manager.h>
66 #include <dali/internal/render/queue/render-queue.h>
67 #include <dali/internal/render/common/performance-monitor.h>
68 #include <dali/internal/render/gl-resources/texture-cache.h>
69 #include <dali/internal/render/shaders/scene-graph-shader.h>
70 #include <dali/internal/render/renderers/render-sampler.h>
72 // Un-comment to enable node tree debug logging
73 //#define NODE_TREE_LOGGING 1
75 #if ( defined( DEBUG_ENABLED ) && defined( NODE_TREE_LOGGING ) )
76 #define SNAPSHOT_NODE_LOGGING \
77 const int FRAME_COUNT_TRIGGER = 16;\
78 if( mImpl->frameCounter >= FRAME_COUNT_TRIGGER )\
80 if ( NULL != mImpl->root )\
82 mImpl->frameCounter = 0;\
83 PrintNodeTree( *mImpl->root, mSceneGraphBuffers.GetUpdateBufferIndex(), "" );\
86 mImpl->frameCounter++;
88 #define SNAPSHOT_NODE_LOGGING
91 #if defined(DEBUG_ENABLED)
92 extern Debug::Filter* gRenderTaskLogFilter;
96 using namespace Dali::Integration;
97 using Dali::Internal::Update::MessageQueue;
111 void DestroyNodeSet( std::set<Node*>& nodeSet )
113 for( std::set<Node*>::iterator iter = nodeSet.begin(); iter != nodeSet.end(); ++iter )
117 // Call Node::OnDestroy as each node is destroyed
127 typedef OwnerContainer< Shader* > ShaderContainer;
128 typedef ShaderContainer::Iterator ShaderIter;
129 typedef ShaderContainer::ConstIterator ShaderConstIter;
131 typedef std::vector<Internal::ShaderDataPtr> ShaderDataBinaryQueue;
133 typedef OwnerContainer<PanGesture*> GestureContainer;
134 typedef GestureContainer::Iterator GestureIter;
135 typedef GestureContainer::ConstIterator GestureConstIter;
139 * Structure to contain UpdateManager internal data
141 struct UpdateManager::Impl
143 Impl( NotificationManager& notificationManager,
144 GlSyncAbstraction& glSyncAbstraction,
145 CompleteNotificationInterface& animationFinishedNotifier,
146 PropertyNotifier& propertyNotifier,
147 ResourceManager& resourceManager,
148 DiscardQueue& discardQueue,
149 RenderController& renderController,
150 RenderManager& renderManager,
151 RenderQueue& renderQueue,
152 TextureCache& textureCache,
153 TouchResampler& touchResampler,
154 SceneGraphBuffers& sceneGraphBuffers )
156 renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
157 notificationManager( notificationManager ),
158 animationFinishedNotifier( animationFinishedNotifier ),
159 propertyNotifier( propertyNotifier ),
161 resourceManager( resourceManager ),
162 discardQueue( discardQueue ),
163 renderController( renderController ),
164 sceneController( NULL ),
165 renderManager( renderManager ),
166 renderQueue( renderQueue ),
167 renderInstructions( renderManager.GetRenderInstructionContainer() ),
168 completeStatusManager( glSyncAbstraction, renderMessageDispatcher, resourceManager ),
169 touchResampler( touchResampler ),
170 backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
171 taskList ( completeStatusManager ),
172 systemLevelTaskList ( completeStatusManager ),
174 systemLevelRoot( NULL ),
175 renderers( sceneGraphBuffers, discardQueue ),
176 geometries( sceneGraphBuffers, discardQueue ),
177 materials( sceneGraphBuffers, discardQueue ),
178 messageQueue( renderController, sceneGraphBuffers ),
179 keepRenderingSeconds( 0.0f ),
180 animationFinishedDuringUpdate( false ),
181 nodeDirtyFlags( TransformFlag ), // set to TransformFlag to ensure full update the first time through Update()
182 previousUpdateScene( false ),
184 renderSortingHelper(),
185 renderTaskWaiting( false )
187 sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue, textureCache, completeStatusManager );
189 renderers.SetSceneController( *sceneController );
190 geometries.SetSceneController( *sceneController );
191 materials.SetSceneController( *sceneController );
196 // Disconnect render tasks from nodes, before destroying the nodes
197 RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
198 for (RenderTaskList::RenderTaskContainer::Iterator iter = tasks.Begin(); iter != tasks.End(); ++iter)
200 (*iter)->SetSourceNode( NULL );
202 // ..repeat for system level RenderTasks
203 RenderTaskList::RenderTaskContainer& systemLevelTasks = systemLevelTaskList.GetTasks();
204 for (RenderTaskList::RenderTaskContainer::Iterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter)
206 (*iter)->SetSourceNode( NULL );
209 // UpdateManager owns the Nodes
210 DestroyNodeSet( activeDisconnectedNodes );
211 DestroyNodeSet( connectedNodes );
212 DestroyNodeSet( disconnectedNodes );
214 // If there is root, reset it, otherwise do nothing as rendering was never started
223 if( systemLevelRoot )
225 systemLevelRoot->OnDestroy();
227 delete systemLevelRoot;
228 systemLevelRoot = NULL;
231 sceneController->GetTextureCache().SetBufferIndices(NULL); // TODO - Remove
232 delete sceneController;
235 SceneGraphBuffers sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read
236 RenderMessageDispatcher renderMessageDispatcher; ///< Used for passing messages to the render-thread
237 NotificationManager& notificationManager; ///< Queues notification messages for the event-thread.
238 CompleteNotificationInterface& animationFinishedNotifier; ///< Provides notification to applications when animations are finished.
239 PropertyNotifier& propertyNotifier; ///< Provides notification to applications when properties are modified.
240 ShaderSaver* shaderSaver; ///< Saves shader binaries.
241 ResourceManager& resourceManager; ///< resource manager
242 DiscardQueue& discardQueue; ///< Nodes are added here when disconnected from the scene-graph.
243 RenderController& renderController; ///< render controller
244 SceneControllerImpl* sceneController; ///< scene controller
245 RenderManager& renderManager; ///< This is responsible for rendering the results of each "update"
246 RenderQueue& renderQueue; ///< Used to queue messages for the next render
247 RenderInstructionContainer& renderInstructions; ///< Used to prepare the render instructions
248 CompleteStatusManager completeStatusManager; ///< Complete Status Manager
249 TouchResampler& touchResampler; ///< Used to resample touch events on every update.
251 Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
253 RenderTaskList taskList; ///< The list of scene graph render-tasks
254 RenderTaskList systemLevelTaskList; ///< Separate render-tasks for system-level content
256 Layer* root; ///< The root node (root is a layer)
257 Layer* systemLevelRoot; ///< A separate root-node for system-level content
258 std::set< Node* > activeDisconnectedNodes; ///< A container of new or modified nodes (without parent) owned by UpdateManager
259 std::set< Node* > connectedNodes; ///< A container of connected (with parent) nodes owned by UpdateManager
260 std::set< Node* > disconnectedNodes; ///< A container of inactive disconnected nodes (without parent) owned by UpdateManager
262 SortedLayerPointers sortedLayers; ///< A container of Layer pointers sorted by depth
263 SortedLayerPointers systemLevelSortedLayers; ///< A separate container of system-level Layers
265 OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties)
267 AnimationContainer animations; ///< A container of owned animations
268 PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
270 ObjectOwnerContainer<Renderer> renderers;
271 ObjectOwnerContainer<Geometry> geometries; ///< A container of geometries
272 ObjectOwnerContainer<Material> materials; ///< A container of materials
274 ShaderContainer shaders; ///< A container of owned shaders
276 MessageQueue messageQueue; ///< The messages queued from the event-thread
277 ShaderDataBinaryQueue renderCompiledShaders; ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread.
278 ShaderDataBinaryQueue updateCompiledShaders; ///< Shaders to be sent from Update to Event
279 Mutex compiledShaderMutex; ///< lock to ensure no corruption on the renderCompiledShaders
281 float keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering
282 bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
284 int nodeDirtyFlags; ///< cumulative node dirty flags from previous frame
285 bool previousUpdateScene; ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
287 int frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
288 RendererSortingHelper renderSortingHelper; ///< helper used to sort transparent renderers
290 GestureContainer gestures; ///< A container of owned gesture detectors
291 bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered
294 UpdateManager::UpdateManager( NotificationManager& notificationManager,
295 GlSyncAbstraction& glSyncAbstraction,
296 CompleteNotificationInterface& animationFinishedNotifier,
297 PropertyNotifier& propertyNotifier,
298 ResourceManager& resourceManager,
299 DiscardQueue& discardQueue,
300 RenderController& controller,
301 RenderManager& renderManager,
302 RenderQueue& renderQueue,
303 TextureCache& textureCache,
304 TouchResampler& touchResampler )
307 mImpl = new Impl( notificationManager,
309 animationFinishedNotifier,
318 mSceneGraphBuffers );
320 textureCache.SetBufferIndices( &mSceneGraphBuffers );
323 UpdateManager::~UpdateManager()
328 void UpdateManager::InstallRoot( SceneGraph::Layer* layer, bool systemLevel )
330 DALI_ASSERT_DEBUG( layer->IsLayer() );
331 DALI_ASSERT_DEBUG( layer->GetParent() == NULL);
335 DALI_ASSERT_DEBUG( mImpl->root == NULL && "Root Node already installed" );
340 DALI_ASSERT_DEBUG( mImpl->systemLevelRoot == NULL && "System-level Root Node already installed" );
341 mImpl->systemLevelRoot = layer;
344 layer->SetRoot(true);
347 void UpdateManager::AddNode( Node* node )
349 DALI_ASSERT_ALWAYS( NULL != node );
350 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
352 mImpl->activeDisconnectedNodes.insert( node ); // Takes ownership of node
355 void UpdateManager::ConnectNode( Node* parent, Node* node )
357 DALI_ASSERT_ALWAYS( NULL != parent );
358 DALI_ASSERT_ALWAYS( NULL != node );
359 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
361 // Move from active/disconnectedNodes to connectedNodes
362 std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
365 removed = mImpl->disconnectedNodes.erase( node );
366 DALI_ASSERT_ALWAYS( removed );
368 mImpl->connectedNodes.insert( node );
370 node->SetActive( true );
372 parent->ConnectChild( node );
375 void UpdateManager::DisconnectNode( Node* node )
377 Node* parent = node->GetParent();
378 DALI_ASSERT_ALWAYS( NULL != parent );
379 parent->SetDirtyFlag( ChildDeletedFlag ); // make parent dirty so that render items dont get reused
381 // Move from connectedNodes to activeDisconnectedNodes (reset properties next frame)
382 parent->DisconnectChild( mSceneGraphBuffers.GetUpdateBufferIndex(), *node, mImpl->connectedNodes, mImpl->activeDisconnectedNodes );
385 void UpdateManager::SetNodeActive( Node* node )
387 DALI_ASSERT_ALWAYS( NULL != node );
388 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
390 // Move from disconnectedNodes to activeDisconnectedNodes (reset properties next frame)
391 std::set<Node*>::size_type removed = mImpl->disconnectedNodes.erase( node );
392 DALI_ASSERT_ALWAYS( removed );
393 mImpl->activeDisconnectedNodes.insert( node );
395 node->SetActive( true );
398 void UpdateManager::DestroyNode( Node* node )
400 DALI_ASSERT_ALWAYS( NULL != node );
401 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should have been disconnected
403 // Transfer ownership from new/disconnectedNodes to the discard queue
404 // This keeps the nodes alive, until the render-thread has finished with them
405 std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
408 removed = mImpl->disconnectedNodes.erase( node );
409 DALI_ASSERT_ALWAYS( removed );
411 mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), node );
413 // Notify the Node about impending destruction
417 //@todo MESH_REWORK Extend to allow arbitrary scene objects to connect to each other
418 void UpdateManager::AttachToNode( Node* node, NodeAttachment* attachment )
420 DALI_ASSERT_DEBUG( node != NULL );
421 DALI_ASSERT_DEBUG( attachment != NULL );
423 // attach node to attachment first so that parent is known by the time attachment is connected
424 node->Attach( *attachment ); // node takes ownership
427 void UpdateManager::AddObject( PropertyOwner* object )
429 DALI_ASSERT_DEBUG( NULL != object );
431 mImpl->customObjects.PushBack( object );
434 void UpdateManager::RemoveObject( PropertyOwner* object )
436 DALI_ASSERT_DEBUG( NULL != object );
438 OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
440 // Find the object and destroy it
441 for ( OwnerContainer< PropertyOwner* >::Iterator iter = customObjects.Begin(); iter != customObjects.End(); ++iter )
443 PropertyOwner* current = *iter;
444 if ( current == object )
446 customObjects.Erase( iter );
451 // Should not reach here
452 DALI_ASSERT_DEBUG(false);
455 void UpdateManager::AddAnimation( Animation* animation )
457 mImpl->animations.PushBack( animation );
460 void UpdateManager::StopAnimation( Animation* animation )
462 DALI_ASSERT_DEBUG( animation && "NULL animation called to stop" );
464 bool animationFinished = animation->Stop( mSceneGraphBuffers.GetUpdateBufferIndex() );
466 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || animationFinished;
469 void UpdateManager::RemoveAnimation( Animation* animation )
471 DALI_ASSERT_DEBUG( animation && "NULL animation called to remove" );
473 animation->OnDestroy( mSceneGraphBuffers.GetUpdateBufferIndex() );
475 DALI_ASSERT_DEBUG( animation->GetState() == Animation::Destroyed );
478 bool UpdateManager::IsAnimationRunning() const
480 bool isRunning(false);
481 AnimationContainer& animations = mImpl->animations;
483 // Find any animation that isn't stopped or paused
485 const AnimationIter endIter = animations.End();
486 for ( AnimationIter iter = animations.Begin(); !isRunning && iter != endIter; ++iter )
488 const Animation::State state = (*iter)->GetState();
490 if (state != Animation::Stopped &&
491 state != Animation::Paused)
500 void UpdateManager::AddPropertyNotification( PropertyNotification* propertyNotification )
502 mImpl->propertyNotifications.PushBack( propertyNotification );
505 void UpdateManager::RemovePropertyNotification( PropertyNotification* propertyNotification )
507 PropertyNotificationContainer &propertyNotifications = mImpl->propertyNotifications;
508 PropertyNotificationIter iter = propertyNotifications.Begin();
510 while ( iter != propertyNotifications.End() )
512 if( *iter == propertyNotification )
514 propertyNotifications.Erase(iter);
521 void UpdateManager::PropertyNotificationSetNotify( PropertyNotification* propertyNotification, PropertyNotification::NotifyMode notifyMode )
523 DALI_ASSERT_DEBUG( propertyNotification && "propertyNotification scene graph object missing" );
524 propertyNotification->SetNotifyMode( notifyMode );
527 ObjectOwnerContainer<Geometry>& UpdateManager::GetGeometryOwner()
529 return mImpl->geometries;
532 ObjectOwnerContainer<Renderer>& UpdateManager::GetRendererOwner()
534 return mImpl->renderers;
538 ObjectOwnerContainer<Material>& UpdateManager::GetMaterialOwner()
540 return mImpl->materials;
543 void UpdateManager::AddShader( Shader* shader )
545 DALI_ASSERT_DEBUG( NULL != shader );
547 if( mImpl->shaders.Count() == 0 )
549 // the first added shader becomes our default shader
550 // Construct message in the render queue memory; note that delete should not be called on the return value
551 typedef MessageValue1< RenderManager, Shader* > DerivedType;
553 // Reserve some memory inside the render queue
554 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
556 // Construct message in the render queue memory; note that delete should not be called on the return value
557 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetDefaultShader, shader );
560 mImpl->shaders.PushBack( shader );
562 // Allows the shader to dispatch texture requests to the cache
563 shader->Initialize( mImpl->renderQueue, mImpl->sceneController->GetTextureCache() );
566 void UpdateManager::RemoveShader( Shader* shader )
568 DALI_ASSERT_DEBUG(shader != NULL);
570 ShaderContainer& shaders = mImpl->shaders;
572 // Find the shader and destroy it
573 for ( ShaderIter iter = shaders.Begin(); iter != shaders.End(); ++iter )
575 Shader& current = **iter;
576 if ( ¤t == shader )
578 // Transfer ownership to the discard queue
579 // This keeps the shader alive, until the render-thread has finished with it
580 mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), shaders.Release( iter ) );
585 // Should not reach here
586 DALI_ASSERT_DEBUG(false);
589 void UpdateManager::SetShaderProgram( Shader* shader,
590 Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
595 typedef MessageValue3< Shader, Internal::ShaderDataPtr, ProgramCache*, bool> DerivedType;
597 // Reserve some memory inside the render queue
598 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
600 // Construct message in the render queue memory; note that delete should not be called on the return value
601 new (slot) DerivedType( shader, &Shader::SetProgram, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
605 void UpdateManager::SaveBinary( Internal::ShaderDataPtr shaderData )
607 DALI_ASSERT_DEBUG( shaderData && "No NULL shader data pointers please." );
608 DALI_ASSERT_DEBUG( shaderData->GetBufferSize() > 0 && "Shader binary empty so nothing to save." );
610 // lock as update might be sending previously compiled shaders to event thread
611 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
612 mImpl->renderCompiledShaders.push_back( shaderData );
616 RenderTaskList* UpdateManager::GetRenderTaskList( bool systemLevel )
620 // copy the list, this is only likely to happen once in application life cycle
621 return &(mImpl->taskList);
625 // copy the list, this is only likely to happen once in application life cycle
626 return &(mImpl->systemLevelTaskList);
630 void UpdateManager::AddGesture( PanGesture* gesture )
632 DALI_ASSERT_DEBUG( NULL != gesture );
634 mImpl->gestures.PushBack( gesture );
637 void UpdateManager::RemoveGesture( PanGesture* gesture )
639 DALI_ASSERT_DEBUG( gesture != NULL );
641 GestureContainer& gestures = mImpl->gestures;
643 // Find the gesture and destroy it
644 for ( GestureIter iter = gestures.Begin(), endIter = gestures.End(); iter != endIter; ++iter )
646 PanGesture& current = **iter;
647 if ( ¤t == gesture )
649 mImpl->gestures.Erase( iter );
653 // Should not reach here
654 DALI_ASSERT_DEBUG(false);
657 unsigned int* UpdateManager::ReserveMessageSlot( std::size_t size, bool updateScene )
659 return mImpl->messageQueue.ReserveMessageSlot( size, updateScene );
662 void UpdateManager::EventProcessingStarted()
664 mImpl->messageQueue.EventProcessingStarted();
667 bool UpdateManager::FlushQueue()
669 return mImpl->messageQueue.FlushQueue();
672 void UpdateManager::ResetProperties( BufferIndex bufferIndex )
674 PERF_MONITOR_START(PerformanceMonitor::RESET_PROPERTIES);
676 // Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped
677 mImpl->animationFinishedDuringUpdate = false;
679 // Animated properties have to be reset to their original value each frame
681 // Reset root properties
684 mImpl->root->ResetToBaseValues( bufferIndex );
686 if ( mImpl->systemLevelRoot )
688 mImpl->systemLevelRoot->ResetToBaseValues( bufferIndex );
691 // Reset the Connected Nodes
692 const std::set<Node*>::iterator endIter = mImpl->connectedNodes.end();
693 for( std::set<Node*>::iterator iter = mImpl->connectedNodes.begin(); endIter != iter; ++iter )
695 (*iter)->ResetToBaseValues( bufferIndex );
698 // If a Node is disconnected, it may still be "active" (requires a reset in next frame)
699 for( std::set<Node*>::iterator iter = mImpl->activeDisconnectedNodes.begin(); mImpl->activeDisconnectedNodes.end() != iter; iter = mImpl->activeDisconnectedNodes.begin() )
702 node->ResetToBaseValues( bufferIndex );
703 node->SetActive( false );
705 // Move everything from activeDisconnectedNodes to disconnectedNodes (no need to reset again)
706 mImpl->activeDisconnectedNodes.erase( iter );
707 mImpl->disconnectedNodes.insert( node );
710 // Reset system-level render-task list properties to base values
711 const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
713 for (RenderTaskList::RenderTaskContainer::ConstIterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter)
715 (*iter)->ResetToBaseValues( bufferIndex );
718 // Reset render-task list properties to base values.
719 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
721 for (RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(); iter != tasks.End(); ++iter)
723 (*iter)->ResetToBaseValues( bufferIndex );
726 // Reset custom object properties to base values
727 for (OwnerContainer<PropertyOwner*>::Iterator iter = mImpl->customObjects.Begin(); iter != mImpl->customObjects.End(); ++iter)
729 (*iter)->ResetToBaseValues( bufferIndex );
732 mImpl->materials.ResetToBaseValues( bufferIndex );
733 mImpl->geometries.ResetToBaseValues( bufferIndex );
734 mImpl->renderers.ResetToBaseValues( bufferIndex );
737 // Reset animatable shader properties to base values
738 for (ShaderIter iter = mImpl->shaders.Begin(); iter != mImpl->shaders.End(); ++iter)
740 (*iter)->ResetToBaseValues( bufferIndex );
743 PERF_MONITOR_END(PerformanceMonitor::RESET_PROPERTIES);
746 bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
748 bool gestureUpdated( false );
750 // constrain gestures... (in construction order)
751 GestureContainer& gestures = mImpl->gestures;
753 for ( GestureIter iter = gestures.Begin(), endIter = gestures.End(); iter != endIter; ++iter )
755 PanGesture& gesture = **iter;
756 gesture.ResetToBaseValues( bufferIndex ); // Needs to be done every time as gesture data is written directly to an update-buffer rather than via a message
757 gestureUpdated |= gesture.UpdateProperties( lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
760 return gestureUpdated;
763 void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
765 PERF_MONITOR_START(PerformanceMonitor::ANIMATE_NODES);
767 AnimationContainer &animations = mImpl->animations;
768 AnimationIter iter = animations.Begin();
769 while ( iter != animations.End() )
771 Animation* animation = *iter;
772 bool finished = animation->Update( bufferIndex, elapsedSeconds );
774 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
776 // Remove animations that had been destroyed but were still waiting for an update
777 if (animation->GetState() == Animation::Destroyed)
779 iter = animations.Erase(iter);
787 if ( mImpl->animationFinishedDuringUpdate )
789 // The application should be notified by NotificationManager, in another thread
790 mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationFinishedNotifier );
793 PERF_MONITOR_END(PerformanceMonitor::ANIMATE_NODES);
796 void UpdateManager::ApplyConstraints( BufferIndex bufferIndex )
798 PERF_MONITOR_START(PerformanceMonitor::APPLY_CONSTRAINTS);
800 // constrain custom objects... (in construction order)
801 OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
803 const OwnerContainer< PropertyOwner* >::Iterator endIter = customObjects.End();
804 for ( OwnerContainer< PropertyOwner* >::Iterator iter = customObjects.Begin(); endIter != iter; ++iter )
806 PropertyOwner& object = **iter;
807 ConstrainPropertyOwner( object, bufferIndex );
810 // constrain nodes... (in Depth First traversal order)
813 ConstrainNodes( *(mImpl->root), bufferIndex );
816 if ( mImpl->systemLevelRoot )
818 ConstrainNodes( *(mImpl->systemLevelRoot), bufferIndex );
821 // constrain other property-owners after nodes as they are more likely to depend on a node's
822 // current frame property than vice versa. They tend to be final constraints (no further
823 // constraints depend on their properties)
824 // e.g. ShaderEffect uniform a function of Actor's position.
825 // Mesh vertex a function of Actor's position or world position.
827 // TODO: refactor this code (and reset nodes) as these are all just lists of property-owners
828 // they can be all processed in a super-list of property-owners.
830 // Constrain system-level render-tasks
831 const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
833 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter )
835 RenderTask& task = **iter;
836 ConstrainPropertyOwner( task, bufferIndex );
839 // Constrain render-tasks
840 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
842 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(); iter != tasks.End(); ++iter )
844 RenderTask& task = **iter;
845 ConstrainPropertyOwner( task, bufferIndex );
848 // Constrain Materials and geometries
849 mImpl->materials.ConstrainObjects( bufferIndex );
850 mImpl->geometries.ConstrainObjects( bufferIndex );
851 mImpl->renderers.ConstrainObjects( bufferIndex );
853 // constrain shaders... (in construction order)
854 ShaderContainer& shaders = mImpl->shaders;
856 for ( ShaderIter iter = shaders.Begin(); iter != shaders.End(); ++iter )
858 Shader& shader = **iter;
859 ConstrainPropertyOwner( shader, bufferIndex );
862 PERF_MONITOR_END(PerformanceMonitor::APPLY_CONSTRAINTS);
865 void UpdateManager::ProcessPropertyNotifications( BufferIndex bufferIndex )
867 PropertyNotificationContainer ¬ifications = mImpl->propertyNotifications;
868 PropertyNotificationIter iter = notifications.Begin();
870 while ( iter != notifications.End() )
872 PropertyNotification* notification = *iter;
873 bool valid = notification->Check( bufferIndex );
876 mImpl->notificationManager.QueueMessage( PropertyChangedMessage( mImpl->propertyNotifier, notification, notification->GetValidity() ) );
882 void UpdateManager::ForwardCompiledShadersToEventThread()
884 DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." );
885 if( mImpl->shaderSaver )
887 // lock and swap the queues
889 // render might be attempting to send us more binaries at the same time
890 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
891 mImpl->renderCompiledShaders.swap( mImpl->updateCompiledShaders );
894 if( mImpl->updateCompiledShaders.size() > 0 )
896 ShaderSaver& factory = *mImpl->shaderSaver;
897 ShaderDataBinaryQueue::iterator i = mImpl->updateCompiledShaders.begin();
898 ShaderDataBinaryQueue::iterator end = mImpl->updateCompiledShaders.end();
899 for( ; i != end; ++i )
901 mImpl->notificationManager.QueueMessage( ShaderCompiledMessage( factory, *i ) );
903 // we don't need them in update anymore
904 mImpl->updateCompiledShaders.clear();
909 void UpdateManager::UpdateRenderers( BufferIndex bufferIndex )
911 const OwnerContainer<Renderer*>& rendererContainer( mImpl->renderers.GetObjectContainer() );
912 unsigned int rendererCount( rendererContainer.Size() );
913 for( unsigned int i(0); i<rendererCount; ++i )
915 if( rendererContainer[i]->IsReferenced() )
917 rendererContainer[i]->PrepareResources(bufferIndex, mImpl->resourceManager);
918 rendererContainer[i]->PrepareRender( bufferIndex );
923 void UpdateManager::UpdateNodes( BufferIndex bufferIndex )
925 mImpl->nodeDirtyFlags = NothingFlag;
932 PERF_MONITOR_START( PerformanceMonitor::UPDATE_NODES );
934 // Prepare resources, update shaders, update attachments, for each node
935 // And add the renderers to the sorted layers. Start from root, which is also a layer
936 mImpl->nodeDirtyFlags = UpdateNodesAndAttachments( *( mImpl->root ),
938 mImpl->resourceManager,
939 mImpl->renderQueue );
941 if ( mImpl->systemLevelRoot )
943 mImpl->nodeDirtyFlags |= UpdateNodesAndAttachments( *( mImpl->systemLevelRoot ),
945 mImpl->resourceManager,
946 mImpl->renderQueue );
949 PERF_MONITOR_END( PerformanceMonitor::UPDATE_NODES );
952 unsigned int UpdateManager::Update( float elapsedSeconds,
953 unsigned int lastVSyncTimeMilliseconds,
954 unsigned int nextVSyncTimeMilliseconds )
956 PERF_MONITOR_END(PerformanceMonitor::FRAME_RATE); // Mark the End of the last frame
957 PERF_MONITOR_NEXT_FRAME(); // Prints out performance info for the last frame (if enabled)
958 PERF_MONITOR_START(PerformanceMonitor::FRAME_RATE); // Mark the start of this current frame
960 // Measure the time spent in UpdateManager::Update
961 PERF_MONITOR_START(PerformanceMonitor::UPDATE);
963 const BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
965 // 1) Clear nodes/resources which were previously discarded
966 mImpl->discardQueue.Clear( bufferIndex );
968 // 2) Grab any loaded resources
969 bool resourceChanged = mImpl->resourceManager.UpdateCache( bufferIndex );
971 // 3) Process Touches & Gestures
972 mImpl->touchResampler.Update();
973 const bool gestureUpdated = ProcessGestures( bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
975 const bool updateScene = // The scene-graph requires an update if..
976 (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || // ..nodes were dirty in previous frame OR
977 IsAnimationRunning() || // ..at least one animation is running OR
978 mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR
979 resourceChanged || // ..one or more resources were updated/changed OR
980 gestureUpdated; // ..a gesture property was updated
983 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
984 // values if the scene was updated in the previous frame.
985 if( updateScene || mImpl->previousUpdateScene )
987 // 4) Reset properties from the previous update
988 ResetProperties( bufferIndex );
991 // 5) Process the queued scene messages
992 mImpl->messageQueue.ProcessMessages( bufferIndex );
994 // 6) Post Process Ids of resources updated by renderer
995 mImpl->resourceManager.PostProcessResources( bufferIndex );
997 // 6.1) Forward compiled shader programs to event thread for saving
998 ForwardCompiledShadersToEventThread();
1000 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
1001 // renderer lists if the scene was updated in the previous frame.
1002 // We should not start skipping update steps or reusing lists until there has been two frames where nothing changes
1003 if( updateScene || mImpl->previousUpdateScene )
1006 Animate( bufferIndex, elapsedSeconds );
1008 // 8) Apply Constraints
1009 ApplyConstraints( bufferIndex );
1011 // 9) Check Property Notifications
1012 ProcessPropertyNotifications( bufferIndex );
1014 // 10) Clear the lists of renderable-attachments from the previous update
1015 for( size_t i(0); i<mImpl->sortedLayers.size(); ++i )
1017 mImpl->sortedLayers[i]->ClearRenderables();
1020 for( size_t i(0); i<mImpl->systemLevelSortedLayers.size(); ++i )
1022 mImpl->systemLevelSortedLayers[i]->ClearRenderables();
1025 // 11) Update node hierarchy and perform sorting / culling.
1026 // This will populate each Layer with a list of renderers which are ready.
1027 UpdateNodes( bufferIndex );
1028 UpdateRenderers( bufferIndex );
1031 PERF_MONITOR_START(PerformanceMonitor::PROCESS_RENDER_TASKS);
1033 // 12) Process the RenderTasks; this creates the instructions for rendering the next frame.
1034 // reset the update buffer index and make sure there is enough room in the instruction container
1035 mImpl->renderInstructions.ResetAndReserve( bufferIndex,
1036 mImpl->taskList.GetTasks().Count() + mImpl->systemLevelTaskList.GetTasks().Count() );
1038 if ( NULL != mImpl->root )
1040 ProcessRenderTasks( bufferIndex,
1041 mImpl->completeStatusManager,
1044 mImpl->sortedLayers,
1045 mImpl->renderSortingHelper,
1046 mImpl->renderInstructions );
1048 // Process the system-level RenderTasks last
1049 if ( NULL != mImpl->systemLevelRoot )
1051 ProcessRenderTasks( bufferIndex,
1052 mImpl->completeStatusManager,
1053 mImpl->systemLevelTaskList,
1054 *mImpl->systemLevelRoot,
1055 mImpl->systemLevelSortedLayers,
1056 mImpl->renderSortingHelper,
1057 mImpl->renderInstructions );
1062 // check the countdown and notify (note, at the moment this is only done for normal tasks, not for systemlevel tasks)
1063 bool doRenderOnceNotify = false;
1064 mImpl->renderTaskWaiting = false;
1065 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
1066 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(), endIter = tasks.End();
1067 endIter != iter; ++iter )
1069 RenderTask& renderTask(*(*iter));
1071 renderTask.UpdateState();
1073 if( renderTask.IsWaitingToRender() &&
1074 renderTask.ReadyToRender( bufferIndex ) /*avoid updating forever when source actor is off-stage*/ )
1076 mImpl->renderTaskWaiting = true; // keep update/render threads alive
1079 if( renderTask.HasRendered() )
1081 doRenderOnceNotify = true;
1085 if( doRenderOnceNotify )
1087 DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
1088 mImpl->notificationManager.QueueCompleteNotification( mImpl->taskList.GetCompleteNotificationInterface() );
1091 PERF_MONITOR_END(PerformanceMonitor::PROCESS_RENDER_TASKS);
1093 // Macro is undefined in release build.
1094 SNAPSHOT_NODE_LOGGING;
1096 // A ResetProperties() may be required in the next frame
1097 mImpl->previousUpdateScene = updateScene;
1099 // Check whether further updates are required
1100 unsigned int keepUpdating = KeepUpdatingCheck( elapsedSeconds );
1102 #ifdef PERFORMANCE_MONITOR_ENABLED
1103 // Always keep rendering when measuring FPS
1104 keepUpdating |= KeepUpdating::MONITORING_PERFORMANCE;
1107 // tell the update manager that we're done so the queue can be given to event thread
1108 mImpl->notificationManager.UpdateCompleted();
1110 // The update has finished; swap the double-buffering indices
1111 mSceneGraphBuffers.Swap();
1113 PERF_MONITOR_END(PerformanceMonitor::UPDATE);
1115 return keepUpdating;
1118 unsigned int UpdateManager::KeepUpdatingCheck( float elapsedSeconds ) const
1120 // Update the duration set via Stage::KeepRendering()
1121 if ( mImpl->keepRenderingSeconds > 0.0f )
1123 mImpl->keepRenderingSeconds -= elapsedSeconds;
1126 unsigned int keepUpdatingRequest = KeepUpdating::NOT_REQUESTED;
1128 // If Stage::KeepRendering() has been called, then continue until the duration has elapsed.
1129 // Keep updating until no messages are received and no animations are running.
1130 // If an animation has just finished, update at least once more for Discard end-actions.
1131 // No need to check for renderQueue as there is always a render after update and if that
1132 // render needs another update it will tell the adaptor to call update again
1134 if ( mImpl->keepRenderingSeconds > 0.0f )
1136 keepUpdatingRequest |= KeepUpdating::STAGE_KEEP_RENDERING;
1139 if ( IsAnimationRunning() ||
1140 mImpl->animationFinishedDuringUpdate )
1142 keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING;
1145 if ( mImpl->renderTaskWaiting )
1147 keepUpdatingRequest |= KeepUpdating::RENDER_TASK_SYNC;
1150 return keepUpdatingRequest;
1153 void UpdateManager::SetBackgroundColor( const Vector4& color )
1155 typedef MessageValue1< RenderManager, Vector4 > DerivedType;
1157 // Reserve some memory inside the render queue
1158 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1160 // Construct message in the render queue memory; note that delete should not be called on the return value
1161 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetBackgroundColor, color );
1164 void UpdateManager::SetDefaultSurfaceRect( const Rect<int>& rect )
1166 typedef MessageValue1< RenderManager, Rect<int> > DerivedType;
1168 // Reserve some memory inside the render queue
1169 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1171 // Construct message in the render queue memory; note that delete should not be called on the return value
1172 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetDefaultSurfaceRect, rect );
1175 void UpdateManager::KeepRendering( float durationSeconds )
1177 mImpl->keepRenderingSeconds = std::max( mImpl->keepRenderingSeconds, durationSeconds );
1180 void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, bool systemLevel )
1184 // just copy the vector of pointers
1185 mImpl->sortedLayers = layers;
1189 mImpl->systemLevelSortedLayers = layers;
1193 void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
1195 mImpl->shaderSaver = &upstream;
1198 void UpdateManager::AddSampler( Render::Sampler* sampler )
1200 typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
1202 // Reserve some memory inside the render queue
1203 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1205 // Construct message in the render queue memory; note that delete should not be called on the return value
1206 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddSampler, sampler );
1209 void UpdateManager::RemoveSampler( Render::Sampler* sampler )
1211 typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
1213 // Reserve some memory inside the render queue
1214 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1216 // Construct message in the render queue memory; note that delete should not be called on the return value
1217 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveSampler, sampler );
1220 void UpdateManager::SetFilterMode( Render::Sampler* sampler, unsigned int minFilterMode, unsigned int magFilterMode )
1222 typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
1224 // Reserve some memory inside the render queue
1225 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1227 // Construct message in the render queue memory; note that delete should not be called on the return value
1228 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetFilterMode, sampler, minFilterMode, magFilterMode );
1231 void UpdateManager::SetWrapMode( Render::Sampler* sampler, unsigned int uWrapMode, unsigned int vWrapMode )
1233 typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
1235 // Reserve some memory inside the render queue
1236 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1238 // Construct message in the render queue memory; note that delete should not be called on the return value
1239 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetWrapMode, sampler, uWrapMode, vWrapMode );
1242 void UpdateManager::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer )
1244 typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
1246 // Reserve some memory inside the render queue
1247 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1249 // Construct message in the render queue memory; note that delete should not be called on the return value
1250 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddPropertyBuffer, propertyBuffer );
1253 void UpdateManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
1255 typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
1257 // Reserve some memory inside the render queue
1258 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1260 // Construct message in the render queue memory; note that delete should not be called on the return value
1261 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemovePropertyBuffer, propertyBuffer );
1264 void UpdateManager::SetPropertyBufferFormat(Render::PropertyBuffer* propertyBuffer, Render::PropertyBuffer::Format* format )
1266 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, Render::PropertyBuffer::Format* > DerivedType;
1268 // Reserve some memory inside the render queue
1269 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1271 // Construct message in the render queue memory; note that delete should not be called on the return value
1272 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferFormat, propertyBuffer, format );
1275 void UpdateManager::SetPropertyBufferData(Render::PropertyBuffer* propertyBuffer, Dali::Vector<char>* data)
1277 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, Dali::Vector<char>* > DerivedType;
1279 // Reserve some memory inside the render queue
1280 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1282 // Construct message in the render queue memory; note that delete should not be called on the return value
1283 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferData, propertyBuffer, data );
1286 void UpdateManager::SetPropertyBufferSize(Render::PropertyBuffer* propertyBuffer, size_t size )
1288 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, size_t > DerivedType;
1290 // Reserve some memory inside the render queue
1291 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1293 // Construct message in the render queue memory; note that delete should not be called on the return value
1294 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferSize, propertyBuffer, size );
1297 } // namespace SceneGraph
1299 } // namespace Internal