/*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// INTERNAL INCLUDES
#include <dali/public-api/common/stage.h>
#include <dali/devel-api/common/set-wrapper.h>
-#include <dali/devel-api/common/mutex.h>
+#include <dali/devel-api/common/owner-container.h>
+#include <dali/devel-api/threading/mutex.h>
#include <dali/integration-api/core.h>
#include <dali/integration-api/render-controller.h>
#include <dali/integration-api/debug.h>
#include <dali/internal/common/core-impl.h>
-#include <dali/internal/common/owner-container.h>
#include <dali/internal/common/message.h>
#include <dali/internal/event/common/notification-manager.h>
#include <dali/internal/update/animation/scene-graph-animation.h>
#include <dali/internal/update/common/discard-queue.h>
#include <dali/internal/update/common/scene-graph-buffers.h>
-#include <dali/internal/update/common/scene-graph-property-buffer.h>
+#include <dali/internal/update/common/texture-cache-dispatcher.h>
#include <dali/internal/update/controllers/render-message-dispatcher.h>
#include <dali/internal/update/controllers/scene-controller-impl.h>
#include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
#include <dali/internal/update/manager/object-owner-container.h>
-#include <dali/internal/update/manager/prepare-render-algorithms.h>
-#include <dali/internal/update/manager/process-render-tasks.h>
+#include <dali/internal/update/manager/render-task-processor.h>
#include <dali/internal/update/manager/sorted-layers.h>
#include <dali/internal/update/manager/update-algorithms.h>
#include <dali/internal/update/manager/update-manager-debug.h>
-#include <dali/internal/update/node-attachments/scene-graph-camera-attachment.h>
-#include <dali/internal/update/node-attachments/scene-graph-image-attachment.h>
+#include <dali/internal/update/manager/transform-manager.h>
#include <dali/internal/update/nodes/node.h>
#include <dali/internal/update/nodes/scene-graph-layer.h>
#include <dali/internal/update/queue/update-message-queue.h>
#include <dali/internal/update/render-tasks/scene-graph-render-task.h>
#include <dali/internal/update/render-tasks/scene-graph-render-task-list.h>
-#include <dali/internal/update/rendering/scene-graph-material.h>
-#include <dali/internal/update/rendering/scene-graph-sampler.h>
-#include <dali/internal/update/rendering/scene-graph-geometry.h>
+#include <dali/internal/update/rendering/scene-graph-texture-set.h>
#include <dali/internal/update/resources/resource-manager.h>
-#include <dali/internal/update/resources/complete-status-manager.h>
-#include <dali/internal/update/touch/touch-resampler.h>
#include <dali/internal/render/common/render-instruction-container.h>
#include <dali/internal/render/common/render-manager.h>
#include <dali/internal/render/queue/render-queue.h>
-#include <dali/internal/render/common/performance-monitor.h>
#include <dali/internal/render/gl-resources/texture-cache.h>
#include <dali/internal/render/shaders/scene-graph-shader.h>
+#include <dali/internal/render/renderers/render-frame-buffer.h>
+#include <dali/internal/render/renderers/render-sampler.h>
+#include <dali/internal/update/render-tasks/scene-graph-camera.h>
// Un-comment to enable node tree debug logging
//#define NODE_TREE_LOGGING 1
namespace SceneGraph
{
-namespace
-{
-
-void DestroyNodeSet( std::set<Node*>& nodeSet )
-{
- for( std::set<Node*>::iterator iter = nodeSet.begin(); iter != nodeSet.end(); ++iter )
- {
- Node* node( *iter );
-
- // Call Node::OnDestroy as each node is destroyed
- node->OnDestroy();
-
- delete node;
- }
- nodeSet.clear();
-}
-
-} //namespace
-
typedef OwnerContainer< Shader* > ShaderContainer;
typedef ShaderContainer::Iterator ShaderIter;
typedef ShaderContainer::ConstIterator ShaderConstIter;
typedef GestureContainer::Iterator GestureIter;
typedef GestureContainer::ConstIterator GestureConstIter;
+typedef OwnerContainer< TextureSet* > TextureSetContainer;
+typedef TextureSetContainer::Iterator TextureSetIter;
+typedef TextureSetContainer::ConstIterator TextureSetConstIter;
/**
* Structure to contain UpdateManager internal data
struct UpdateManager::Impl
{
Impl( NotificationManager& notificationManager,
- GlSyncAbstraction& glSyncAbstraction,
CompleteNotificationInterface& animationFinishedNotifier,
PropertyNotifier& propertyNotifier,
ResourceManager& resourceManager,
RenderController& renderController,
RenderManager& renderManager,
RenderQueue& renderQueue,
- TextureCache& textureCache,
- TouchResampler& touchResampler,
- SceneGraphBuffers& sceneGraphBuffers )
- :
- renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
+ SceneGraphBuffers& sceneGraphBuffers,
+ RenderTaskProcessor& renderTaskProcessor )
+ : renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
notificationManager( notificationManager ),
+ transformManager(),
animationFinishedNotifier( animationFinishedNotifier ),
propertyNotifier( propertyNotifier ),
shaderSaver( NULL ),
renderManager( renderManager ),
renderQueue( renderQueue ),
renderInstructions( renderManager.GetRenderInstructionContainer() ),
- completeStatusManager( glSyncAbstraction, renderMessageDispatcher, resourceManager ),
- touchResampler( touchResampler ),
+ renderTaskProcessor( renderTaskProcessor ),
backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
- taskList ( completeStatusManager ),
- systemLevelTaskList ( completeStatusManager ),
+ taskList( renderMessageDispatcher, resourceManager ),
+ systemLevelTaskList( renderMessageDispatcher, resourceManager ),
root( NULL ),
systemLevelRoot( NULL ),
renderers( sceneGraphBuffers, discardQueue ),
- geometries( sceneGraphBuffers, discardQueue ),
- materials( sceneGraphBuffers, discardQueue ),
- samplers( sceneGraphBuffers, discardQueue ),
- propertyBuffers( sceneGraphBuffers, discardQueue ),
+ textureSets(),
messageQueue( renderController, sceneGraphBuffers ),
keepRenderingSeconds( 0.0f ),
animationFinishedDuringUpdate( false ),
nodeDirtyFlags( TransformFlag ), // set to TransformFlag to ensure full update the first time through Update()
previousUpdateScene( false ),
frameCounter( 0 ),
- renderSortingHelper(),
renderTaskWaiting( false )
{
- sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue, textureCache, completeStatusManager );
+ sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
renderers.SetSceneController( *sceneController );
- geometries.SetSceneController( *sceneController );
- materials.SetSceneController( *sceneController );
- propertyBuffers.SetSceneController( *sceneController );
- samplers.SetSceneController( *sceneController );
+
+ // create first 'dummy' node
+ nodes.PushBack(0u);
}
~Impl()
}
// UpdateManager owns the Nodes
- DestroyNodeSet( activeDisconnectedNodes );
- DestroyNodeSet( connectedNodes );
- DestroyNodeSet( disconnectedNodes );
+ Vector<Node*>::Iterator iter = nodes.Begin()+1;
+ Vector<Node*>::Iterator endIter = nodes.End();
+ for(;iter!=endIter;++iter)
+ {
+ (*iter)->OnDestroy();
+ delete(*iter);
+ }
// If there is root, reset it, otherwise do nothing as rendering was never started
if( root )
systemLevelRoot = NULL;
}
- sceneController->GetTextureCache().SetBufferIndices(NULL); // TODO - Remove
delete sceneController;
}
SceneGraphBuffers sceneGraphBuffers; ///< Used to keep track of which buffers are being written or read
RenderMessageDispatcher renderMessageDispatcher; ///< Used for passing messages to the render-thread
NotificationManager& notificationManager; ///< Queues notification messages for the event-thread.
+ TransformManager transformManager; ///< Used to update the transformation matrices of the nodes
CompleteNotificationInterface& animationFinishedNotifier; ///< Provides notification to applications when animations are finished.
PropertyNotifier& propertyNotifier; ///< Provides notification to applications when properties are modified.
ShaderSaver* shaderSaver; ///< Saves shader binaries.
RenderManager& renderManager; ///< This is responsible for rendering the results of each "update"
RenderQueue& renderQueue; ///< Used to queue messages for the next render
RenderInstructionContainer& renderInstructions; ///< Used to prepare the render instructions
- CompleteStatusManager completeStatusManager; ///< Complete Status Manager
- TouchResampler& touchResampler; ///< Used to resample touch events on every update.
+ RenderTaskProcessor& renderTaskProcessor; ///< Handles RenderTasks and RenderInstrucitons
Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
Layer* root; ///< The root node (root is a layer)
Layer* systemLevelRoot; ///< A separate root-node for system-level content
- std::set< Node* > activeDisconnectedNodes; ///< A container of new or modified nodes (without parent) owned by UpdateManager
- std::set< Node* > connectedNodes; ///< A container of connected (with parent) nodes owned by UpdateManager
- std::set< Node* > disconnectedNodes; ///< A container of inactive disconnected nodes (without parent) owned by UpdateManager
+
+ Vector<Node*> nodes; ///< A container of all instantiated nodes
SortedLayerPointers sortedLayers; ///< A container of Layer pointers sorted by depth
SortedLayerPointers systemLevelSortedLayers; ///< A separate container of system-level Layers
+ OwnerContainer< Camera* > cameras; ///< A container of cameras
OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties)
AnimationContainer animations; ///< A container of owned animations
PropertyNotificationContainer propertyNotifications; ///< A container of owner property notifications.
ObjectOwnerContainer<Renderer> renderers;
- ObjectOwnerContainer<Geometry> geometries; ///< A container of geometries
- ObjectOwnerContainer<Material> materials; ///< A container of materials
- ObjectOwnerContainer<Sampler> samplers; ///< A container of samplers
- ObjectOwnerContainer<PropertyBuffer> propertyBuffers; ///< A container of property buffers
+ TextureSetContainer textureSets; ///< A container of texture sets
ShaderContainer shaders; ///< A container of owned shaders
bool previousUpdateScene; ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
int frameCounter; ///< Frame counter used in debugging to choose which frame to debug and which to ignore.
- RendererSortingHelper renderSortingHelper; ///< helper used to sort transparent renderers
GestureContainer gestures; ///< A container of owned gesture detectors
bool renderTaskWaiting; ///< A REFRESH_ONCE render task is waiting to be rendered
};
UpdateManager::UpdateManager( NotificationManager& notificationManager,
- GlSyncAbstraction& glSyncAbstraction,
CompleteNotificationInterface& animationFinishedNotifier,
PropertyNotifier& propertyNotifier,
ResourceManager& resourceManager,
RenderController& controller,
RenderManager& renderManager,
RenderQueue& renderQueue,
- TextureCache& textureCache,
- TouchResampler& touchResampler )
+ TextureCacheDispatcher& textureCacheDispatcher,
+ RenderTaskProcessor& renderTaskProcessor )
: mImpl(NULL)
{
mImpl = new Impl( notificationManager,
- glSyncAbstraction,
animationFinishedNotifier,
propertyNotifier,
resourceManager,
controller,
renderManager,
renderQueue,
- textureCache,
- touchResampler,
- mSceneGraphBuffers );
+ mSceneGraphBuffers,
+ renderTaskProcessor );
- textureCache.SetBufferIndices( &mSceneGraphBuffers );
+ textureCacheDispatcher.SetBufferIndices( &mSceneGraphBuffers );
}
UpdateManager::~UpdateManager()
{
DALI_ASSERT_DEBUG( mImpl->root == NULL && "Root Node already installed" );
mImpl->root = layer;
+ mImpl->root->CreateTransform( &mImpl->transformManager);
}
else
{
DALI_ASSERT_DEBUG( mImpl->systemLevelRoot == NULL && "System-level Root Node already installed" );
mImpl->systemLevelRoot = layer;
+ mImpl->systemLevelRoot->CreateTransform( &mImpl->transformManager);
}
layer->SetRoot(true);
DALI_ASSERT_ALWAYS( NULL != node );
DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
- mImpl->activeDisconnectedNodes.insert( node ); // Takes ownership of node
+ // Nodes must be sorted by pointer
+ Vector<Node*>::Iterator begin = mImpl->nodes.Begin();
+ for(Vector<Node*>::Iterator iter = mImpl->nodes.End()-1; iter >= begin; --iter)
+ {
+ if(node > (*iter))
+ {
+ mImpl->nodes.Insert((iter+1), node);
+ node->CreateTransform( &mImpl->transformManager);
+ break;
+ }
+ }
}
void UpdateManager::ConnectNode( Node* parent, Node* node )
DALI_ASSERT_ALWAYS( NULL != node );
DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
- // Move from active/disconnectedNodes to connectedNodes
- std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
- if( !removed )
- {
- removed = mImpl->disconnectedNodes.erase( node );
- DALI_ASSERT_ALWAYS( removed );
- }
- mImpl->connectedNodes.insert( node );
-
- node->SetActive( true );
-
parent->ConnectChild( node );
}
DALI_ASSERT_ALWAYS( NULL != parent );
parent->SetDirtyFlag( ChildDeletedFlag ); // make parent dirty so that render items dont get reused
- // Move from connectedNodes to activeDisconnectedNodes (reset properties next frame)
- parent->DisconnectChild( mSceneGraphBuffers.GetUpdateBufferIndex(), *node, mImpl->connectedNodes, mImpl->activeDisconnectedNodes );
-}
-
-void UpdateManager::SetNodeActive( Node* node )
-{
- DALI_ASSERT_ALWAYS( NULL != node );
- DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should not have a parent yet
-
- // Move from disconnectedNodes to activeDisconnectedNodes (reset properties next frame)
- std::set<Node*>::size_type removed = mImpl->disconnectedNodes.erase( node );
- DALI_ASSERT_ALWAYS( removed );
- mImpl->activeDisconnectedNodes.insert( node );
-
- node->SetActive( true );
+ parent->DisconnectChild( mSceneGraphBuffers.GetUpdateBufferIndex(), *node );
}
void UpdateManager::DestroyNode( Node* node )
DALI_ASSERT_ALWAYS( NULL != node );
DALI_ASSERT_ALWAYS( NULL == node->GetParent() ); // Should have been disconnected
- // Transfer ownership from new/disconnectedNodes to the discard queue
- // This keeps the nodes alive, until the render-thread has finished with them
- std::set<Node*>::size_type removed = mImpl->activeDisconnectedNodes.erase( node );
- if( !removed )
+ Vector<Node*>::Iterator iter = mImpl->nodes.Begin()+1;
+ Vector<Node*>::Iterator endIter = mImpl->nodes.End();
+ for(;iter!=endIter;++iter)
{
- removed = mImpl->disconnectedNodes.erase( node );
- DALI_ASSERT_ALWAYS( removed );
+ if((*iter) == node)
+ {
+ mImpl->nodes.Erase(iter);
+ break;
+ }
}
+
mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), node );
// Notify the Node about impending destruction
node->OnDestroy();
}
-//@todo MESH_REWORK Extend to allow arbitrary scene objects to connect to each other
-void UpdateManager::AttachToNode( Node* node, NodeAttachment* attachment )
+void UpdateManager::AddCamera( Camera* camera )
{
- DALI_ASSERT_DEBUG( node != NULL );
- DALI_ASSERT_DEBUG( attachment != NULL );
+ DALI_ASSERT_DEBUG( camera != NULL );
- // attach node to attachment first so that parent is known by the time attachment is connected
- node->Attach( *attachment ); // node takes ownership
+ mImpl->cameras.PushBack( camera ); // takes ownership
+}
- // @todo MESH_REWORK Remove after merge of SceneGraph::RenderableAttachment and SceneGraph::RendererAttachment
- if( dynamic_cast<SceneGraph::ImageAttachment*>( attachment ) != NULL )
+void UpdateManager::RemoveCamera( const Camera* camera )
+{
+ // Find the camera
+ OwnerContainer<Camera*>::Iterator iter = mImpl->cameras.Begin();
+ OwnerContainer<Camera*>::ConstIterator end = mImpl->cameras.End();
+ for ( ; iter != end; ++iter )
{
- attachment->Initialize( *mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex() );
+ Camera* value = *iter;
+ if ( camera == value )
+ {
+ // Transfer ownership to the discard queue
+ mImpl->discardQueue.Add( mSceneGraphBuffers.GetUpdateBufferIndex(), mImpl->cameras.Release( iter ) );
+
+ return;
+ }
}
+
}
void UpdateManager::AddObject( PropertyOwner* object )
propertyNotification->SetNotifyMode( notifyMode );
}
-ObjectOwnerContainer<Geometry>& UpdateManager::GetGeometryOwner()
-{
- return mImpl->geometries;
-}
-
ObjectOwnerContainer<Renderer>& UpdateManager::GetRendererOwner()
{
return mImpl->renderers;
}
-
-ObjectOwnerContainer<Material>& UpdateManager::GetMaterialOwner()
-{
- return mImpl->materials;
-}
-
-ObjectOwnerContainer<Sampler>& UpdateManager::GetSamplerOwner()
-{
- return mImpl->samplers;
-}
-
-ObjectOwnerContainer<PropertyBuffer>& UpdateManager::GetPropertyBufferOwner()
-{
- return mImpl->propertyBuffers;
-}
-
void UpdateManager::AddShader( Shader* shader )
{
DALI_ASSERT_DEBUG( NULL != shader );
}
mImpl->shaders.PushBack( shader );
-
- // Allows the shader to dispatch texture requests to the cache
- shader->Initialize( mImpl->renderQueue, mImpl->sceneController->GetTextureCache() );
}
void UpdateManager::RemoveShader( Shader* shader )
DALI_ASSERT_DEBUG(false);
}
+void UpdateManager::AddTextureSet( TextureSet* textureSet )
+{
+ DALI_ASSERT_DEBUG( NULL != textureSet );
+ mImpl->textureSets.PushBack( textureSet );
+}
+
+void UpdateManager::RemoveTextureSet( TextureSet* textureSet )
+{
+ DALI_ASSERT_DEBUG(textureSet != NULL);
+ size_t textureSetCount( mImpl->textureSets.Size() );
+ for( size_t i(0); i<textureSetCount; ++i )
+ {
+ if( textureSet == mImpl->textureSets[i] )
+ {
+ mImpl->textureSets.Remove( mImpl->textureSets.Begin() + i );
+ return;
+ }
+ }
+}
+
unsigned int* UpdateManager::ReserveMessageSlot( std::size_t size, bool updateScene )
{
return mImpl->messageQueue.ReserveMessageSlot( size, updateScene );
void UpdateManager::ResetProperties( BufferIndex bufferIndex )
{
- PERF_MONITOR_START(PerformanceMonitor::RESET_PROPERTIES);
-
// Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped
mImpl->animationFinishedDuringUpdate = false;
mImpl->systemLevelRoot->ResetToBaseValues( bufferIndex );
}
- // Reset the Connected Nodes
- const std::set<Node*>::iterator endIter = mImpl->connectedNodes.end();
- for( std::set<Node*>::iterator iter = mImpl->connectedNodes.begin(); endIter != iter; ++iter )
+ // Reset all the nodes
+ Vector<Node*>::Iterator iter = mImpl->nodes.Begin()+1;
+ Vector<Node*>::Iterator endIter = mImpl->nodes.End();
+ for(;iter != endIter; ++iter)
{
(*iter)->ResetToBaseValues( bufferIndex );
}
- // If a Node is disconnected, it may still be "active" (requires a reset in next frame)
- for( std::set<Node*>::iterator iter = mImpl->activeDisconnectedNodes.begin(); mImpl->activeDisconnectedNodes.end() != iter; iter = mImpl->activeDisconnectedNodes.begin() )
- {
- Node* node = *iter;
- node->ResetToBaseValues( bufferIndex );
- node->SetActive( false );
-
- // Move everything from activeDisconnectedNodes to disconnectedNodes (no need to reset again)
- mImpl->activeDisconnectedNodes.erase( iter );
- mImpl->disconnectedNodes.insert( node );
- }
-
// Reset system-level render-task list properties to base values
const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
(*iter)->ResetToBaseValues( bufferIndex );
}
- mImpl->materials.ResetToBaseValues( bufferIndex );
- mImpl->geometries.ResetToBaseValues( bufferIndex );
- mImpl->propertyBuffers.ResetToBaseValues( bufferIndex );
- mImpl->samplers.ResetToBaseValues( bufferIndex );
mImpl->renderers.ResetToBaseValues( bufferIndex );
-
// Reset animatable shader properties to base values
for (ShaderIter iter = mImpl->shaders.Begin(); iter != mImpl->shaders.End(); ++iter)
{
(*iter)->ResetToBaseValues( bufferIndex );
}
-
- PERF_MONITOR_END(PerformanceMonitor::RESET_PROPERTIES);
}
bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
{
- PERF_MONITOR_START(PerformanceMonitor::ANIMATE_NODES);
-
AnimationContainer &animations = mImpl->animations;
AnimationIter iter = animations.Begin();
+ bool animationLooped = false;
while ( iter != animations.End() )
{
Animation* animation = *iter;
- bool finished = animation->Update( bufferIndex, elapsedSeconds );
+ bool finished = false;
+ bool looped = false;
+ animation->Update( bufferIndex, elapsedSeconds, looped, finished );
mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
+ animationLooped = animationLooped || looped;
// Remove animations that had been destroyed but were still waiting for an update
if (animation->GetState() == Animation::Destroyed)
}
}
- if ( mImpl->animationFinishedDuringUpdate )
+ // queue the notification on finished or looped (to update loop count)
+ if ( mImpl->animationFinishedDuringUpdate || animationLooped )
{
// The application should be notified by NotificationManager, in another thread
mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationFinishedNotifier );
}
-
- PERF_MONITOR_END(PerformanceMonitor::ANIMATE_NODES);
}
-void UpdateManager::ApplyConstraints( BufferIndex bufferIndex )
+void UpdateManager::ConstrainCustomObjects( BufferIndex bufferIndex )
{
- PERF_MONITOR_START(PerformanceMonitor::APPLY_CONSTRAINTS);
-
- // constrain custom objects... (in construction order)
+ //Constrain custom objects (in construction order)
OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
-
const OwnerContainer< PropertyOwner* >::Iterator endIter = customObjects.End();
for ( OwnerContainer< PropertyOwner* >::Iterator iter = customObjects.Begin(); endIter != iter; ++iter )
{
PropertyOwner& object = **iter;
ConstrainPropertyOwner( object, bufferIndex );
}
+}
- // constrain nodes... (in Depth First traversal order)
- if ( mImpl->root )
- {
- ConstrainNodes( *(mImpl->root), bufferIndex );
- }
-
- if ( mImpl->systemLevelRoot )
- {
- ConstrainNodes( *(mImpl->systemLevelRoot), bufferIndex );
- }
-
- // constrain other property-owners after nodes as they are more likely to depend on a node's
- // current frame property than vice versa. They tend to be final constraints (no further
- // constraints depend on their properties)
- // e.g. ShaderEffect uniform a function of Actor's position.
- // Mesh vertex a function of Actor's position or world position.
-
- // TODO: refactor this code (and reset nodes) as these are all just lists of property-owners
- // they can be all processed in a super-list of property-owners.
-
+void UpdateManager::ConstrainRenderTasks( BufferIndex bufferIndex )
+{
// Constrain system-level render-tasks
const RenderTaskList::RenderTaskContainer& systemLevelTasks = mImpl->systemLevelTaskList.GetTasks();
-
for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = systemLevelTasks.Begin(); iter != systemLevelTasks.End(); ++iter )
{
RenderTask& task = **iter;
// Constrain render-tasks
const RenderTaskList::RenderTaskContainer& tasks = mImpl->taskList.GetTasks();
-
for ( RenderTaskList::RenderTaskContainer::ConstIterator iter = tasks.Begin(); iter != tasks.End(); ++iter )
{
RenderTask& task = **iter;
ConstrainPropertyOwner( task, bufferIndex );
}
+}
- // Constrain Materials and geometries
- mImpl->materials.ConstrainObjects( bufferIndex );
- mImpl->geometries.ConstrainObjects( bufferIndex );
- mImpl->samplers.ConstrainObjects( bufferIndex );
- mImpl->propertyBuffers.ConstrainObjects( bufferIndex );
- mImpl->renderers.ConstrainObjects( bufferIndex );
-
+void UpdateManager::ConstrainShaders( BufferIndex bufferIndex )
+{
// constrain shaders... (in construction order)
ShaderContainer& shaders = mImpl->shaders;
-
for ( ShaderIter iter = shaders.Begin(); iter != shaders.End(); ++iter )
{
Shader& shader = **iter;
ConstrainPropertyOwner( shader, bufferIndex );
}
-
- PERF_MONITOR_END(PerformanceMonitor::APPLY_CONSTRAINTS);
}
void UpdateManager::ProcessPropertyNotifications( BufferIndex bufferIndex )
}
}
+void UpdateManager::PrepareTextureSets( BufferIndex bufferIndex )
+{
+ size_t textureSetCount( mImpl->textureSets.Size() );
+ for( size_t i(0); i<textureSetCount; ++i )
+ {
+ //Prepare texture set
+ mImpl->textureSets[i]->Prepare( mImpl->resourceManager );
+ }
+}
+
void UpdateManager::ForwardCompiledShadersToEventThread()
{
DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." );
void UpdateManager::UpdateRenderers( BufferIndex bufferIndex )
{
- const Internal::OwnerContainer<Renderer*>& rendererContainer( mImpl->renderers.GetObjectContainer() );
+ const OwnerContainer<Renderer*>& rendererContainer( mImpl->renderers.GetObjectContainer() );
unsigned int rendererCount( rendererContainer.Size() );
for( unsigned int i(0); i<rendererCount; ++i )
{
- if( rendererContainer[i]->IsReferenced() )
- {
- rendererContainer[i]->PrepareResources(bufferIndex, mImpl->resourceManager);
- rendererContainer[i]->PrepareRender( bufferIndex );
- }
+ //Apply constraints
+ ConstrainPropertyOwner( *rendererContainer[i], bufferIndex );
+
+ rendererContainer[i]->PrepareRender( bufferIndex );
}
}
return;
}
- PERF_MONITOR_START( PerformanceMonitor::UPDATE_NODES );
-
- // Prepare resources, update shaders, update attachments, for each node
+ // Prepare resources, update shaders, for each node
// And add the renderers to the sorted layers. Start from root, which is also a layer
- mImpl->nodeDirtyFlags = UpdateNodesAndAttachments( *( mImpl->root ),
- bufferIndex,
- mImpl->resourceManager,
- mImpl->renderQueue );
+ mImpl->nodeDirtyFlags = UpdateNodeTree( *( mImpl->root ),
+ bufferIndex,
+ mImpl->resourceManager,
+ mImpl->renderQueue );
if ( mImpl->systemLevelRoot )
{
- mImpl->nodeDirtyFlags |= UpdateNodesAndAttachments( *( mImpl->systemLevelRoot ),
- bufferIndex,
- mImpl->resourceManager,
- mImpl->renderQueue );
+ mImpl->nodeDirtyFlags |= UpdateNodeTree( *( mImpl->systemLevelRoot ),
+ bufferIndex,
+ mImpl->resourceManager,
+ mImpl->renderQueue );
}
-
- PERF_MONITOR_END( PerformanceMonitor::UPDATE_NODES );
}
unsigned int UpdateManager::Update( float elapsedSeconds,
unsigned int lastVSyncTimeMilliseconds,
unsigned int nextVSyncTimeMilliseconds )
{
- PERF_MONITOR_END(PerformanceMonitor::FRAME_RATE); // Mark the End of the last frame
- PERF_MONITOR_NEXT_FRAME(); // Prints out performance info for the last frame (if enabled)
- PERF_MONITOR_START(PerformanceMonitor::FRAME_RATE); // Mark the start of this current frame
-
- // Measure the time spent in UpdateManager::Update
- PERF_MONITOR_START(PerformanceMonitor::UPDATE);
-
const BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
- // Update the frame time delta on the render thread.
- mImpl->renderManager.SetFrameDeltaTime(elapsedSeconds);
-
- // 1) Clear nodes/resources which were previously discarded
+ //Clear nodes/resources which were previously discarded
mImpl->discardQueue.Clear( bufferIndex );
- // 2) Grab any loaded resources
+ //Grab any loaded resources
bool resourceChanged = mImpl->resourceManager.UpdateCache( bufferIndex );
- // 3) Process Touches & Gestures
- mImpl->touchResampler.Update();
+ //Process Touches & Gestures
const bool gestureUpdated = ProcessGestures( bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
const bool updateScene = // The scene-graph requires an update if..
// values if the scene was updated in the previous frame.
if( updateScene || mImpl->previousUpdateScene )
{
- // 4) Reset properties from the previous update
+ //Reset properties from the previous update
ResetProperties( bufferIndex );
+ mImpl->transformManager.ResetToBaseValue();
}
- // 5) Process the queued scene messages
+ //Process the queued scene messages
mImpl->messageQueue.ProcessMessages( bufferIndex );
- // 6) Post Process Ids of resources updated by renderer
+ //Post Process Ids of resources updated by renderer
mImpl->resourceManager.PostProcessResources( bufferIndex );
- // 6.1) Forward compiled shader programs to event thread for saving
+ //Forward compiled shader programs to event thread for saving
ForwardCompiledShadersToEventThread();
// Although the scene-graph may not require an update, we still need to synchronize double-buffered
// We should not start skipping update steps or reusing lists until there has been two frames where nothing changes
if( updateScene || mImpl->previousUpdateScene )
{
- // 7) Animate
+ //Animate
Animate( bufferIndex, elapsedSeconds );
- // 8) Apply Constraints
- ApplyConstraints( bufferIndex );
+ //Constraint custom objects
+ ConstrainCustomObjects( bufferIndex );
- // 9) Check Property Notifications
- ProcessPropertyNotifications( bufferIndex );
+ //Prepare texture sets and apply constraints to them
+ PrepareTextureSets( bufferIndex );
- // 10) Clear the lists of renderable-attachments from the previous update
- ClearRenderables( mImpl->sortedLayers );
- ClearRenderables( mImpl->systemLevelSortedLayers );
+ //Clear the lists of renderers from the previous update
+ for( size_t i(0); i<mImpl->sortedLayers.size(); ++i )
+ {
+ mImpl->sortedLayers[i]->ClearRenderables();
+ }
- // 11) Update node hierarchy and perform sorting / culling.
- // This will populate each Layer with a list of renderers which are ready.
+ for( size_t i(0); i<mImpl->systemLevelSortedLayers.size(); ++i )
+ {
+ mImpl->systemLevelSortedLayers[i]->ClearRenderables();
+ }
+
+ //Update node hierarchy, apply constraints and perform sorting / culling.
+ //This will populate each Layer with a list of renderers which are ready.
UpdateNodes( bufferIndex );
- UpdateRenderers( bufferIndex );
+ //Apply constraints to RenderTasks, shaders
+ ConstrainRenderTasks( bufferIndex );
+ ConstrainShaders( bufferIndex );
- // 12) Prepare for the next render
- PERF_MONITOR_START(PerformanceMonitor::PREPARE_RENDERABLES);
+ //Update renderers and apply constraints
+ UpdateRenderers( bufferIndex );
- PrepareRenderables( bufferIndex, mImpl->sortedLayers );
- PrepareRenderables( bufferIndex, mImpl->systemLevelSortedLayers );
- PERF_MONITOR_END(PerformanceMonitor::PREPARE_RENDERABLES);
+ //Update the trnasformations of all the nodes
+ mImpl->transformManager.Update();
- PERF_MONITOR_START(PerformanceMonitor::PROCESS_RENDER_TASKS);
+ //Process Property Notifications
+ ProcessPropertyNotifications( bufferIndex );
- // 14) Process the RenderTasks; this creates the instructions for rendering the next frame.
- // reset the update buffer index and make sure there is enough room in the instruction container
+ //Process the RenderTasks; this creates the instructions for rendering the next frame.
+ //reset the update buffer index and make sure there is enough room in the instruction container
mImpl->renderInstructions.ResetAndReserve( bufferIndex,
mImpl->taskList.GetTasks().Count() + mImpl->systemLevelTaskList.GetTasks().Count() );
if ( NULL != mImpl->root )
{
- ProcessRenderTasks( bufferIndex,
- mImpl->completeStatusManager,
- mImpl->taskList,
- *mImpl->root,
- mImpl->sortedLayers,
- mImpl->renderSortingHelper,
- mImpl->renderInstructions );
+ mImpl->renderTaskProcessor.Process( bufferIndex,
+ mImpl->taskList,
+ *mImpl->root,
+ mImpl->sortedLayers,
+ mImpl->renderInstructions );
// Process the system-level RenderTasks last
if ( NULL != mImpl->systemLevelRoot )
{
- ProcessRenderTasks( bufferIndex,
- mImpl->completeStatusManager,
- mImpl->systemLevelTaskList,
- *mImpl->systemLevelRoot,
- mImpl->systemLevelSortedLayers,
- mImpl->renderSortingHelper,
- mImpl->renderInstructions );
+ mImpl->renderTaskProcessor.Process( bufferIndex,
+ mImpl->systemLevelTaskList,
+ *mImpl->systemLevelRoot,
+ mImpl->systemLevelSortedLayers,
+ mImpl->renderInstructions );
}
}
}
mImpl->notificationManager.QueueCompleteNotification( mImpl->taskList.GetCompleteNotificationInterface() );
}
- PERF_MONITOR_END(PerformanceMonitor::PROCESS_RENDER_TASKS);
-
// Macro is undefined in release build.
SNAPSHOT_NODE_LOGGING;
// Check whether further updates are required
unsigned int keepUpdating = KeepUpdatingCheck( elapsedSeconds );
-#ifdef PERFORMANCE_MONITOR_ENABLED
- // Always keep rendering when measuring FPS
- keepUpdating |= KeepUpdating::MONITORING_PERFORMANCE;
-#endif
-
// tell the update manager that we're done so the queue can be given to event thread
mImpl->notificationManager.UpdateCompleted();
// The update has finished; swap the double-buffering indices
mSceneGraphBuffers.Swap();
- PERF_MONITOR_END(PerformanceMonitor::UPDATE);
-
return keepUpdating;
}
mImpl->shaderSaver = &upstream;
}
+void UpdateManager::AddSampler( Render::Sampler* sampler )
+{
+ typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddSampler, sampler );
+}
+
+void UpdateManager::RemoveSampler( Render::Sampler* sampler )
+{
+ typedef MessageValue1< RenderManager, Render::Sampler* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveSampler, sampler );
+}
+
+void UpdateManager::SetFilterMode( Render::Sampler* sampler, unsigned int minFilterMode, unsigned int magFilterMode )
+{
+ typedef MessageValue3< RenderManager, Render::Sampler*, unsigned int, unsigned int > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetFilterMode, sampler, minFilterMode, magFilterMode );
+}
+
+void UpdateManager::SetWrapMode( Render::Sampler* sampler, unsigned int rWrapMode, unsigned int sWrapMode, unsigned int tWrapMode )
+{
+ typedef MessageValue4< RenderManager, Render::Sampler*, unsigned int, unsigned int, unsigned int > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetWrapMode, sampler, rWrapMode, sWrapMode, tWrapMode );
+}
+
+void UpdateManager::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer )
+{
+ typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddPropertyBuffer, propertyBuffer );
+}
+
+void UpdateManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer )
+{
+ typedef MessageValue1< RenderManager, Render::PropertyBuffer* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemovePropertyBuffer, propertyBuffer );
+}
+
+void UpdateManager::SetPropertyBufferFormat(Render::PropertyBuffer* propertyBuffer, Render::PropertyBuffer::Format* format )
+{
+ typedef MessageValue2< RenderManager, Render::PropertyBuffer*, Render::PropertyBuffer::Format* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferFormat, propertyBuffer, format );
+}
+
+void UpdateManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, Dali::Vector<char>* data, size_t size )
+{
+ typedef MessageValue3< RenderManager, Render::PropertyBuffer*, Dali::Vector<char>*, size_t > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetPropertyBufferData, propertyBuffer, data, size );
+}
+
+void UpdateManager::AddGeometry( Render::Geometry* geometry )
+{
+ typedef MessageValue1< RenderManager, Render::Geometry* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddGeometry, geometry );
+}
+
+void UpdateManager::RemoveGeometry( Render::Geometry* geometry )
+{
+ typedef MessageValue1< RenderManager, Render::Geometry* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveGeometry, geometry );
+}
+
+void UpdateManager::SetGeometryType( Render::Geometry* geometry, unsigned int geometryType )
+{
+ typedef MessageValue2< RenderManager, Render::Geometry*, unsigned int > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SetGeometryType, geometry, geometryType );
+}
+
+void UpdateManager::SetIndexBuffer( Render::Geometry* geometry, Dali::Vector<unsigned short>& indices )
+{
+ typedef IndexBufferMessage< RenderManager > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, geometry, indices );
+}
+
+void UpdateManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
+{
+ typedef MessageValue2< RenderManager, Render::Geometry*, Render::PropertyBuffer* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveVertexBuffer, geometry, propertyBuffer );
+}
+
+void UpdateManager::AddVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer )
+{
+ typedef MessageValue2< RenderManager, Render::Geometry*, Render::PropertyBuffer* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddVertexBuffer, geometry, propertyBuffer );
+}
+
+void UpdateManager::AddTexture( Render::NewTexture* texture )
+{
+ typedef MessageValue1< RenderManager, Render::NewTexture* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddTexture, texture );
+}
+
+void UpdateManager::RemoveTexture( Render::NewTexture* texture)
+{
+ typedef MessageValue1< RenderManager, Render::NewTexture* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveTexture, texture );
+}
+
+void UpdateManager::UploadTexture( Render::NewTexture* texture, PixelDataPtr pixelData, const NewTexture::UploadParams& params )
+{
+ typedef MessageValue3< RenderManager, Render::NewTexture*, PixelDataPtr, NewTexture::UploadParams > DerivedType;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::UploadTexture, texture, pixelData, params );
+}
+
+void UpdateManager::GenerateMipmaps( Render::NewTexture* texture )
+{
+ typedef MessageValue1< RenderManager, Render::NewTexture* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::GenerateMipmaps, texture );
+}
+
+void UpdateManager::AddFrameBuffer( Render::FrameBuffer* frameBuffer )
+{
+ typedef MessageValue1< RenderManager, Render::FrameBuffer* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AddFrameBuffer, frameBuffer );
+}
+
+void UpdateManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer)
+{
+ typedef MessageValue1< RenderManager, Render::FrameBuffer* > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::RemoveFrameBuffer, frameBuffer );
+}
+
+void UpdateManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::NewTexture* texture, unsigned int mipmapLevel, unsigned int layer )
+{
+ typedef MessageValue4< RenderManager, Render::FrameBuffer*, Render::NewTexture*, unsigned int, unsigned int > DerivedType;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot( mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof( DerivedType ) );
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new (slot) DerivedType( &mImpl->renderManager, &RenderManager::AttachColorTextureToFrameBuffer, frameBuffer, texture, mipmapLevel, layer );
+}
+
} // namespace SceneGraph
} // namespace Internal