From: Tom Robinson Date: Tue, 27 Jun 2017 15:01:02 +0000 (+0100) Subject: Performance Improvements: Reduce glClear calls X-Git-Tag: dali_1.2.46~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=301038f992b9ac1994812d0eb90f827b138e52ad;p=platform%2Fcore%2Fuifw%2Fdali-core.git Performance Improvements: Reduce glClear calls 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 --- diff --git a/dali/internal/event/actors/camera-actor-impl.cpp b/dali/internal/event/actors/camera-actor-impl.cpp index c5015de..c8f5d75 100644 --- a/dali/internal/event/actors/camera-actor-impl.cpp +++ b/dali/internal/event/actors/camera-actor-impl.cpp @@ -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 diff --git a/dali/internal/event/actors/camera-actor-impl.h b/dali/internal/event/actors/camera-actor-impl.h index 30f9bc6..a3a4ae6 100644 --- a/dali/internal/event/actors/camera-actor-impl.h +++ b/dali/internal/event/actors/camera-actor-impl.h @@ -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 diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp index 253bb77..bc511af 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -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 diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index 569bc55..64bf05f 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -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 ); + } } } } diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index 96588bd..602a04b 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -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 ); diff --git a/dali/internal/update/render-tasks/scene-graph-camera.cpp b/dali/internal/update/render-tasks/scene-graph-camera.cpp index c9e4b7a..e6b088c 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.cpp +++ b/dali/internal/update/render-tasks/scene-graph-camera.cpp @@ -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 ); diff --git a/dali/internal/update/render-tasks/scene-graph-camera.h b/dali/internal/update/render-tasks/scene-graph-camera.h index 1f00cd5..44b7518 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.h +++ b/dali/internal/update/render-tasks/scene-graph-camera.h @@ -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 diff --git a/dali/internal/update/render-tasks/scene-graph-render-task.cpp b/dali/internal/update/render-tasks/scene-graph-render-task.cpp index 4a239cd..007d341 100644 --- a/dali/internal/update/render-tasks/scene-graph-render-task.cpp +++ b/dali/internal/update/render-tasks/scene-graph-render-task.cpp @@ -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; }