X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Fcommon%2Frender-manager.cpp;h=d157b764d21903efc05b738d00ec6c5a9fb8d3a2;hb=62cfeeb09f1e213ede6115bb36e3c7157dade816;hp=ab3548d698d2d345eeb31e2f6631cc2fcc171a72;hpb=96e565913a48d738c7e94b18695ffc3cb01f023c;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 ab3548d..d157b76 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -24,11 +24,11 @@ // INTERNAL INCLUDES #include #include -#include #include #include +#include #include #include @@ -36,10 +36,16 @@ #include #include #include +#include #include #include +#include +#include +#include #include +#include + namespace Dali { namespace Internal @@ -53,6 +59,43 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_REN } // unnamed namespace #endif +namespace +{ +inline Graphics::Rect2D RecalculateScissorArea(Graphics::Rect2D scissorArea, int orientation, Rect viewportRect) +{ + Graphics::Rect2D newScissorArea; + + if(orientation == 90) + { + newScissorArea.x = viewportRect.height - (scissorArea.y + scissorArea.height); + newScissorArea.y = scissorArea.x; + newScissorArea.width = scissorArea.height; + newScissorArea.height = scissorArea.width; + } + else if(orientation == 180) + { + newScissorArea.x = viewportRect.width - (scissorArea.x + scissorArea.width); + newScissorArea.y = viewportRect.height - (scissorArea.y + scissorArea.height); + newScissorArea.width = scissorArea.width; + newScissorArea.height = scissorArea.height; + } + else if(orientation == 270) + { + newScissorArea.x = scissorArea.y; + newScissorArea.y = viewportRect.width - (scissorArea.x + scissorArea.width); + newScissorArea.width = scissorArea.height; + newScissorArea.height = scissorArea.width; + } + else + { + newScissorArea.x = scissorArea.x; + newScissorArea.y = scissorArea.y; + newScissorArea.width = scissorArea.width; + newScissorArea.height = scissorArea.height; + } + return newScissorArea; +} +} // namespace /** * Structure to contain internal data */ @@ -62,11 +105,9 @@ struct RenderManager::Impl Integration::DepthBufferAvailable depthBufferAvailableParam, Integration::StencilBufferAvailable stencilBufferAvailableParam, Integration::PartialUpdateAvailable partialUpdateAvailableParam) - : context(graphicsController.GetGlAbstraction(), &sceneContextContainer), - currentContext(&context), - graphicsController(graphicsController), + : graphicsController(graphicsController), renderQueue(), - renderAlgorithms(), + renderAlgorithms(graphicsController), frameCount(0u), renderBufferIndex(SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX), rendererContainer(), @@ -75,13 +116,17 @@ struct RenderManager::Impl frameBufferContainer(), lastFrameWasRendered(false), programController(graphicsController), + shaderCache(graphicsController), depthBufferAvailable(depthBufferAvailableParam), stencilBufferAvailable(stencilBufferAvailableParam), partialUpdateAvailable(partialUpdateAvailableParam) { // 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 = std::make_unique(); threadPool->Initialize(1u); + + uniformBufferManager = std::make_unique(&graphicsController); + pipelineCache = std::make_unique(graphicsController); } ~Impl() @@ -91,7 +136,7 @@ struct RenderManager::Impl void AddRenderTracker(Render::RenderTracker* renderTracker) { - DALI_ASSERT_DEBUG(renderTracker != NULL); + DALI_ASSERT_DEBUG(renderTracker != nullptr); mRenderTrackers.PushBack(renderTracker); } @@ -100,33 +145,6 @@ struct RenderManager::Impl mRenderTrackers.EraseObject(renderTracker); } - Context* CreateSceneContext() - { - Context* context = new Context(graphicsController.GetGlAbstraction()); - sceneContextContainer.PushBack(context); - return context; - } - - void DestroySceneContext(Context* sceneContext) - { - auto iter = std::find(sceneContextContainer.Begin(), sceneContextContainer.End(), sceneContext); - if(iter != sceneContextContainer.End()) - { - (*iter)->GlContextDestroyed(); - sceneContextContainer.Erase(iter); - } - } - - Context* ReplaceSceneContext(Context* oldSceneContext) - { - Context* newContext = new Context(graphicsController.GetGlAbstraction()); - - oldSceneContext->GlContextDestroyed(); - - std::replace(sceneContextContainer.begin(), sceneContextContainer.end(), oldSceneContext, newContext); - return newContext; - } - void UpdateTrackers() { for(auto&& iter : mRenderTrackers) @@ -136,12 +154,8 @@ struct RenderManager::Impl } // 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 sceneContextContainer; ///< List of owned contexts holding the GL state per scene - Graphics::Controller& graphicsController; - RenderQueue renderQueue; ///< A message queue for receiving messages from the update-thread. + 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 @@ -161,15 +175,19 @@ struct RenderManager::Impl OwnerContainer mRenderTrackers; ///< List of render trackers - ProgramController programController; ///< Owner of the GL programs + 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 binded textures + Vector boundTextures; ///< The textures bound for rendering + Vector textureDependencyList; ///< The dependency list of bound textures }; RenderManager* RenderManager::New(Graphics::Controller& graphicsController, @@ -177,8 +195,8 @@ RenderManager* RenderManager::New(Graphics::Controller& graphicsCo Integration::StencilBufferAvailable stencilBufferAvailable, Integration::PartialUpdateAvailable partialUpdateAvailable) { - RenderManager* manager = new RenderManager; - manager->mImpl = new Impl(graphicsController, + auto* manager = new RenderManager; + manager->mImpl = new Impl(graphicsController, depthBufferAvailable, stencilBufferAvailable, partialUpdateAvailable); @@ -200,54 +218,14 @@ RenderQueue& RenderManager::GetRenderQueue() return mImpl->renderQueue; } -void RenderManager::ContextCreated() -{ - 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) { - mImpl->programController.SetShaderSaver(upstream); } void RenderManager::AddRenderer(OwnerPointer& renderer) { // Initialize the renderer as we are now in render thread - renderer->Initialize(mImpl->context, mImpl->programController); + renderer->Initialize(mImpl->graphicsController, mImpl->programController, mImpl->shaderCache, *(mImpl->uniformBufferManager.get()), *(mImpl->pipelineCache.get())); mImpl->rendererContainer.PushBack(renderer.Release()); } @@ -259,6 +237,7 @@ void RenderManager::RemoveRenderer(Render::Renderer* renderer) void RenderManager::AddSampler(OwnerPointer& sampler) { + sampler->Initialize(mImpl->graphicsController); mImpl->samplerContainer.PushBack(sampler.Release()); } @@ -269,7 +248,7 @@ void RenderManager::RemoveSampler(Render::Sampler* sampler) void RenderManager::AddTexture(OwnerPointer& texture) { - texture->Initialize(mImpl->context); + texture->Initialize(mImpl->graphicsController); mImpl->textureContainer.PushBack(texture.Release()); } @@ -277,75 +256,68 @@ void RenderManager::RemoveTexture(Render::Texture* texture) { DALI_ASSERT_DEBUG(NULL != texture); - // Find the texture, use reference to pointer so we can do the erase safely - for(auto&& iter : mImpl->textureContainer) + // Find the texture, use std::find so we can do the erase safely + auto iter = std::find(mImpl->textureContainer.begin(), mImpl->textureContainer.end(), texture); + + if(iter != mImpl->textureContainer.end()) { - if(iter == texture) - { - texture->Destroy(mImpl->context); - mImpl->textureContainer.Erase(&iter); // Texture found; now destroy it - return; - } + texture->Destroy(); + mImpl->textureContainer.Erase(iter); // Texture found; now destroy it } } void RenderManager::UploadTexture(Render::Texture* texture, PixelDataPtr pixelData, const Texture::UploadParams& params) { - texture->Upload(mImpl->context, pixelData, params); + texture->Upload(pixelData, params); } void RenderManager::GenerateMipmaps(Render::Texture* texture) { - texture->GenerateMipmaps(mImpl->context); + texture->GenerateMipmaps(); } 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) { - 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& frameBuffer) { Render::FrameBuffer* frameBufferPtr = frameBuffer.Release(); mImpl->frameBufferContainer.PushBack(frameBufferPtr); - frameBufferPtr->Initialize(mImpl->context); + frameBufferPtr->Initialize(mImpl->graphicsController); } 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) { - scene->Initialize(*mImpl->CreateSceneContext()); + scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable); mImpl->sceneContainer.push_back(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()) { @@ -355,23 +327,22 @@ void RenderManager::UninitializeScene(SceneGraph::Scene* scene) void RenderManager::SurfaceReplaced(SceneGraph::Scene* scene) { - Context* newContext = mImpl->ReplaceSceneContext(scene->GetContext()); - scene->Initialize(*newContext); + scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable); } void RenderManager::AttachColorTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel, uint32_t layer) { - frameBuffer->AttachColorTexture(mImpl->context, texture, mipmapLevel, layer); + frameBuffer->AttachColorTexture(texture, mipmapLevel, layer); } void RenderManager::AttachDepthTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel) { - frameBuffer->AttachDepthTexture(mImpl->context, texture, mipmapLevel); + frameBuffer->AttachDepthTexture(texture, mipmapLevel); } void RenderManager::AttachDepthStencilTextureToFrameBuffer(Render::FrameBuffer* frameBuffer, Render::Texture* texture, uint32_t mipmapLevel) { - frameBuffer->AttachDepthStencilTexture(mImpl->context, texture, mipmapLevel); + frameBuffer->AttachDepthStencilTexture(texture, mipmapLevel); } void RenderManager::AddVertexBuffer(OwnerPointer& vertexBuffer) @@ -406,12 +377,17 @@ void RenderManager::AddGeometry(OwnerPointer& 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) { - DALI_ASSERT_DEBUG(NULL != geometry); + DALI_ASSERT_DEBUG(nullptr != geometry); // Find the geometry for(auto&& iter : mImpl->geometryContainer) @@ -426,7 +402,7 @@ void RenderManager::AttachVertexBuffer(Render::Geometry* geometry, Render::Verte 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) @@ -454,17 +430,12 @@ 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) { 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; @@ -473,9 +444,9 @@ void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear 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; @@ -487,63 +458,15 @@ void RenderManager::PreRender(Integration::RenderStatus& status, bool 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->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent(); - } - - // Clear the current cached program when the context is switched - mImpl->programController.ClearCurrentProgram(); - } - // 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); } } } -void RenderManager::PreRender(Integration::Scene& scene, std::vector>& damagedRects) +void RenderManager::PreRender(Integration::RenderStatus& status, Integration::Scene& scene, std::vector>& damagedRects) { if(mImpl->partialUpdateAvailable != Integration::PartialUpdateAvailable::TRUE) { @@ -556,14 +479,18 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& if(sceneObject->IsRenderingSkipped()) { // We don't need to calculate dirty rects + status.SetNeedsUpdate(false); return; } + status.SetNeedsUpdate(true); + class DamagedRectsCleaner { public: - DamagedRectsCleaner(std::vector>& damagedRects) + explicit DamagedRectsCleaner(std::vector>& damagedRects, Rect& surfaceRect) : mDamagedRects(damagedRects), + mSurfaceRect(surfaceRect), mCleanOnReturn(true) { } @@ -578,18 +505,20 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& if(mCleanOnReturn) { mDamagedRects.clear(); + mDamagedRects.push_back(mSurfaceRect); } } private: std::vector>& mDamagedRects; + Rect mSurfaceRect; bool mCleanOnReturn; }; 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); // 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()); @@ -599,8 +528,8 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& dirtyRect.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); @@ -662,50 +591,78 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& for(RenderListContainer::SizeType index = 0u; index < count; ++index) { const RenderList* renderList = instruction.GetRenderList(index); - if(renderList && !renderList->IsEmpty()) + 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, do early exit and clean the damaged rect array + if(item.mUpdateSize == Vector3::ZERO) + { + return; + } - 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); + 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; + + rect = RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, item.mUpdateSize, viewportRect.width, viewportRect.height); + if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty()) + { + 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); + + int c = 1; + while(++dirtyRectPos != itemsDirtyRects.end()) + { + if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer) + { + break; + } + + dirtyRectPos->visited = true; + Rect& dirtRect = dirtyRectPos->rect; + rect.Merge(dirtRect); + + c++; + if(c > 3) // no more then 3 previous rects + { + itemsDirtyRects.erase(dirtyRectPos); + break; + } + } - rect = item.CalculateViewportSpaceAABB(item.mUpdateSize, viewportRect.width, viewportRect.height); - if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty()) + damagedRects.push_back(rect); + } + } + else { - 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. + // 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. - // 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); - - int c = 1; - while(++dirtyRectPos != itemsDirtyRects.end()) + while(dirtyRectPos != itemsDirtyRects.end()) { if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer) { @@ -713,36 +670,17 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& } dirtyRectPos->visited = true; - Rect& dirtRect = dirtyRectPos->rect; - rect.Merge(dirtRect); - - c++; - if(c > 3) // no more then 3 previous rects - { - itemsDirtyRects.erase(dirtyRectPos); - break; - } + dirtyRectPos++; } - - 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()) - { - if(dirtyRectPos->node != item.mNode || dirtyRectPos->renderer != item.mRenderer) - { - break; - } + } - dirtyRectPos->visited = true; - dirtyRectPos++; - } - } + // Reset updated flag from the root + Layer* sourceLayer = renderList->GetSourceLayer(); + if(sourceLayer) + { + sourceLayer->SetUpdatedTree(false); } } } @@ -778,11 +716,33 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo, Rect& clippingRect) { + 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; + + 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) { RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i); @@ -796,57 +756,85 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: status.SetNeedsPostRender(true); Rect viewportRect; - Vector4 clearColor; - if(instruction.mIsClearColorSet) - { - clearColor = instruction.mClearColor; - } - else - { - clearColor = Dali::RenderTask::DEFAULT_CLEAR_COLOR; - } - - Rect surfaceRect = sceneObject->GetSurfaceRect(); - int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation(); + int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation(); + // @todo Should these be part of scene? Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable; + 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->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent(); + continue; } + } + + auto& clearValues = instruction.mFrameBuffer->GetGraphicsRenderPassClearValues(); - // Clear the current cached program when the context is switched - mImpl->programController.ClearCurrentProgram(); + // 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; } + + 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 @@ -854,54 +842,19 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: 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)); + 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)) { // Offscreen buffer rendering if(instruction.mIsViewportSet) { - // For glViewport the lower-left corner is (0,0) + // 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); } @@ -916,7 +869,7 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: // 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) + // 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); } @@ -927,18 +880,16 @@ 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; + /*** 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); - } if(!clippingRect.IsEmpty()) { @@ -950,139 +901,77 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: clearFullFrameRect = false; } - mImpl->currentContext->Viewport(viewportRect.x, viewportRect.y, viewportRect.width, viewportRect.height); - + 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(!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); - } - 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); + scissorArea = {clippingRect.x, clippingRect.y, uint32_t(clippingRect.width), uint32_t(clippingRect.height)}; } } - 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, viewportRect); + + // 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()) - { - // 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->graphicsController.GetGlContextHelperAbstraction().WaitClient(); - - // Clear the dependency list - mImpl->textureDependencyList.Clear(); - } - else - { - // Worker thread lambda function - auto& glContextHelperAbstraction = mImpl->graphicsController.GetGlContextHelperAbstraction(); - 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(); - } - } - } - } - + viewportRect, + clippingRect, + surfaceOrientation); + + 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) { - // 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->graphicsController.GetGlSyncAbstraction()); - instruction.mRenderTracker = nullptr; // Only create once. - } - - if(renderToFbo) - { - mImpl->currentContext->Flush(); + syncObject = instruction.mRenderTracker->CreateSyncObject(mImpl->graphicsController); + instruction.mRenderTracker = nullptr; } + mainCommandBuffer->EndRenderPass(syncObject); } + mImpl->renderAlgorithms.SubmitCommandBuffer(); - GLenum attachments[] = {GL_DEPTH, GL_STENCIL}; - mImpl->currentContext->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); -} + std::sort(targetstoPresent.begin(), targetstoPresent.end()); -void RenderManager::PostRender(bool uploadOnly) -{ - if(!uploadOnly) + Graphics::RenderTarget* rt = nullptr; + for(auto& target : targetstoPresent) { - if(mImpl->currentContext->IsSurfacelessContextSupported()) + if(target != rt) { - mImpl->graphicsController.GetGlContextHelperAbstraction().MakeSurfacelessContextCurrent(); + mImpl->graphicsController.PresentRenderTarget(target); + rt = target; } - - GLenum attachments[] = {GL_DEPTH, GL_STENCIL}; - mImpl->context.InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); } +} - //Notify RenderGeometries that rendering has finished +void RenderManager::PostRender(bool uploadOnly) +{ + // Notify RenderGeometries that rendering has finished for(auto&& iter : mImpl->geometryContainer) { iter->OnRenderFinished(); @@ -1091,9 +980,9 @@ void RenderManager::PostRender(bool uploadOnly) 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;