X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Fcommon%2Frender-manager.cpp;h=3a1466d1a958070e472fcd97d2bb3b488d81574d;hb=refs%2Fchanges%2F80%2F286080%2F11;hp=54c31af37ab8c21e4760c5f74848d134efa9eda5;hpb=797352aeff6cea19a77cccd39caeff46584a51e2;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 54c31af..3a1466d --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * Copyright (c) 2023 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. @@ -24,176 +24,175 @@ // INTERNAL INCLUDES #include #include -#include + #include + +#include +#include +#include + +#include + #include #include +#include #include #include +#include +#include +#include +#include +#include +#include #include +#include + namespace Dali { - namespace Internal { - namespace SceneGraph { - #if defined(DEBUG_ENABLED) namespace { -Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER" ); +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_RENDER_MANAGER"); } // unnamed namespace #endif -/** - * Structure to contain internal data - */ -struct RenderManager::Impl +namespace +{ +inline Graphics::Rect2D RecalculateScissorArea(Graphics::Rect2D scissorArea, int orientation, Rect viewportRect) { - Impl( Integration::GlAbstraction& glAbstraction, - Integration::GlSyncAbstraction& glSyncAbstraction, - Integration::GlContextHelperAbstraction& glContextHelperAbstraction, - Integration::DepthBufferAvailable depthBufferAvailableParam, - Integration::StencilBufferAvailable stencilBufferAvailableParam, - Integration::PartialUpdateAvailable partialUpdateAvailableParam ) - : context( glAbstraction, &sceneContextContainer ), - currentContext( &context ), - glAbstraction( glAbstraction ), - glSyncAbstraction( glSyncAbstraction ), - glContextHelperAbstraction( glContextHelperAbstraction ), - renderQueue(), - renderAlgorithms(), - frameCount( 0u ), - renderBufferIndex( SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX ), - defaultSurfaceRect(), - rendererContainer(), - samplerContainer(), - textureContainer(), - frameBufferContainer(), - lastFrameWasRendered( false ), - programController( glAbstraction ), - depthBufferAvailable( depthBufferAvailableParam ), - stencilBufferAvailable( stencilBufferAvailableParam ), - partialUpdateAvailable( partialUpdateAvailableParam ), - defaultSurfaceOrientation(0) + Graphics::Rect2D newScissorArea; + + if(orientation == 90) { - // 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 ); + newScissorArea.x = viewportRect.height - (scissorArea.y + scissorArea.height); + newScissorArea.y = scissorArea.x; + newScissorArea.width = scissorArea.height; + newScissorArea.height = scissorArea.width; } - - ~Impl() + else if(orientation == 180) { - threadPool.reset( nullptr ); // reset now to maintain correct destruction order + newScissorArea.x = viewportRect.width - (scissorArea.x + scissorArea.width); + newScissorArea.y = viewportRect.height - (scissorArea.y + scissorArea.height); + newScissorArea.width = scissorArea.width; + newScissorArea.height = scissorArea.height; } - - void AddRenderTracker( Render::RenderTracker* renderTracker ) + else if(orientation == 270) { - DALI_ASSERT_DEBUG( renderTracker != NULL ); - mRenderTrackers.PushBack( renderTracker ); + newScissorArea.x = scissorArea.y; + newScissorArea.y = viewportRect.width - (scissorArea.x + scissorArea.width); + newScissorArea.width = scissorArea.height; + newScissorArea.height = scissorArea.width; } - - void RemoveRenderTracker( Render::RenderTracker* renderTracker ) + else { - mRenderTrackers.EraseObject( renderTracker ); + newScissorArea.x = scissorArea.x; + newScissorArea.y = scissorArea.y; + newScissorArea.width = scissorArea.width; + newScissorArea.height = scissorArea.height; } + return newScissorArea; +} +} // namespace - Context* CreateSceneContext() +/** + * Structure to contain internal data + */ +struct RenderManager::Impl +{ + Impl(Graphics::Controller& graphicsController, + Integration::DepthBufferAvailable depthBufferAvailableParam, + Integration::StencilBufferAvailable stencilBufferAvailableParam, + Integration::PartialUpdateAvailable partialUpdateAvailableParam) + : graphicsController(graphicsController), + renderAlgorithms(graphicsController), + programController(graphicsController), + shaderCache(graphicsController), + depthBufferAvailable(depthBufferAvailableParam), + stencilBufferAvailable(stencilBufferAvailableParam), + partialUpdateAvailable(partialUpdateAvailableParam) { - Context* context = new Context( glAbstraction ); - sceneContextContainer.PushBack( context ); - return context; + // Create thread pool with just one thread ( there may be a need to create more threads in the future ). + threadPool = std::make_unique(); + threadPool->Initialize(1u); + + uniformBufferManager = std::make_unique(&graphicsController); + pipelineCache = std::make_unique(graphicsController); } - void DestroySceneContext( Context* sceneContext ) + ~Impl() { - auto iter = std::find( sceneContextContainer.Begin(), sceneContextContainer.End(), sceneContext ); - if( iter != sceneContextContainer.End() ) - { - ( *iter )->GlContextDestroyed(); - sceneContextContainer.Erase( iter ); - } + threadPool.reset(nullptr); // reset now to maintain correct destruction order } - Context* ReplaceSceneContext( Context* oldSceneContext ) + void AddRenderTracker(Render::RenderTracker* renderTracker) { - Context* newContext = new Context( glAbstraction ); - - oldSceneContext->GlContextDestroyed(); + DALI_ASSERT_DEBUG(renderTracker != nullptr); + mRenderTrackers.PushBack(renderTracker); + } - std::replace( sceneContextContainer.begin(), sceneContextContainer.end(), oldSceneContext, newContext ); - return newContext; + void RemoveRenderTracker(Render::RenderTracker* renderTracker) + { + mRenderTrackers.EraseObject(renderTracker); } void UpdateTrackers() { - for( auto&& iter : mRenderTrackers ) + for(auto&& iter : mRenderTrackers) { iter->PollSyncObject(); } } // the order is important for destruction, - // 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* > 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::RenderAlgorithms renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction - - 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 - - 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::VertexBuffer* > vertexBufferContainer; ///< List of owned vertex buffers - OwnerContainer< Render::Geometry* > geometryContainer; ///< List of owned Geometries - - bool lastFrameWasRendered; ///< Keeps track of the last frame being rendered due to having render instructions - - OwnerContainer< Render::RenderTracker* > mRenderTrackers; ///< List of render trackers - - 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 - + Graphics::Controller& graphicsController; + RenderQueue renderQueue; ///< A message queue for receiving messages from the update-thread. + std::vector 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 + + OwnerContainer samplerContainer; ///< List of owned samplers + OwnerContainer frameBufferContainer; ///< List of owned framebuffers + OwnerContainer vertexBufferContainer; ///< List of owned vertex buffers + OwnerContainer geometryContainer; ///< List of owned Geometries + OwnerContainer mRenderTrackers; ///< List of render trackers + OwnerKeyContainer rendererContainer; ///< List of owned renderers + OwnerKeyContainer textureContainer; ///< List of owned textures + + ProgramController programController; ///< Owner of the programs + Render::ShaderCache shaderCache; ///< The cache for the graphics shaders + + std::unique_ptr uniformBufferManager; ///< The uniform buffer manager + std::unique_ptr pipelineCache; + + 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 bound textures + + uint32_t frameCount{0u}; ///< The current frame count + BufferIndex renderBufferIndex{SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX}; ///< The index of the buffer to read from; this is opposite of the "update" buffer + + bool lastFrameWasRendered{false}; ///< Keeps track of the last frame being rendered due to having render instructions + bool commandBufferSubmitted{false}; }; -RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction, - Integration::GlSyncAbstraction& glSyncAbstraction, - Integration::GlContextHelperAbstraction& glContextHelperAbstraction, - Integration::DepthBufferAvailable depthBufferAvailable, - Integration::StencilBufferAvailable stencilBufferAvailable, - Integration::PartialUpdateAvailable partialUpdateAvailable ) +RenderManager* RenderManager::New(Graphics::Controller& graphicsController, + Integration::DepthBufferAvailable depthBufferAvailable, + Integration::StencilBufferAvailable stencilBufferAvailable, + Integration::PartialUpdateAvailable partialUpdateAvailable) { - RenderManager* manager = new RenderManager; - manager->mImpl = new Impl( glAbstraction, - glSyncAbstraction, - glContextHelperAbstraction, - depthBufferAvailable, - stencilBufferAvailable, - partialUpdateAvailable ); + auto* manager = new RenderManager; + manager->mImpl = new Impl(graphicsController, + depthBufferAvailable, + stencilBufferAvailable, + partialUpdateAvailable); return manager; } @@ -212,373 +211,276 @@ RenderQueue& RenderManager::GetRenderQueue() return mImpl->renderQueue; } -void RenderManager::ContextCreated() +void RenderManager::SetShaderSaver(ShaderSaver& upstream) { - mImpl->context.GlContextCreated(); - mImpl->programController.GlContextCreated(); - - // renderers, textures and gpu buffers cannot reinitialize themselves - // so they rely on someone reloading the data for them -} - -void RenderManager::ContextDestroyed() -{ - mImpl->context.GlContextDestroyed(); - mImpl->programController.GlContextDestroyed(); - - //Inform textures - for( auto&& texture : mImpl->textureContainer ) - { - texture->GlContextDestroyed(); - } - - //Inform framebuffers - for( auto&& framebuffer : mImpl->frameBufferContainer ) - { - framebuffer->GlContextDestroyed(); - } - - // inform renderers - for( auto&& renderer : mImpl->rendererContainer ) - { - renderer->GlContextDestroyed(); - } - - // inform context - for( auto&& context : mImpl->sceneContextContainer ) - { - context->GlContextDestroyed(); - } } -void RenderManager::SetShaderSaver( ShaderSaver& upstream ) +void RenderManager::AddRenderer(const Render::RendererKey& renderer) { - mImpl->programController.SetShaderSaver( upstream ); -} + // Initialize the renderer as we are now in render thread + renderer->Initialize(mImpl->graphicsController, mImpl->programController, mImpl->shaderCache, *(mImpl->uniformBufferManager.get()), *(mImpl->pipelineCache.get())); -void RenderManager::SetDefaultSurfaceRect(const Rect& rect) -{ - mImpl->defaultSurfaceRect = rect; + mImpl->rendererContainer.PushBack(renderer); } -void RenderManager::SetDefaultSurfaceOrientation(int orientation) +void RenderManager::RemoveRenderer(const Render::RendererKey& renderer) { - mImpl->defaultSurfaceOrientation = orientation; + mImpl->rendererContainer.EraseKey(renderer); } -void RenderManager::AddRenderer( OwnerPointer< Render::Renderer >& renderer ) +void RenderManager::AddSampler(OwnerPointer& sampler) { - // Initialize the renderer as we are now in render thread - renderer->Initialize( mImpl->context ); - - mImpl->rendererContainer.PushBack( renderer.Release() ); + sampler->Initialize(mImpl->graphicsController); + mImpl->samplerContainer.PushBack(sampler.Release()); } -void RenderManager::RemoveRenderer( Render::Renderer* renderer ) +void RenderManager::RemoveSampler(Render::Sampler* sampler) { - mImpl->rendererContainer.EraseObject( renderer ); + mImpl->samplerContainer.EraseObject(sampler); } -void RenderManager::AddSampler( OwnerPointer< Render::Sampler >& sampler ) +void RenderManager::AddTexture(const Render::TextureKey& textureKey) { - mImpl->samplerContainer.PushBack( sampler.Release() ); -} + DALI_ASSERT_DEBUG(textureKey && "Trying to add empty texture key"); -void RenderManager::RemoveSampler( Render::Sampler* sampler ) -{ - mImpl->samplerContainer.EraseObject( sampler ); + textureKey->Initialize(mImpl->graphicsController); + mImpl->textureContainer.PushBack(textureKey); } -void RenderManager::AddTexture( OwnerPointer< Render::Texture >& texture ) +void RenderManager::RemoveTexture(const Render::TextureKey& textureKey) { - texture->Initialize( mImpl->context ); - mImpl->textureContainer.PushBack( texture.Release() ); -} + DALI_ASSERT_DEBUG(textureKey && "Trying to remove empty texture key"); -void RenderManager::RemoveTexture( Render::Texture* texture ) -{ - DALI_ASSERT_DEBUG( NULL != texture ); + // Find the texture, use std::find so we can do the erase safely + auto iter = std::find(mImpl->textureContainer.begin(), mImpl->textureContainer.end(), textureKey); - // Find the texture, use reference to pointer so we can do the erase safely - for ( auto&& iter : mImpl->textureContainer ) + if(iter != mImpl->textureContainer.end()) { - if ( iter == texture ) - { - texture->Destroy( mImpl->context ); - mImpl->textureContainer.Erase( &iter ); // Texture found; now destroy it - return; - } + textureKey->Destroy(); + mImpl->textureContainer.Erase(iter); // Texture found; now destroy it } } -void RenderManager::UploadTexture( Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params ) +void RenderManager::UploadTexture(const Render::TextureKey& textureKey, PixelDataPtr pixelData, const Texture::UploadParams& params) { - texture->Upload( mImpl->context, pixelData, params ); + DALI_ASSERT_DEBUG(textureKey && "Trying to upload to empty texture key"); + textureKey->Upload(pixelData, params); } -void RenderManager::GenerateMipmaps( Render::Texture* texture ) +void RenderManager::GenerateMipmaps(const Render::TextureKey& textureKey) { - texture->GenerateMipmaps( mImpl->context ); + DALI_ASSERT_DEBUG(textureKey && "Trying to generate mipmaps on empty texture key"); + textureKey->GenerateMipmaps(); } -void RenderManager::SetFilterMode( Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode ) +void RenderManager::SetFilterMode(Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode) { - sampler->mMinificationFilter = static_cast(minFilterMode); - sampler->mMagnificationFilter = static_cast(magFilterMode ); + sampler->SetFilterMode(static_cast(minFilterMode), + static_cast(magFilterMode)); } -void RenderManager::SetWrapMode( Render::Sampler* sampler, uint32_t rWrapMode, uint32_t sWrapMode, uint32_t 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); + sampler->SetWrapMode(static_cast(rWrapMode), + static_cast(sWrapMode), + static_cast(tWrapMode)); } -void RenderManager::AddFrameBuffer( OwnerPointer< Render::FrameBuffer >& frameBuffer ) +void RenderManager::AddFrameBuffer(OwnerPointer& frameBuffer) { Render::FrameBuffer* frameBufferPtr = frameBuffer.Release(); - mImpl->frameBufferContainer.PushBack( frameBufferPtr ); - frameBufferPtr->Initialize( mImpl->context ); + mImpl->frameBufferContainer.PushBack(frameBufferPtr); + frameBufferPtr->Initialize(mImpl->graphicsController); } -void RenderManager::RemoveFrameBuffer( Render::FrameBuffer* frameBuffer ) +void RenderManager::RemoveFrameBuffer(Render::FrameBuffer* frameBuffer) { - DALI_ASSERT_DEBUG( NULL != frameBuffer ); + DALI_ASSERT_DEBUG(nullptr != frameBuffer); - // Find the sampler, use reference so we can safely do the erase - for ( auto&& iter : mImpl->frameBufferContainer ) - { - if ( iter == frameBuffer ) - { - frameBuffer->Destroy( mImpl->context ); - mImpl->frameBufferContainer.Erase( &iter ); // frameBuffer found; now destroy it + // Find the framebuffer, use std:find so we can safely do the erase + auto iter = std::find(mImpl->frameBufferContainer.begin(), mImpl->frameBufferContainer.end(), frameBuffer); - break; - } + if(iter != mImpl->frameBufferContainer.end()) + { + frameBuffer->Destroy(); + mImpl->frameBufferContainer.Erase(iter); // frameBuffer found; now destroy it } } -void RenderManager::InitializeScene( SceneGraph::Scene* scene ) + +void RenderManager::InitializeScene(SceneGraph::Scene* scene) { - scene->Initialize( *mImpl->CreateSceneContext() ); - mImpl->sceneContainer.push_back( scene ); + scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable); + mImpl->sceneContainer.push_back(scene); } -void RenderManager::UninitializeScene( SceneGraph::Scene* scene ) +void RenderManager::UninitializeScene(SceneGraph::Scene* scene) { - mImpl->DestroySceneContext( scene->GetContext() ); - - auto iter = std::find( mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene ); - if( iter != mImpl->sceneContainer.end() ) + auto iter = std::find(mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene); + if(iter != mImpl->sceneContainer.end()) { - mImpl->sceneContainer.erase( iter ); + mImpl->sceneContainer.erase(iter); } } -void RenderManager::SurfaceReplaced( SceneGraph::Scene* scene ) +void RenderManager::SurfaceReplaced(SceneGraph::Scene* scene) +{ + scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable); +} + +void RenderManager::AttachColorTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer) { - Context* newContext = mImpl->ReplaceSceneContext( scene->GetContext() ); - scene->Initialize( *newContext ); + frameBuffer->AttachColorTexture(texture, mipmapLevel, layer); } -void RenderManager::AttachColorTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer ) +void RenderManager::AttachDepthTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel) { - frameBuffer->AttachColorTexture( mImpl->context, texture, mipmapLevel, layer ); + frameBuffer->AttachDepthTexture(texture, mipmapLevel); } -void RenderManager::AttachDepthTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel ) +void RenderManager::AttachDepthStencilTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel) { - frameBuffer->AttachDepthTexture( mImpl->context, texture, mipmapLevel ); + frameBuffer->AttachDepthStencilTexture(texture, mipmapLevel); } -void RenderManager::AttachDepthStencilTextureToFrameBuffer( Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel ) +void RenderManager::SetMultiSamplingLevelToFrameBuffer(Render::FrameBuffer* frameBuffer, uint8_t multiSamplingLevel) { - frameBuffer->AttachDepthStencilTexture( mImpl->context, texture, mipmapLevel ); + frameBuffer->SetMultiSamplingLevel(multiSamplingLevel); } -void RenderManager::AddVertexBuffer( OwnerPointer< Render::VertexBuffer >& vertexBuffer ) +void RenderManager::AddVertexBuffer(OwnerPointer& vertexBuffer) { - mImpl->vertexBufferContainer.PushBack( vertexBuffer.Release() ); + mImpl->vertexBufferContainer.PushBack(vertexBuffer.Release()); } -void RenderManager::RemoveVertexBuffer( Render::VertexBuffer* vertexBuffer ) +void RenderManager::RemoveVertexBuffer(Render::VertexBuffer* vertexBuffer) { - mImpl->vertexBufferContainer.EraseObject( vertexBuffer ); + mImpl->vertexBufferContainer.EraseObject(vertexBuffer); } -void RenderManager::SetVertexBufferFormat( Render::VertexBuffer* vertexBuffer, OwnerPointer< Render::VertexBuffer::Format>& format ) +void RenderManager::SetVertexBufferFormat(Render::VertexBuffer* vertexBuffer, OwnerPointer& format) { - vertexBuffer->SetFormat( format.Release() ); + vertexBuffer->SetFormat(format.Release()); } -void RenderManager::SetVertexBufferData( Render::VertexBuffer* vertexBuffer, OwnerPointer< Vector >& data, uint32_t size ) +void RenderManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, OwnerPointer>& data, uint32_t size) { - vertexBuffer->SetData( data.Release(), size ); + vertexBuffer->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 ); + geometry->SetIndexBuffer(indices); } -void RenderManager::AddGeometry( OwnerPointer< Render::Geometry >& geometry ) +void RenderManager::AddGeometry(OwnerPointer& geometry) { - mImpl->geometryContainer.PushBack( geometry.Release() ); + mImpl->geometryContainer.PushBack(geometry.Release()); } -void RenderManager::RemoveGeometry( Render::Geometry* geometry ) +void RenderManager::RemoveGeometry(Render::Geometry* geometry) { - mImpl->geometryContainer.EraseObject( geometry ); + auto iter = std::find(mImpl->geometryContainer.begin(), mImpl->geometryContainer.end(), geometry); + + if(iter != mImpl->geometryContainer.end()) + { + mImpl->geometryContainer.Erase(iter); + } } -void RenderManager::AttachVertexBuffer( Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer ) +void RenderManager::AttachVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer) { - DALI_ASSERT_DEBUG( NULL != geometry ); + DALI_ASSERT_DEBUG(nullptr != geometry); // Find the geometry - for ( auto&& iter : mImpl->geometryContainer ) + for(auto&& iter : mImpl->geometryContainer) { - if ( iter == geometry ) + if(iter == geometry) { - iter->AddVertexBuffer( vertexBuffer ); + iter->AddVertexBuffer(vertexBuffer); break; } } } -void RenderManager::RemoveVertexBuffer( Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer ) +void RenderManager::RemoveVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer) { - DALI_ASSERT_DEBUG( NULL != geometry ); + DALI_ASSERT_DEBUG(nullptr != geometry); // Find the geometry - for ( auto&& iter : mImpl->geometryContainer ) + for(auto&& iter : mImpl->geometryContainer) { - if ( iter == geometry ) + if(iter == geometry) { - iter->RemoveVertexBuffer( vertexBuffer ); + iter->RemoveVertexBuffer(vertexBuffer); break; } } } -void RenderManager::SetGeometryType( Render::Geometry* geometry, uint32_t geometryType ) +void RenderManager::SetGeometryType(Render::Geometry* geometry, uint32_t geometryType) { - geometry->SetType( Render::Geometry::Type(geometryType) ); + geometry->SetType(Render::Geometry::Type(geometryType)); } -void RenderManager::AddRenderTracker( Render::RenderTracker* renderTracker ) +void RenderManager::AddRenderTracker(Render::RenderTracker* renderTracker) { mImpl->AddRenderTracker(renderTracker); } -void RenderManager::RemoveRenderTracker( Render::RenderTracker* renderTracker ) +void RenderManager::RemoveRenderTracker(Render::RenderTracker* renderTracker) { mImpl->RemoveRenderTracker(renderTracker); } -ProgramCache* RenderManager::GetProgramCache() -{ - return &(mImpl->programController); -} - -void RenderManager::PreRender( Integration::RenderStatus& status, bool forceClear, bool uploadOnly ) +void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear) { - DALI_PRINT_RENDER_START( mImpl->renderBufferIndex ); + DALI_PRINT_RENDER_START(mImpl->renderBufferIndex); - // Core::Render documents that GL context must be current before calling Render - DALI_ASSERT_DEBUG( mImpl->context.IsGlContextCreated() ); + // Rollback + mImpl->uniformBufferManager->GetUniformBufferViewPool(mImpl->renderBufferIndex)->Rollback(); // Increment the frame count at the beginning of each frame ++mImpl->frameCount; // Process messages queued during previous update - mImpl->renderQueue.ProcessMessages( mImpl->renderBufferIndex ); + mImpl->renderQueue.ProcessMessages(mImpl->renderBufferIndex); uint32_t count = 0u; - for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) + for(auto& i : mImpl->sceneContainer) { - count += mImpl->sceneContainer[i]->GetRenderInstructions().Count( mImpl->renderBufferIndex ); + count += i->GetRenderInstructions().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" ); + 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 ) + if(haveInstructions || mImpl->lastFrameWasRendered || forceClear) { - DALI_LOG_INFO( gLogFilter, Debug::General, "Render: Processing\n" ); - - // 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(); - } + DALI_LOG_INFO(gLogFilter, Debug::General, "Render: Processing\n"); // Upload the geometries - for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) + for(auto&& geom : mImpl->geometryContainer) { - 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 ); - } - } - } - } - } - } + geom->Upload(mImpl->graphicsController); } } + + mImpl->commandBufferSubmitted = false; } -void RenderManager::PreRender( Integration::Scene& scene, std::vector>& damagedRects ) +void RenderManager::PreRender(Integration::Scene& scene, std::vector>& damagedRects) { - if (mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE) + if(mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE) { return; } - Internal::Scene& sceneInternal = GetImplementation(scene); - SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); + Internal::Scene& sceneInternal = GetImplementation(scene); + SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); - if( sceneObject->IsRenderingSkipped() ) + if(sceneObject->IsRenderingSkipped()) { // We don't need to calculate dirty rects return; @@ -587,8 +489,9 @@ void RenderManager::PreRender( Integration::Scene& scene, std::vector> class DamagedRectsCleaner { public: - DamagedRectsCleaner(std::vector>& damagedRects) + explicit DamagedRectsCleaner(std::vector>& damagedRects, Rect& surfaceRect) : mDamagedRects(damagedRects), + mSurfaceRect(surfaceRect), mCleanOnReturn(true) { } @@ -600,78 +503,80 @@ void RenderManager::PreRender( Integration::Scene& scene, std::vector> ~DamagedRectsCleaner() { - if (mCleanOnReturn) + if(mCleanOnReturn) { mDamagedRects.clear(); + mDamagedRects.push_back(mSurfaceRect); } } private: std::vector>& mDamagedRects; - bool mCleanOnReturn; + Rect mSurfaceRect; + bool mCleanOnReturn; }; - Rect surfaceRect = Rect(0, 0, static_cast( scene.GetSize().width ), static_cast( scene.GetSize().height )); + Rect surfaceRect = sceneObject->GetSurfaceRect(); // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions. - DamagedRectsCleaner damagedRectCleaner(damagedRects); + DamagedRectsCleaner damagedRectCleaner(damagedRects, surfaceRect); + bool cleanDamagedRect = false; - // Mark previous dirty rects in the sorted array. The array is already sorted by node and renderer, frame number. - // so you don't need to sort: std::stable_sort(itemsDirtyRects.begin(), itemsDirtyRects.end()); - std::vector& itemsDirtyRects = sceneInternal.GetItemsDirtyRects(); - for (DirtyRect& dirtyRect : itemsDirtyRects) + // Mark previous dirty rects in the std::unordered_map. + Scene::ItemsDirtyRectsContainer& itemsDirtyRects = sceneObject->GetItemsDirtyRects(); + for(auto& dirtyRectPair : itemsDirtyRects) { - dirtyRect.visited = false; + dirtyRectPair.second.visited = false; } - uint32_t count = sceneObject->GetRenderInstructions().Count( mImpl->renderBufferIndex ); - for (uint32_t i = 0; i < count; ++i) + uint32_t instructionCount = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex); + for(uint32_t i = 0; i < instructionCount; ++i) { - RenderInstruction& instruction = sceneObject->GetRenderInstructions().At( mImpl->renderBufferIndex, i ); + RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i); - if (instruction.mFrameBuffer) + if(instruction.mFrameBuffer) { - return; // TODO: reset, we don't deal with render tasks with framebuffers (for now) + cleanDamagedRect = true; + continue; // TODO: reset, we don't deal with render tasks with framebuffers (for now) } const Camera* camera = instruction.GetCamera(); - if (camera->mType == Camera::DEFAULT_TYPE && camera->mTargetPosition == Camera::DEFAULT_TARGET_POSITION) + if(camera && camera->mType == Camera::DEFAULT_TYPE && camera->mTargetPosition == Camera::DEFAULT_TARGET_POSITION) { - const Node* node = instruction.GetCamera()->GetNode(); - if (node) + Vector3 position; + Vector3 scale; + Quaternion orientation; + camera->GetWorldMatrix(mImpl->renderBufferIndex).GetTransformComponents(position, orientation, scale); + + Vector3 orientationAxis; + Radian orientationAngle; + orientation.ToAxisAngle(orientationAxis, orientationAngle); + + if(position.x > Math::MACHINE_EPSILON_10000 || + position.y > Math::MACHINE_EPSILON_10000 || + orientationAxis != Vector3(0.0f, 1.0f, 0.0f) || + orientationAngle != ANGLE_180 || + scale != Vector3(1.0f, 1.0f, 1.0f)) { - Vector3 position; - Vector3 scale; - Quaternion orientation; - node->GetWorldMatrix(mImpl->renderBufferIndex).GetTransformComponents(position, orientation, scale); - - Vector3 orientationAxis; - Radian orientationAngle; - orientation.ToAxisAngle( orientationAxis, orientationAngle ); - - if (position.x > Math::MACHINE_EPSILON_10000 || - position.y > Math::MACHINE_EPSILON_10000 || - orientationAxis != Vector3(0.0f, 1.0f, 0.0f) || - orientationAngle != ANGLE_180 || - scale != Vector3(1.0f, 1.0f, 1.0f)) - { - return; - } + cleanDamagedRect = true; + continue; } } else { - return; + cleanDamagedRect = true; + continue; } Rect viewportRect; - if (instruction.mIsViewportSet) + if(instruction.mIsViewportSet) { const int32_t y = (surfaceRect.height - instruction.mViewport.height) - instruction.mViewport.y; - viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height); - if (viewportRect.IsEmpty() || !viewportRect.IsValid()) + viewportRect.Set(instruction.mViewport.x, y, instruction.mViewport.width, instruction.mViewport.height); + if(viewportRect.IsEmpty() || !viewportRect.IsValid()) { - return; // just skip funny use cases for now, empty viewport means it is set somewhere else + cleanDamagedRect = true; + continue; // just skip funny use cases for now, empty viewport means it is set somewhere else } } else @@ -681,91 +586,102 @@ void RenderManager::PreRender( Integration::Scene& scene, std::vector> const Matrix* viewMatrix = instruction.GetViewMatrix(mImpl->renderBufferIndex); const Matrix* projectionMatrix = instruction.GetProjectionMatrix(mImpl->renderBufferIndex); - if (viewMatrix && projectionMatrix) + if(viewMatrix && projectionMatrix) { const RenderListContainer::SizeType count = instruction.RenderListCount(); - for (RenderListContainer::SizeType index = 0u; index < count; ++index) + for(RenderListContainer::SizeType index = 0u; index < count; ++index) { - const RenderList* renderList = instruction.GetRenderList( index ); - if (renderList && !renderList->IsEmpty()) + const RenderList* renderList = instruction.GetRenderList(index); + if(renderList) { - const std::size_t count = renderList->Count(); - for (uint32_t index = 0u; index < count; ++index) + if(!renderList->IsEmpty()) { - RenderItem& item = renderList->GetItem( index ); - // If the item does 3D transformation, do early exit and clean the damaged rect array - if (item.mUpdateSize == Vector3::ZERO) + const std::size_t listCount = renderList->Count(); + for(uint32_t listIndex = 0u; listIndex < listCount; ++listIndex) { - return; - } + RenderItem& item = renderList->GetItem(listIndex); + // If the item does 3D transformation, make full update + if(item.mUpdateArea == Vector4::ZERO) + { + cleanDamagedRect = true; - Rect rect; - DirtyRect dirtyRect(item.mNode, item.mRenderer, mImpl->frameCount, rect); - // If the item refers to updated node or renderer. - if (item.mIsUpdated || - (item.mNode && - (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated(mImpl->renderBufferIndex, item.mNode))))) - { - item.mIsUpdated = false; - item.mNode->SetUpdated(false); + // Save the full rect in the damaged list. We need it when this item is removed + DirtyRectKey dirtyRectKey(item.mNode, item.mRenderer); + auto dirtyRectPos = itemsDirtyRects.find(dirtyRectKey); + if(dirtyRectPos != itemsDirtyRects.end()) + { + // Replace the rect + dirtyRectPos->second.visited = true; + dirtyRectPos->second.rect = surfaceRect; + } + else + { + // Else, just insert the new dirtyrect + itemsDirtyRects.insert({dirtyRectKey, surfaceRect}); + } + continue; + } - rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, viewportRect.width, viewportRect.height); - if (rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty()) + Rect rect; + DirtyRectKey dirtyRectKey(item.mNode, item.mRenderer); + // If the item refers to updated node or renderer. + if(item.mIsUpdated || + (item.mNode && + (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated(mImpl->renderBufferIndex))))) { - const int left = rect.x; - const int top = rect.y; - const int right = rect.x + rect.width; - const int bottom = rect.y + rect.height; - rect.x = (left / 16) * 16; - rect.y = (top / 16) * 16; - rect.width = ((right + 16) / 16) * 16 - rect.x; - rect.height = ((bottom + 16) / 16) * 16 - rect.y; - - // Found valid dirty rect. - // 1. Insert it in the sorted array of the dirty rects. - // 2. Mark the related dirty rects as visited so they will not be removed below. - // 3. Keep only last 3 dirty rects for the same node and renderer (Tizen uses 3 back buffers, Ubuntu 1). - dirtyRect.rect = rect; - auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect); - dirtyRectPos = itemsDirtyRects.insert(dirtyRectPos, dirtyRect); + item.mIsUpdated = false; + + Vector4 updateArea = item.mRenderer ? item.mRenderer->GetVisualTransformedUpdateArea(mImpl->renderBufferIndex, item.mUpdateArea) : item.mUpdateArea; - int c = 1; - while (++dirtyRectPos != itemsDirtyRects.end()) + rect = RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3(updateArea.x, updateArea.y, 0.0f), Vector3(updateArea.z, updateArea.w, 0.0f), viewportRect.width, viewportRect.height); + if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty()) { - if (dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer) + const int left = rect.x; + const int top = rect.y; + const int right = rect.x + rect.width; + const int bottom = rect.y + rect.height; + rect.x = (left / 16) * 16; + rect.y = (top / 16) * 16; + rect.width = ((right + 16) / 16) * 16 - rect.x; + rect.height = ((bottom + 16) / 16) * 16 - rect.y; + + // Found valid dirty rect. + auto dirtyRectPos = itemsDirtyRects.find(dirtyRectKey); + if(dirtyRectPos != itemsDirtyRects.end()) { - break; - } + Rect currentRect = rect; - dirtyRectPos->visited = true; - Rect& dirtRect = dirtyRectPos->rect; - rect.Merge(dirtRect); + // Same item, merge it with the previous rect + rect.Merge(dirtyRectPos->second.rect); - c++; - if (c > 3) // no more then 3 previous rects + // Replace the rect as current + dirtyRectPos->second.visited = true; + dirtyRectPos->second.rect = currentRect; + } + else { - itemsDirtyRects.erase(dirtyRectPos); - break; + // Else, just insert the new dirtyrect + itemsDirtyRects.insert({dirtyRectKey, rect}); } - } - damagedRects.push_back(rect); + damagedRects.push_back(rect); + } } - } - else - { - // 1. The item is not dirty, the node and renderer referenced by the item are still exist. - // 2. Mark the related dirty rects as visited so they will not be removed below. - auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect); - while (dirtyRectPos != itemsDirtyRects.end()) + else { - if (dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer) + // 1. The item is not dirty, the node and renderer referenced by the item are still exist. + // 2. Mark the related dirty rects as visited so they will not be removed below. + auto dirtyRectPos = itemsDirtyRects.find(dirtyRectKey); + if(dirtyRectPos != itemsDirtyRects.end()) { - break; + dirtyRectPos->second.visited = true; + } + else + { + // The item is not in the list for some reason. Add it! + itemsDirtyRects.insert({dirtyRectKey, surfaceRect}); + cleanDamagedRect = true; // And make full update at this frame } - - dirtyRectPos->visited = true; - dirtyRectPos++; } } } @@ -775,176 +691,199 @@ void RenderManager::PreRender( Integration::Scene& scene, std::vector> } // Check removed nodes or removed renderers dirty rects - auto i = itemsDirtyRects.begin(); - auto j = itemsDirtyRects.begin(); - while (i != itemsDirtyRects.end()) + // Note, std::unordered_map end iterator is validate if we call erase. + for(auto iter = itemsDirtyRects.cbegin(), iterEnd = itemsDirtyRects.cend(); iter != iterEnd;) { - if (i->visited) + if(!iter->second.visited) { - *j++ = *i; + damagedRects.push_back(iter->second.rect); + iter = itemsDirtyRects.erase(iter); } else { - Rect& dirtRect = i->rect; - damagedRects.push_back(dirtRect); + ++iter; } - i++; } - itemsDirtyRects.resize(j - itemsDirtyRects.begin()); - damagedRectCleaner.SetCleanOnReturn(false); + if(!cleanDamagedRect) + { + damagedRectCleaner.SetCleanOnReturn(false); + } } -void RenderManager::RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo ) +void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo) { - Rect clippingRect; - RenderScene( status, scene, renderToFbo, clippingRect); + SceneGraph::Scene* sceneObject = GetImplementation(scene).GetSceneObject(); + Rect clippingRect = sceneObject->GetSurfaceRect(); + + RenderScene(status, scene, renderToFbo, clippingRect); } -void RenderManager::RenderScene( Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect ) +void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect) { - Internal::Scene& sceneInternal = GetImplementation( scene ); - SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); + if(mImpl->partialUpdateAvailable == Integration::PartialUpdateAvailable::TRUE && !renderToFbo && clippingRect.IsEmpty()) + { + // ClippingRect is empty. Skip rendering + return; + } + + // Reset main algorithms command buffer + mImpl->renderAlgorithms.ResetCommandBuffer(); + + auto mainCommandBuffer = mImpl->renderAlgorithms.GetMainCommandBuffer(); + + Internal::Scene& sceneInternal = GetImplementation(scene); + SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); + + uint32_t count = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex); + + std::vector targetstoPresent; - uint32_t count = sceneObject->GetRenderInstructions().Count( mImpl->renderBufferIndex ); + Rect surfaceRect = sceneObject->GetSurfaceRect(); + if(clippingRect == surfaceRect) + { + // Full rendering case + // Make clippingRect empty because we're doing full rendering now if the clippingRect is empty. + // To reduce side effects, keep this logic now. + clippingRect = Rect(); + } - for( uint32_t i = 0; i < count; ++i ) + // Prepare to lock and map standalone uniform buffer. + mImpl->uniformBufferManager->ReadyToLockUniformBuffer(mImpl->renderBufferIndex); + + for(uint32_t i = 0; i < count; ++i) { - RenderInstruction& instruction = sceneObject->GetRenderInstructions().At( mImpl->renderBufferIndex, i ); + RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i); - if ( ( renderToFbo && !instruction.mFrameBuffer ) || ( !renderToFbo && instruction.mFrameBuffer ) ) + if((renderToFbo && !instruction.mFrameBuffer) || (!renderToFbo && instruction.mFrameBuffer)) { continue; // skip } // Mark that we will require a post-render step to be performed (includes swap-buffers). - status.SetNeedsPostRender( true ); + status.SetNeedsPostRender(true); Rect viewportRect; - Vector4 clearColor; - if ( instruction.mIsClearColorSet ) - { - clearColor = instruction.mClearColor; - } - else + int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation() + sceneObject->GetScreenOrientation(); + if(surfaceOrientation >= 360) { - clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR; + surfaceOrientation -= 360; } - Rect surfaceRect = mImpl->defaultSurfaceRect; - Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; + // @todo Should these be part of scene? + Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable; - int surfaceOrientation = sceneInternal.GetSurfaceOrientation(); - if ( instruction.mFrameBuffer ) + Graphics::RenderTarget* currentRenderTarget = nullptr; + Graphics::RenderPass* currentRenderPass = nullptr; + std::vector currentClearValues{}; + + if(instruction.mFrameBuffer) { - // offscreen buffer - if ( mImpl->currentContext != &mImpl->context ) + // Ensure graphics framebuffer is created, bind attachments and create render passes + // Only happens once per framebuffer. If the create fails, e.g. no attachments yet, + // then don't render to this framebuffer. + if(!instruction.mFrameBuffer->GetGraphicsObject()) { - // Switch to shared context for off-screen buffer - mImpl->currentContext = &mImpl->context; - - if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + const bool created = instruction.mFrameBuffer->CreateGraphicsObjects(); + if(!created) { - mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); + continue; } + } - // Clear the current cached program when the context is switched - mImpl->programController.ClearCurrentProgram(); + auto& clearValues = instruction.mFrameBuffer->GetGraphicsRenderPassClearValues(); + + // Set the clear color for first color attachment + if(instruction.mIsClearColorSet && !clearValues.empty()) + { + clearValues[0].color = { + instruction.mClearColor.r, + instruction.mClearColor.g, + instruction.mClearColor.b, + instruction.mClearColor.a}; } + + currentClearValues = clearValues; + + auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD; + + // offscreen buffer + currentRenderTarget = instruction.mFrameBuffer->GetGraphicsRenderTarget(); + currentRenderPass = instruction.mFrameBuffer->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE); } - else + else // no framebuffer { - if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + // surface + auto& clearValues = sceneObject->GetGraphicsRenderPassClearValues(); + + if(instruction.mIsClearColorSet) { - if ( mImpl->currentContext != sceneObject->GetContext() ) - { - // Switch the correct context if rendering to a surface - mImpl->currentContext = sceneObject->GetContext(); + clearValues[0].color = { + instruction.mClearColor.r, + instruction.mClearColor.g, + instruction.mClearColor.b, + instruction.mClearColor.a}; + } - // Clear the current cached program when the context is switched - mImpl->programController.ClearCurrentProgram(); - } + currentClearValues = clearValues; + + // @todo SceneObject should already have the depth clear / stencil clear in the clearValues array. + // if the window has a depth/stencil buffer. + if((depthBufferAvailable == Integration::DepthBufferAvailable::TRUE || + stencilBufferAvailable == Integration::StencilBufferAvailable::TRUE) && + (currentClearValues.size() <= 1)) + { + currentClearValues.emplace_back(); + currentClearValues.back().depthStencil.depth = 0; + currentClearValues.back().depthStencil.stencil = 0; } - surfaceRect = Rect( 0, 0, static_cast( scene.GetSize().width ), static_cast( scene.GetSize().height ) ); + auto loadOp = instruction.mIsClearColorSet ? Graphics::AttachmentLoadOp::CLEAR : Graphics::AttachmentLoadOp::LOAD; + + currentRenderTarget = sceneObject->GetSurfaceRenderTarget(); + currentRenderPass = sceneObject->GetGraphicsRenderPass(loadOp, Graphics::AttachmentStoreOp::STORE); } - // Make sure that GL context must be created - mImpl->currentContext->GlContextCreated(); + targetstoPresent.emplace_back(currentRenderTarget); // 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 ) + 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) + for(unsigned int i0 = 0, i1 = instruction.mFrameBuffer->GetColorAttachmentCount(); i0 < i1; ++i0) { - mImpl->textureDependencyList.PushBack( instruction.mFrameBuffer->GetTextureId(i0) ); + mImpl->textureDependencyList.PushBack(instruction.mFrameBuffer->GetTexture(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 != nullptr ) ) + if(!instruction.mIgnoreRenderToFbo && (instruction.mFrameBuffer != nullptr)) { // Offscreen buffer rendering - if ( instruction.mIsViewportSet ) + 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 ); + // For Viewport 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() ); + 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.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 ); + // For Viewport 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 { @@ -953,22 +892,20 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: } // Set surface orientation - mImpl->currentContext->SetSurfaceOrientation(surfaceOrientation); + // @todo Inform graphics impl by another route. + // was: mImpl->currentContext->SetSurfaceOrientation(surfaceOrientation); - bool clearFullFrameRect = true; - if( instruction.mFrameBuffer != nullptr ) + /*** Clear region of framebuffer or surface before drawing ***/ + bool clearFullFrameRect = (surfaceRect == viewportRect); + if(instruction.mFrameBuffer != nullptr) { - Viewport frameRect( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); - clearFullFrameRect = ( frameRect == viewportRect ); - } - else - { - clearFullFrameRect = ( surfaceRect == viewportRect ); + Viewport frameRect(0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight()); + clearFullFrameRect = (frameRect == viewportRect); } - if (!clippingRect.IsEmpty()) + if(!clippingRect.IsEmpty()) { - if (!clippingRect.Intersect(viewportRect)) + if(!clippingRect.Intersect(viewportRect)) { DALI_LOG_ERROR("Invalid clipping rect %d %d %d %d\n", clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height); clippingRect = Rect(); @@ -976,156 +913,111 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: clearFullFrameRect = false; } - mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); - - if (instruction.mIsClearColorSet) + Graphics::Rect2D scissorArea{viewportRect.x, viewportRect.y, uint32_t(viewportRect.width), uint32_t(viewportRect.height)}; + if(instruction.mIsClearColorSet) { - mImpl->currentContext->ClearColor(clearColor.r, - clearColor.g, - clearColor.b, - clearColor.a); - if (!clearFullFrameRect) + if(!clearFullFrameRect) { - if (!clippingRect.IsEmpty()) + if(!clippingRect.IsEmpty()) { - mImpl->currentContext->SetScissorTest(true); - mImpl->currentContext->Scissor(clippingRect.x, clippingRect.y, clippingRect.width, clippingRect.height); - mImpl->currentContext->Clear(clearMask, Context::FORCE_CLEAR); - mImpl->currentContext->SetScissorTest(false); + scissorArea = {clippingRect.x, clippingRect.y, uint32_t(clippingRect.width), uint32_t(clippingRect.height)}; } - else - { - 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); } } + // Scissor's value should be set based on the default system coordinates. + // When the surface is rotated, the input values already were set with the rotated angle. + // So, re-calculation is needed. + scissorArea = RecalculateScissorArea(scissorArea, surfaceOrientation, surfaceRect); + + // Begin render pass + mainCommandBuffer->BeginRenderPass( + currentRenderPass, + currentRenderTarget, + scissorArea, + currentClearValues); + + mainCommandBuffer->SetViewport({float(viewportRect.x), + float(viewportRect.y), + float(viewportRect.width), + float(viewportRect.height)}); + // Clear the list of bound textures mImpl->boundTextures.Clear(); mImpl->renderAlgorithms.ProcessRenderInstruction( - instruction, - *mImpl->currentContext, - mImpl->renderBufferIndex, - depthBufferAvailable, - stencilBufferAvailable, - mImpl->boundTextures, - clippingRect ); - - // Synchronise the FBO/Texture access when there are multiple contexts - if ( mImpl->currentContext->IsSurfacelessContextSupported() ) + instruction, + mImpl->renderBufferIndex, + depthBufferAvailable, + stencilBufferAvailable, + mImpl->boundTextures, + viewportRect, + clippingRect, + surfaceOrientation, + Uint16Pair(surfaceRect.width, surfaceRect.height)); + + Graphics::SyncObject* syncObject{nullptr}; + // If the render instruction has an associated render tracker (owned separately) + // and framebuffer, create a one shot sync object, and use it to determine when + // the render pass has finished executing on GPU. + if(instruction.mRenderTracker && instruction.mFrameBuffer) { - // 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(); + syncObject = instruction.mRenderTracker->CreateSyncObject(mImpl->graphicsController); + instruction.mRenderTracker = nullptr; + } + mainCommandBuffer->EndRenderPass(syncObject); + } - // Must clear the context in the worker thread - // Otherwise the shared context cannot be switched to from the render thread - glContextHelperAbstraction.MakeContextNull(); - }; + // Unlock standalone uniform buffer. + mImpl->uniformBufferManager->UnlockUniformBuffer(mImpl->renderBufferIndex); - auto future = mImpl->threadPool->SubmitTask( 0u, workerFunction ); - if ( future ) - { - mImpl->threadPool->Wait(); - - // Clear the dependency list - mImpl->textureDependencyList.Clear(); - } - } - } - } + mImpl->renderAlgorithms.SubmitCommandBuffer(); + mImpl->commandBufferSubmitted = true; - 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. - } + std::sort(targetstoPresent.begin(), targetstoPresent.end()); - if ( renderToFbo ) + Graphics::RenderTarget* rt = nullptr; + for(auto& target : targetstoPresent) + { + if(target != rt) { - mImpl->currentContext->Flush(); + mImpl->graphicsController.PresentRenderTarget(target); + rt = target; } } - - GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; - mImpl->currentContext->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); - } -void RenderManager::PostRender( bool uploadOnly ) +void RenderManager::PostRender() { - if ( !uploadOnly ) + if(!mImpl->commandBufferSubmitted) { - if ( mImpl->currentContext->IsSurfacelessContextSupported() ) - { - mImpl->glContextHelperAbstraction.MakeSurfacelessContextCurrent(); - } + // Rendering is skipped but there may be pending tasks. Flush them. + Graphics::SubmitInfo submitInfo; + submitInfo.cmdBuffer.clear(); // Only flush + submitInfo.flags = 0 | Graphics::SubmitFlagBits::FLUSH; + mImpl->graphicsController.SubmitCommandBuffers(submitInfo); - GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; - mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); + mImpl->commandBufferSubmitted = true; } - //Notify RenderGeometries that rendering has finished - for ( auto&& iter : mImpl->geometryContainer ) + // Notify RenderGeometries that rendering has finished + for(auto&& iter : mImpl->geometryContainer) { iter->OnRenderFinished(); } - mImpl->UpdateTrackers(); + // Notify RenderTexture that rendering has finished + for(auto&& iter : mImpl->textureContainer) + { + iter->OnRenderFinished(); + } + mImpl->UpdateTrackers(); uint32_t count = 0u; - for( uint32_t i = 0; i < mImpl->sceneContainer.size(); ++i ) + for(auto& scene : mImpl->sceneContainer) { - count += mImpl->sceneContainer[i]->GetRenderInstructions().Count( mImpl->renderBufferIndex ); + count += scene->GetRenderInstructions().Count(mImpl->renderBufferIndex); } const bool haveInstructions = count > 0u;