2 * Copyright (c) 2017 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/owner-container.h>
24 #include <dali/devel-api/threading/mutex.h>
26 #include <dali/integration-api/core.h>
27 #include <dali/integration-api/render-controller.h>
28 #include <dali/internal/common/shader-data.h>
29 #include <dali/integration-api/debug.h>
31 #include <dali/internal/common/core-impl.h>
32 #include <dali/internal/common/message.h>
34 #include <dali/internal/event/common/notification-manager.h>
35 #include <dali/internal/event/common/property-notification-impl.h>
36 #include <dali/internal/event/common/property-notifier.h>
37 #include <dali/internal/event/effects/shader-factory.h>
38 #include <dali/internal/event/animation/animation-playlist.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/render-task-processor.h>
48 #include <dali/internal/update/manager/sorted-layers.h>
49 #include <dali/internal/update/manager/update-algorithms.h>
50 #include <dali/internal/update/manager/update-manager-debug.h>
51 #include <dali/internal/update/manager/transform-manager.h>
52 #include <dali/internal/update/nodes/node.h>
53 #include <dali/internal/update/nodes/scene-graph-layer.h>
54 #include <dali/internal/update/queue/update-message-queue.h>
55 #include <dali/internal/update/render-tasks/scene-graph-render-task.h>
56 #include <dali/internal/update/render-tasks/scene-graph-render-task-list.h>
57 #include <dali/internal/update/render-tasks/scene-graph-camera.h>
59 #include <dali/internal/render/common/render-instruction-container.h>
60 #include <dali/internal/render/common/render-manager.h>
61 #include <dali/internal/render/queue/render-queue.h>
62 #include <dali/internal/render/shaders/scene-graph-shader.h>
64 // Un-comment to enable node tree debug logging
65 //#define NODE_TREE_LOGGING 1
67 #if ( defined( DEBUG_ENABLED ) && defined( NODE_TREE_LOGGING ) )
68 #define SNAPSHOT_NODE_LOGGING \
69 const int FRAME_COUNT_TRIGGER = 16;\
70 if( mImpl->frameCounter >= FRAME_COUNT_TRIGGER )\
72 if ( NULL != mImpl->root )\
74 mImpl->frameCounter = 0;\
75 PrintNodeTree( *mImpl->root, mSceneGraphBuffers.GetUpdateBufferIndex(), "" );\
78 mImpl->frameCounter++;
80 #define SNAPSHOT_NODE_LOGGING
83 #if defined(DEBUG_ENABLED)
84 extern Debug::Filter* gRenderTaskLogFilter;
88 using namespace Dali::Integration;
89 using Dali::Internal::Update::MessageQueue;
103 * Helper to reset animate-able objects to base values
104 * @param container to iterate over
105 * @param updateBufferIndex to use
108 inline void ResetToBaseValues( OwnerContainer<T*>& container, BufferIndex updateBufferIndex )
110 // Reset animatable properties to base values
111 // use reference to avoid extra copies of the iterator
112 for( auto&& iter : container )
114 iter->ResetToBaseValues( updateBufferIndex );
119 * Helper to Erase an object from OwnerContainer using discard queue
120 * @param container to remove from
121 * @param object to remove
122 * @param discardQueue to put the object to
123 * @param updateBufferIndex to use
126 inline void EraseUsingDiscardQueue( OwnerContainer<T*>& container, T* object, DiscardQueue& discardQueue, BufferIndex updateBufferIndex )
128 DALI_ASSERT_DEBUG( object && "NULL object not allowed" );
130 // need to use the reference version of auto as we need the pointer to the pointer for the Release call below
131 for( auto&& iter : container )
133 if ( iter == object )
135 // Transfer ownership to the discard queue, this keeps the object alive, until the render-thread has finished with it
136 discardQueue.Add( updateBufferIndex, container.Release( &iter ) ); // take the address of the reference to a pointer (iter)
137 return; // return as we only ever remove one object. Iterators to container are now invalidated as well so cannot continue
143 * Descends into node's hierarchy and sorts the children of each child according to their depth-index.
144 * @param[in] node The node whose hierarchy to descend
146 void SortSiblingNodesRecursively( Node& node )
148 NodeContainer& container = node.GetChildren();
149 std::sort( container.Begin(), container.End(),
150 []( Node* a, Node* b ) { return a->GetDepthIndex() < b->GetDepthIndex(); } );
152 // Descend tree and sort as well
153 for( auto&& iter : container )
155 SortSiblingNodesRecursively( *iter );
159 } // unnamed namespace
162 * Structure to contain UpdateManager internal data
164 struct UpdateManager::Impl
166 Impl( NotificationManager& notificationManager,
167 CompleteNotificationInterface& animationPlaylist,
168 PropertyNotifier& propertyNotifier,
169 DiscardQueue& discardQueue,
170 RenderController& renderController,
171 RenderManager& renderManager,
172 RenderQueue& renderQueue,
173 SceneGraphBuffers& sceneGraphBuffers,
174 RenderTaskProcessor& renderTaskProcessor )
175 : renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
176 notificationManager( notificationManager ),
178 animationPlaylist( animationPlaylist ),
179 propertyNotifier( propertyNotifier ),
181 discardQueue( discardQueue ),
182 renderController( renderController ),
183 sceneController( NULL ),
184 renderManager( renderManager ),
185 renderQueue( renderQueue ),
186 renderInstructions( renderManager.GetRenderInstructionContainer() ),
187 renderTaskProcessor( renderTaskProcessor ),
188 backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
189 taskList( renderMessageDispatcher ),
190 systemLevelTaskList( renderMessageDispatcher ),
192 systemLevelRoot( NULL ),
196 panGestureProcessor( NULL ),
197 messageQueue( renderController, sceneGraphBuffers ),
198 keepRenderingSeconds( 0.0f ),
199 nodeDirtyFlags( TransformFlag ), // set to TransformFlag to ensure full update the first time through Update()
201 animationFinishedDuringUpdate( false ),
202 previousUpdateScene( false ),
203 renderTaskWaiting( false ),
204 renderersAdded( false )
206 sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
208 // create first 'dummy' node
214 // Disconnect render tasks from nodes, before destroying the nodes
215 RenderTaskList::RenderTaskContainer& tasks = taskList.GetTasks();
216 for ( auto&& iter : tasks )
218 iter->SetSourceNode( NULL );
220 // ..repeat for system level RenderTasks
221 RenderTaskList::RenderTaskContainer& systemLevelTasks = systemLevelTaskList.GetTasks();
222 for ( auto&& iter : systemLevelTasks )
224 iter->SetSourceNode( NULL );
227 // UpdateManager owns the Nodes. Although Nodes are pool allocated they contain heap allocated parts
228 // like custom properties, which get released here
229 Vector<Node*>::Iterator iter = nodes.Begin()+1;
230 Vector<Node*>::Iterator endIter = nodes.End();
231 for(;iter!=endIter;++iter)
233 (*iter)->OnDestroy();
237 // If there is root, reset it, otherwise do nothing as rendering was never started
242 Node::Delete( root );
246 if( systemLevelRoot )
248 systemLevelRoot->OnDestroy();
250 Node::Delete( systemLevelRoot );
251 systemLevelRoot = NULL;
254 delete sceneController;
257 SceneGraphBuffers sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read
258 RenderMessageDispatcher renderMessageDispatcher; ///< Used for passing messages to the render-thread
259 NotificationManager& notificationManager; ///< Queues notification messages for the event-thread.
260 TransformManager transformManager; ///< Used to update the transformation matrices of the nodes
261 CompleteNotificationInterface& animationPlaylist; ///< Holds handles to all the animations
262 PropertyNotifier& propertyNotifier; ///< Provides notification to applications when properties are modified.
263 ShaderSaver* shaderSaver; ///< Saves shader binaries.
264 DiscardQueue& discardQueue; ///< Nodes are added here when disconnected from the scene-graph.
265 RenderController& renderController; ///< render controller
266 SceneControllerImpl* sceneController; ///< scene controller
267 RenderManager& renderManager; ///< This is responsible for rendering the results of each "update"
268 RenderQueue& renderQueue; ///< Used to queue messages for the next render
269 RenderInstructionContainer& renderInstructions; ///< Used to prepare the render instructions
270 RenderTaskProcessor& renderTaskProcessor; ///< Handles RenderTasks and RenderInstrucitons
272 Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
274 RenderTaskList taskList; ///< The list of scene graph render-tasks
275 RenderTaskList systemLevelTaskList; ///< Separate render-tasks for system-level content
277 Layer* root; ///< The root node (root is a layer)
278 Layer* systemLevelRoot; ///< A separate root-node for system-level content
280 Vector<Node*> nodes; ///< A container of all instantiated nodes
282 SortedLayerPointers sortedLayers; ///< A container of Layer pointers sorted by depth
283 SortedLayerPointers systemLevelSortedLayers; ///< A separate container of system-level Layers
285 OwnerContainer< Camera* > cameras; ///< A container of cameras
286 OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties)
288 AnimationContainer animations; ///< A container of owned animations
289 PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
291 OwnerContainer< Renderer* > renderers; ///< A container of owned renderers
292 OwnerContainer< TextureSet* > textureSets; ///< A container of owned texture sets
293 OwnerContainer< Shader* > shaders; ///< A container of owned shaders
294 OwnerPointer< PanGesture > panGestureProcessor; ///< Owned pan gesture processor; it lives for the lifecycle of UpdateManager
296 MessageQueue messageQueue; ///< The messages queued from the event-thread
297 std::vector<Internal::ShaderDataPtr> renderCompiledShaders; ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread.
298 std::vector<Internal::ShaderDataPtr> updateCompiledShaders; ///< Shaders to be sent from Update to Event
299 Mutex compiledShaderMutex; ///< lock to ensure no corruption on the renderCompiledShaders
301 float keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering
302 int nodeDirtyFlags; ///< cumulative node dirty flags from previous frame
303 int frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
305 bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
306 bool previousUpdateScene; ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
307 bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered
308 bool renderersAdded; ///< Flag to keep track when renderers have been added to avoid unnecessary processing
312 Impl( const Impl& ); ///< Undefined
313 Impl& operator=( const Impl& ); ///< Undefined
316 UpdateManager::UpdateManager( NotificationManager& notificationManager,
317 CompleteNotificationInterface& animationFinishedNotifier,
318 PropertyNotifier& propertyNotifier,
319 DiscardQueue& discardQueue,
320 RenderController& controller,
321 RenderManager& renderManager,
322 RenderQueue& renderQueue,
323 RenderTaskProcessor& renderTaskProcessor )
326 mImpl = new Impl( notificationManager,
327 animationFinishedNotifier,
334 renderTaskProcessor );
338 UpdateManager::~UpdateManager()
343 void UpdateManager::InstallRoot( OwnerPointer<Layer>& layer, bool systemLevel )
345 DALI_ASSERT_DEBUG( layer->IsLayer() );
346 DALI_ASSERT_DEBUG( layer->GetParent() == NULL);
350 DALI_ASSERT_DEBUG( mImpl->root == NULL && "Root Node already installed" );
351 mImpl->root = layer.Release();
352 mImpl->root->CreateTransform( &mImpl->transformManager );
353 mImpl->root->SetRoot(true);
357 DALI_ASSERT_DEBUG( mImpl->systemLevelRoot == NULL && "System-level Root Node already installed" );
358 mImpl->systemLevelRoot = layer.Release();
359 mImpl->systemLevelRoot->CreateTransform( &mImpl->transformManager );
360 mImpl->systemLevelRoot->SetRoot(true);
365 void UpdateManager::AddNode( OwnerPointer<Node>& node )
367 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
369 // Nodes must be sorted by pointer
370 Node* rawNode = node.Release();
371 Vector<Node*>::Iterator begin = mImpl->nodes.Begin();
372 for( Vector<Node*>::Iterator iter = mImpl->nodes.End()-1; iter >= begin; --iter )
374 if( rawNode > (*iter) )
376 mImpl->nodes.Insert((iter+1), rawNode );
377 rawNode->CreateTransform( &mImpl->transformManager );
383 void UpdateManager::ConnectNode( Node* parent, Node* node )
385 DALI_ASSERT_ALWAYS( NULL != parent );
386 DALI_ASSERT_ALWAYS( NULL != node );
387 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
389 parent->ConnectChild( node );
392 void UpdateManager::DisconnectNode( Node* node )
394 Node* parent = node->GetParent();
395 DALI_ASSERT_ALWAYS( NULL != parent );
396 parent->SetDirtyFlag( ChildDeletedFlag ); // make parent dirty so that render items dont get reused
398 parent->DisconnectChild( mSceneGraphBuffers.GetUpdateBufferIndex(), *node );
401 void UpdateManager::DestroyNode( Node* node )
403 DALI_ASSERT_ALWAYS( NULL != node );
404 DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should have been disconnected
406 Vector<Node*>::Iterator iter = mImpl->nodes.Begin()+1;
407 Vector<Node*>::Iterator endIter = mImpl->nodes.End();
408 for(;iter!=endIter;++iter)
412 mImpl->nodes.Erase(iter);
417 mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), node );
419 // Notify the Node about impending destruction
423 void UpdateManager::AddCamera( OwnerPointer< Camera >& camera )
425 mImpl->cameras.PushBack( camera.Release() ); // takes ownership
428 void UpdateManager::RemoveCamera( const Camera* camera )
430 // Find the camera and destroy it
431 EraseUsingDiscardQueue( mImpl->cameras, const_cast<Camera*>( camera ), mImpl->discardQueue, mSceneGraphBuffers.GetUpdateBufferIndex() );
434 void UpdateManager::AddObject( OwnerPointer<PropertyOwner>& object )
436 mImpl->customObjects.PushBack( object.Release() );
439 void UpdateManager::RemoveObject( PropertyOwner* object )
441 mImpl->customObjects.EraseObject( object );
444 void UpdateManager::AddAnimation( OwnerPointer< SceneGraph::Animation >& animation )
446 mImpl->animations.PushBack( animation.Release() );
449 void UpdateManager::StopAnimation( Animation* animation )
451 DALI_ASSERT_DEBUG( animation && "NULL animation called to stop" );
453 bool animationFinished = animation->Stop( mSceneGraphBuffers.GetUpdateBufferIndex() );
455 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || animationFinished;
458 void UpdateManager::RemoveAnimation( Animation* animation )
460 DALI_ASSERT_DEBUG( animation && "NULL animation called to remove" );
462 animation->OnDestroy( mSceneGraphBuffers.GetUpdateBufferIndex() );
464 DALI_ASSERT_DEBUG( animation->GetState() == Animation::Destroyed );
467 bool UpdateManager::IsAnimationRunning() const
469 // Find any animation that isn't stopped or paused
470 for ( auto&& iter : mImpl->animations )
472 const Animation::State state = iter->GetState();
474 if (state != Animation::Stopped &&
475 state != Animation::Paused)
477 return true; // stop iteration as soon as first one is found
484 void UpdateManager::AddPropertyNotification( OwnerPointer< PropertyNotification >& propertyNotification )
486 mImpl->propertyNotifications.PushBack( propertyNotification.Release() );
489 void UpdateManager::RemovePropertyNotification( PropertyNotification* propertyNotification )
491 mImpl->propertyNotifications.EraseObject( propertyNotification );
494 void UpdateManager::PropertyNotificationSetNotify( PropertyNotification* propertyNotification, PropertyNotification::NotifyMode notifyMode )
496 DALI_ASSERT_DEBUG( propertyNotification && "propertyNotification scene graph object missing" );
497 propertyNotification->SetNotifyMode( notifyMode );
500 void UpdateManager::AddShader( OwnerPointer< Shader >& shader )
502 mImpl->shaders.PushBack( shader.Release() );
505 void UpdateManager::RemoveShader( Shader* shader )
507 // Find the shader and destroy it
508 EraseUsingDiscardQueue( mImpl->shaders, shader, mImpl->discardQueue, mSceneGraphBuffers.GetUpdateBufferIndex() );
511 void UpdateManager::SetShaderProgram( Shader* shader,
512 Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
517 typedef MessageValue3< Shader, Internal::ShaderDataPtr, ProgramCache*, bool> DerivedType;
519 // Reserve some memory inside the render queue
520 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
522 // Construct message in the render queue memory; note that delete should not be called on the return value
523 new (slot) DerivedType( shader, &Shader::SetProgram, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
527 void UpdateManager::SaveBinary( Internal::ShaderDataPtr shaderData )
529 DALI_ASSERT_DEBUG( shaderData && "No NULL shader data pointers please." );
530 DALI_ASSERT_DEBUG( shaderData->GetBufferSize() > 0 && "Shader binary empty so nothing to save." );
532 // lock as update might be sending previously compiled shaders to event thread
533 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
534 mImpl->renderCompiledShaders.push_back( shaderData );
538 void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
540 mImpl->shaderSaver = &upstream;
543 void UpdateManager::AddRenderer( OwnerPointer< Renderer >& renderer )
545 renderer->ConnectToSceneGraph( *mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex() );
546 mImpl->renderers.PushBack( renderer.Release() );
547 mImpl->renderersAdded = true;
550 void UpdateManager::RemoveRenderer( Renderer* renderer )
552 // Find the renderer and destroy it
553 EraseUsingDiscardQueue( mImpl->renderers, renderer, mImpl->discardQueue, mSceneGraphBuffers.GetUpdateBufferIndex() );
554 // Need to remove the render object as well
555 renderer->DisconnectFromSceneGraph( *mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex() );
558 void UpdateManager::SetPanGestureProcessor( PanGesture* panGestureProcessor )
560 DALI_ASSERT_DEBUG( NULL != panGestureProcessor );
562 mImpl->panGestureProcessor = panGestureProcessor;
565 void UpdateManager::AddTextureSet( OwnerPointer< TextureSet >& textureSet )
567 mImpl->textureSets.PushBack( textureSet.Release() );
570 void UpdateManager::RemoveTextureSet( TextureSet* textureSet )
572 mImpl->textureSets.EraseObject( textureSet );
575 RenderTaskList* UpdateManager::GetRenderTaskList( bool systemLevel )
579 // copy the list, this is only likely to happen once in application life cycle
580 return &(mImpl->taskList);
584 // copy the list, this is only likely to happen once in application life cycle
585 return &(mImpl->systemLevelTaskList);
589 unsigned int* UpdateManager::ReserveMessageSlot( std::size_t size, bool updateScene )
591 return mImpl->messageQueue.ReserveMessageSlot( size, updateScene );
594 void UpdateManager::EventProcessingStarted()
596 mImpl->messageQueue.EventProcessingStarted();
599 bool UpdateManager::FlushQueue()
601 return mImpl->messageQueue.FlushQueue();
604 void UpdateManager::ResetProperties( BufferIndex bufferIndex )
606 // Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped
607 mImpl->animationFinishedDuringUpdate = false;
609 // Animated properties have to be reset to their original value each frame
611 // Reset root properties
614 mImpl->root->ResetToBaseValues( bufferIndex );
616 if ( mImpl->systemLevelRoot )
618 mImpl->systemLevelRoot->ResetToBaseValues( bufferIndex );
621 // Reset all the nodes
622 Vector<Node*>::Iterator iter = mImpl->nodes.Begin()+1;
623 Vector<Node*>::Iterator endIter = mImpl->nodes.End();
624 for( ;iter != endIter; ++iter )
626 (*iter)->ResetToBaseValues( bufferIndex );
629 // Reset system-level render-task list properties to base values
630 ResetToBaseValues( mImpl->systemLevelTaskList.GetTasks(), bufferIndex );
632 // Reset render-task list properties to base values.
633 ResetToBaseValues( mImpl->taskList.GetTasks(), bufferIndex );
635 // Reset custom object properties to base values
636 ResetToBaseValues( mImpl->customObjects, bufferIndex );
638 // Reset animatable renderer properties to base values
639 ResetToBaseValues( mImpl->renderers, bufferIndex );
641 // Reset animatable shader properties to base values
642 ResetToBaseValues( mImpl->shaders, bufferIndex );
645 bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
647 bool gestureUpdated( false );
649 if( mImpl->panGestureProcessor )
651 // gesture processor only supports default properties
652 mImpl->panGestureProcessor->ResetDefaultProperties( bufferIndex ); // Needs to be done every time as gesture data is written directly to an update-buffer rather than via a message
653 gestureUpdated |= mImpl->panGestureProcessor->UpdateProperties( lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
656 return gestureUpdated;
659 void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
661 AnimationContainer &animations = mImpl->animations;
662 AnimationIter iter = animations.Begin();
663 bool animationLooped = false;
665 while ( iter != animations.End() )
667 Animation* animation = *iter;
668 bool finished = false;
670 bool progressMarkerReached = false;
671 animation->Update( bufferIndex, elapsedSeconds, looped, finished, progressMarkerReached );
673 if ( progressMarkerReached )
675 mImpl->notificationManager.QueueMessage( Internal::NotifyProgressReachedMessage( mImpl->animationPlaylist, animation ) );
678 mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
679 animationLooped = animationLooped || looped;
681 // Remove animations that had been destroyed but were still waiting for an update
682 if (animation->GetState() == Animation::Destroyed)
684 iter = animations.Erase(iter);
692 // queue the notification on finished or looped (to update loop count)
693 if ( mImpl->animationFinishedDuringUpdate || animationLooped )
695 // The application should be notified by NotificationManager, in another thread
696 mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationPlaylist );
700 void UpdateManager::ConstrainCustomObjects( BufferIndex bufferIndex )
702 //Constrain custom objects (in construction order)
703 for ( auto&& object : mImpl->customObjects )
705 ConstrainPropertyOwner( *object, bufferIndex );
709 void UpdateManager::ConstrainRenderTasks( BufferIndex bufferIndex )
711 // Constrain system-level render-tasks
712 const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
713 for ( auto&& task : systemLevelTasks )
715 ConstrainPropertyOwner( *task, bufferIndex );
718 // Constrain render-tasks
719 const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
720 for ( auto&& task : tasks )
722 ConstrainPropertyOwner( *task, bufferIndex );
726 void UpdateManager::ConstrainShaders( BufferIndex bufferIndex )
728 // constrain shaders... (in construction order)
729 for ( auto&& shader : mImpl->shaders )
731 ConstrainPropertyOwner( *shader, bufferIndex );
735 void UpdateManager::ProcessPropertyNotifications( BufferIndex bufferIndex )
737 for( auto&& notification : mImpl->propertyNotifications )
739 bool valid = notification->Check( bufferIndex );
742 mImpl->notificationManager.QueueMessage( PropertyChangedMessage( mImpl->propertyNotifier, notification, notification->GetValidity() ) );
747 void UpdateManager::ForwardCompiledShadersToEventThread()
749 DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." );
750 if( mImpl->shaderSaver )
752 // lock and swap the queues
754 // render might be attempting to send us more binaries at the same time
755 Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
756 mImpl->renderCompiledShaders.swap( mImpl->updateCompiledShaders );
759 if( mImpl->updateCompiledShaders.size() > 0 )
761 ShaderSaver& factory = *mImpl->shaderSaver;
762 for( auto&& shader : mImpl->updateCompiledShaders )
764 mImpl->notificationManager.QueueMessage( ShaderCompiledMessage( factory, shader ) );
766 // we don't need them in update anymore
767 mImpl->updateCompiledShaders.clear();
772 void UpdateManager::UpdateRenderers( BufferIndex bufferIndex )
774 const unsigned int rendererCount = mImpl->renderers.Count();
775 for( unsigned int i = 0; i < rendererCount; ++i )
778 ConstrainPropertyOwner( *mImpl->renderers[i], bufferIndex );
780 mImpl->renderers[i]->PrepareRender( bufferIndex );
784 void UpdateManager::UpdateNodes( BufferIndex bufferIndex )
786 mImpl->nodeDirtyFlags = NothingFlag;
793 // Prepare resources, update shaders, for each node
794 // And add the renderers to the sorted layers. Start from root, which is also a layer
795 mImpl->nodeDirtyFlags = UpdateNodeTree( *( mImpl->root ),
797 mImpl->renderQueue );
799 if ( mImpl->systemLevelRoot )
801 mImpl->nodeDirtyFlags |= UpdateNodeTree( *( mImpl->systemLevelRoot ),
803 mImpl->renderQueue );
807 unsigned int UpdateManager::Update( float elapsedSeconds,
808 unsigned int lastVSyncTimeMilliseconds,
809 unsigned int nextVSyncTimeMilliseconds,
810 bool renderToFboEnabled,
811 bool isRenderingToFbo )
813 const BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
815 //Clear nodes/resources which were previously discarded
816 mImpl->discardQueue.Clear( bufferIndex );
818 //Process Touches & Gestures
819 const bool gestureUpdated = ProcessGestures( bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
821 bool updateScene = // The scene-graph requires an update if..
822 (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || // ..nodes were dirty in previous frame OR
823 IsAnimationRunning() || // ..at least one animation is running OR
824 mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR
825 gestureUpdated; // ..a gesture property was updated
828 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
829 // values if the scene was updated in the previous frame.
830 if( updateScene || mImpl->previousUpdateScene )
832 //Reset properties from the previous update
833 ResetProperties( bufferIndex );
834 mImpl->transformManager.ResetToBaseValue();
837 // Process the queued scene messages. Note, MessageQueue::FlushQueue may be called
838 // between calling IsSceneUpdateRequired() above and here, so updateScene should
840 updateScene |= mImpl->messageQueue.ProcessMessages( bufferIndex );
842 //Forward compiled shader programs to event thread for saving
843 ForwardCompiledShadersToEventThread();
845 // Although the scene-graph may not require an update, we still need to synchronize double-buffered
846 // renderer lists if the scene was updated in the previous frame.
847 // We should not start skipping update steps or reusing lists until there has been two frames where nothing changes
848 if( updateScene || mImpl->previousUpdateScene )
851 Animate( bufferIndex, elapsedSeconds );
853 //Constraint custom objects
854 ConstrainCustomObjects( bufferIndex );
856 //Clear the lists of renderers from the previous update
857 for( size_t i(0); i<mImpl->sortedLayers.size(); ++i )
859 mImpl->sortedLayers[i]->ClearRenderables();
862 for( size_t i(0); i<mImpl->systemLevelSortedLayers.size(); ++i )
864 mImpl->systemLevelSortedLayers[i]->ClearRenderables();
867 //Update node hierarchy, apply constraints and perform sorting / culling.
868 //This will populate each Layer with a list of renderers which are ready.
869 UpdateNodes( bufferIndex );
871 //Apply constraints to RenderTasks, shaders
872 ConstrainRenderTasks( bufferIndex );
873 ConstrainShaders( bufferIndex );
875 //Update renderers and apply constraints
876 UpdateRenderers( bufferIndex );
878 //Update the trnasformations of all the nodes
879 mImpl->transformManager.Update();
881 //Process Property Notifications
882 ProcessPropertyNotifications( bufferIndex );
885 for( auto&& cameraIterator : mImpl->cameras )
887 cameraIterator->Update( bufferIndex );
890 //Process the RenderTasks if renderers exist. This creates the instructions for rendering the next frame.
891 //reset the update buffer index and make sure there is enough room in the instruction container
892 if( mImpl->renderersAdded )
894 mImpl->renderInstructions.ResetAndReserve( bufferIndex,
895 mImpl->taskList.GetTasks().Count() + mImpl->systemLevelTaskList.GetTasks().Count() );
897 if ( NULL != mImpl->root )
899 mImpl->renderTaskProcessor.Process( bufferIndex,
903 mImpl->renderInstructions,
907 // Process the system-level RenderTasks last
908 if ( NULL != mImpl->systemLevelRoot )
910 mImpl->renderTaskProcessor.Process( bufferIndex,
911 mImpl->systemLevelTaskList,
912 *mImpl->systemLevelRoot,
913 mImpl->systemLevelSortedLayers,
914 mImpl->renderInstructions,
922 // check the countdown and notify (note, at the moment this is only done for normal tasks, not for systemlevel tasks)
923 bool doRenderOnceNotify = false;
924 mImpl->renderTaskWaiting = false;
925 for ( auto&& renderTask : mImpl->taskList.GetTasks() )
927 renderTask->UpdateState();
929 if( renderTask->IsWaitingToRender() &&
930 renderTask->ReadyToRender( bufferIndex ) /*avoid updating forever when source actor is off-stage*/ )
932 mImpl->renderTaskWaiting = true; // keep update/render threads alive
935 if( renderTask->HasRendered() )
937 doRenderOnceNotify = true;
941 if( doRenderOnceNotify )
943 DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
944 mImpl->notificationManager.QueueCompleteNotification( mImpl->taskList.GetCompleteNotificationInterface() );
947 // Macro is undefined in release build.
948 SNAPSHOT_NODE_LOGGING;
950 // A ResetProperties() may be required in the next frame
951 mImpl->previousUpdateScene = updateScene;
953 // Check whether further updates are required
954 unsigned int keepUpdating = KeepUpdatingCheck( elapsedSeconds );
956 // tell the update manager that we're done so the queue can be given to event thread
957 mImpl->notificationManager.UpdateCompleted();
959 // The update has finished; swap the double-buffering indices
960 mSceneGraphBuffers.Swap();
965 unsigned int UpdateManager::KeepUpdatingCheck( float elapsedSeconds ) const
967 // Update the duration set via Stage::KeepRendering()
968 if ( mImpl->keepRenderingSeconds > 0.0f )
970 mImpl->keepRenderingSeconds -= elapsedSeconds;
973 unsigned int keepUpdatingRequest = KeepUpdating::NOT_REQUESTED;
975 // If Stage::KeepRendering() has been called, then continue until the duration has elapsed.
976 // Keep updating until no messages are received and no animations are running.
977 // If an animation has just finished, update at least once more for Discard end-actions.
978 // No need to check for renderQueue as there is always a render after update and if that
979 // render needs another update it will tell the adaptor to call update again
981 if ( mImpl->keepRenderingSeconds > 0.0f )
983 keepUpdatingRequest |= KeepUpdating::STAGE_KEEP_RENDERING;
986 if ( IsAnimationRunning() ||
987 mImpl->animationFinishedDuringUpdate )
989 keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING;
992 if ( mImpl->renderTaskWaiting )
994 keepUpdatingRequest |= KeepUpdating::RENDER_TASK_SYNC;
997 return keepUpdatingRequest;
1000 void UpdateManager::SetBackgroundColor( const Vector4& color )
1002 typedef MessageValue1< RenderManager, Vector4 > DerivedType;
1004 // Reserve some memory inside the render queue
1005 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1007 // Construct message in the render queue memory; note that delete should not be called on the return value
1008 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetBackgroundColor, color );
1011 void UpdateManager::SetDefaultSurfaceRect( const Rect<int>& rect )
1013 typedef MessageValue1< RenderManager, Rect<int> > DerivedType;
1015 // Reserve some memory inside the render queue
1016 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1018 // Construct message in the render queue memory; note that delete should not be called on the return value
1019 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetDefaultSurfaceRect, rect );
1022 void UpdateManager::KeepRendering( float durationSeconds )
1024 mImpl->keepRenderingSeconds = std::max( mImpl->keepRenderingSeconds, durationSeconds );
1027 void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, bool systemLevel )
1031 // just copy the vector of pointers
1032 mImpl->sortedLayers = layers;
1036 mImpl->systemLevelSortedLayers = layers;
1040 void UpdateManager::SetDepthIndices( OwnerPointer< NodeDepths >& nodeDepths )
1042 // note,this vector is already in depth order. It could be used as-is to
1043 // remove sorting in update algorithm. However, it lacks layer boundary markers.
1044 for( auto&& iter : nodeDepths->nodeDepths )
1046 iter.node->SetDepthIndex( iter.sortedDepth );
1049 // Go through node hierarchy and rearrange siblings according to depth-index
1050 SortSiblingNodesRecursively( *( mImpl->root ) );
1053 void UpdateManager::AddSampler( OwnerPointer< Render::Sampler >& sampler )
1055 // Message has ownership of Sampler while in transit from update to render
1056 typedef MessageValue1< RenderManager, OwnerPointer< Render::Sampler > > DerivedType;
1058 // Reserve some memory inside the render queue
1059 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1061 // Construct message in the render queue memory; note that delete should not be called on the return value
1062 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddSampler, sampler );
1065 void UpdateManager::RemoveSampler( Render::Sampler* sampler )
1067 typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
1069 // Reserve some memory inside the render queue
1070 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1072 // Construct message in the render queue memory; note that delete should not be called on the return value
1073 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveSampler, sampler );
1076 void UpdateManager::SetFilterMode( Render::Sampler* sampler, unsigned int minFilterMode, unsigned int magFilterMode )
1078 typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
1080 // Reserve some memory inside the render queue
1081 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1083 // Construct message in the render queue memory; note that delete should not be called on the return value
1084 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetFilterMode, sampler, minFilterMode, magFilterMode );
1087 void UpdateManager::SetWrapMode( Render::Sampler* sampler, unsigned int rWrapMode, unsigned int sWrapMode, unsigned int tWrapMode )
1089 typedef MessageValue4< RenderManager, Render::Sampler*, unsigned int, unsigned int, unsigned int > DerivedType;
1091 // Reserve some memory inside the render queue
1092 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1094 // Construct message in the render queue memory; note that delete should not be called on the return value
1095 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetWrapMode, sampler, rWrapMode, sWrapMode, tWrapMode );
1098 void UpdateManager::AddPropertyBuffer( OwnerPointer< Render::PropertyBuffer >& propertyBuffer )
1100 // Message has ownership of format while in transit from update -> render
1101 typedef MessageValue1< RenderManager, OwnerPointer< Render::PropertyBuffer > > DerivedType;
1103 // Reserve some memory inside the render queue
1104 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1106 // Construct message in the render queue memory; note that delete should not be called on the return value
1107 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddPropertyBuffer, propertyBuffer );
1110 void UpdateManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
1112 typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
1114 // Reserve some memory inside the render queue
1115 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1117 // Construct message in the render queue memory; note that delete should not be called on the return value
1118 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemovePropertyBuffer, propertyBuffer );
1121 void UpdateManager::SetPropertyBufferFormat( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Render::PropertyBuffer::Format>& format )
1123 // Message has ownership of format while in transit from update -> render
1124 typedef MessageValue2< RenderManager, Render::PropertyBuffer*, OwnerPointer< Render::PropertyBuffer::Format > > DerivedType;
1126 // Reserve some memory inside the render queue
1127 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1129 // Construct message in the render queue memory; note that delete should not be called on the return value
1130 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferFormat, propertyBuffer, format );
1133 void UpdateManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Vector<char> >& data, size_t size )
1135 // Message has ownership of format while in transit from update -> render
1136 typedef MessageValue3< RenderManager, Render::PropertyBuffer*, OwnerPointer< Dali::Vector<char> >, size_t > DerivedType;
1138 // Reserve some memory inside the render queue
1139 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1141 // Construct message in the render queue memory; note that delete should not be called on the return value
1142 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferData, propertyBuffer, data, size );
1145 void UpdateManager::AddGeometry( OwnerPointer< Render::Geometry >& geometry )
1147 // Message has ownership of format while in transit from update -> render
1148 typedef MessageValue1< RenderManager, OwnerPointer< Render::Geometry > > DerivedType;
1150 // Reserve some memory inside the render queue
1151 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1153 // Construct message in the render queue memory; note that delete should not be called on the return value
1154 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddGeometry, geometry );
1157 void UpdateManager::RemoveGeometry( Render::Geometry* geometry )
1159 typedef MessageValue1< RenderManager, Render::Geometry* > DerivedType;
1161 // Reserve some memory inside the render queue
1162 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1164 // Construct message in the render queue memory; note that delete should not be called on the return value
1165 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveGeometry, geometry );
1168 void UpdateManager::SetGeometryType( Render::Geometry* geometry, unsigned int geometryType )
1170 typedef MessageValue2< RenderManager, Render::Geometry*, unsigned int > DerivedType;
1172 // Reserve some memory inside the render queue
1173 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1175 // Construct message in the render queue memory; note that delete should not be called on the return value
1176 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetGeometryType, geometry, geometryType );
1179 void UpdateManager::SetIndexBuffer( Render::Geometry* geometry, Dali::Vector<unsigned short>& indices )
1181 typedef IndexBufferMessage< RenderManager > DerivedType;
1183 // Reserve some memory inside the render queue
1184 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1186 // Construct message in the render queue memory; note that delete should not be called on the return value
1187 new (slot) DerivedType( &mImpl->renderManager, geometry, indices );
1190 void UpdateManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
1192 typedef MessageValue2< RenderManager, Render::Geometry*, Render::PropertyBuffer* > DerivedType;
1194 // Reserve some memory inside the render queue
1195 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1197 // Construct message in the render queue memory; note that delete should not be called on the return value
1198 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveVertexBuffer, geometry, propertyBuffer );
1201 void UpdateManager::AttachVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
1203 typedef MessageValue2< RenderManager, Render::Geometry*, Render::PropertyBuffer* > DerivedType;
1205 // Reserve some memory inside the render queue
1206 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1208 // Construct message in the render queue memory; note that delete should not be called on the return value
1209 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AttachVertexBuffer, geometry, propertyBuffer );
1212 void UpdateManager::AddTexture( OwnerPointer< Render::Texture >& texture )
1214 // Message has ownership of Texture while in transit from update -> render
1215 typedef MessageValue1< RenderManager, OwnerPointer< Render::Texture > > DerivedType;
1217 // Reserve some memory inside the render queue
1218 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1220 // Construct message in the render queue memory; note that delete should not be called on the return value
1221 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddTexture, texture );
1224 void UpdateManager::RemoveTexture( Render::Texture* texture)
1226 typedef MessageValue1< RenderManager, Render::Texture* > DerivedType;
1228 // Reserve some memory inside the render queue
1229 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1231 // Construct message in the render queue memory; note that delete should not be called on the return value
1232 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveTexture, texture );
1235 void UpdateManager::UploadTexture( Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params )
1237 typedef MessageValue3< RenderManager, Render::Texture*, PixelDataPtr, Texture::UploadParams > DerivedType;
1239 // Reserve some memory inside the message queue
1240 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1242 // Construct message in the message queue memory; note that delete should not be called on the return value
1243 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::UploadTexture, texture, pixelData, params );
1246 void UpdateManager::GenerateMipmaps( Render::Texture* texture )
1248 typedef MessageValue1< RenderManager, Render::Texture* > DerivedType;
1250 // Reserve some memory inside the render queue
1251 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1253 // Construct message in the render queue memory; note that delete should not be called on the return value
1254 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::GenerateMipmaps, texture );
1257 void UpdateManager::AddFrameBuffer( Render::FrameBuffer* frameBuffer )
1259 typedef MessageValue1< RenderManager, Render::FrameBuffer* > DerivedType;
1261 // Reserve some memory inside the render queue
1262 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1264 // Construct message in the render queue memory; note that delete should not be called on the return value
1265 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddFrameBuffer, frameBuffer );
1268 void UpdateManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer)
1270 typedef MessageValue1< RenderManager, Render::FrameBuffer* > DerivedType;
1272 // Reserve some memory inside the render queue
1273 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1275 // Construct message in the render queue memory; note that delete should not be called on the return value
1276 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveFrameBuffer, frameBuffer );
1279 void UpdateManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, unsigned int mipmapLevel, unsigned int layer )
1281 typedef MessageValue4< RenderManager, Render::FrameBuffer*, Render::Texture*, unsigned int, unsigned int > DerivedType;
1283 // Reserve some memory inside the render queue
1284 unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
1286 // Construct message in the render queue memory; note that delete should not be called on the return value
1287 new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AttachColorTextureToFrameBuffer, frameBuffer, texture, mipmapLevel, layer );
1290 } // namespace SceneGraph
1292 } // namespace Internal