X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Fcommon%2Frender-manager.cpp;h=24c310f35459a7048cdb092e8247476c7ac608bf;hb=79881246746f65474b24ea4fe14151ccef8df3f4;hp=b44847dcd4250e02f4e42e0cf354db294e9fc986;hpb=b7a2625f66a16845af4fc44256126f32b9a0ac7e;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 index b44847d..24c310f 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) 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. @@ -18,14 +18,20 @@ // CLASS HEADER #include +// EXTERNAL INCLUDES +#include + // INTERNAL INCLUDES #include #include #include #include +#include #include #include +#include #include +#include #include #include #include @@ -38,6 +44,7 @@ #include #include #include +#include namespace Dali { @@ -48,27 +55,12 @@ namespace Internal namespace SceneGraph { -typedef OwnerContainer< Render::Renderer* > RendererOwnerContainer; -typedef RendererOwnerContainer::Iterator RendererOwnerIter; - -typedef OwnerContainer< Render::Geometry* > GeometryOwnerContainer; -typedef GeometryOwnerContainer::Iterator GeometryOwnerIter; - -typedef OwnerContainer< Render::Sampler* > SamplerOwnerContainer; -typedef SamplerOwnerContainer::Iterator SamplerOwnerIter; - -typedef OwnerContainer< Render::Texture* > TextureOwnerContainer; -typedef TextureOwnerContainer::Iterator TextureOwnerIter; - -typedef OwnerContainer< Render::FrameBuffer* > FrameBufferOwnerContainer; -typedef FrameBufferOwnerContainer::Iterator FrameBufferOwnerIter; - -typedef OwnerContainer< Render::PropertyBuffer* > PropertyBufferOwnerContainer; -typedef PropertyBufferOwnerContainer::Iterator PropertyBufferOwnerIter; - -typedef OwnerContainer< Render::RenderTracker* > RenderTrackerContainer; -typedef RenderTrackerContainer::Iterator RenderTrackerIter; -typedef RenderTrackerContainer::ConstIterator RenderTrackerConstIter; +#if defined(DEBUG_ENABLED) +namespace +{ +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER" ); +} // unnamed namespace +#endif /** * Structure to contain internal data @@ -76,26 +68,37 @@ typedef RenderTrackerContainer::ConstIterator RenderTrackerConstIter; struct RenderManager::Impl { Impl( Integration::GlAbstraction& glAbstraction, - Integration::GlSyncAbstraction& glSyncAbstraction ) - : context( glAbstraction ), + Integration::GlSyncAbstraction& glSyncAbstraction, + Integration::GlContextHelperAbstraction& glContextHelperAbstraction, + Integration::DepthBufferAvailable depthBufferAvailableParam, + Integration::StencilBufferAvailable stencilBufferAvailableParam ) + : context( glAbstraction, &sceneContextContainer ), + currentContext( &context ), + glAbstraction( glAbstraction ), glSyncAbstraction( glSyncAbstraction ), + glContextHelperAbstraction( glContextHelperAbstraction ), renderQueue(), - instructions(), - backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ), - frameCount( 0 ), + renderAlgorithms(), + frameCount( 0u ), renderBufferIndex( SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX ), defaultSurfaceRect(), rendererContainer(), samplerContainer(), textureContainer(), frameBufferContainer(), - renderersAdded( false ), - programController( glAbstraction ) + lastFrameWasRendered( false ), + programController( glAbstraction ), + depthBufferAvailable( depthBufferAvailableParam ), + stencilBufferAvailable( stencilBufferAvailableParam ) { + // 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 ) @@ -106,63 +109,91 @@ struct RenderManager::Impl void RemoveRenderTracker( Render::RenderTracker* renderTracker ) { - DALI_ASSERT_DEBUG( renderTracker != NULL ); - for(RenderTrackerIter iter = mRenderTrackers.Begin(), end = mRenderTrackers.End(); iter != end; ++iter) + mRenderTrackers.EraseObject( renderTracker ); + } + + Context* CreateSceneContext() + { + sceneContextContainer.push_back( new Context( glAbstraction ) ); + return sceneContextContainer[ sceneContextContainer.size() - 1 ]; + } + + void DestroySceneContext( Context* sceneContext ) + { + auto iter = std::find( sceneContextContainer.begin(), sceneContextContainer.end(), sceneContext ); + if( iter != sceneContextContainer.end() ) { - if( *iter == renderTracker ) - { - mRenderTrackers.Erase( iter ); - break; - } + sceneContextContainer.erase( iter ); } } + Context* ReplaceSceneContext( Context* oldSceneContext ) + { + Context* newContext = new Context( glAbstraction ); + std::replace( sceneContextContainer.begin(), sceneContextContainer.end(), oldSceneContext, newContext ); + return newContext; + } + void UpdateTrackers() { - for(RenderTrackerIter iter = mRenderTrackers.Begin(), end = mRenderTrackers.End(); iter != end; ++iter) + for( auto&& iter : mRenderTrackers ) { - (*iter)->PollSyncObject(); + iter->PollSyncObject(); } } // the order is important for destruction, // programs are owned by context at the moment. - Context context; ///< holds the GL state - Integration::GlSyncAbstraction& glSyncAbstraction; ///< GL sync abstraction - RenderQueue renderQueue; ///< A message queue for receiving messages from the update-thread. + Context context; ///< Holds the GL state of the share resource context + Context* currentContext; ///< Holds the GL state of the current context for rendering + 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. + + std::vector< SceneGraph::Scene* > sceneContainer; ///< List of pointers to the scene graph objects of the scenes - // 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; + Render::RenderAlgorithms renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction - Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame. + uint32_t frameCount; ///< The current frame count + BufferIndex renderBufferIndex; ///< The index of the buffer to read from; this is opposite of the "update" buffer - unsigned int 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 + OwnerContainer< Render::Texture* > textureContainer; ///< List of owned textures + OwnerContainer< Render::FrameBuffer* > frameBufferContainer; ///< List of owned framebuffers + OwnerContainer< Render::PropertyBuffer* > propertyBufferContainer; ///< List of owned property buffers + OwnerContainer< Render::Geometry* > geometryContainer; ///< List of owned Geometries - RendererOwnerContainer rendererContainer; ///< List of owned renderers - SamplerOwnerContainer samplerContainer; ///< List of owned samplers - TextureOwnerContainer textureContainer; ///< List of owned textures - FrameBufferOwnerContainer frameBufferContainer; ///< List of owned framebuffers - PropertyBufferOwnerContainer propertyBufferContainer; ///< List of owned property buffers - GeometryOwnerContainer geometryContainer; ///< List of owned Geometries + bool lastFrameWasRendered; ///< Keeps track of the last frame being rendered due to having render instructions - bool renderersAdded; + OwnerContainer< Render::RenderTracker* > mRenderTrackers; ///< List of render trackers - RenderTrackerContainer mRenderTrackers; ///< List of render trackers + ProgramController programController; ///< Owner of the GL programs - 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 + std::unique_ptr threadPool; ///< The thread pool + Vector boundTextures; ///< The textures bound for rendering + Vector textureDependencyList; ///< The dependency list of binded textures }; RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction, - Integration::GlSyncAbstraction& glSyncAbstraction ) + Integration::GlSyncAbstraction& glSyncAbstraction, + Integration::GlContextHelperAbstraction& glContextHelperAbstraction, + Integration::DepthBufferAvailable depthBufferAvailable, + Integration::StencilBufferAvailable stencilBufferAvailable ) { RenderManager* manager = new RenderManager; manager->mImpl = new Impl( glAbstraction, - glSyncAbstraction ); + glSyncAbstraction, + glContextHelperAbstraction, + depthBufferAvailable, + stencilBufferAvailable ); return manager; } @@ -196,24 +227,27 @@ void RenderManager::ContextDestroyed() mImpl->programController.GlContextDestroyed(); //Inform textures - for( TextureOwnerIter iter = mImpl->textureContainer.Begin(); iter != mImpl->textureContainer.End(); ++iter ) + for( auto&& texture : mImpl->textureContainer ) { - (*iter)->GlContextDestroyed(); + texture->GlContextDestroyed(); } //Inform framebuffers - for( FrameBufferOwnerIter iter = mImpl->frameBufferContainer.Begin(); iter != mImpl->frameBufferContainer.End(); ++iter ) + for( auto&& framebuffer : mImpl->frameBufferContainer ) { - (*iter)->GlContextDestroyed(); + framebuffer->GlContextDestroyed(); } // inform renderers - RendererOwnerContainer::Iterator end = mImpl->rendererContainer.End(); - RendererOwnerContainer::Iterator iter = mImpl->rendererContainer.Begin(); - for( ; iter != end; ++iter ) + for( auto&& renderer : mImpl->rendererContainer ) { - GlResourceOwner* renderer = *iter; - renderer->GlContextDestroyed(); // Clear up vertex buffers + renderer->GlContextDestroyed(); + } + + // inform scenes + for( auto&& scene : mImpl->sceneContainer ) + { + scene->GlContextDestroyed(); } } @@ -222,93 +256,52 @@ void RenderManager::SetShaderSaver( ShaderSaver& upstream ) mImpl->programController.SetShaderSaver( upstream ); } -RenderInstructionContainer& RenderManager::GetRenderInstructionContainer() -{ - return mImpl->instructions; -} - -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::AddRenderer( Render::Renderer* renderer ) +void RenderManager::AddRenderer( OwnerPointer< Render::Renderer >& renderer ) { // Initialize the renderer as we are now in render thread renderer->Initialize( mImpl->context ); - mImpl->rendererContainer.PushBack( renderer ); - - if( !mImpl->renderersAdded ) - { - mImpl->renderersAdded = true; - } + mImpl->rendererContainer.PushBack( renderer.Release() ); } void RenderManager::RemoveRenderer( Render::Renderer* renderer ) { - DALI_ASSERT_DEBUG( NULL != renderer ); - - RendererOwnerContainer& renderers = mImpl->rendererContainer; - - // Find the renderer - for ( RendererOwnerIter iter = renderers.Begin(); iter != renderers.End(); ++iter ) - { - if ( *iter == renderer ) - { - renderers.Erase( iter ); // Renderer found; now destroy it - break; - } - } + mImpl->rendererContainer.EraseObject( renderer ); } -void RenderManager::AddSampler( Render::Sampler* sampler ) +void RenderManager::AddSampler( OwnerPointer< Render::Sampler >& sampler ) { - mImpl->samplerContainer.PushBack( sampler ); + mImpl->samplerContainer.PushBack( sampler.Release() ); } void RenderManager::RemoveSampler( Render::Sampler* sampler ) { - DALI_ASSERT_DEBUG( NULL != sampler ); - - SamplerOwnerContainer& samplers = mImpl->samplerContainer; - - // Find the sampler - for ( SamplerOwnerIter iter = samplers.Begin(); iter != samplers.End(); ++iter ) - { - if ( *iter == sampler ) - { - samplers.Erase( iter ); // Sampler found; now destroy it - break; - } - } + mImpl->samplerContainer.EraseObject( sampler ); } -void RenderManager::AddTexture( Render::Texture* texture ) +void RenderManager::AddTexture( OwnerPointer< Render::Texture >& texture ) { - mImpl->textureContainer.PushBack( texture ); - texture->Initialize(mImpl->context); + texture->Initialize( mImpl->context ); + mImpl->textureContainer.PushBack( texture.Release() ); } void RenderManager::RemoveTexture( Render::Texture* texture ) { DALI_ASSERT_DEBUG( NULL != texture ); - TextureOwnerContainer& textures = mImpl->textureContainer; - - // Find the texture - for ( TextureOwnerIter iter = textures.Begin(); iter != textures.End(); ++iter ) + // Find the texture, use reference to pointer so we can do the erase safely + for ( auto&& iter : mImpl->textureContainer ) { - if ( *iter == texture ) + if ( iter == texture ) { texture->Destroy( mImpl->context ); - textures.Erase( iter ); // Texture found; now destroy it - break; + mImpl->textureContainer.Erase( &iter ); // Texture found; now destroy it + return; } } } @@ -323,119 +316,115 @@ 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 ); + frameBufferPtr->Initialize( mImpl->context ); } void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer ) { DALI_ASSERT_DEBUG( NULL != frameBuffer ); - FrameBufferOwnerContainer& framebuffers = mImpl->frameBufferContainer; - - // Find the sampler - for ( FrameBufferOwnerIter iter = framebuffers.Begin(); iter != framebuffers.End(); ++iter ) + // Find the sampler, use reference so we can safely do the erase + for ( auto&& iter : mImpl->frameBufferContainer ) { - if ( *iter == frameBuffer ) + if ( iter == frameBuffer ) { frameBuffer->Destroy( mImpl->context ); - framebuffers.Erase( iter ); // frameBuffer found; now destroy it + 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, unsigned int mipmapLevel, unsigned int layer ) +void RenderManager::UninitializeScene( SceneGraph::Scene* scene ) { - frameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer ); + mImpl->DestroySceneContext( scene->GetContext() ); + + auto iter = std::find( mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene ); + if( iter != mImpl->sceneContainer.end() ) + { + mImpl->sceneContainer.erase( iter ); + } } -void RenderManager::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer ) +void RenderManager::SurfaceReplaced( SceneGraph::Scene* scene ) { - mImpl->propertyBufferContainer.PushBack( propertyBuffer ); + Context* newContext = mImpl->ReplaceSceneContext( scene->GetContext() ); + scene->Initialize( *newContext ); } -void RenderManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer ) +void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer ) { - DALI_ASSERT_DEBUG( NULL != propertyBuffer ); + frameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer ); +} - PropertyBufferOwnerContainer& propertyBuffers = mImpl->propertyBufferContainer; +void RenderManager::AddPropertyBuffer( OwnerPointer< Render::PropertyBuffer >& propertyBuffer ) +{ + mImpl->propertyBufferContainer.PushBack( propertyBuffer.Release() ); +} - // Find the sampler - for ( PropertyBufferOwnerIter iter = propertyBuffers.Begin(); iter != propertyBuffers.End(); ++iter ) - { - if ( *iter == propertyBuffer ) - { - propertyBuffers.Erase( iter ); // Property buffer found; now destroy it - break; - } - } +void RenderManager::RemovePropertyBuffer( Render::PropertyBuffer* propertyBuffer ) +{ + mImpl->propertyBufferContainer.EraseObject( propertyBuffer ); } -void RenderManager::SetPropertyBufferFormat(Render::PropertyBuffer* propertyBuffer, Render::PropertyBuffer::Format* format ) +void RenderManager::SetPropertyBufferFormat( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Render::PropertyBuffer::Format>& format ) { - propertyBuffer->SetFormat( format ); + propertyBuffer->SetFormat( format.Release() ); } -void RenderManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, Dali::Vector* data, size_t size ) +void RenderManager::SetPropertyBufferData( Render::PropertyBuffer* propertyBuffer, OwnerPointer< Vector >& data, uint32_t size ) { - propertyBuffer->SetData( data, 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 ); } -void RenderManager::AddGeometry( Render::Geometry* geometry ) +void RenderManager::AddGeometry( OwnerPointer< Render::Geometry >& geometry ) { - mImpl->geometryContainer.PushBack( geometry ); + mImpl->geometryContainer.PushBack( geometry.Release() ); } void RenderManager::RemoveGeometry( Render::Geometry* geometry ) { - DALI_ASSERT_DEBUG( NULL != geometry ); - - GeometryOwnerContainer& geometries = mImpl->geometryContainer; - - // Find the geometry - for ( GeometryOwnerIter iter = geometries.Begin(); iter != geometries.End(); ++iter ) - { - if ( *iter == geometry ) - { - geometries.Erase( iter ); // Geometry found; now destroy it - break; - } - } + mImpl->geometryContainer.EraseObject( geometry ); } -void RenderManager::AddVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer ) +void RenderManager::AttachVertexBuffer( Render::Geometry* geometry, Render::PropertyBuffer* propertyBuffer ) { DALI_ASSERT_DEBUG( NULL != geometry ); - GeometryOwnerContainer& geometries = mImpl->geometryContainer; - - // Find the renderer - for ( GeometryOwnerIter iter = geometries.Begin(); iter != geometries.End(); ++iter ) + // Find the geometry + for ( auto&& iter : mImpl->geometryContainer ) { - if ( *iter == geometry ) + if ( iter == geometry ) { - (*iter)->AddPropertyBuffer( propertyBuffer ); + iter->AddPropertyBuffer( propertyBuffer ); break; } } @@ -445,20 +434,18 @@ void RenderManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::Prop { DALI_ASSERT_DEBUG( NULL != geometry ); - GeometryOwnerContainer& geometries = mImpl->geometryContainer; - - // Find the renderer - for ( GeometryOwnerIter iter = geometries.Begin(); iter != geometries.End(); ++iter ) + // Find the geometry + for ( auto&& iter : mImpl->geometryContainer ) { - if ( *iter == geometry ) + if ( iter == geometry ) { - (*iter)->RemovePropertyBuffer( propertyBuffer ); + iter->RemovePropertyBuffer( propertyBuffer ); break; } } } -void RenderManager::SetGeometryType( Render::Geometry* geometry, unsigned int geometryType ) +void RenderManager::SetGeometryType( Render::Geometry* geometry, uint32_t geometryType ) { geometry->SetType( Render::Geometry::Type(geometryType) ); } @@ -478,7 +465,7 @@ ProgramCache* RenderManager::GetProgramCache() return &(mImpl->programController); } -bool RenderManager::Render( Integration::RenderStatus& status ) +void RenderManager::PreRender( Integration::RenderStatus& status, bool forceClear, bool uploadOnly ) { DALI_PRINT_RENDER_START( mImpl->renderBufferIndex ); @@ -486,145 +473,403 @@ bool 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 ); - // 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 ) + uint32_t count = 0u; + for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) { - RenderInstruction& instruction = mImpl->instructions.At( mImpl->renderBufferIndex, i ); - - DoRender( instruction ); + count += mImpl->sceneContainer[i]->GetRenderInstructions().Count( mImpl->renderBufferIndex ); } - GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; - mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); - mImpl->UpdateTrackers(); + const bool haveInstructions = count > 0u; - //Notify RenderGeometries that rendering has finished - for ( GeometryOwnerIter iter = mImpl->geometryContainer.Begin(); iter != mImpl->geometryContainer.End(); ++iter ) + 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 || forceClear ) { - (*iter)->OnRenderFinished(); - } + DALI_LOG_INFO( gLogFilter, Debug::General, "Render: Processing\n" ); - /** - * 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; + if ( !uploadOnly ) + { + // Mark that we will require a post-render step to be performed (includes swap-buffers). + status.SetNeedsPostRender( true ); + } - DALI_PRINT_RENDER_END(); + // Switch to the shared context + if ( mImpl->currentContext != &mImpl->context ) + { + mImpl->currentContext = &mImpl->context; + + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + { + mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); + } + + // Clear the current cached program when the context is switched + mImpl->programController.ClearCurrentProgram(); + } - return false; + // Upload the geometries + for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) + { + RenderInstructionContainer& instructions = mImpl->sceneContainer[i]->GetRenderInstructions(); + for ( uint32_t j = 0; j < instructions.Count( mImpl->renderBufferIndex ); ++j ) + { + RenderInstruction& instruction = instructions.At( mImpl->renderBufferIndex, j ); + + 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 ); + } + } + } + } + } + } + } + } } -void RenderManager::DoRender( RenderInstruction& instruction ) + +void RenderManager::RenderScene( Integration::Scene& scene, bool renderToFbo ) { - Rect viewportRect; - Vector4 clearColor; + Internal::Scene& sceneInternal = GetImplementation( scene ); + SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); - if ( instruction.mIsClearColorSet ) - { - clearColor = instruction.mClearColor; - } - else - { - clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR; - } + uint32_t count = sceneObject->GetRenderInstructions().Count( mImpl->renderBufferIndex ); - if( instruction.mFrameBuffer != 0 ) + for( uint32_t i = 0; i < count; ++i ) { - instruction.mFrameBuffer->Bind( mImpl->context ); - if ( instruction.mIsViewportSet ) + RenderInstruction& instruction = sceneObject->GetRenderInstructions().At( mImpl->renderBufferIndex, i ); + + if ( ( renderToFbo && !instruction.mFrameBuffer ) || ( !renderToFbo && instruction.mFrameBuffer ) ) + { + continue; // skip + } + + Rect viewportRect; + Vector4 clearColor; + + if ( instruction.mIsClearColorSet ) { - // 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 ); + clearColor = instruction.mClearColor; } else { - viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); + clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR; } - } - else // !(instruction.mOffscreenTexture) - { - // switch rendering to adaptor provided (default) buffer - mImpl->context.BindFramebuffer( GL_FRAMEBUFFER, 0 ); - // Check whether a viewport is specified, otherwise the full surface size is used - if ( instruction.mIsViewportSet ) + Rect surfaceRect = mImpl->defaultSurfaceRect; + Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; + Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable; + + if ( instruction.mFrameBuffer ) { - // 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 ); + // offscreen buffer + if ( mImpl->currentContext != &mImpl->context ) + { + // 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 { - viewportRect = mImpl->defaultSurfaceRect; + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + { + if ( mImpl->currentContext != sceneObject->GetContext() ) + { + // Switch the correct context if rendering to a surface + mImpl->currentContext = sceneObject->GetContext(); + + // Clear the current cached program when the context is switched + mImpl->programController.ClearCurrentProgram(); + } + } + + surfaceRect = Rect( 0, 0, static_cast( scene.GetSize().width ), static_cast( scene.GetSize().height ) ); + } + + 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 ); + + // For each offscreen buffer, update the dependency list with the new texture id used by this frame buffer. + for (unsigned int i0 = 0, i1 = instruction.mFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0) + { + mImpl->textureDependencyList.PushBack( instruction.mFrameBuffer->GetTextureId(i0) ); + } + } + else + { + mImpl->currentContext->BindFramebuffer( GL_FRAMEBUFFER, 0u ); + } + + if ( !instruction.mFrameBuffer ) + { + 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 ) ) + { + // 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() ); + } + } + 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 = ( surfaceRect.height - instruction.mViewport.height ) - instruction.mViewport.y; + viewportRect.Set( instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height ); + } + else + { + viewportRect = surfaceRect; + } + } + + bool clearFullFrameRect = true; + if( instruction.mFrameBuffer != 0 ) + { + Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); + clearFullFrameRect = ( frameRect == viewportRect ); + } + else + { + clearFullFrameRect = ( surfaceRect == viewportRect ); + } + + 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 ) + { + 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 ); + } + } + + // Clear the list of bound textures + mImpl->boundTextures.Clear(); + + mImpl->renderAlgorithms.ProcessRenderInstruction( + instruction, + *mImpl->currentContext, + mImpl->renderBufferIndex, + depthBufferAvailable, + stencilBufferAvailable, + mImpl->boundTextures ); + + // 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 ( 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 ) + { + // 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 + { + // 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 ) + { + // 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(); } } - mImpl->context.Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); + GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; + mImpl->currentContext->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +} - if ( instruction.mIsClearColorSet ) +void RenderManager::PostRender( bool uploadOnly ) +{ + if ( !uploadOnly ) { - mImpl->context.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 ); + if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + { + mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); + } + + GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; + mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); } - Render::ProcessRenderInstruction( instruction, - mImpl->context, - mImpl->renderBufferIndex ); + //Notify RenderGeometries that rendering has finished + for ( auto&& iter : mImpl->geometryContainer ) + { + iter->OnRenderFinished(); + } - if( instruction.mRenderTracker && ( instruction.mFrameBuffer != NULL ) ) + mImpl->UpdateTrackers(); + + + uint32_t count = 0u; + for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) { - // 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. + 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