Performance Improvements: Reduce glClear calls 72/135972/4
authorTom Robinson <tom.robinson@samsung.com>
Tue, 27 Jun 2017 15:01:02 +0000 (16:01 +0100)
committerTom Robinson <tom.robinson@samsung.com>
Wed, 28 Jun 2017 11:30:34 +0000 (12:30 +0100)
Notes on this change so far:
* Camera still exists within rendertask as is required for some methods - this can be removed as part of later refactor?

Change-Id: I49e73be70773fa295803a7077392bb60d693f9be

dali/internal/event/actors/camera-actor-impl.cpp
dali/internal/event/actors/camera-actor-impl.h
dali/internal/render/common/render-manager.cpp
dali/internal/update/manager/update-manager.cpp
dali/internal/update/manager/update-manager.h
dali/internal/update/render-tasks/scene-graph-camera.cpp
dali/internal/update/render-tasks/scene-graph-camera.h
dali/internal/update/render-tasks/scene-graph-render-task.cpp

index c5015de..c8f5d75 100644 (file)
@@ -138,20 +138,12 @@ void BuildOrthoPickingRay( const Matrix& viewMatrix,
 
 CameraActorPtr CameraActor::New( const Size& size )
 {
-  CameraActorPtr actor(new CameraActor());
+  CameraActorPtr actor( new CameraActor() );
 
   // Second-phase construction
-
   actor->Initialize();
 
-  actor->SetName("DefaultCamera");
-
-  // Create scene-object and keep raw pointer for message passing
-  SceneGraph::Camera* camera = SceneGraph::Camera::New();
-  actor->mSceneObject = camera;
-  OwnerPointer< SceneGraph::Camera > transferOwnership( camera );
-  AddCameraMessage( actor->GetEventThreadServices().GetUpdateManager(), transferOwnership );
-
+  actor->SetName( "DefaultCamera" );
   actor->SetPerspectiveProjection( size );
 
   // By default Actors face in the positive Z direction in world space
@@ -188,6 +180,21 @@ CameraActor::~CameraActor()
   }
 }
 
+void CameraActor::OnInitialize()
+{
+  // Create scene-object and keep raw pointer for message passing.
+  SceneGraph::Camera* sceneGraphCamera = SceneGraph::Camera::New();
+
+  // Store a pointer to this camera node inside the scene-graph camera.
+  sceneGraphCamera->SetNode( mNode );
+
+  mSceneObject = sceneGraphCamera;
+  OwnerPointer< SceneGraph::Camera > sceneGraphCameraOwner( sceneGraphCamera );
+
+  // Send message to inform update of this camera (and move ownership).
+  AddCameraMessage( GetEventThreadServices().GetUpdateManager(), sceneGraphCameraOwner );
+}
+
 void CameraActor::SetTarget( const Vector3& target )
 {
   if( target != mTarget ) // using range epsilon
index 30f9bc6..a3a4ae6 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __DALI_INTERNAL_CAMERA_ACTOR_H__
-#define __DALI_INTERNAL_CAMERA_ACTOR_H__
+#ifndef DALI_INTERNAL_CAMERA_ACTOR_H
+#define DALI_INTERNAL_CAMERA_ACTOR_H
 
 /*
  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
@@ -275,6 +275,13 @@ private:
    */
   virtual ~CameraActor();
 
+
+  /**
+   * @copydoc Dali::Internal::Actor::OnInitialize()
+   */
+  virtual void OnInitialize();
+
+
 private: // Data
 
   const SceneGraph::Camera* mSceneObject; ///< Not owned
@@ -318,4 +325,4 @@ inline const Internal::CameraActor& GetImplementation(const Dali::CameraActor& c
 
 } // namespace Dali
 
-#endif // __DALI_INTERNAL_CAMERA_ACTOR_H__
+#endif // DALI_INTERNAL_CAMERA_ACTOR_H
index 253bb77..bc511af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -89,7 +89,7 @@ struct RenderManager::Impl
     samplerContainer(),
     textureContainer(),
     frameBufferContainer(),
-    renderersAdded( false ),
+    lastFrameWasRendered( false ),
     programController( glAbstraction )
   {
   }
@@ -141,7 +141,7 @@ struct RenderManager::Impl
   PropertyBufferOwnerContainer  propertyBufferContainer;  ///< List of owned property buffers
   GeometryOwnerContainer        geometryContainer;        ///< List of owned Geometries
 
-  bool                          renderersAdded;
+  bool                          lastFrameWasRendered;     ///< Keeps track of the last frame being rendered due to having render instructions
 
   RenderTrackerContainer        mRenderTrackers;          ///< List of render trackers
 
@@ -235,11 +235,6 @@ void RenderManager::AddRenderer( OwnerPointer< Render::Renderer >& renderer )
   renderer->Initialize( mImpl->context );
 
   mImpl->rendererContainer.PushBack( renderer.Release() );
-
-  if( !mImpl->renderersAdded )
-  {
-    mImpl->renderersAdded = true;
-  }
 }
 
 void RenderManager::RemoveRenderer( Render::Renderer* renderer )
@@ -435,53 +430,63 @@ void RenderManager::Render( Integration::RenderStatus& status )
   // Process messages queued during previous update
   mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex );
 
-  // switch rendering to adaptor provided (default) buffer
-  mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 );
-
-  mImpl->context.Viewport( mImpl->defaultSurfaceRect.x,
-                           mImpl->defaultSurfaceRect.y,
-                           mImpl->defaultSurfaceRect.width,
-                           mImpl->defaultSurfaceRect.height );
-
-  mImpl->context.ClearColor( mImpl->backgroundColor.r,
-                             mImpl->backgroundColor.g,
-                             mImpl->backgroundColor.b,
-                             mImpl->backgroundColor.a );
-
-  mImpl->context.ClearStencil( 0 );
-
-  // Clear the entire color, depth and stencil buffers for the default framebuffer.
-  // It is important to clear all 3 buffers, for performance on deferred renderers like Mali
-  // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
-  // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
-  mImpl->context.SetScissorTest( false );
-  mImpl->context.ColorMask( true );
-  mImpl->context.DepthMask( true );
-  mImpl->context.StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
-  mImpl->context.Clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,  Context::FORCE_CLEAR );
-
-  // reset the program matrices for all programs once per frame
-  // this ensures we will set view and projection matrix once per program per camera
-  mImpl->programController.ResetProgramMatrices();
-
-  size_t count = mImpl->instructions.Count( mImpl->renderBufferIndex );
-  for ( size_t i = 0; i < count; ++i )
+  const size_t count = mImpl->instructions.Count( mImpl->renderBufferIndex );
+  const bool haveInstructions = count > 0u;
+
+  // Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required).
+  if( haveInstructions || mImpl->lastFrameWasRendered )
   {
-    RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i );
+    // switch rendering to adaptor provided (default) buffer
+    mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 );
 
-    DoRender( instruction );
-  }
-  GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
-  mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
+    mImpl->context.Viewport( mImpl->defaultSurfaceRect.x,
+                             mImpl->defaultSurfaceRect.y,
+                             mImpl->defaultSurfaceRect.width,
+                             mImpl->defaultSurfaceRect.height );
 
-  mImpl->UpdateTrackers();
+    mImpl->context.ClearColor( mImpl->backgroundColor.r,
+                               mImpl->backgroundColor.g,
+                               mImpl->backgroundColor.b,
+                               mImpl->backgroundColor.a );
 
-  //Notify RenderGeometries that rendering has finished
-  for ( GeometryOwnerIter iter = mImpl->geometryContainer.Begin(); iter != mImpl->geometryContainer.End(); ++iter )
-  {
-    (*iter)->OnRenderFinished();
+    mImpl->context.ClearStencil( 0 );
+
+    // Clear the entire color, depth and stencil buffers for the default framebuffer.
+    // It is important to clear all 3 buffers, for performance on deferred renderers like Mali
+    // e.g. previously when the depth & stencil buffers were NOT cleared, it caused the DDK to exceed a "vertex count limit",
+    // and then stall. That problem is only noticeable when rendering a large number of vertices per frame.
+    mImpl->context.SetScissorTest( false );
+    mImpl->context.ColorMask( true );
+    mImpl->context.DepthMask( true );
+    mImpl->context.StencilMask( 0xFF ); // 8 bit stencil mask, all 1's
+    mImpl->context.Clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, Context::FORCE_CLEAR );
+
+    // reset the program matrices for all programs once per frame
+    // this ensures we will set view and projection matrix once per program per camera
+    mImpl->programController.ResetProgramMatrices();
+
+    for( size_t i = 0; i < count; ++i )
+    {
+      RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i );
+
+      DoRender( instruction );
+    }
+
+    GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
+    mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
+
+    mImpl->UpdateTrackers();
+
+    //Notify RenderGeometries that rendering has finished
+    for ( GeometryOwnerIter iter = mImpl->geometryContainer.Begin(); iter != mImpl->geometryContainer.End(); ++iter )
+    {
+      (*iter)->OnRenderFinished();
+    }
   }
 
+  // If this frame was rendered due to instructions existing, we mark this so we know to clear the next frame.
+  mImpl->lastFrameWasRendered = haveInstructions;
+
   /**
    * The rendering has finished; swap to the next buffer.
    * Ideally the update has just finished using this buffer; otherwise the render thread
index 569bc55..64bf05f 100644 (file)
@@ -198,7 +198,8 @@ struct UpdateManager::Impl
     frameCounter( 0 ),
     animationFinishedDuringUpdate( false ),
     previousUpdateScene( false ),
-    renderTaskWaiting( false )
+    renderTaskWaiting( false ),
+    renderersAdded( false )
   {
     sceneController = new SceneControllerImpl( renderMessageDispatcher, renderQueue, discardQueue );
 
@@ -302,6 +303,7 @@ struct UpdateManager::Impl
   bool                                animationFinishedDuringUpdate; ///< Flag whether any animations finished during the Update()
   bool                                previousUpdateScene;           ///< True if the scene was updated in the previous frame (otherwise it was optimized out)
   bool                                renderTaskWaiting;             ///< A REFRESH_ONCE render task is waiting to be rendered
+  bool                                renderersAdded;                ///< Flag to keep track when renderers have been added to avoid unnecessary processing
 
 private:
 
@@ -545,6 +547,7 @@ void UpdateManager::AddRenderer( OwnerPointer< Renderer >& renderer )
 {
   renderer->ConnectToSceneGraph( *mImpl->sceneController, mSceneGraphBuffers.GetUpdateBufferIndex() );
   mImpl->renderers.PushBack( renderer.Release() );
+  mImpl->renderersAdded = true;
 }
 
 void UpdateManager::RemoveRenderer( Renderer* renderer )
@@ -893,27 +896,37 @@ unsigned int UpdateManager::Update( float elapsedSeconds,
     //Process Property Notifications
     ProcessPropertyNotifications( bufferIndex );
 
-    //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() );
+    //Update cameras
+    const CameraOwner::Iterator endCameraIterator = mImpl->cameras.End();
+    for( CameraOwner::Iterator cameraIterator = mImpl->cameras.Begin(); endCameraIterator != cameraIterator; ++cameraIterator )
+    {
+      ( *cameraIterator )->Update( bufferIndex );
+    }
 
-    if ( NULL != mImpl->root )
+    //Process the RenderTasks if renderers exist. 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
+    if( mImpl->renderersAdded )
     {
-      mImpl->renderTaskProcessor.Process( bufferIndex,
-                                        mImpl->taskList,
-                                        *mImpl->root,
-                                        mImpl->sortedLayers,
-                                        mImpl->renderInstructions );
-
-      // Process the system-level RenderTasks last
-      if ( NULL != mImpl->systemLevelRoot )
+      mImpl->renderInstructions.ResetAndReserve( bufferIndex,
+                                                 mImpl->taskList.GetTasks().Count() + mImpl->systemLevelTaskList.GetTasks().Count() );
+
+      if ( NULL != mImpl->root )
       {
         mImpl->renderTaskProcessor.Process( bufferIndex,
-                                          mImpl->systemLevelTaskList,
-                                          *mImpl->systemLevelRoot,
-                                          mImpl->systemLevelSortedLayers,
+                                          mImpl->taskList,
+                                          *mImpl->root,
+                                          mImpl->sortedLayers,
                                           mImpl->renderInstructions );
+
+        // Process the system-level RenderTasks last
+        if ( NULL != mImpl->systemLevelRoot )
+        {
+          mImpl->renderTaskProcessor.Process( bufferIndex,
+                                            mImpl->systemLevelTaskList,
+                                            *mImpl->systemLevelRoot,
+                                            mImpl->systemLevelSortedLayers,
+                                            mImpl->renderInstructions );
+        }
       }
     }
   }
index 96588bd..602a04b 100644 (file)
@@ -188,7 +188,7 @@ public:
 
   /**
    * Add a camera on scene
-   * @param[in] camera to add
+   * @param[in] camera The camera to add
    */
   void AddCamera( OwnerPointer< Camera >& camera );
 
index c9e4b7a..e6b088c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -182,6 +182,11 @@ Camera::~Camera()
 {
 }
 
+void Camera::SetNode( const Node* node )
+{
+  mNode = node;
+}
+
 void Camera::SetType( Dali::Camera::Type type )
 {
   mType = type;
@@ -284,14 +289,14 @@ const PropertyInputImpl* Camera::GetViewMatrix() const
   return &mViewMatrix;
 }
 
-void Camera::Update( BufferIndex updateBufferIndex, const Node& owningNode )
+void Camera::Update( BufferIndex updateBufferIndex )
 {
   // if owning node has changes in world position we need to update camera for next 2 frames
-  if( owningNode.IsLocalMatrixDirty() )
+  if( mNode->IsLocalMatrixDirty() )
   {
     mUpdateViewFlag = UPDATE_COUNT;
   }
-  if( owningNode.GetDirtyFlags() & VisibleFlag )
+  if( mNode->GetDirtyFlags() & VisibleFlag )
   {
     // If the visibility changes, the projection matrix needs to be re-calculated.
     // It may happen the first time an actor is rendered it's rendered only once and becomes invisible,
@@ -301,7 +306,7 @@ void Camera::Update( BufferIndex updateBufferIndex, const Node& owningNode )
   }
 
   // if either matrix changed, we need to recalculate the inverse matrix for hit testing to work
-  unsigned int viewUpdateCount = UpdateViewMatrix( updateBufferIndex, owningNode );
+  unsigned int viewUpdateCount = UpdateViewMatrix( updateBufferIndex );
   unsigned int projectionUpdateCount = UpdateProjection( updateBufferIndex );
 
   // if model or view matrix changed we need to either recalculate the inverse VP or copy previous
@@ -328,7 +333,7 @@ bool Camera::ViewMatrixUpdated()
   return 0u != mUpdateViewFlag;
 }
 
-unsigned int Camera::UpdateViewMatrix( BufferIndex updateBufferIndex, const Node& owningNode )
+unsigned int Camera::UpdateViewMatrix( BufferIndex updateBufferIndex )
 {
   unsigned int retval( mUpdateViewFlag );
   if( 0u != mUpdateViewFlag )
@@ -346,7 +351,7 @@ unsigned int Camera::UpdateViewMatrix( BufferIndex updateBufferIndex, const Node
         case Dali::Camera::FREE_LOOK:
         {
           Matrix& viewMatrix = mViewMatrix.Get( updateBufferIndex );
-          viewMatrix = owningNode.GetWorldMatrix( updateBufferIndex );
+          viewMatrix = mNode->GetWorldMatrix( updateBufferIndex );
           viewMatrix.Invert();
           mViewMatrix.SetDirty( updateBufferIndex );
           break;
@@ -354,7 +359,7 @@ unsigned int Camera::UpdateViewMatrix( BufferIndex updateBufferIndex, const Node
           // camera orientation constrained to look at a target
         case Dali::Camera::LOOK_AT_TARGET:
         {
-          const Matrix& owningNodeMatrix( owningNode.GetWorldMatrix( updateBufferIndex ) );
+          const Matrix& owningNodeMatrix( mNode->GetWorldMatrix( updateBufferIndex ) );
           Vector3 position, scale;
           Quaternion orientation;
           owningNodeMatrix.GetTransformComponents( position, orientation, scale );
index 1f00cd5..44b7518 100644 (file)
@@ -1,8 +1,8 @@
-#ifndef __DALI_INTERNAL_SCENE_GRAPH_CAMERA_H__
-#define __DALI_INTERNAL_SCENE_GRAPH_CAMERA_H__
+#ifndef DALI_INTERNAL_SCENE_GRAPH_CAMERA_H
+#define DALI_INTERNAL_SCENE_GRAPH_CAMERA_H
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -94,6 +94,12 @@ public:
   ~Camera();
 
   /**
+   * Set the node this scene graph camera belongs to.
+   * @param[in] node The owning node.
+   */
+  void SetNode( const Node* node );
+
+  /**
    * @copydoc Dali::Internal::CameraActor::SetType
    */
   void SetType( Dali::Camera::Type type );
@@ -219,9 +225,8 @@ public:
    * Updates view and projection matrices.
    * Called by the render task using the camera
    * @param[in] updateBufferIndex The buffer to read from.
-   * @param[in] owningNode The node that owns the camera
    */
-  void Update( BufferIndex updateBufferIndex, const Node& owningNode );
+  void Update( BufferIndex updateBufferIndex );
 
   /**
    * @return true if the view matrix of camera is updated this or the previous frame
@@ -244,10 +249,9 @@ private:
   /**
    * Recalculates the view matrix.
    * @param[in] bufferIndex The current update buffer index.
-   * @param[in] owningNode to use for calculations.
    * @return count how many frames ago the matrix was changed.
    */
-  unsigned int UpdateViewMatrix( BufferIndex updateBufferIndex, const Node& owningNode );
+  unsigned int UpdateViewMatrix( BufferIndex updateBufferIndex );
 
   /**
    * Recalculates the projection matrix.
@@ -268,6 +272,7 @@ private:
 
   unsigned int                  mUpdateViewFlag;       ///< This is non-zero if the view matrix requires an update
   unsigned int                  mUpdateProjectionFlag; ///< This is non-zero if the projection matrix requires an update
+  const Node*                   mNode;                 ///< The node this scene graph camera belongs to
 
 public:  // PROPERTIES
   Dali::Camera::Type            mType;                 // Non-animatable
@@ -444,4 +449,4 @@ inline void SetInvertYAxisMessage( EventThreadServices& eventThreadServices, con
 
 } // namespace Dali
 
-#endif // __DALI_INTERNAL_SCENE_GRAPH_CAMERA_H__
+#endif // DALI_INTERNAL_SCENE_GRAPH_CAMERA_H
index 4a239cd..007d341 100644 (file)
@@ -201,28 +201,26 @@ bool RenderTask::ReadyToRender( BufferIndex updateBufferIndex )
   // If the source node of the render task is invisible we should still render
   // We want the render task to complete and possible clear colors to happen
 
-  // Check source node
-  if ( NULL == mSourceNode ||
-       ( !mSourceNode->IsRoot() && NULL == mSourceNode->GetParent() ) )
+  // Check the source node.
+  if( NULL == mSourceNode ||
+      ( !mSourceNode->IsRoot() && NULL == mSourceNode->GetParent() ) )
   {
-    TASK_LOG_FMT(Debug::General, " =F  No source actor  FC:%d\n", mFrameCounter );
+    TASK_LOG_FMT( Debug::General, " Source actor not on stage.  Frame counter: %d\n", mFrameCounter );
 
-    // Source node is missing or disconnected
+    // The source node is missing or disconnected.
     return false;
   }
 
   // Check camera node
-  if ( NULL == mCameraNode ||
-       NULL == mCameraNode->GetParent() ||
-       NULL == mCamera )
+  if( NULL == mCameraNode ||
+      NULL == mCameraNode->GetParent() ||
+      NULL == mCamera )
   {
-    // Camera node is missing or disconnected
+    // The camera node is missing or disconnected.
     TASK_LOG_FMT(Debug::General, " =F  No Camera  FC:%d\n", mFrameCounter );
-
     return false;
   }
 
-  mCamera->Update( updateBufferIndex, *mCameraNode );
   return true;
 }