/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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/integration-api/core.h>
#include <dali/integration-api/render-controller.h>
-#include <dali/integration-api/shader-data.h>
+#include <dali/internal/common/shader-data.h>
#include <dali/integration-api/debug.h>
#include <dali/internal/common/core-impl.h>
#include <dali/internal/event/common/notification-manager.h>
#include <dali/internal/event/common/property-notification-impl.h>
#include <dali/internal/event/common/property-notifier.h>
+#include <dali/internal/event/effects/shader-factory.h>
#include <dali/internal/update/animation/scene-graph-animator.h>
#include <dali/internal/update/animation/scene-graph-animation.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-renderer-attachment.h>
#include <dali/internal/update/node-attachments/scene-graph-image-attachment.h>
#include <dali/internal/update/nodes/node.h>
#include <dali/internal/update/nodes/scene-graph-layer.h>
#include <dali/internal/render/gl-resources/texture-cache.h>
#include <dali/internal/render/shaders/scene-graph-shader.h>
-#ifdef DALI_DYNAMICS_SUPPORT
-#include <dali/integration-api/dynamics/dynamics-world-settings.h>
-#include <dali/internal/update/dynamics/scene-graph-dynamics-world.h>
-#endif
-
// Un-comment to enable node tree debug logging
//#define NODE_TREE_LOGGING 1
typedef ShaderContainer::Iterator ShaderIter;
typedef ShaderContainer::ConstIterator ShaderConstIter;
+typedef std::vector<Internal::ShaderDataPtr> ShaderDataBinaryQueue;
+
typedef OwnerContainer<PanGesture*> GestureContainer;
typedef GestureContainer::Iterator GestureIter;
typedef GestureContainer::ConstIterator GestureConstIter;
notificationManager( notificationManager ),
animationFinishedNotifier( animationFinishedNotifier ),
propertyNotifier( propertyNotifier ),
+ shaderSaver( NULL ),
resourceManager( resourceManager ),
discardQueue( discardQueue ),
renderController( renderController ),
systemLevelTaskList ( completeStatusManager ),
root( NULL ),
systemLevelRoot( NULL ),
- geometries( sceneGraphBuffers, discardQueue ),
+ renderers( sceneGraphBuffers, discardQueue ),
+ geometries( sceneGraphBuffers, discardQueue ),
materials( sceneGraphBuffers, discardQueue ),
samplers( sceneGraphBuffers, discardQueue ),
propertyBuffers( sceneGraphBuffers, discardQueue ),
messageQueue( renderController, sceneGraphBuffers ),
- dynamicsChanged( false ),
keepRenderingSeconds( 0.0f ),
animationFinishedDuringUpdate( false ),
nodeDirtyFlags( TransformFlag ), // set to TransformFlag to ensure full update the first time through Update()
{
sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue, textureCache, completeStatusManager );
+ renderers.SetSceneController( *sceneController );
geometries.SetSceneController( *sceneController );
materials.SetSceneController( *sceneController );
propertyBuffers.SetSceneController( *sceneController );
NotificationManager& notificationManager; ///< Queues notification messages for the event-thread.
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.
ResourceManager& resourceManager; ///< resource manager
DiscardQueue& discardQueue; ///< Nodes are added here when disconnected from the scene-graph.
RenderController& renderController; ///< render controller
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
+ ObjectOwnerContainer<PropertyBuffer> propertyBuffers; ///< A container of property buffers
ShaderContainer shaders; ///< A container of owned shaders
MessageQueue messageQueue; ///< The messages queued from the event-thread
-
-#ifdef DALI_DYNAMICS_SUPPORT
- OwnerPointer<DynamicsWorld> dynamicsWorld; ///< Wrapper for dynamics simulation
-#endif
- bool dynamicsChanged; ///< This is set to true if an object is changed in the dynamics simulation tick
+ ShaderDataBinaryQueue renderCompiledShaders; ///< Shaders compiled on Render thread are inserted here for update thread to pass on to event thread.
+ ShaderDataBinaryQueue updateCompiledShaders; ///< Shaders to be sent from Update to Event
+ Mutex compiledShaderMutex; ///< lock to ensure no corruption on the renderCompiledShaders
float keepRenderingSeconds; ///< Set via Dali::Stage::KeepRendering
bool animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
mImpl->activeDisconnectedNodes.insert( node ); // Takes ownership of node
}
-void UpdateManager::ConnectNode( Node* parent, Node* node, int index )
+void UpdateManager::ConnectNode( Node* parent, Node* node )
{
DALI_ASSERT_ALWAYS( NULL != parent );
DALI_ASSERT_ALWAYS( NULL != node );
node->SetActive( true );
- parent->ConnectChild( node, index );
+ parent->ConnectChild( node );
}
void UpdateManager::DisconnectNode( Node* node )
}
}
-void UpdateManager::AttachToSceneGraph( RendererAttachment* renderer )
-{
- // @todo MESH_REWORK Take ownership of this object after merge with SceneGraph::RenderableAttachment
-
- SceneGraph::NodeAttachment* attachment = static_cast<SceneGraph::NodeAttachment*>(renderer);
- attachment->Initialize( *mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex() );
-}
-
void UpdateManager::AddObject( PropertyOwner* object )
{
DALI_ASSERT_DEBUG( NULL != object );
return mImpl->geometries;
}
+ObjectOwnerContainer<Renderer>& UpdateManager::GetRendererOwner()
+{
+ return mImpl->renderers;
+}
+
+
ObjectOwnerContainer<Material>& UpdateManager::GetMaterialOwner()
{
return mImpl->materials;
}
void UpdateManager::SetShaderProgram( Shader* shader,
- ResourceId resourceId, size_t shaderHash, bool modifiesGeometry )
+ Internal::ShaderDataPtr shaderData, bool modifiesGeometry )
{
- DALI_LOG_TRACE_METHOD_FMT(Debug::Filter::gShader, " - (id:%d hash:%d)\n", resourceId, shaderHash);
-
- DALI_ASSERT_ALWAYS( NULL != shader && "shader is uninitialized" );
-
- Integration::ShaderDataPtr shaderData( mImpl->resourceManager.GetShaderData(resourceId) );
if( shaderData )
{
- shaderData->SetHashValue( shaderHash );
- shaderData->SetResourceId( resourceId );
- typedef MessageValue4< Shader, Integration::ResourceId, Integration::ShaderDataPtr, ProgramCache*, bool> DerivedType;
+ typedef MessageValue3< Shader, Internal::ShaderDataPtr, ProgramCache*, bool> 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( shader, &Shader::SetProgram, resourceId, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
+ new (slot) DerivedType( shader, &Shader::SetProgram, shaderData, mImpl->renderManager.GetProgramCache(), modifiesGeometry );
+ }
+}
+
+void UpdateManager::SaveBinary( Internal::ShaderDataPtr shaderData )
+{
+ DALI_ASSERT_DEBUG( shaderData && "No NULL shader data pointers please." );
+ DALI_ASSERT_DEBUG( shaderData->GetBufferSize() > 0 && "Shader binary empty so nothing to save." );
+ {
+ // lock as update might be sending previously compiled shaders to event thread
+ Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
+ mImpl->renderCompiledShaders.push_back( shaderData );
}
}
return mImpl->messageQueue.FlushQueue();
}
-void UpdateManager::ResetNodeProperty( Node& node )
-{
- BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
-
- node.ResetToBaseValues( bufferIndex );
-}
-
-void UpdateManager::ResetProperties()
+void UpdateManager::ResetProperties( BufferIndex bufferIndex )
{
PERF_MONITOR_START(PerformanceMonitor::RESET_PROPERTIES);
- BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
-
// Clear the "animations finished" flag; This should be set if any (previously playing) animation is stopped
mImpl->animationFinishedDuringUpdate = false;
// Animated properties have to be reset to their original value each frame
- // Reset node properties
+ // Reset root properties
if ( mImpl->root )
{
- ResetNodeProperty( *mImpl->root );
+ mImpl->root->ResetToBaseValues( bufferIndex );
}
-
if ( mImpl->systemLevelRoot )
{
- ResetNodeProperty( *mImpl->systemLevelRoot );
+ 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 )
{
- ResetNodeProperty( **iter );
+ (*iter)->ResetToBaseValues( bufferIndex );
}
// If a Node is disconnected, it may still be "active" (requires a reset in next frame)
mImpl->geometries.ResetToBaseValues( bufferIndex );
mImpl->propertyBuffers.ResetToBaseValues( bufferIndex );
mImpl->samplers.ResetToBaseValues( bufferIndex );
+ mImpl->renderers.ResetToBaseValues( bufferIndex );
// Reset animatable shader properties to base values
PERF_MONITOR_END(PerformanceMonitor::RESET_PROPERTIES);
}
-bool UpdateManager::ProcessGestures( unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
+bool UpdateManager::ProcessGestures( BufferIndex bufferIndex, unsigned int lastVSyncTimeMilliseconds, unsigned int nextVSyncTimeMilliseconds )
{
bool gestureUpdated( false );
for ( GestureIter iter = gestures.Begin(), endIter = gestures.End(); iter != endIter; ++iter )
{
PanGesture& gesture = **iter;
- gesture.ResetToBaseValues( mSceneGraphBuffers.GetUpdateBufferIndex() ); // Needs to be done every time as gesture data is written directly to an update-buffer rather than via a message
+ gesture.ResetToBaseValues( bufferIndex ); // Needs to be done every time as gesture data is written directly to an update-buffer rather than via a message
gestureUpdated |= gesture.UpdateProperties( lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
}
return gestureUpdated;
}
-void UpdateManager::Animate( float elapsedSeconds )
+void UpdateManager::Animate( BufferIndex bufferIndex, float elapsedSeconds )
{
PERF_MONITOR_START(PerformanceMonitor::ANIMATE_NODES);
while ( iter != animations.End() )
{
Animation* animation = *iter;
- bool finished = animation->Update(mSceneGraphBuffers.GetUpdateBufferIndex(), elapsedSeconds);
+ bool finished = animation->Update( bufferIndex, elapsedSeconds );
mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
PERF_MONITOR_END(PerformanceMonitor::ANIMATE_NODES);
}
-void UpdateManager::ApplyConstraints()
+void UpdateManager::ApplyConstraints( BufferIndex bufferIndex )
{
PERF_MONITOR_START(PerformanceMonitor::APPLY_CONSTRAINTS);
- BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
-
// constrain custom objects... (in construction order)
OwnerContainer< PropertyOwner* >& customObjects = mImpl->customObjects;
mImpl->geometries.ConstrainObjects( bufferIndex );
mImpl->samplers.ConstrainObjects( bufferIndex );
mImpl->propertyBuffers.ConstrainObjects( bufferIndex );
+ mImpl->renderers.ConstrainObjects( bufferIndex );
// constrain shaders... (in construction order)
ShaderContainer& shaders = mImpl->shaders;
PERF_MONITOR_END(PerformanceMonitor::APPLY_CONSTRAINTS);
}
-void UpdateManager::ProcessPropertyNotifications()
+void UpdateManager::ProcessPropertyNotifications( BufferIndex bufferIndex )
{
PropertyNotificationContainer ¬ifications = mImpl->propertyNotifications;
PropertyNotificationIter iter = notifications.Begin();
- BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
-
while ( iter != notifications.End() )
{
PropertyNotification* notification = *iter;
}
}
-void UpdateManager::UpdateNodes()
+void UpdateManager::ForwardCompiledShadersToEventThread()
+{
+ DALI_ASSERT_DEBUG( (mImpl->shaderSaver != 0) && "shaderSaver should be wired-up during startup." );
+ if( mImpl->shaderSaver )
+ {
+ // lock and swap the queues
+ {
+ // render might be attempting to send us more binaries at the same time
+ Mutex::ScopedLock lock( mImpl->compiledShaderMutex );
+ mImpl->renderCompiledShaders.swap( mImpl->updateCompiledShaders );
+ }
+
+ if( mImpl->updateCompiledShaders.size() > 0 )
+ {
+ ShaderSaver& factory = *mImpl->shaderSaver;
+ ShaderDataBinaryQueue::iterator i = mImpl->updateCompiledShaders.begin();
+ ShaderDataBinaryQueue::iterator end = mImpl->updateCompiledShaders.end();
+ for( ; i != end; ++i )
+ {
+ mImpl->notificationManager.QueueMessage( ShaderCompiledMessage( factory, *i ) );
+ }
+ // we don't need them in update anymore
+ mImpl->updateCompiledShaders.clear();
+ }
+ }
+}
+
+void UpdateManager::UpdateRenderers( BufferIndex bufferIndex )
+{
+ const Internal::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 );
+ }
+ }
+}
+
+void UpdateManager::UpdateNodes( BufferIndex bufferIndex )
{
mImpl->nodeDirtyFlags = NothingFlag;
// Prepare resources, update shaders, update attachments, for each node
// And add the renderers to the sorted layers. Start from root, which is also a layer
mImpl->nodeDirtyFlags = UpdateNodesAndAttachments( *( mImpl->root ),
- mSceneGraphBuffers.GetUpdateBufferIndex(),
+ bufferIndex,
mImpl->resourceManager,
mImpl->renderQueue );
if ( mImpl->systemLevelRoot )
{
mImpl->nodeDirtyFlags |= UpdateNodesAndAttachments( *( mImpl->systemLevelRoot ),
- mSceneGraphBuffers.GetUpdateBufferIndex(),
+ bufferIndex,
mImpl->resourceManager,
mImpl->renderQueue );
}
// Measure the time spent in UpdateManager::Update
PERF_MONITOR_START(PerformanceMonitor::UPDATE);
- BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
+ const BufferIndex bufferIndex = mSceneGraphBuffers.GetUpdateBufferIndex();
// Update the frame time delta on the render thread.
mImpl->renderManager.SetFrameDeltaTime(elapsedSeconds);
// 3) Process Touches & Gestures
mImpl->touchResampler.Update();
- const bool gestureUpdated = ProcessGestures( lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
+ const bool gestureUpdated = ProcessGestures( bufferIndex, lastVSyncTimeMilliseconds, nextVSyncTimeMilliseconds );
+
+ const bool updateScene = // The scene-graph requires an update if..
+ (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || // ..nodes were dirty in previous frame OR
+ IsAnimationRunning() || // ..at least one animation is running OR
+ mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR
+ resourceChanged || // ..one or more resources were updated/changed OR
+ gestureUpdated; // ..a gesture property was updated
- const bool updateScene = // The scene-graph requires an update if..
- (mImpl->nodeDirtyFlags & RenderableUpdateFlags) || // ..nodes were dirty in previous frame OR
- IsAnimationRunning() || // ..at least one animation is running OR
- mImpl->dynamicsChanged || // ..there was a change in the dynamics simulation OR
- mImpl->messageQueue.IsSceneUpdateRequired() || // ..a message that modifies the scene graph node tree is queued OR
- resourceChanged || // ..one or more resources were updated/changed OR
- gestureUpdated; // ..a gesture property was updated
// Although the scene-graph may not require an update, we still need to synchronize double-buffered
// values if the scene was updated in the previous frame.
if( updateScene || mImpl->previousUpdateScene )
{
// 4) Reset properties from the previous update
- ResetProperties();
+ ResetProperties( bufferIndex );
}
// 5) Process the queued scene messages
- mImpl->messageQueue.ProcessMessages();
+ mImpl->messageQueue.ProcessMessages( bufferIndex );
// 6) Post Process Ids of resources updated by renderer
mImpl->resourceManager.PostProcessResources( bufferIndex );
+ // 6.1) 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
// renderer lists if the scene was updated in the previous frame.
// 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( elapsedSeconds );
+ Animate( bufferIndex, elapsedSeconds );
// 8) Apply Constraints
- ApplyConstraints();
-
-#ifdef DALI_DYNAMICS_SUPPORT
- // 9) Update dynamics simulation
- mImpl->dynamicsChanged = false;
- if( mImpl->dynamicsWorld )
- {
- mImpl->dynamicsChanged = mImpl->dynamicsWorld->Update( elapsedSeconds );
- }
-#endif
+ ApplyConstraints( bufferIndex );
- // 10) Check Property Notifications
- ProcessPropertyNotifications();
+ // 9) Check Property Notifications
+ ProcessPropertyNotifications( bufferIndex );
- // 11) Clear the lists of renderable-attachments from the previous update
+ // 10) Clear the lists of renderable-attachments from the previous update
ClearRenderables( mImpl->sortedLayers );
ClearRenderables( mImpl->systemLevelSortedLayers );
- // 12) Update node hierarchy and perform sorting / culling.
+ // 11) Update node hierarchy and perform sorting / culling.
// This will populate each Layer with a list of renderers which are ready.
- UpdateNodes();
+ UpdateNodes( bufferIndex );
+ UpdateRenderers( bufferIndex );
+
- // 13) Prepare for the next render
+ // 12) Prepare for the next render
PERF_MONITOR_START(PerformanceMonitor::PREPARE_RENDERABLES);
PrepareRenderables( bufferIndex, mImpl->sortedLayers );
// 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
- mImpl->renderInstructions.ResetAndReserve( mSceneGraphBuffers.GetUpdateBufferIndex(),
+ mImpl->renderInstructions.ResetAndReserve( bufferIndex,
mImpl->taskList.GetTasks().Count() + mImpl->systemLevelTaskList.GetTasks().Count() );
if ( NULL != mImpl->root )
keepUpdating |= KeepUpdating::MONITORING_PERFORMANCE;
#endif
- // The update has finished; swap the double-buffering indices
- mSceneGraphBuffers.Swap();
-
// 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;
keepUpdatingRequest |= KeepUpdating::ANIMATIONS_RUNNING;
}
- if ( mImpl->dynamicsChanged )
- {
- keepUpdatingRequest |= KeepUpdating::DYNAMICS_CHANGED;
- }
-
if ( mImpl->renderTaskWaiting )
{
keepUpdatingRequest |= KeepUpdating::RENDER_TASK_SYNC;
}
}
-#ifdef DALI_DYNAMICS_SUPPORT
-
-void UpdateManager::InitializeDynamicsWorld( SceneGraph::DynamicsWorld* dynamicsWorld, Integration::DynamicsWorldSettings* worldSettings )
-{
- dynamicsWorld->Initialize( mImpl->sceneController, worldSettings, &mSceneGraphBuffers );
- mImpl->dynamicsWorld = dynamicsWorld;
-}
-
-void UpdateManager::TerminateDynamicsWorld()
+void UpdateManager::SetShaderSaver( ShaderSaver& upstream )
{
- mImpl->dynamicsWorld.Reset();
+ mImpl->shaderSaver = &upstream;
}
-#endif // DALI_DYNAMICS_SUPPORT
-
} // namespace SceneGraph
} // namespace Internal