X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Fcommon%2Frender-manager.cpp;h=a1b3d4538afb36b5fa0fd28d756fa8b293d69b4d;hb=d353bae63798f48237dc24c078c2e8cb2aa0bc62;hp=e878e8a0e815b32b7eeb54692cefced79b25646b;hpb=bb2d338097bf95b7a222d42e4dfca515655837d8;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp old mode 100755 new mode 100644 index e878e8a..a1b3d45 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -39,12 +40,11 @@ #include #include #include -#include -#include #include #include #include #include +#include namespace Dali { @@ -62,37 +62,6 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_REN } // unnamed namespace #endif -namespace -{ -const float partialUpdateRatio = 0.8f; // If the partial update area exceeds 80%, change to full update. - -/** - * @brief Find the intersection of two AABB rectangles. - * This is a logical AND operation. IE. The intersection is the area overlapped by both rectangles. - * @param[in] aabbA Rectangle A - * @param[in] aabbB Rectangle B - * @return The intersection of rectangle A & B (result is a rectangle) - */ -inline ClippingBox IntersectAABB( const ClippingBox& aabbA, const ClippingBox& aabbB ) -{ - ClippingBox intersectionBox; - - // First calculate the largest starting positions in X and Y. - intersectionBox.x = std::max( aabbA.x, aabbB.x ); - intersectionBox.y = std::max( aabbA.y, aabbB.y ); - - // Now calculate the smallest ending positions, and take the largest starting - // positions from the result, to get the width and height respectively. - // If the two boxes do not intersect at all, then we need a 0 width and height clipping area. - // We use max here to clamp both width and height to >= 0 for this use-case. - intersectionBox.width = std::max( std::min( aabbA.x + aabbA.width, aabbB.x + aabbB.width ) - intersectionBox.x, 0 ); - intersectionBox.height = std::max( std::min( aabbA.y + aabbA.height, aabbB.y + aabbB.height ) - intersectionBox.y, 0 ); - - return intersectionBox; -} - -} - /** * Structure to contain internal data */ @@ -102,15 +71,13 @@ struct RenderManager::Impl Integration::GlSyncAbstraction& glSyncAbstraction, Integration::GlContextHelperAbstraction& glContextHelperAbstraction, Integration::DepthBufferAvailable depthBufferAvailableParam, - Integration::StencilBufferAvailable stencilBufferAvailableParam, - Integration::PartialUpdateAvailable partialUpdateAvailableParam ) - : context( glAbstraction, &surfaceContextContainer ), + Integration::StencilBufferAvailable stencilBufferAvailableParam ) + : context( glAbstraction, &sceneContextContainer ), currentContext( &context ), glAbstraction( glAbstraction ), glSyncAbstraction( glSyncAbstraction ), glContextHelperAbstraction( glContextHelperAbstraction ), renderQueue(), - instructions(), renderAlgorithms(), frameCount( 0u ), renderBufferIndex( SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX ), @@ -123,7 +90,6 @@ struct RenderManager::Impl programController( glAbstraction ), depthBufferAvailable( depthBufferAvailableParam ), stencilBufferAvailable( stencilBufferAvailableParam ), - partialUpdateAvailable( partialUpdateAvailableParam ), defaultSurfaceOrientation( 0 ) { // Create thread pool with just one thread ( there may be a need to create more threads in the future ). @@ -147,15 +113,26 @@ struct RenderManager::Impl mRenderTrackers.EraseObject( renderTracker ); } - Context* CreateSurfaceContext() + Context* CreateSceneContext() { - surfaceContextContainer.PushBack( new Context( glAbstraction ) ); - return surfaceContextContainer[ surfaceContextContainer.Count() - 1 ]; + sceneContextContainer.push_back( new Context( glAbstraction ) ); + return sceneContextContainer[ sceneContextContainer.size() - 1 ]; } - void DestroySurfaceContext( Context* surfaceContext ) + void DestroySceneContext( Context* sceneContext ) { - surfaceContextContainer.EraseObject( surfaceContext ); + auto iter = std::find( sceneContextContainer.begin(), sceneContextContainer.end(), sceneContext ); + if( iter != sceneContextContainer.end() ) + { + sceneContextContainer.erase( iter ); + } + } + + Context* ReplaceSceneContext( Context* oldSceneContext ) + { + Context* newContext = new Context( glAbstraction ); + std::replace( sceneContextContainer.begin(), sceneContextContainer.end(), oldSceneContext, newContext ); + return newContext; } void UpdateTrackers() @@ -170,15 +147,14 @@ struct RenderManager::Impl // programs are owned by context at the moment. Context context; ///< Holds the GL state of the share resource context Context* currentContext; ///< Holds the GL state of the current context for rendering - OwnerContainer< Context* > surfaceContextContainer; ///< List of owned contexts holding the GL state per surface + std::vector< Context* > sceneContextContainer; ///< List of owned contexts holding the GL state per scene Integration::GlAbstraction& glAbstraction; ///< GL abstraction Integration::GlSyncAbstraction& glSyncAbstraction; ///< GL sync abstraction Integration::GlContextHelperAbstraction& glContextHelperAbstraction; ///< GL context helper abstraction RenderQueue renderQueue; ///< A message queue for receiving messages from the update-thread. - // Render instructions describe what should be rendered during RenderManager::Render() - // Owned by RenderManager. Update manager updates instructions for the next frame while we render the current one - RenderInstructionContainer instructions; + std::vector< SceneGraph::Scene* > sceneContainer; ///< List of pointers to the scene graph objects of the scenes + Render::RenderAlgorithms renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction uint32_t frameCount; ///< The current frame count @@ -201,7 +177,6 @@ struct RenderManager::Impl Integration::DepthBufferAvailable depthBufferAvailable; ///< Whether the depth buffer is available Integration::StencilBufferAvailable stencilBufferAvailable; ///< Whether the stencil buffer is available - Integration::PartialUpdateAvailable partialUpdateAvailable; ///< Whether the partial update is available std::unique_ptr threadPool; ///< The thread pool Vector boundTextures; ///< The textures bound for rendering @@ -214,16 +189,14 @@ RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction, Integration::GlSyncAbstraction& glSyncAbstraction, Integration::GlContextHelperAbstraction& glContextHelperAbstraction, Integration::DepthBufferAvailable depthBufferAvailable, - Integration::StencilBufferAvailable stencilBufferAvailable, - Integration::PartialUpdateAvailable partialUpdateAvailable ) + Integration::StencilBufferAvailable stencilBufferAvailable ) { RenderManager* manager = new RenderManager; manager->mImpl = new Impl( glAbstraction, glSyncAbstraction, glContextHelperAbstraction, depthBufferAvailable, - stencilBufferAvailable, - partialUpdateAvailable ); + stencilBufferAvailable ); return manager; } @@ -273,6 +246,12 @@ void RenderManager::ContextDestroyed() { renderer->GlContextDestroyed(); } + + // inform scenes + for( auto&& scene : mImpl->sceneContainer ) + { + scene->GlContextDestroyed(); + } } void RenderManager::SetShaderSaver( ShaderSaver& upstream ) @@ -280,11 +259,6 @@ void RenderManager::SetShaderSaver( ShaderSaver& upstream ) mImpl->programController.SetShaderSaver( upstream ); } -RenderInstructionContainer& RenderManager::GetRenderInstructionContainer() -{ - return mImpl->instructions; -} - void RenderManager::SetDefaultSurfaceRect(const Rect& rect) { mImpl->defaultSurfaceRect = rect; @@ -367,14 +341,7 @@ void RenderManager::AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBu { Render::FrameBuffer* frameBufferPtr = frameBuffer.Release(); mImpl->frameBufferContainer.PushBack( frameBufferPtr ); - if ( frameBufferPtr->IsSurfaceBacked() ) - { - frameBufferPtr->Initialize( *mImpl->CreateSurfaceContext() ); - } - else - { - frameBufferPtr->Initialize( mImpl->context ); - } + frameBufferPtr->Initialize( mImpl->context ); } void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer ) @@ -387,29 +354,40 @@ void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer ) if ( iter == frameBuffer ) { frameBuffer->Destroy( mImpl->context ); - - if ( frameBuffer->IsSurfaceBacked() ) - { - auto surfaceFrameBuffer = static_cast( frameBuffer ); - mImpl->DestroySurfaceContext( surfaceFrameBuffer->GetContext() ); - } - mImpl->frameBufferContainer.Erase( &iter ); // frameBuffer found; now destroy it break; } } } +void RenderManager::InitializeScene( SceneGraph::Scene* scene ) +{ + scene->Initialize( *mImpl->CreateSceneContext() ); + mImpl->sceneContainer.push_back( scene ); +} -void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer ) +void RenderManager::UninitializeScene( SceneGraph::Scene* scene ) { - if ( !frameBuffer->IsSurfaceBacked() ) + mImpl->DestroySceneContext( scene->GetContext() ); + + auto iter = std::find( mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene ); + if( iter != mImpl->sceneContainer.end() ) { - auto textureFrameBuffer = static_cast( frameBuffer ); - textureFrameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer ); + mImpl->sceneContainer.erase( iter ); } } +void RenderManager::SurfaceReplaced( SceneGraph::Scene* scene ) +{ + Context* newContext = mImpl->ReplaceSceneContext( scene->GetContext() ); + scene->Initialize( *newContext ); +} + +void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer ) +{ + frameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer ); +} + void RenderManager::AddPropertyBuffer( OwnerPointer< Render::PropertyBuffer >& propertyBuffer ) { mImpl->propertyBufferContainer.PushBack( propertyBuffer.Release() ); @@ -495,7 +473,7 @@ ProgramCache* RenderManager::GetProgramCache() return &(mImpl->programController); } -void RenderManager::Render( Integration::RenderStatus& status, bool forceClear, bool uploadOnly ) +void RenderManager::PreRender( Integration::RenderStatus& status, bool forceClear, bool uploadOnly ) { DALI_PRINT_RENDER_START( mImpl->renderBufferIndex ); @@ -508,7 +486,12 @@ void RenderManager::Render( Integration::RenderStatus& status, bool forceClear, // Process messages queued during previous update mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex ); - const uint32_t count = mImpl->instructions.Count( mImpl->renderBufferIndex ); + uint32_t count = 0u; + for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) + { + count += mImpl->sceneContainer[i]->GetRenderInstructions().Count( mImpl->renderBufferIndex ); + } + const bool haveInstructions = count > 0u; DALI_LOG_INFO( gLogFilter, Debug::General, @@ -543,329 +526,168 @@ void RenderManager::Render( Integration::RenderStatus& status, bool forceClear, } // Upload the geometries - for( uint32_t i = 0; i < count; ++i ) + for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) { - RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i ); - - const Matrix* viewMatrix = instruction.GetViewMatrix( mImpl->renderBufferIndex ); - const Matrix* projectionMatrix = instruction.GetProjectionMatrix( mImpl->renderBufferIndex ); + RenderInstructionContainer& instructions = mImpl->sceneContainer[i]->GetRenderInstructions(); + for ( uint32_t j = 0; j < instructions.Count( mImpl->renderBufferIndex ); ++j ) + { + RenderInstruction& instruction = instructions.At( mImpl->renderBufferIndex, j ); - DALI_ASSERT_DEBUG( viewMatrix ); - DALI_ASSERT_DEBUG( projectionMatrix ); + const Matrix* viewMatrix = instruction.GetViewMatrix( mImpl->renderBufferIndex ); + const Matrix* projectionMatrix = instruction.GetProjectionMatrix( mImpl->renderBufferIndex ); - if( viewMatrix && projectionMatrix ) - { - const RenderListContainer::SizeType renderListCount = instruction.RenderListCount(); + DALI_ASSERT_DEBUG( viewMatrix ); + DALI_ASSERT_DEBUG( projectionMatrix ); - // Iterate through each render list. - for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index ) + if( viewMatrix && projectionMatrix ) { - const RenderList* renderList = instruction.GetRenderList( index ); + const RenderListContainer::SizeType renderListCount = instruction.RenderListCount(); - if( renderList && !renderList->IsEmpty() ) + // Iterate through each render list. + for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index ) { - const std::size_t itemCount = renderList->Count(); - for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex ) + const RenderList* renderList = instruction.GetRenderList( index ); + + if( renderList && !renderList->IsEmpty() ) { - const RenderItem& item = renderList->GetItem( itemIndex ); - if( DALI_LIKELY( item.mRenderer ) ) + const std::size_t itemCount = renderList->Count(); + for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex ) { - item.mRenderer->Upload( *mImpl->currentContext ); + const RenderItem& item = renderList->GetItem( itemIndex ); + if( DALI_LIKELY( item.mRenderer ) ) + { + item.mRenderer->Upload( *mImpl->currentContext ); + } } } } } } } - - if ( !uploadOnly ) - { - for( uint32_t i = 0; i < count; ++i ) - { - RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i ); - - DoRender( instruction ); - } - - if ( mImpl->currentContext->IsSurfacelessContextSupported() ) - { - mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); - } - - GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; - mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); - for ( auto&& context : mImpl->surfaceContextContainer ) - { - context->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); - } - } - - //Notify RenderGeometries that rendering has finished - for ( auto&& iter : mImpl->geometryContainer ) - { - iter->OnRenderFinished(); - } } - else - { - DALI_LOG_RELEASE_INFO( "RenderManager::Render: Skip rendering [%d, %d, %d]\n", haveInstructions, mImpl->lastFrameWasRendered, forceClear ); - } - - mImpl->UpdateTrackers(); - - // 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 - * should block until the update has finished. - */ - mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1; - - DALI_PRINT_RENDER_END(); } -bool GetDamagedRect( Rect &viewportRect, RenderInstruction& instruction, Rect &damagedRect ) -{ - // merge bounding - int dx1 = viewportRect.width, dx2 = 0, dy1 = viewportRect.height, dy2 = 0; - int checkWidth = static_cast( static_cast( viewportRect.width ) * partialUpdateRatio ); - int checkHeight = static_cast( static_cast( viewportRect.height ) * partialUpdateRatio ); - Rect screenRect; - bool isPartialUpdate = false; +void RenderManager::RenderScene( Integration::Scene& scene, bool renderToFbo ) +{ + Internal::Scene& sceneInternal = GetImplementation( scene ); + SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); - const RenderListContainer::SizeType renderListCount = instruction.RenderListCount(); - // Iterate through each render list. + uint32_t count = sceneObject->GetRenderInstructions().Count( mImpl->renderBufferIndex ); - for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index ) + for( uint32_t i = 0; i < count; ++i ) { - const RenderList* renderList = instruction.GetRenderList( index ); + RenderInstruction& instruction = sceneObject->GetRenderInstructions().At( mImpl->renderBufferIndex, i ); - if( renderList && !renderList->IsEmpty() && renderList->IsPartialUpdateEnabled() ) + if ( ( renderToFbo && !instruction.mFrameBuffer ) || ( !renderToFbo && instruction.mFrameBuffer ) ) { - const std::size_t itemCount = renderList->Count(); - for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex ) - { - const RenderItem& item = renderList->GetItem( itemIndex ); - - if( item.mPartialUpdateEnabled ) - { - isPartialUpdate = true; - - screenRect = item.CalculateViewportSpaceAABB( viewportRect.width, viewportRect.height, true ); - - dx1 = std::min( screenRect.x, dx1 ); - dx2 = std::max( screenRect.x + screenRect.width, dx2); - dy1 = std::min( screenRect.y, dy1 ); - dy2 = std::max( screenRect.y + screenRect.height, dy2 ); - - if( ( dx2 - dx1 ) > checkWidth && ( dy2 - dy1 ) > checkHeight ) - { - return false; - } - } - } + continue; // skip } - } - if( isPartialUpdate ) - { - if( dx1 < 0.0f ) - { - dx1 = 0.0f; - } - if( dy1 < 0.0f ) - { - dy1 = 0.0f; - } - if( dx2 > viewportRect.width ) + Rect viewportRect; + Vector4 clearColor; + + if ( instruction.mIsClearColorSet ) { - dx2 = viewportRect.width; + clearColor = instruction.mClearColor; } - if( dy2 > viewportRect.height ) + else { - dy2 = viewportRect.height; + clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR; } - damagedRect.x = dx1; - damagedRect.y = dy1; - damagedRect.width = dx2 - dx1; - damagedRect.height = dy2 - dy1; - } - - return isPartialUpdate; -} - -void RenderManager::DoRender( RenderInstruction& instruction ) -{ - Rect viewportRect; - Vector4 clearColor; - bool isPartialUpdate = false; - Dali::DamagedRect damagedRect; - Dali::DamagedRect mergedRect; - Dali::ClippingBox scissorBox; - Dali::ClippingBox intersectRect; - - if ( instruction.mIsClearColorSet ) - { - clearColor = instruction.mClearColor; - } - else - { - clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR; - } - - Rect surfaceRect = mImpl->defaultSurfaceRect; - int surfaceOrientation = mImpl->defaultSurfaceOrientation; - Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; - Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable; - Integration::PartialUpdateAvailable partialUpdateAvailable = mImpl->partialUpdateAvailable; + Rect surfaceRect = mImpl->defaultSurfaceRect; + Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; + Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable; + int surfaceOrientation = mImpl->defaultSurfaceOrientation; - Render::SurfaceFrameBuffer* surfaceFrameBuffer = nullptr; - if ( instruction.mFrameBuffer != 0 ) - { - if ( instruction.mFrameBuffer->IsSurfaceBacked() ) + if ( instruction.mFrameBuffer ) { - surfaceFrameBuffer = static_cast( instruction.mFrameBuffer ); - - if ( !surfaceFrameBuffer->IsSurfaceValid() ) + // offscreen buffer + if ( mImpl->currentContext != &mImpl->context ) { - // Skip rendering the frame buffer if the render surface becomes invalid - return; - } + // Switch to shared context for off-screen buffer + mImpl->currentContext = &mImpl->context; + + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + { + mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); + } + // Clear the current cached program when the context is switched + mImpl->programController.ClearCurrentProgram(); + } + } + else + { if ( mImpl->currentContext->IsSurfacelessContextSupported() ) { - Context* surfaceContext = surfaceFrameBuffer->GetContext(); - if ( mImpl->currentContext != surfaceContext ) + if ( mImpl->currentContext != sceneObject->GetContext() ) { // Switch the correct context if rendering to a surface - mImpl->currentContext = surfaceContext; - surfaceFrameBuffer->MakeContextCurrent(); + mImpl->currentContext = sceneObject->GetContext(); // Clear the current cached program when the context is switched mImpl->programController.ClearCurrentProgram(); } } - surfaceRect = Rect( 0, 0, static_cast( surfaceFrameBuffer->GetWidth() ), static_cast( surfaceFrameBuffer->GetHeight() ) ); + surfaceRect = Rect( 0, 0, static_cast( scene.GetSize().width ), static_cast( scene.GetSize().height ) ); } - else - { - // Switch to shared context for off-screen buffer - mImpl->currentContext = &mImpl->context; - if ( mImpl->currentContext->IsSurfacelessContextSupported() ) - { - mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); - } - } - } - - DALI_ASSERT_DEBUG( mImpl->currentContext->IsGlContextCreated() ); + DALI_ASSERT_DEBUG( mImpl->currentContext->IsGlContextCreated() ); - // 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(); - - if( instruction.mFrameBuffer ) - { - instruction.mFrameBuffer->Bind( *mImpl->currentContext ); + // 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(); - if ( !instruction.mFrameBuffer->IsSurfaceBacked() ) + if( instruction.mFrameBuffer ) { + instruction.mFrameBuffer->Bind( *mImpl->currentContext ); + // For each offscreen buffer, update the dependency list with the new texture id used by this frame buffer. - Render::TextureFrameBuffer* textureFrameBuffer = static_cast( instruction.mFrameBuffer ); - for (unsigned int i0 = 0, i1 = textureFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0) + for (unsigned int i0 = 0, i1 = instruction.mFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0) { - mImpl->textureDependencyList.PushBack( textureFrameBuffer->GetTextureId(i0) ); + mImpl->textureDependencyList.PushBack( instruction.mFrameBuffer->GetTextureId(i0) ); } } - } - else - { - mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u ); - } - - - if( surfaceFrameBuffer && - partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE ) - { - // Iterate through each render list. - if( surfaceFrameBuffer->IsPartialUpdateEnabled() ) + else { - isPartialUpdate = GetDamagedRect( surfaceRect, instruction, damagedRect ) ; + mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u ); } - if( !isPartialUpdate ) + if ( !instruction.mFrameBuffer ) { - damagedRect = surfaceRect; + mImpl->currentContext->Viewport( surfaceRect.x, + surfaceRect.y, + surfaceRect.width, + surfaceRect.height ); } - surfaceFrameBuffer->SetDamagedRect( damagedRect, mergedRect ); + // Clear the entire color, depth and stencil buffers for the default framebuffer, if required. + // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers + // 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. + GLbitfield clearMask = GL_COLOR_BUFFER_BIT; - if( mergedRect.IsEmpty() ) - { - isPartialUpdate = false; - } - else + mImpl->currentContext->ColorMask( true ); + + if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE ) { - scissorBox.x = mergedRect.x; - scissorBox.y = mergedRect.y; - scissorBox.width = mergedRect.width; - scissorBox.height = mergedRect.height; + mImpl->currentContext->DepthMask( true ); + clearMask |= GL_DEPTH_BUFFER_BIT; } - } - - if ( surfaceFrameBuffer ) - { - mImpl->currentContext->Viewport( surfaceRect.x, - surfaceRect.y, - surfaceRect.width, - surfaceRect.height ); - } - - // Clear the entire color, depth and stencil buffers for the default framebuffer, if required. - // It is important to clear all 3 buffers when they are being used, for performance on deferred renderers - // 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. - GLbitfield clearMask = GL_COLOR_BUFFER_BIT; - - mImpl->currentContext->ColorMask( true ); - - if( depthBufferAvailable == Integration::DepthBufferAvailable::TRUE ) - { - mImpl->currentContext->DepthMask( true ); - clearMask |= GL_DEPTH_BUFFER_BIT; - } - - if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE) - { - mImpl->currentContext->ClearStencil( 0 ); - mImpl->currentContext->StencilMask( 0xFF ); // 8 bit stencil mask, all 1's - clearMask |= GL_STENCIL_BUFFER_BIT; - } - if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) ) - { - if ( instruction.mFrameBuffer->IsSurfaceBacked() ) // Surface rendering + if( stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE) { - if ( instruction.mIsViewportSet ) - { - // For glViewport the lower-left corner is (0,0) - // For glViewport the lower-left corner is (0,0) - const int32_t y = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y; - viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height ); - } - else - { - viewportRect = surfaceRect; - } + mImpl->currentContext->ClearStencil( 0 ); + mImpl->currentContext->StencilMask( 0xFF ); // 8 bit stencil mask, all 1's + clearMask |= GL_STENCIL_BUFFER_BIT; } - else // Offscreen buffer rendering + + if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) ) { + // Offscreen buffer rendering if ( instruction.mIsViewportSet ) { // For glViewport the lower-left corner is (0,0) @@ -878,171 +700,194 @@ void RenderManager::DoRender( RenderInstruction& instruction ) } surfaceOrientation = 0; } - } - else // No Offscreen frame buffer rendering - { - // Check whether a viewport is specified, otherwise the full surface size is used - if ( instruction.mFrameBuffer != 0 ) + else // No Offscreen frame buffer rendering { + // Check whether a viewport is specified, otherwise the full surface size is used if ( instruction.mIsViewportSet ) { // For glViewport the lower-left corner is (0,0) - const int32_t y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y; - viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height ); + const int32_t y = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y; + viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height ); } else { - viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); + viewportRect = surfaceRect; } } - else + + if( surfaceOrientation == 90 || surfaceOrientation == 270 ) { - viewportRect = surfaceRect; + int temp = viewportRect.width; + viewportRect.width = viewportRect.height; + viewportRect.height = temp; } - } - - bool clearFullFrameRect = true; - if( instruction.mFrameBuffer != 0 ) - { - Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); - clearFullFrameRect = ( frameRect == viewportRect ); - } - else - { - clearFullFrameRect = ( surfaceRect == viewportRect ); - } - - if ( surfaceOrientation == 90 || surfaceOrientation == 270 ) - { - int temp = viewportRect.width; - viewportRect.width = viewportRect.height; - viewportRect.height = temp; - } - - mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); - - if( instruction.mIsClearColorSet ) - { - mImpl->currentContext->ClearColor( clearColor.r, - clearColor.g, - clearColor.b, - clearColor.a ); - if( !clearFullFrameRect ) + bool clearFullFrameRect = true; + if( instruction.mFrameBuffer != 0 ) { - mImpl->currentContext->SetScissorTest( true ); - if( isPartialUpdate ) - { - intersectRect = IntersectAABB( scissorBox, viewportRect ); - mImpl->currentContext->Scissor( intersectRect.x, intersectRect.y, intersectRect.width, intersectRect.height ); - } - else - { - mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height ); - } - mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR ); - mImpl->currentContext->SetScissorTest( false ); + Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); + clearFullFrameRect = ( frameRect == viewportRect ); } else { - mImpl->currentContext->SetScissorTest( false ); - mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR ); + clearFullFrameRect = ( surfaceRect == viewportRect ); } - } - // Clear the list of bound textures - mImpl->boundTextures.Clear(); - - mImpl->renderAlgorithms.ProcessRenderInstruction( - instruction, - *mImpl->currentContext, - mImpl->renderBufferIndex, - depthBufferAvailable, - stencilBufferAvailable, - mImpl->boundTextures, - surfaceOrientation, - scissorBox ); - - // Synchronise the FBO/Texture access when there are multiple contexts - if ( mImpl->currentContext->IsSurfacelessContextSupported() ) - { - // Check whether any binded texture is in the dependency list - bool textureFound = false; + mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); - if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u ) + if( instruction.mIsClearColorSet ) { - for ( auto textureId : mImpl->textureDependencyList ) - { + mImpl->currentContext->ClearColor( clearColor.r, + clearColor.g, + clearColor.b, + clearColor.a ); - textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(), - [textureId]( GLuint id ) - { - return textureId == id; - } ) != mImpl->boundTextures.End(); + if( !clearFullFrameRect ) + { + mImpl->currentContext->SetScissorTest( true ); + mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height ); + mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR ); + mImpl->currentContext->SetScissorTest( false ); + } + else + { + mImpl->currentContext->SetScissorTest( false ); + mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR ); } } - if ( textureFound ) + // Clear the list of bound textures + mImpl->boundTextures.Clear(); + + mImpl->renderAlgorithms.ProcessRenderInstruction( + instruction, + *mImpl->currentContext, + mImpl->renderBufferIndex, + depthBufferAvailable, + stencilBufferAvailable, + mImpl->boundTextures, + surfaceOrientation ); + + // Synchronise the FBO/Texture access when there are multiple contexts + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) { + // Check whether any binded texture is in the dependency list + bool textureFound = false; - if ( !instruction.mFrameBuffer || !instruction.mFrameBuffer->IsSurfaceBacked() ) + if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u ) { - // For off-screen buffer - - // Wait until all rendering calls for the currently context are executed - mImpl->glContextHelperAbstraction.WaitClient(); + for ( auto textureId : mImpl->textureDependencyList ) + { - // Clear the dependency list - mImpl->textureDependencyList.Clear(); + textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(), + [textureId]( GLuint id ) + { + return textureId == id; + } ) != mImpl->boundTextures.End(); + } } - else + + if ( textureFound ) { - // For surface-backed frame buffer + if ( instruction.mFrameBuffer ) + { + // For off-screen buffer + + // Wait until all rendering calls for the currently context are executed + mImpl->glContextHelperAbstraction.WaitClient(); - // Worker thread lambda function - auto& glContextHelperAbstraction = mImpl->glContextHelperAbstraction; - auto workerFunction = [&glContextHelperAbstraction]( int workerThread ) + // Clear the dependency list + mImpl->textureDependencyList.Clear(); + } + else { - // Switch to the shared context in the worker thread - glContextHelperAbstraction.MakeSurfacelessContextCurrent(); + // Worker thread lambda function + auto& glContextHelperAbstraction = mImpl->glContextHelperAbstraction; + auto workerFunction = [&glContextHelperAbstraction]( int workerThread ) + { + // Switch to the shared context in the worker thread + glContextHelperAbstraction.MakeSurfacelessContextCurrent(); - // Wait until all rendering calls for the shared context are executed - glContextHelperAbstraction.WaitClient(); + // Wait until all rendering calls for the shared context are executed + glContextHelperAbstraction.WaitClient(); - // Must clear the context in the worker thread - // Otherwise the shared context cannot be switched to from the render thread - glContextHelperAbstraction.MakeContextNull(); - }; + // Must clear the context in the worker thread + // Otherwise the shared context cannot be switched to from the render thread + glContextHelperAbstraction.MakeContextNull(); + }; - auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction ); - if ( future ) - { - mImpl->threadPool->Wait(); + auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction ); + if ( future ) + { + mImpl->threadPool->Wait(); - // Clear the dependency list - mImpl->textureDependencyList.Clear(); + // Clear the dependency list + mImpl->textureDependencyList.Clear(); + } } } } + + if( instruction.mRenderTracker && instruction.mFrameBuffer ) + { + // This will create a sync object every frame this render tracker + // is alive (though it should be now be created only for + // render-once render tasks) + instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction ); + instruction.mRenderTracker = nullptr; // Only create once. + } + + if ( renderToFbo ) + { + mImpl->currentContext->Flush(); + } } - if( instruction.mRenderTracker && ( instruction.mFrameBuffer != 0 ) ) + GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; + mImpl->currentContext->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +} + +void RenderManager::PostRender( bool uploadOnly ) +{ + if ( !uploadOnly ) { - // This will create a sync object every frame this render tracker - // is alive (though it should be now be created only for - // render-once render tasks) - instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction ); - instruction.mRenderTracker = NULL; // Only create once. + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + { + mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); + } + + GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; + mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); } - if ( surfaceFrameBuffer ) + //Notify RenderGeometries that rendering has finished + for ( auto&& iter : mImpl->geometryContainer ) { - surfaceFrameBuffer->PostRender(); + iter->OnRenderFinished(); } - else + + mImpl->UpdateTrackers(); + + + uint32_t count = 0u; + for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) { - mImpl->currentContext->Flush(); + count += mImpl->sceneContainer[i]->GetRenderInstructions().Count( mImpl->renderBufferIndex ); } + + const bool haveInstructions = count > 0u; + + // 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 + * should block until the update has finished. + */ + mImpl->renderBufferIndex = (0 != mImpl->renderBufferIndex) ? 0 : 1; + + DALI_PRINT_RENDER_END(); } } // namespace SceneGraph