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/nodes/node.h>
55 #include <dali/internal/update/nodes/scene-graph-layer.h>
56 #include <dali/internal/update/queue/update-message-queue.h>
57 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
58 #include <dali/internal/update/render-tasks/scene-graph-render-task-list.h>
59 #include <dali/internal/update/rendering/scene-graph-material.h>
60 #include <dali/internal/update/rendering/scene-graph-geometry.h>
61 #include <dali/internal/update/resources/resource-manager.h>
62 #include <dali/internal/update/resources/complete-status-manager.h>
63 #include <dali/internal/update/touch/touch-resampler.h>
65 #include <dali/internal/render/common/render-instruction-container.h>
66 #include <dali/internal/render/common/render-manager.h>
67 #include <dali/internal/render/queue/render-queue.h>
68 #include <dali/internal/render/common/performance-monitor.h>
69 #include <dali/internal/render/gl-resources/texture-cache.h>
70 #include <dali/internal/render/shaders/scene-graph-shader.h>
71 #include <dali/internal/render/renderers/render-sampler.h>
73 // Un-comment to enable node tree debug logging
74 //#define NODE_TREE_LOGGING 1
76 #if ( defined( DEBUG_ENABLED ) && defined( NODE_TREE_LOGGING ) )
77 #define SNAPSHOT_NODE_LOGGING \
78 const int FRAME_COUNT_TRIGGER = 16;\
79 if( mImpl->frameCounter >= FRAME_COUNT_TRIGGER )\
81 if ( NULL != mImpl->root )\
83 mImpl->frameCounter = 0;\
84 PrintNodeTree( *mImpl->root, mSceneGraphBuffers.GetUpdateBufferIndex(), "" );\
87 mImpl->frameCounter++;
89 #define SNAPSHOT_NODE_LOGGING
92 #if defined(DEBUG_ENABLED)
93 extern Debug::Filter* gRenderTaskLogFilter;
97 using namespace Dali::Integration;
98 using Dali::Internal::Update::MessageQueue;
112 void DestroyNodeSet( std::set<Node*>& nodeSet )
114 for( std::set<Node*>::iterator iter = nodeSet.begin(); iter != nodeSet.end(); ++iter )
118 // Call Node::OnDestroy as each node is destroyed
128 typedef OwnerContainer< Shader* > ShaderContainer;
129 typedef ShaderContainer::Iterator ShaderIter;
130 typedef ShaderContainer::ConstIterator ShaderConstIter;
132 typedef std::vector<Internal::ShaderDataPtr> ShaderDataBinaryQueue;
134 typedef OwnerContainer<PanGesture*> GestureContainer;
135 typedef GestureContainer::Iterator GestureIter;
136 typedef GestureContainer::ConstIterator GestureConstIter;
140 * Structure to contain UpdateManager internal data
142 struct UpdateManager::Impl
144 Impl( NotificationManager& notificationManager,
145 GlSyncAbstraction& glSyncAbstraction,
146 CompleteNotificationInterface& animationFinishedNotifier,
147 PropertyNotifier& propertyNotifier,
148 ResourceManager& resourceManager,
149 DiscardQueue& discardQueue,
150 RenderController& renderController,
151 RenderManager& renderManager,
152 RenderQueue& renderQueue,
153 TextureCache& textureCache,
154 TouchResampler& touchResampler,
155 SceneGraphBuffers& sceneGraphBuffers )
157 renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
158 notificationManager( notificationManager ),
159 animationFinishedNotifier( animationFinishedNotifier ),
160 propertyNotifier( propertyNotifier ),
162 resourceManager( resourceManager ),
163 discardQueue( discardQueue ),
164 renderController( renderController ),
165 sceneController( NULL ),
166 renderManager( renderManager ),
167 renderQueue( renderQueue ),
168 renderInstructions( renderManager.GetRenderInstructionContainer() ),
169 completeStatusManager( glSyncAbstraction, renderMessageDispatcher, resourceManager ),
170 touchResampler( touchResampler ),
171 backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
172 taskList ( completeStatusManager ),
173 systemLevelTaskList ( completeStatusManager ),
175 systemLevelRoot( NULL ),
176 renderers( sceneGraphBuffers, discardQueue ),
177 geometries( sceneGraphBuffers, discardQueue ),
178 materials( sceneGraphBuffers, discardQueue ),
179 messageQueue( renderController, sceneGraphBuffers ),
180 keepRenderingSeconds( 0.0f ),
181 animationFinishedDuringUpdate( false ),
182 nodeDirtyFlags( TransformFlag ), // set to TransformFlag to ensure full update the first time through Update()
183 previousUpdateScene( false ),
185 renderSortingHelper(),
186 renderTaskWaiting( false )
188 sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue, textureCache, completeStatusManager );
190 renderers.SetSceneController( *sceneController );
191 geometries.SetSceneController( *sceneController );
192 materials.SetSceneController( *sceneController );
197 // Disconnect render tasks from nodes, before destroying the nodes
198 RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
199 for (RenderTaskList::RenderTaskContainer::Iterator iter = tasks.Begin(); iter != tasks.End(); ++iter)
201 (*iter)->SetSourceNode( NULL );
203 // ..repeat for system level RenderTasks
204 RenderTaskList::RenderTaskContainer& systemLevelTasks = systemLevelTaskList.GetTasks();
205 for (RenderTaskList::RenderTaskContainer::Iterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter)
207 (*iter)->SetSourceNode( NULL );
210 // UpdateManager owns the Nodes
211 DestroyNodeSet( activeDisconnectedNodes );
212 DestroyNodeSet( connectedNodes );
213 DestroyNodeSet( disconnectedNodes );
215 // If there is root, reset it, otherwise do nothing as rendering was never started
224 if( systemLevelRoot )
226 systemLevelRoot->OnDestroy();
228 delete systemLevelRoot;
229 systemLevelRoot = NULL;
232 sceneController->GetTextureCache().SetBufferIndices(NULL); // TODO - Remove
233 delete sceneController;
236 SceneGraphBuffers sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read
237 RenderMessageDispatcher renderMessageDispatcher; ///< Used for passing messages to the render-thread
238 NotificationManager& notificationManager; ///< Queues notification messages for the event-thread.
239 CompleteNotificationInterface& animationFinishedNotifier; ///< Provides notification to applications when animations are finished.
240 PropertyNotifier& propertyNotifier; ///< Provides notification to applications when properties are modified.
241 ShaderSaver* shaderSaver; ///< Saves shader binaries.
242 ResourceManager& resourceManager; ///< resource manager
243 DiscardQueue& discardQueue; ///< Nodes are added here when disconnected from the scene-graph.
244 RenderController& renderController; ///< render controller
245 SceneControllerImpl* sceneController; ///< scene controller
246 RenderManager& renderManager; ///< This is responsible for rendering the results of each "update"
247 RenderQueue& renderQueue; ///< Used to queue messages for the next render
248 RenderInstructionContainer& renderInstructions; ///< Used to prepare the render instructions
249 CompleteStatusManager completeStatusManager; ///< Complete Status Manager
250 TouchResampler& touchResampler; ///< Used to resample touch events on every update.
252 Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
254 RenderTaskList taskList; ///< The list of scene graph render-tasks
255 RenderTaskList systemLevelTaskList; ///< Separate render-tasks for system-level content
257 Layer* root; ///< The root node (root is a layer)
258 Layer* systemLevelRoot; ///< A separate root-node for system-level content
259 std::set< Node* > activeDisconnectedNodes; ///< A container of new or modified nodes (without parent) owned by UpdateManager
260 std::set< Node* > connectedNodes; ///< A container of connected (with parent) nodes owned by UpdateManager
261 std::set< Node* > disconnectedNodes; ///< A container of inactive disconnected nodes (without parent) owned by UpdateManager
263 SortedLayerPointers sortedLayers; ///< A container of Layer pointers sorted by depth
264 SortedLayerPointers systemLevelSortedLayers; ///< A separate container of system-level Layers
266 OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties)
268 AnimationContainer animations; ///< A container of owned animations
269 PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
271 ObjectOwnerContainer<Renderer> renderers;
272 ObjectOwnerContainer<Geometry> geometries; ///< A container of geometries
273 ObjectOwnerContainer<Material> materials; ///< A container of materials
275 ShaderContainer shaders; ///< A container of owned shaders
277 MessageQueue messageQueue; ///< The messages queued from the event-thread
278 ShaderDataBinaryQueue renderCompiledShaders; ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread.
279 ShaderDataBinaryQueue updateCompiledShaders; ///< Shaders to be sent from Update to Event
280 Mutex compiledShaderMutex; ///< lock to ensure no corruption on the renderCompiledShaders
282 float keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering
283 bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
285 int nodeDirtyFlags; ///< cumulative node dirty flags from previous frame
286 bool previousUpdateScene; ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
288 int frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
289 RendererSortingHelper renderSortingHelper; ///< helper used to sort transparent renderers
291 GestureContainer gestures; ///< A container of owned gesture detectors
292 bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered
295 UpdateManager::UpdateManager( NotificationManager& notificationManager,
296 GlSyncAbstraction& glSyncAbstraction,
297 CompleteNotificationInterface& animationFinishedNotifier,
298 PropertyNotifier& propertyNotifier,
299 ResourceManager& resourceManager,
300 DiscardQueue& discardQueue,
301 RenderController& controller,
302 RenderManager& renderManager,
303 RenderQueue& renderQueue,
304 TextureCache& textureCache,
305 TouchResampler& touchResampler )
308 mImpl = new Impl( notificationManager,
310 animationFinishedNotifier,
319 mSceneGraphBuffers );
321 textureCache.SetBufferIndices( &mSceneGraphBuffers );
324 UpdateManager::~UpdateManager()
329 void UpdateManager::InstallRoot( SceneGraph::Layer* layer, bool systemLevel )
331 DALI_ASSERT_DEBUG( layer->IsLayer() );
332 DALI_ASSERT_DEBUG( layer->GetParent() == NULL);
336 DALI_ASSERT_DEBUG( mImpl->root == NULL && "Root Node already installed" );
341 DALI_ASSERT_DEBUG( mImpl->systemLevelRoot == NULL && "System-level Root Node already installed" );
342 mImpl->systemLevelRoot = layer;
345 layer->SetRoot(true);
348 void UpdateManager::AddNode( Node* node )
350 DALI_ASSERT_ALWAYS( NULL != node );
351 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
353 mImpl->activeDisconnectedNodes.insert( node ); // Takes ownership of node
356 void UpdateManager::ConnectNode( Node* parent, Node* node )
358 DALI_ASSERT_ALWAYS( NULL != parent );
359 DALI_ASSERT_ALWAYS( NULL != node );
360 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
362 // Move from active/disconnectedNodes to connectedNodes
363 std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
366 removed = mImpl->disconnectedNodes.erase( node );
367 DALI_ASSERT_ALWAYS( removed );
369 mImpl->connectedNodes.insert( node );
371 node->SetActive( true );
373 parent->ConnectChild( node );
376 void UpdateManager::DisconnectNode( Node* node )
378 Node* parent = node->GetParent();
379 DALI_ASSERT_ALWAYS( NULL != parent );
380 parent->SetDirtyFlag( ChildDeletedFlag ); // make parent dirty so that render items dont get reused
382 // Move from connectedNodes to activeDisconnectedNodes (reset properties next frame)
383 parent->DisconnectChild( mSceneGraphBuffers.GetUpdateBufferIndex(), *node, mImpl->connectedNodes, mImpl->activeDisconnectedNodes );
386 void UpdateManager::SetNodeActive( Node* node )
388 DALI_ASSERT_ALWAYS( NULL != node );
389 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
391 // Move from disconnectedNodes to activeDisconnectedNodes (reset properties next frame)
392 std::set<Node*>::size_type removed = mImpl->disconnectedNodes.erase( node );
393 DALI_ASSERT_ALWAYS( removed );
394 mImpl->activeDisconnectedNodes.insert( node );
396 node->SetActive( true );
399 void UpdateManager::DestroyNode( Node* node )
401 DALI_ASSERT_ALWAYS( NULL != node );
402 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should have been disconnected
404 // Transfer ownership from new/disconnectedNodes to the discard queue
405 // This keeps the nodes alive, until the render-thread has finished with them
406 std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
409 removed = mImpl->disconnectedNodes.erase( node );
410 DALI_ASSERT_ALWAYS( removed );
412 mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), node );
414 // Notify the Node about impending destruction
418 //@todo MESH_REWORK Extend to allow arbitrary scene objects to connect to each other
419 void UpdateManager::AttachToNode( Node* node, NodeAttachment* attachment )
421 DALI_ASSERT_DEBUG( node != NULL );
422 DALI_ASSERT_DEBUG( attachment != NULL );
424 // attach node to attachment first so that parent is known by the time attachment is connected
425 node->Attach( *attachment ); // node takes ownership
428 void UpdateManager::AddObject( PropertyOwner* object )
430 DALI_ASSERT_DEBUG( NULL != object );
432 mImpl->customObjects.PushBack( object );
435 void UpdateManager::RemoveObject( PropertyOwner* object )
437 DALI_ASSERT_DEBUG( NULL != object );
439 OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
441 // Find the object and destroy it
442 for ( OwnerContainer< PropertyOwner* >::Iterator iter = customObjects.Begin(); iter != customObjects.End(); ++iter )
444 PropertyOwner* current = *iter;
445 if ( current == object )
447 customObjects.Erase( iter );
452 // Should not reach here
453 DALI_ASSERT_DEBUG(false);
456 void UpdateManager::AddAnimation( Animation* animation )
458 mImpl->animations.PushBack( animation );
461 void UpdateManager::StopAnimation( Animation* animation )
463 DALI_ASSERT_DEBUG( animation && "NULL animation called to stop" );
465 bool animationFinished = animation->Stop( mSceneGraphBuffers.GetUpdateBufferIndex() );
467 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || animationFinished;
470 void UpdateManager::RemoveAnimation( Animation* animation )
472 DALI_ASSERT_DEBUG( animation && "NULL animation called to remove" );
474 animation->OnDestroy( mSceneGraphBuffers.GetUpdateBufferIndex() );
476 DALI_ASSERT_DEBUG( animation->GetState() == Animation::Destroyed );
479 bool UpdateManager::IsAnimationRunning() const
481 bool isRunning(false);
482 AnimationContainer& animations = mImpl->animations;
484 // Find any animation that isn't stopped or paused
486 const AnimationIter endIter = animations.End();
487 for ( AnimationIter iter = animations.Begin(); !isRunning && iter != endIter; ++iter )
489 const Animation::State state = (*iter)->GetState();
491 if (state != Animation::Stopped &&
492 state != Animation::Paused)
501 void UpdateManager::AddPropertyNotification( PropertyNotification* propertyNotification )
503 mImpl->propertyNotifications.PushBack( propertyNotification );
506 void UpdateManager::RemovePropertyNotification( PropertyNotification* propertyNotification )
508 PropertyNotificationContainer &propertyNotifications = mImpl->propertyNotifications;
509 PropertyNotificationIter iter = propertyNotifications.Begin();
511 while ( iter != propertyNotifications.End() )
513 if( *iter == propertyNotification )
515 propertyNotifications.Erase(iter);
522 void UpdateManager::PropertyNotificationSetNotify( PropertyNotification* propertyNotification, PropertyNotification::NotifyMode notifyMode )
524 DALI_ASSERT_DEBUG( propertyNotification && "propertyNotification scene graph object missing" );
525 propertyNotification->SetNotifyMode( notifyMode );
528 ObjectOwnerContainer<Geometry>& UpdateManager::GetGeometryOwner()
530 return mImpl->geometries;
533 ObjectOwnerContainer<Renderer>& UpdateManager::GetRendererOwner()
535 return mImpl->renderers;
539 ObjectOwnerContainer<Material>& UpdateManager::GetMaterialOwner()
541 return mImpl->materials;
544 void UpdateManager::AddShader( Shader* shader )
546 DALI_ASSERT_DEBUG( NULL != shader );
548 if( mImpl->shaders.Count() == 0 )
550 // the first added shader becomes our default shader
551 // Construct message in the render queue memory; note that delete should not be called on the return value
552 typedef MessageValue1< RenderManager, Shader* > DerivedType;
554 // Reserve some memory inside the render queue
555 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
557 // Construct message in the render queue memory; note that delete should not be called on the return value
558 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetDefaultShader, shader );
561 mImpl->shaders.PushBack( shader );
563 // Allows the shader to dispatch texture requests to the cache
564 shader->Initialize( mImpl->renderQueue, mImpl->sceneController->GetTextureCache() );
567 void UpdateManager::RemoveShader( Shader* shader )
569 DALI_ASSERT_DEBUG(shader != NULL);
571 ShaderContainer& shaders = mImpl->shaders;
573 // Find the shader and destroy it
574 for ( ShaderIter iter = shaders.Begin(); iter != shaders.End(); ++iter )
576 Shader& current = **iter;
577 if ( ¤t == shader )
579 // Transfer ownership to the discard queue
580 // This keeps the shader alive, until the render-thread has finished with it
581 mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), shaders.Release( iter ) );
586 // Should not reach here
587 DALI_ASSERT_DEBUG(false);
590 void UpdateManager::SetShaderProgram( Shader* shader,
591 Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
596 typedef MessageValue3< Shader, Internal::ShaderDataPtr, ProgramCache*, bool> DerivedType;
598 // Reserve some memory inside the render queue
599 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
601 // Construct message in the render queue memory; note that delete should not be called on the return value
602 new (slot) DerivedType( shader, &Shader::SetProgram, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
606 void UpdateManager::SaveBinary( Internal::ShaderDataPtr shaderData )
608 DALI_ASSERT_DEBUG( shaderData && "No NULL shader data pointers please." );
609 DALI_ASSERT_DEBUG( shaderData->GetBufferSize() > 0 && "Shader binary empty so nothing to save." );
611 // lock as update might be sending previously compiled shaders to event thread
612 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
613 mImpl->renderCompiledShaders.push_back( shaderData );
617 RenderTaskList* UpdateManager::GetRenderTaskList( bool systemLevel )
621 // copy the list, this is only likely to happen once in application life cycle
622 return &(mImpl->taskList);
626 // copy the list, this is only likely to happen once in application life cycle
627 return &(mImpl->systemLevelTaskList);
631 void UpdateManager::AddGesture( PanGesture* gesture )
633 DALI_ASSERT_DEBUG( NULL != gesture );
635 mImpl->gestures.PushBack( gesture );
638 void UpdateManager::RemoveGesture( PanGesture* gesture )
640 DALI_ASSERT_DEBUG( gesture != NULL );
642 GestureContainer& gestures = mImpl->gestures;
644 // Find the gesture and destroy it
645 for ( GestureIter iter = gestures.Begin(), endIter = gestures.End(); iter != endIter; ++iter )
647 PanGesture& current = **iter;
648 if ( ¤t == gesture )
650 mImpl->gestures.Erase( iter );
654 // Should not reach here
655 DALI_ASSERT_DEBUG(false);
658 unsigned int* UpdateManager::ReserveMessageSlot( std::size_t size, bool updateScene )
660 return mImpl->messageQueue.ReserveMessageSlot( size, updateScene );
663 void UpdateManager::EventProcessingStarted()
665 mImpl->messageQueue.EventProcessingStarted();
668 bool UpdateManager::FlushQueue()
670 return mImpl->messageQueue.FlushQueue();
673 void UpdateManager::ResetProperties( BufferIndex bufferIndex )
675 PERF_MONITOR_START(PerformanceMonitor::RESET_PROPERTIES);
677 // Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped
678 mImpl->animationFinishedDuringUpdate = false;
680 // Animated properties have to be reset to their original value each frame
682 // Reset root properties
685 mImpl->root->ResetToBaseValues( bufferIndex );
687 if ( mImpl->systemLevelRoot )
689 mImpl->systemLevelRoot->ResetToBaseValues( bufferIndex );
692 // Reset the Connected Nodes
693 const std::set<Node*>::iterator endIter = mImpl->connectedNodes.end();
694 for( std::set<Node*>::iterator iter = mImpl->connectedNodes.begin(); endIter != iter; ++iter )
696 (*iter)->ResetToBaseValues( bufferIndex );
699 // If a Node is disconnected, it may still be "active" (requires a reset in next frame)
700 for( std::set<Node*>::iterator iter = mImpl->activeDisconnectedNodes.begin(); mImpl->activeDisconnectedNodes.end() != iter; iter = mImpl->activeDisconnectedNodes.begin() )
703 node->ResetToBaseValues( bufferIndex );
704 node->SetActive( false );
706 // Move everything from activeDisconnectedNodes to disconnectedNodes (no need to reset again)
707 mImpl->activeDisconnectedNodes.erase( iter );
708 mImpl->disconnectedNodes.insert( node );
711 // Reset system-level render-task list properties to base values
712 const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
714 for (RenderTaskList::RenderTaskContainer::ConstIterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter)
716 (*iter)->ResetToBaseValues( bufferIndex );
719 // Reset render-task list properties to base values.
720 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
722 for (RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(); iter != tasks.End(); ++iter)
724 (*iter)->ResetToBaseValues( bufferIndex );
727 // Reset custom object properties to base values
728 for (OwnerContainer<PropertyOwner*>::Iterator iter = mImpl->customObjects.Begin(); iter != mImpl->customObjects.End(); ++iter)
730 (*iter)->ResetToBaseValues( bufferIndex );
733 mImpl->materials.ResetToBaseValues( bufferIndex );
734 mImpl->geometries.ResetToBaseValues( bufferIndex );
735 mImpl->renderers.ResetToBaseValues( bufferIndex );
738 // Reset animatable shader properties to base values
739 for (ShaderIter iter = mImpl->shaders.Begin(); iter != mImpl->shaders.End(); ++iter)
741 (*iter)->ResetToBaseValues( bufferIndex );
744 PERF_MONITOR_END(PerformanceMonitor::RESET_PROPERTIES);
747 bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
749 bool gestureUpdated( false );
751 // constrain gestures... (in construction order)
752 GestureContainer& gestures = mImpl->gestures;
754 for ( GestureIter iter = gestures.Begin(), endIter = gestures.End(); iter != endIter; ++iter )
756 PanGesture& gesture = **iter;
757 gesture.ResetToBaseValues( bufferIndex ); // Needs to be done every time as gesture data is written directly to an update-buffer rather than via a message
758 gestureUpdated |= gesture.UpdateProperties( lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
761 return gestureUpdated;
764 void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
766 PERF_MONITOR_START(PerformanceMonitor::ANIMATE_NODES);
768 AnimationContainer &animations = mImpl->animations;
769 AnimationIter iter = animations.Begin();
770 while ( iter != animations.End() )
772 Animation* animation = *iter;
773 bool finished = animation->Update( bufferIndex, elapsedSeconds );
775 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
777 // Remove animations that had been destroyed but were still waiting for an update
778 if (animation->GetState() == Animation::Destroyed)
780 iter = animations.Erase(iter);
788 if ( mImpl->animationFinishedDuringUpdate )
790 // The application should be notified by NotificationManager, in another thread
791 mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationFinishedNotifier );
794 PERF_MONITOR_END(PerformanceMonitor::ANIMATE_NODES);
797 void UpdateManager::ApplyConstraints( BufferIndex bufferIndex )
799 PERF_MONITOR_START(PerformanceMonitor::APPLY_CONSTRAINTS);
801 // constrain custom objects... (in construction order)
802 OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
804 const OwnerContainer< PropertyOwner* >::Iterator endIter = customObjects.End();
805 for ( OwnerContainer< PropertyOwner* >::Iterator iter = customObjects.Begin(); endIter != iter; ++iter )
807 PropertyOwner& object = **iter;
808 ConstrainPropertyOwner( object, bufferIndex );
811 // constrain nodes... (in Depth First traversal order)
814 ConstrainNodes( *(mImpl->root), bufferIndex );
817 if ( mImpl->systemLevelRoot )
819 ConstrainNodes( *(mImpl->systemLevelRoot), bufferIndex );
822 // constrain other property-owners after nodes as they are more likely to depend on a node's
823 // current frame property than vice versa. They tend to be final constraints (no further
824 // constraints depend on their properties)
825 // e.g. ShaderEffect uniform a function of Actor's position.
826 // Mesh vertex a function of Actor's position or world position.
828 // TODO: refactor this code (and reset nodes) as these are all just lists of property-owners
829 // they can be all processed in a super-list of property-owners.
831 // Constrain system-level render-tasks
832 const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
834 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter )
836 RenderTask& task = **iter;
837 ConstrainPropertyOwner( task, bufferIndex );
840 // Constrain render-tasks
841 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
843 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(); iter != tasks.End(); ++iter )
845 RenderTask& task = **iter;
846 ConstrainPropertyOwner( task, bufferIndex );
849 // Constrain Materials and geometries
850 mImpl->materials.ConstrainObjects( bufferIndex );
851 mImpl->geometries.ConstrainObjects( bufferIndex );
852 mImpl->renderers.ConstrainObjects( bufferIndex );
854 // constrain shaders... (in construction order)
855 ShaderContainer& shaders = mImpl->shaders;
857 for ( ShaderIter iter = shaders.Begin(); iter != shaders.End(); ++iter )
859 Shader& shader = **iter;
860 ConstrainPropertyOwner( shader, bufferIndex );
863 PERF_MONITOR_END(PerformanceMonitor::APPLY_CONSTRAINTS);
866 void UpdateManager::ProcessPropertyNotifications( BufferIndex bufferIndex )
868 PropertyNotificationContainer ¬ifications = mImpl->propertyNotifications;
869 PropertyNotificationIter iter = notifications.Begin();
871 while ( iter != notifications.End() )
873 PropertyNotification* notification = *iter;
874 bool valid = notification->Check( bufferIndex );
877 mImpl->notificationManager.QueueMessage( PropertyChangedMessage( mImpl->propertyNotifier, notification, notification->GetValidity() ) );
883 void UpdateManager::ForwardCompiledShadersToEventThread()
885 DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." );
886 if( mImpl->shaderSaver )
888 // lock and swap the queues
890 // render might be attempting to send us more binaries at the same time
891 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
892 mImpl->renderCompiledShaders.swap( mImpl->updateCompiledShaders );
895 if( mImpl->updateCompiledShaders.size() > 0 )
897 ShaderSaver& factory = *mImpl->shaderSaver;
898 ShaderDataBinaryQueue::iterator i = mImpl->updateCompiledShaders.begin();
899 ShaderDataBinaryQueue::iterator end = mImpl->updateCompiledShaders.end();
900 for( ; i != end; ++i )
902 mImpl->notificationManager.QueueMessage( ShaderCompiledMessage( factory, *i ) );
904 // we don't need them in update anymore
905 mImpl->updateCompiledShaders.clear();
910 void UpdateManager::UpdateRenderers( BufferIndex bufferIndex )
912 const OwnerContainer<Renderer*>& rendererContainer( mImpl->renderers.GetObjectContainer() );
913 unsigned int rendererCount( rendererContainer.Size() );
914 for( unsigned int i(0); i<rendererCount; ++i )
916 if( rendererContainer[i]->IsReferenced() )
918 rendererContainer[i]->PrepareResources(bufferIndex, mImpl->resourceManager);
919 rendererContainer[i]->PrepareRender( bufferIndex );
924 void UpdateManager::UpdateNodes( BufferIndex bufferIndex )
926 mImpl->nodeDirtyFlags = NothingFlag;
933 PERF_MONITOR_START( PerformanceMonitor::UPDATE_NODES );
935 // Prepare resources, update shaders, update attachments, for each node
936 // And add the renderers to the sorted layers. Start from root, which is also a layer
937 mImpl->nodeDirtyFlags = UpdateNodesAndAttachments( *( mImpl->root ),
939 mImpl->resourceManager,
940 mImpl->renderQueue );
942 if ( mImpl->systemLevelRoot )
944 mImpl->nodeDirtyFlags |= UpdateNodesAndAttachments( *( mImpl->systemLevelRoot ),
946 mImpl->resourceManager,
947 mImpl->renderQueue );
950 PERF_MONITOR_END( PerformanceMonitor::UPDATE_NODES );
953 unsigned int UpdateManager::Update( float elapsedSeconds,
954 unsigned int lastVSyncTimeMilliseconds,
955 unsigned int nextVSyncTimeMilliseconds )
957 PERF_MONITOR_END(PerformanceMonitor::FRAME_RATE); // Mark the End of the last frame
958 PERF_MONITOR_NEXT_FRAME(); // Prints out performance info for the last frame (if enabled)
959 PERF_MONITOR_START(PerformanceMonitor::FRAME_RATE); // Mark the start of this current frame
961 // Measure the time spent in UpdateManager::Update
962 PERF_MONITOR_START(PerformanceMonitor::UPDATE);
964 const BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
966 // 1) Clear nodes/resources which were previously discarded
967 mImpl->discardQueue.Clear( bufferIndex );
969 // 2) Grab any loaded resources
970 bool resourceChanged = mImpl->resourceManager.UpdateCache( bufferIndex );
972 // 3) Process Touches & Gestures
973 mImpl->touchResampler.Update();
974 const bool gestureUpdated = ProcessGestures( bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
976 const bool updateScene = // The scene-graph requires an update if..
977 (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || // ..nodes were dirty in previous frame OR
978 IsAnimationRunning() || // ..at least one animation is running OR
979 mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR
980 resourceChanged || // ..one or more resources were updated/changed OR
981 gestureUpdated; // ..a gesture property was updated
984 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
985 // values if the scene was updated in the previous frame.
986 if( updateScene || mImpl->previousUpdateScene )
988 // 4) Reset properties from the previous update
989 ResetProperties( bufferIndex );
992 // 5) Process the queued scene messages
993 mImpl->messageQueue.ProcessMessages( bufferIndex );
995 // 6) Post Process Ids of resources updated by renderer
996 mImpl->resourceManager.PostProcessResources( bufferIndex );
998 // 6.1) Forward compiled shader programs to event thread for saving
999 ForwardCompiledShadersToEventThread();
1001 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
1002 // renderer lists if the scene was updated in the previous frame.
1003 // We should not start skipping update steps or reusing lists until there has been two frames where nothing changes
1004 if( updateScene || mImpl->previousUpdateScene )
1007 Animate( bufferIndex, elapsedSeconds );
1009 // 8) Apply Constraints
1010 ApplyConstraints( bufferIndex );
1012 // 9) Check Property Notifications
1013 ProcessPropertyNotifications( bufferIndex );
1015 // 10) Clear the lists of renderable-attachments from the previous update
1016 ClearRenderables( mImpl->sortedLayers );
1017 ClearRenderables( mImpl->systemLevelSortedLayers );
1019 // 11) Update node hierarchy and perform sorting / culling.
1020 // This will populate each Layer with a list of renderers which are ready.
1021 UpdateNodes( bufferIndex );
1022 UpdateRenderers( bufferIndex );
1025 // 12) Prepare for the next render
1026 PERF_MONITOR_START(PerformanceMonitor::PREPARE_RENDERABLES);
1028 PrepareRenderables( bufferIndex, mImpl->sortedLayers );
1029 PrepareRenderables( bufferIndex, mImpl->systemLevelSortedLayers );
1030 PERF_MONITOR_END(PerformanceMonitor::PREPARE_RENDERABLES);
1032 PERF_MONITOR_START(PerformanceMonitor::PROCESS_RENDER_TASKS);
1034 // 14) Process the RenderTasks; this creates the instructions for rendering the next frame.
1035 // reset the update buffer index and make sure there is enough room in the instruction container
1036 mImpl->renderInstructions.ResetAndReserve( bufferIndex,
1037 mImpl->taskList.GetTasks().Count() + mImpl->systemLevelTaskList.GetTasks().Count() );
1039 if ( NULL != mImpl->root )
1041 ProcessRenderTasks( bufferIndex,
1042 mImpl->completeStatusManager,
1045 mImpl->sortedLayers,
1046 mImpl->renderSortingHelper,
1047 mImpl->renderInstructions );
1049 // Process the system-level RenderTasks last
1050 if ( NULL != mImpl->systemLevelRoot )
1052 ProcessRenderTasks( bufferIndex,
1053 mImpl->completeStatusManager,
1054 mImpl->systemLevelTaskList,
1055 *mImpl->systemLevelRoot,
1056 mImpl->systemLevelSortedLayers,
1057 mImpl->renderSortingHelper,
1058 mImpl->renderInstructions );
1063 // check the countdown and notify (note, at the moment this is only done for normal tasks, not for systemlevel tasks)
1064 bool doRenderOnceNotify = false;
1065 mImpl->renderTaskWaiting = false;
1066 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
1067 for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(), endIter = tasks.End();
1068 endIter != iter; ++iter )
1070 RenderTask& renderTask(*(*iter));
1072 renderTask.UpdateState();
1074 if( renderTask.IsWaitingToRender() &&
1075 renderTask.ReadyToRender( bufferIndex ) /*avoid updating forever when source actor is off-stage*/ )
1077 mImpl->renderTaskWaiting = true; // keep update/render threads alive
1080 if( renderTask.HasRendered() )
1082 doRenderOnceNotify = true;
1086 if( doRenderOnceNotify )
1088 DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
1089 mImpl->notificationManager.QueueCompleteNotification( mImpl->taskList.GetCompleteNotificationInterface() );
1092 PERF_MONITOR_END(PerformanceMonitor::PROCESS_RENDER_TASKS);
1094 // Macro is undefined in release build.
1095 SNAPSHOT_NODE_LOGGING;
1097 // A ResetProperties() may be required in the next frame
1098 mImpl->previousUpdateScene = updateScene;
1100 // Check whether further updates are required
1101 unsigned int keepUpdating = KeepUpdatingCheck( elapsedSeconds );
1103 #ifdef PERFORMANCE_MONITOR_ENABLED
1104 // Always keep rendering when measuring FPS
1105 keepUpdating |= KeepUpdating::MONITORING_PERFORMANCE;
1108 // tell the update manager that we're done so the queue can be given to event thread
1109 mImpl->notificationManager.UpdateCompleted();
1111 // The update has finished; swap the double-buffering indices
1112 mSceneGraphBuffers.Swap();
1114 PERF_MONITOR_END(PerformanceMonitor::UPDATE);
1116 return keepUpdating;
1119 unsigned int UpdateManager::KeepUpdatingCheck( float elapsedSeconds ) const
1121 // Update the duration set via Stage::KeepRendering()
1122 if ( mImpl->keepRenderingSeconds > 0.0f )
1124 mImpl->keepRenderingSeconds -= elapsedSeconds;
1127 unsigned int keepUpdatingRequest = KeepUpdating::NOT_REQUESTED;
1129 // If Stage::KeepRendering() has been called, then continue until the duration has elapsed.
1130 // Keep updating until no messages are received and no animations are running.
1131 // If an animation has just finished, update at least once more for Discard end-actions.
1132 // No need to check for renderQueue as there is always a render after update and if that
1133 // render needs another update it will tell the adaptor to call update again
1135 if ( mImpl->keepRenderingSeconds > 0.0f )
1137 keepUpdatingRequest |= KeepUpdating::STAGE_KEEP_RENDERING;
1140 if ( IsAnimationRunning() ||
1141 mImpl->animationFinishedDuringUpdate )
1143 keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING;
1146 if ( mImpl->renderTaskWaiting )
1148 keepUpdatingRequest |= KeepUpdating::RENDER_TASK_SYNC;
1151 return keepUpdatingRequest;
1154 void UpdateManager::SetBackgroundColor( const Vector4& color )
1156 typedef MessageValue1< RenderManager, Vector4 > DerivedType;
1158 // Reserve some memory inside the render queue
1159 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1161 // Construct message in the render queue memory; note that delete should not be called on the return value
1162 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetBackgroundColor, color );
1165 void UpdateManager::SetDefaultSurfaceRect( const Rect<int>& rect )
1167 typedef MessageValue1< RenderManager, Rect<int> > DerivedType;
1169 // Reserve some memory inside the render queue
1170 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1172 // Construct message in the render queue memory; note that delete should not be called on the return value
1173 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetDefaultSurfaceRect, rect );
1176 void UpdateManager::KeepRendering( float durationSeconds )
1178 mImpl->keepRenderingSeconds = std::max( mImpl->keepRenderingSeconds, durationSeconds );
1181 void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, bool systemLevel )
1185 // just copy the vector of pointers
1186 mImpl->sortedLayers = layers;
1190 mImpl->systemLevelSortedLayers = layers;
1194 void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
1196 mImpl->shaderSaver = &upstream;
1199 void UpdateManager::AddSampler( Render::Sampler* sampler )
1201 typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
1203 // Reserve some memory inside the render queue
1204 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1206 // Construct message in the render queue memory; note that delete should not be called on the return value
1207 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddSampler, sampler );
1210 void UpdateManager::RemoveSampler( Render::Sampler* sampler )
1212 typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
1214 // Reserve some memory inside the render queue
1215 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1217 // Construct message in the render queue memory; note that delete should not be called on the return value
1218 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveSampler, sampler );
1221 void UpdateManager::SetFilterMode( Render::Sampler* sampler, unsigned int minFilterMode, unsigned int magFilterMode )
1223 typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
1225 // Reserve some memory inside the render queue
1226 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1228 // Construct message in the render queue memory; note that delete should not be called on the return value
1229 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetFilterMode, sampler, minFilterMode, magFilterMode );
1232 void UpdateManager::SetWrapMode( Render::Sampler* sampler, unsigned int uWrapMode, unsigned int vWrapMode )
1234 typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
1236 // Reserve some memory inside the render queue
1237 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1239 // Construct message in the render queue memory; note that delete should not be called on the return value
1240 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetWrapMode, sampler, uWrapMode, vWrapMode );
1243 void UpdateManager::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer )
1245 typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
1247 // Reserve some memory inside the render queue
1248 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1250 // Construct message in the render queue memory; note that delete should not be called on the return value
1251 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddPropertyBuffer, propertyBuffer );
1254 void UpdateManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
1256 typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
1258 // Reserve some memory inside the render queue
1259 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1261 // Construct message in the render queue memory; note that delete should not be called on the return value
1262 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemovePropertyBuffer, propertyBuffer );
1265 void UpdateManager::SetPropertyBufferFormat(Render::PropertyBuffer* propertyBuffer, Render::PropertyBuffer::Format* format )
1267 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, Render::PropertyBuffer::Format* > DerivedType;
1269 // Reserve some memory inside the render queue
1270 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1272 // Construct message in the render queue memory; note that delete should not be called on the return value
1273 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferFormat, propertyBuffer, format );
1276 void UpdateManager::SetPropertyBufferData(Render::PropertyBuffer* propertyBuffer, Dali::Vector<char>* data)
1278 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, Dali::Vector<char>* > DerivedType;
1280 // Reserve some memory inside the render queue
1281 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1283 // Construct message in the render queue memory; note that delete should not be called on the return value
1284 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferData, propertyBuffer, data );
1287 void UpdateManager::SetPropertyBufferSize(Render::PropertyBuffer* propertyBuffer, size_t size )
1289 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, size_t > DerivedType;
1291 // Reserve some memory inside the render queue
1292 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1294 // Construct message in the render queue memory; note that delete should not be called on the return value
1295 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferSize, propertyBuffer, size );
1298 } // namespace SceneGraph
1300 } // namespace Internal