X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Fcommon%2Frender-manager.cpp;h=630f870e3da30da25835a337176ba43431992b64;hb=55827866fcb8c7ee47581ac4335a3390472090e8;hp=f19c956a9d1f9b3e5c7d020025d3c4b5fc5625ef;hpb=6d1cfb307eea9fcae35878fa977d43feffd3f84c;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 100644 new mode 100755 index f19c956..630f870 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2019 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. @@ -18,13 +18,18 @@ // CLASS HEADER #include +// EXTERNAL INCLUDES +#include + // INTERNAL INCLUDES #include #include #include #include +#include #include #include +#include #include #include #include @@ -34,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -48,20 +55,37 @@ namespace Internal namespace SceneGraph { +#if defined(DEBUG_ENABLED) +namespace +{ +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER" ); +} // unnamed namespace +#endif + +const int partialUpdateMargin = 4u; +const float partialUpdateRatio = 0.8f; // If the partial update area exceeds 80%, change to full update. + /** * Structure to contain internal data */ struct RenderManager::Impl { Impl( Integration::GlAbstraction& glAbstraction, - Integration::GlSyncAbstraction& glSyncAbstraction ) - : context( glAbstraction ), + Integration::GlSyncAbstraction& glSyncAbstraction, + Integration::GlContextHelperAbstraction& glContextHelperAbstraction, + Integration::DepthBufferAvailable depthBufferAvailableParam, + Integration::StencilBufferAvailable stencilBufferAvailableParam, + Integration::PartialUpdateAvailable partialUpdateAvailableParam ) + : context( glAbstraction, &surfaceContextContainer ), + currentContext( &context ), + glAbstraction( glAbstraction ), glSyncAbstraction( glSyncAbstraction ), + glContextHelperAbstraction( glContextHelperAbstraction ), renderQueue(), instructions(), renderAlgorithms(), backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ), - frameCount( 0 ), + frameCount( 0u ), renderBufferIndex( SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX ), defaultSurfaceRect(), rendererContainer(), @@ -69,12 +93,20 @@ struct RenderManager::Impl textureContainer(), frameBufferContainer(), lastFrameWasRendered( false ), - programController( glAbstraction ) + 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 ). + threadPool = std::unique_ptr( new Dali::ThreadPool() ); + threadPool->Initialize( 1u ); } ~Impl() { + threadPool.reset( nullptr ); // reset now to maintain correct destruction order } void AddRenderTracker( Render::RenderTracker* renderTracker ) @@ -88,6 +120,17 @@ struct RenderManager::Impl mRenderTrackers.EraseObject( renderTracker ); } + Context* CreateSurfaceContext() + { + surfaceContextContainer.PushBack( new Context( glAbstraction ) ); + return surfaceContextContainer[ surfaceContextContainer.Count() - 1 ]; + } + + void DestroySurfaceContext( Context* surfaceContext ) + { + surfaceContextContainer.EraseObject( surfaceContext ); + } + void UpdateTrackers() { for( auto&& iter : mRenderTrackers ) @@ -98,8 +141,12 @@ struct RenderManager::Impl // the order is important for destruction, // programs are owned by context at the moment. - Context context; ///< holds the GL state + 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 + 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() @@ -109,10 +156,10 @@ struct RenderManager::Impl Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame. - unsigned int frameCount; ///< The current frame count + uint32_t frameCount; ///< The current frame count BufferIndex renderBufferIndex; ///< The index of the buffer to read from; this is opposite of the "update" buffer - Rect defaultSurfaceRect; ///< Rectangle for the default surface we are rendering to + Rect defaultSurfaceRect; ///< Rectangle for the default surface we are rendering to OwnerContainer< Render::Renderer* > rendererContainer; ///< List of owned renderers OwnerContainer< Render::Sampler* > samplerContainer; ///< List of owned samplers @@ -127,14 +174,31 @@ struct RenderManager::Impl ProgramController programController; ///< Owner of the GL programs + 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 + Vector textureDependencyList; ///< The dependency list of binded textures + int defaultSurfaceOrientation; ///< defaultSurfaceOrientation for the default surface we are rendering to + }; RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction, - Integration::GlSyncAbstraction& glSyncAbstraction ) + Integration::GlSyncAbstraction& glSyncAbstraction, + Integration::GlContextHelperAbstraction& glContextHelperAbstraction, + Integration::DepthBufferAvailable depthBufferAvailable, + Integration::StencilBufferAvailable stencilBufferAvailable, + Integration::PartialUpdateAvailable partialUpdateAvailable ) { RenderManager* manager = new RenderManager; manager->mImpl = new Impl( glAbstraction, - glSyncAbstraction ); + glSyncAbstraction, + glContextHelperAbstraction, + depthBufferAvailable, + stencilBufferAvailable, + partialUpdateAvailable ); return manager; } @@ -201,11 +265,16 @@ void RenderManager::SetBackgroundColor( const Vector4& color ) mImpl->backgroundColor = color; } -void RenderManager::SetDefaultSurfaceRect(const Rect& rect) +void RenderManager::SetDefaultSurfaceRect(const Rect& rect) { mImpl->defaultSurfaceRect = rect; } +void RenderManager::SetDefaultSurfaceOrientation( int orientation ) +{ + mImpl->defaultSurfaceOrientation = orientation; +} + void RenderManager::AddRenderer( OwnerPointer< Render::Renderer >& renderer ) { // Initialize the renderer as we are now in render thread @@ -261,23 +330,31 @@ void RenderManager::GenerateMipmaps( Render::Texture* texture ) texture->GenerateMipmaps( mImpl->context ); } -void RenderManager::SetFilterMode( Render::Sampler* sampler, unsigned int minFilterMode, unsigned int magFilterMode ) +void RenderManager::SetFilterMode( Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode ) { sampler->mMinificationFilter = static_cast(minFilterMode); sampler->mMagnificationFilter = static_cast(magFilterMode ); } -void RenderManager::SetWrapMode( Render::Sampler* sampler, unsigned int rWrapMode, unsigned int sWrapMode, unsigned int tWrapMode ) +void RenderManager::SetWrapMode( Render::Sampler* sampler, uint32_t rWrapMode, uint32_t sWrapMode, uint32_t tWrapMode ) { sampler->mRWrapMode = static_cast(rWrapMode); sampler->mSWrapMode = static_cast(sWrapMode); sampler->mTWrapMode = static_cast(tWrapMode); } -void RenderManager::AddFrameBuffer( Render::FrameBuffer* frameBuffer ) +void RenderManager::AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer ) { - mImpl->frameBufferContainer.PushBack( frameBuffer ); - frameBuffer->Initialize(mImpl->context); + Render::FrameBuffer* frameBufferPtr = frameBuffer.Release(); + mImpl->frameBufferContainer.PushBack( frameBufferPtr ); + if ( frameBufferPtr->IsSurfaceBacked() ) + { + frameBufferPtr->Initialize( *mImpl->CreateSurfaceContext() ); + } + else + { + frameBufferPtr->Initialize( mImpl->context ); + } } void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer ) @@ -290,15 +367,27 @@ 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::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, unsigned int mipmapLevel, unsigned int layer ) +void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer ) { - frameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer ); + if ( !frameBuffer->IsSurfaceBacked() ) + { + auto textureFrameBuffer = static_cast( frameBuffer ); + textureFrameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer ); + } } void RenderManager::AddPropertyBuffer( OwnerPointer< Render::PropertyBuffer >& propertyBuffer ) @@ -316,12 +405,12 @@ void RenderManager::SetPropertyBufferFormat( Render::PropertyBuffer* propertyBuf propertyBuffer->SetFormat( format.Release() ); } -void RenderManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Vector >& data, size_t size ) +void RenderManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Vector >& data, uint32_t size ) { propertyBuffer->SetData( data.Release(), size ); } -void RenderManager::SetIndexBuffer( Render::Geometry* geometry, Dali::Vector& indices ) +void RenderManager::SetIndexBuffer( Render::Geometry* geometry, Dali::Vector& indices ) { geometry->SetIndexBuffer( indices ); } @@ -366,7 +455,7 @@ void RenderManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::Prop } } -void RenderManager::SetGeometryType( Render::Geometry* geometry, unsigned int geometryType ) +void RenderManager::SetGeometryType( Render::Geometry* geometry, uint32_t geometryType ) { geometry->SetType( Render::Geometry::Type(geometryType) ); } @@ -386,7 +475,7 @@ ProgramCache* RenderManager::GetProgramCache() return &(mImpl->programController); } -void RenderManager::Render( Integration::RenderStatus& status ) +void RenderManager::Render( Integration::RenderStatus& status, bool forceClear ) { DALI_PRINT_RENDER_START( mImpl->renderBufferIndex ); @@ -394,60 +483,96 @@ void RenderManager::Render( Integration::RenderStatus& status ) DALI_ASSERT_DEBUG( mImpl->context.IsGlContextCreated() ); // Increment the frame count at the beginning of each frame - ++(mImpl->frameCount); + ++mImpl->frameCount; // Process messages queued during previous update mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex ); - const size_t count = mImpl->instructions.Count( mImpl->renderBufferIndex ); + const uint32_t count = mImpl->instructions.Count( mImpl->renderBufferIndex ); const bool haveInstructions = count > 0u; + DALI_LOG_INFO( gLogFilter, Debug::General, + "Render: haveInstructions(%s) || mImpl->lastFrameWasRendered(%s) || forceClear(%s)\n", + haveInstructions ? "true" : "false", + mImpl->lastFrameWasRendered ? "true" : "false", + forceClear ? "true" : "false" ); + // Only render if we have instructions to render, or the last frame was rendered (and therefore a clear is required). - if( haveInstructions || mImpl->lastFrameWasRendered ) + if( haveInstructions || mImpl->lastFrameWasRendered || forceClear ) { + DALI_LOG_INFO( gLogFilter, Debug::General, "Render: Processing\n" ); + // Mark that we will require a post-render step to be performed (includes swap-buffers). status.SetNeedsPostRender( true ); - // 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 ); + // Switch to the shared context + if ( mImpl->currentContext != &mImpl->context ) + { + mImpl->currentContext = &mImpl->context; - mImpl->context.ClearColor( mImpl->backgroundColor.r, - mImpl->backgroundColor.g, - mImpl->backgroundColor.b, - mImpl->backgroundColor.a ); + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + { + mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); + } - mImpl->context.ClearStencil( 0 ); + // Clear the current cached program when the context is switched + mImpl->programController.ClearCurrentProgram(); + } - // 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 ); + // Upload the geometries + for( uint32_t i = 0; i < count; ++i ) + { + RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i ); - // 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(); + const Matrix* viewMatrix = instruction.GetViewMatrix( mImpl->renderBufferIndex ); + const Matrix* projectionMatrix = instruction.GetProjectionMatrix( mImpl->renderBufferIndex ); + + DALI_ASSERT_DEBUG( viewMatrix ); + DALI_ASSERT_DEBUG( projectionMatrix ); + + if( viewMatrix && projectionMatrix ) + { + const RenderListContainer::SizeType renderListCount = instruction.RenderListCount(); + + // Iterate through each render list. + for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index ) + { + const RenderList* renderList = instruction.GetRenderList( index ); + + if( renderList && !renderList->IsEmpty() ) + { + const std::size_t itemCount = renderList->Count(); + for( uint32_t itemIndex = 0u; itemIndex < itemCount; ++itemIndex ) + { + const RenderItem& item = renderList->GetItem( itemIndex ); + if( DALI_LIKELY( item.mRenderer ) ) + { + item.mRenderer->Upload( *mImpl->currentContext ); + } + } + } + } + } + } - for( size_t i = 0; i < count; ++i ) + 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); - - mImpl->UpdateTrackers(); + for ( auto&& context : mImpl->surfaceContextContainer ) + { + context->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); + } //Notify RenderGeometries that rendering has finished for ( auto&& iter : mImpl->geometryContainer ) @@ -455,6 +580,12 @@ void RenderManager::Render( Integration::RenderStatus& status ) 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; @@ -469,10 +600,69 @@ void RenderManager::Render( Integration::RenderStatus& status ) 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; + + const RenderListContainer::SizeType renderListCount = instruction.RenderListCount(); + // Iterate through each render list. + + for( RenderListContainer::SizeType index = 0; index < renderListCount; ++index ) + { + const RenderList* renderList = instruction.GetRenderList( index ); + + if( renderList && !renderList->IsEmpty() && renderList->IsPartialUpdateEnabled() ) + { + 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; + } + } + } + } + } + + if( isPartialUpdate ) + { + damagedRect.x = dx1 - partialUpdateMargin; + damagedRect.y = dy1 - partialUpdateMargin; + damagedRect.width = dx2 - dx1 + ( 2 * partialUpdateMargin ); + damagedRect.height = dy2 - dy1 + ( 2 * partialUpdateMargin ); + } + + return isPartialUpdate; +} + void RenderManager::DoRender( RenderInstruction& instruction ) { - Rect viewportRect; + Rect viewportRect; Vector4 clearColor; + bool isPartialUpdate = false; + Rect damagedRect; + Rect mergedRect; + Dali::ClippingBox scissorBox; if ( instruction.mIsClearColorSet ) { @@ -483,58 +673,320 @@ void RenderManager::DoRender( RenderInstruction& instruction ) clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR; } - if( instruction.mFrameBuffer != 0 ) + Rect surfaceRect = mImpl->defaultSurfaceRect; + int surfaceOrientation = mImpl->defaultSurfaceOrientation; + Vector4 backgroundColor = mImpl->backgroundColor; + Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; + Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable; + Integration::PartialUpdateAvailable partialUpdateAvailable = mImpl->partialUpdateAvailable; + + Render::SurfaceFrameBuffer* surfaceFrameBuffer = nullptr; + if ( instruction.mFrameBuffer != 0 ) + { + if ( instruction.mFrameBuffer->IsSurfaceBacked() ) + { + surfaceFrameBuffer = static_cast( instruction.mFrameBuffer ); + + if ( !surfaceFrameBuffer->IsSurfaceValid() ) + { + // Skip rendering the frame buffer if the render surface becomes invalid + return; + } + + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + { + Context* surfaceContext = surfaceFrameBuffer->GetContext(); + if ( mImpl->currentContext != surfaceContext ) + { + // Switch the correct context if rendering to a surface + mImpl->currentContext = surfaceContext; + surfaceFrameBuffer->MakeContextCurrent(); + + // 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() ) ); + backgroundColor = surfaceFrameBuffer->GetBackgroundColor(); + } + 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() ); + + // 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 ); + + if ( !instruction.mFrameBuffer->IsSurfaceBacked() ) + { + // 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 ); + mImpl->textureDependencyList.PushBack( textureFrameBuffer->GetTextureId() ); + } + } + else + { + mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u ); + } + + + if( surfaceFrameBuffer && + partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE ) { - instruction.mFrameBuffer->Bind( mImpl->context ); - if ( instruction.mIsViewportSet ) + const RenderListContainer::SizeType renderListCount = instruction.RenderListCount(); + // Iterate through each render list. + if( surfaceFrameBuffer->IsPartialUpdateEnabled() ) + { + isPartialUpdate = GetDamagedRect( surfaceRect, instruction, damagedRect ) ; + } + + if( !isPartialUpdate ) + { + damagedRect = surfaceRect; + } + + mergedRect = surfaceFrameBuffer->SetDamagedRect( damagedRect ); + + if( mergedRect.IsEmpty() ) { - // For glViewport the lower-left corner is (0,0) - const int y = ( instruction.mFrameBuffer->GetHeight() - instruction.mViewport.height ) - instruction.mViewport.y; - viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height ); + isPartialUpdate = false; } else { - viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); + scissorBox.x = mergedRect.x; + scissorBox.y = mergedRect.y; + scissorBox.width = mergedRect.width; + scissorBox.height = mergedRect.height; } } - else // !(instruction.mOffscreenTexture) + + if ( surfaceFrameBuffer ) { - // switch rendering to adaptor provided (default) buffer - mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 ); + mImpl->currentContext->Viewport( surfaceRect.x, + surfaceRect.y, + surfaceRect.width, + surfaceRect.height ); + + + mImpl->currentContext->ClearColor( backgroundColor.r, + backgroundColor.g, + backgroundColor.b, + backgroundColor.a ); + } + + // 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. + mImpl->currentContext->SetScissorTest( false ); + + if( isPartialUpdate ) + { + mImpl->currentContext->SetScissorTest( true ); + mImpl->currentContext->Scissor( scissorBox.x, scissorBox.y, scissorBox.width, scissorBox.height ); + } + + 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; + } + + mImpl->currentContext->Clear( clearMask, Context::FORCE_CLEAR ); + if( isPartialUpdate ) + { + mImpl->currentContext->SetScissorTest( false ); + } + + + if( !instruction.mIgnoreRenderToFbo && ( instruction.mFrameBuffer != 0 ) ) + { + if ( instruction.mFrameBuffer->IsSurfaceBacked() ) // Surface rendering + { + 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; + } + } + else // Offscreen buffer rendering + { + 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 ); + } + else + { + viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); + } + surfaceOrientation = 0; + } + } + else // No Offscreen frame buffer rendering + { // Check whether a viewport is specified, otherwise the full surface size is used - if ( instruction.mIsViewportSet ) + if ( instruction.mFrameBuffer != 0 ) { - // For glViewport the lower-left corner is (0,0) - const int y = ( mImpl->defaultSurfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y; - viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height ); + 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 ); + } + else + { + viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); + } } else { - viewportRect = mImpl->defaultSurfaceRect; + viewportRect = surfaceRect; } } - mImpl->context.Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); + 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->context.ClearColor( clearColor.r, - clearColor.g, - clearColor.b, - clearColor.a ); + mImpl->currentContext->ClearColor( clearColor.r, + clearColor.g, + clearColor.b, + clearColor.a ); // Clear the viewport area only - mImpl->context.SetScissorTest( true ); - mImpl->context.Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height ); - mImpl->context.ColorMask( true ); - mImpl->context.Clear( GL_COLOR_BUFFER_BIT , Context::CHECK_CACHED_VALUES ); - mImpl->context.SetScissorTest( false ); + mImpl->currentContext->SetScissorTest( true ); + if( isPartialUpdate ) + { + mImpl->currentContext->Scissor( scissorBox.x, scissorBox.y, scissorBox.width, scissorBox.height ); + } + else + { + mImpl->currentContext->Scissor( viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height ); + } + mImpl->currentContext->ColorMask( true ); + mImpl->currentContext->Clear( GL_COLOR_BUFFER_BIT , Context::CHECK_CACHED_VALUES ); + mImpl->currentContext->SetScissorTest( false ); } - mImpl->renderAlgorithms.ProcessRenderInstruction( instruction, mImpl->context, mImpl->renderBufferIndex ); + // 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; - if( instruction.mRenderTracker && ( instruction.mFrameBuffer != NULL ) ) + if ( mImpl->boundTextures.Count() > 0u && mImpl->textureDependencyList.Count() > 0u ) + { + for ( auto textureId : mImpl->textureDependencyList ) + { + + textureFound = std::find_if( mImpl->boundTextures.Begin(), mImpl->boundTextures.End(), + [textureId]( GLuint id ) + { + return textureId == id; + } ) != mImpl->boundTextures.End(); + } + } + + if ( textureFound ) + { + + if ( !instruction.mFrameBuffer || !instruction.mFrameBuffer->IsSurfaceBacked() ) + { + // For off-screen buffer + + // Wait until all rendering calls for the currently context are executed + mImpl->glContextHelperAbstraction.WaitClient(); + + // Clear the dependency list + mImpl->textureDependencyList.Clear(); + } + else + { + // For surface-backed frame buffer + + // 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(); + + // 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(); + + // Clear the dependency list + mImpl->textureDependencyList.Clear(); + } + } + } + } + + if( instruction.mRenderTracker && ( instruction.mFrameBuffer != 0 ) ) { // This will create a sync object every frame this render tracker // is alive (though it should be now be created only for @@ -542,6 +994,15 @@ void RenderManager::DoRender( RenderInstruction& instruction ) instruction.mRenderTracker->CreateSyncObject( mImpl->glSyncAbstraction ); instruction.mRenderTracker = NULL; // Only create once. } + + if ( surfaceFrameBuffer ) + { + surfaceFrameBuffer->PostRender(); + } + else + { + mImpl->currentContext->Flush(); + } } } // namespace SceneGraph