X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Frender%2Fcommon%2Frender-manager.cpp;h=6933ee9282f826d3917e69d6d61908583607a40f;hb=1eac313ff98060f49ae6451a5365093a6024c017;hp=6f28e025b5532303506d0e25f0e325e7b0fe5002;hpb=bc441d8018f9d0b465c3e5ce12b2ea9a0c6fe169;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 6f28e02..6933ee9 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 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,6 +24,7 @@ // INTERNAL INCLUDES #include #include +#include #include @@ -31,6 +32,8 @@ #include #include +#include + #include #include #include @@ -41,7 +44,7 @@ #include #include #include -#include +#include #include #include @@ -61,7 +64,7 @@ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_REN namespace { -inline Graphics::Rect2D RecalculateScissorArea(Graphics::Rect2D scissorArea, int orientation, Rect viewportRect) +inline Graphics::Rect2D RecalculateScissorArea(const Graphics::Rect2D& scissorArea, int orientation, const Rect& viewportRect) { Graphics::Rect2D newScissorArea; @@ -95,6 +98,33 @@ inline Graphics::Rect2D RecalculateScissorArea(Graphics::Rect2D scissorArea, int } return newScissorArea; } + +inline Rect CalculateUpdateArea(RenderItem& item, BufferIndex renderBufferIndex, const Rect& viewportRect) +{ + Vector4 updateArea; + if(item.mNode && item.mNode->IsTextureUpdateAreaUsed() && item.mRenderer) + { + updateArea = item.mRenderer->GetTextureUpdateArea(); + } + else + { + updateArea = item.mRenderer ? item.mRenderer->GetVisualTransformedUpdateArea(renderBufferIndex, item.mUpdateArea) : item.mUpdateArea; + } + + return RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3(updateArea.x, updateArea.y, 0.0f), Vector3(updateArea.z, updateArea.w, 0.0f), viewportRect.width, viewportRect.height); +} + +inline void AlignDamagedRect(Rect& rect) +{ + 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; +} } // namespace /** @@ -107,15 +137,7 @@ struct RenderManager::Impl Integration::StencilBufferAvailable stencilBufferAvailableParam, Integration::PartialUpdateAvailable partialUpdateAvailableParam) : graphicsController(graphicsController), - renderQueue(), renderAlgorithms(graphicsController), - frameCount(0u), - renderBufferIndex(SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX), - rendererContainer(), - samplerContainer(), - textureContainer(), - frameBufferContainer(), - lastFrameWasRendered(false), programController(graphicsController), shaderCache(graphicsController), depthBufferAvailable(depthBufferAvailableParam), @@ -133,6 +155,7 @@ struct RenderManager::Impl ~Impl() { threadPool.reset(nullptr); // reset now to maintain correct destruction order + rendererContainer.Clear(); // clear now before the pipeline cache is deleted } void AddRenderTracker(Render::RenderTracker* renderTracker) @@ -155,26 +178,19 @@ struct RenderManager::Impl } // the order is important for destruction, - 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 + 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 - Render::RenderAlgorithms renderAlgorithms; ///< The RenderAlgorithms object is used to action the renders required by a RenderInstruction + OrderedSet samplerContainer; ///< List of owned samplers + OrderedSet frameBufferContainer; ///< List of owned framebuffers + OrderedSet vertexBufferContainer; ///< List of owned vertex buffers + OrderedSet geometryContainer; ///< List of owned Geometries + OwnerKeyContainer rendererContainer; ///< List of owned renderers + OwnerKeyContainer textureContainer; ///< List of owned textures - uint32_t frameCount; ///< The current frame count - BufferIndex renderBufferIndex; ///< The index of the buffer to read from; this is opposite of the "update" buffer - - OwnerContainer rendererContainer; ///< List of owned renderers - OwnerContainer samplerContainer; ///< List of owned samplers - OwnerContainer textureContainer; ///< List of owned textures - OwnerContainer frameBufferContainer; ///< List of owned framebuffers - OwnerContainer vertexBufferContainer; ///< List of owned vertex buffers - OwnerContainer geometryContainer; ///< List of owned Geometries - - bool lastFrameWasRendered; ///< Keeps track of the last frame being rendered due to having render instructions - - OwnerContainer mRenderTrackers; ///< List of render trackers + OrderedSet mRenderTrackers; ///< List of owned render trackers ProgramController programController; ///< Owner of the programs Render::ShaderCache shaderCache; ///< The cache for the graphics shaders @@ -186,10 +202,13 @@ struct RenderManager::Impl 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 + std::unique_ptr threadPool; ///< The thread pool + Vector updatedTextures{}; ///< The updated texture list + + uint32_t frameCount{0u}; ///< The current frame count + BufferIndex renderBufferIndex{SceneGraphBuffers::INITIAL_UPDATE_BUFFER_INDEX}; ///< The index of the buffer to read from; + bool lastFrameWasRendered{false}; ///< Keeps track of the last frame being rendered due to having render instructions bool commandBufferSubmitted{false}; }; @@ -225,17 +244,17 @@ void RenderManager::SetShaderSaver(ShaderSaver& upstream) { } -void RenderManager::AddRenderer(OwnerPointer& renderer) +void RenderManager::AddRenderer(const Render::RendererKey& renderer) { // Initialize the renderer as we are now in render thread renderer->Initialize(mImpl->graphicsController, mImpl->programController, mImpl->shaderCache, *(mImpl->uniformBufferManager.get()), *(mImpl->pipelineCache.get())); - mImpl->rendererContainer.PushBack(renderer.Release()); + mImpl->rendererContainer.PushBack(renderer); } -void RenderManager::RemoveRenderer(Render::Renderer* renderer) +void RenderManager::RemoveRenderer(const Render::RendererKey& renderer) { - mImpl->rendererContainer.EraseObject(renderer); + mImpl->rendererContainer.EraseKey(renderer); } void RenderManager::AddSampler(OwnerPointer& sampler) @@ -249,34 +268,68 @@ void RenderManager::RemoveSampler(Render::Sampler* sampler) mImpl->samplerContainer.EraseObject(sampler); } -void RenderManager::AddTexture(OwnerPointer& texture) +void RenderManager::AddTexture(const Render::TextureKey& textureKey) { - texture->Initialize(mImpl->graphicsController); - mImpl->textureContainer.PushBack(texture.Release()); + DALI_ASSERT_DEBUG(textureKey && "Trying to add empty texture key"); + + textureKey->Initialize(mImpl->graphicsController, *this); + mImpl->textureContainer.PushBack(textureKey); + mImpl->updatedTextures.PushBack(textureKey); } -void RenderManager::RemoveTexture(Render::Texture* texture) +void RenderManager::RemoveTexture(const Render::TextureKey& textureKey) { - DALI_ASSERT_DEBUG(NULL != texture); + DALI_ASSERT_DEBUG(textureKey && "Trying to remove empty texture key"); - // Find the texture, use std::find so we can do the erase safely - auto iter = std::find(mImpl->textureContainer.begin(), mImpl->textureContainer.end(), texture); + // Find the texture, use std::find so we can do the erase by iterator safely + auto iter = std::find(mImpl->textureContainer.Begin(), mImpl->textureContainer.End(), textureKey); - if(iter != mImpl->textureContainer.end()) + if(iter != mImpl->textureContainer.End()) { - texture->Destroy(); + 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 Graphics::UploadParams& params) { - texture->Upload(pixelData, params); + DALI_ASSERT_DEBUG(textureKey && "Trying to upload to empty texture key"); + textureKey->Upload(pixelData, params); + + mImpl->updatedTextures.PushBack(textureKey); } -void RenderManager::GenerateMipmaps(Render::Texture* texture) +void RenderManager::GenerateMipmaps(const Render::TextureKey& textureKey) { - texture->GenerateMipmaps(); + DALI_ASSERT_DEBUG(textureKey && "Trying to generate mipmaps on empty texture key"); + textureKey->GenerateMipmaps(); + + mImpl->updatedTextures.PushBack(textureKey); +} + +void RenderManager::SetTextureSize(const Render::TextureKey& textureKey, const Dali::ImageDimensions& size) +{ + DALI_ASSERT_DEBUG(textureKey && "Trying to set size on empty texture key"); + textureKey->SetWidth(size.GetWidth()); + textureKey->SetHeight(size.GetHeight()); + + mImpl->updatedTextures.PushBack(textureKey); +} + +void RenderManager::SetTextureFormat(const Render::TextureKey& textureKey, Dali::Pixel::Format pixelFormat) +{ + DALI_ASSERT_DEBUG(textureKey && "Trying to set pixel format on empty texture key"); + textureKey->SetPixelFormat(pixelFormat); + + mImpl->updatedTextures.PushBack(textureKey); +} + +void RenderManager::SetTextureUpdated(const Render::TextureKey& textureKey) +{ + DALI_ASSERT_DEBUG(textureKey && "Trying to set updated on empty texture key"); + textureKey->SetUpdated(true); + + mImpl->updatedTextures.PushBack(textureKey); } void RenderManager::SetFilterMode(Render::Sampler* sampler, uint32_t minFilterMode, uint32_t magFilterMode) @@ -303,10 +356,10 @@ void RenderManager::RemoveFrameBuffer(Render::FrameBuffer* frameBuffer) { DALI_ASSERT_DEBUG(nullptr != frameBuffer); - // Find the framebuffer, use std:find so we can safely do the erase - auto iter = std::find(mImpl->frameBufferContainer.begin(), mImpl->frameBufferContainer.end(), frameBuffer); + // Find the framebuffer, use OrderedSet.Find so we can safely do the erase + auto iter = mImpl->frameBufferContainer.Find(frameBuffer); - if(iter != mImpl->frameBufferContainer.end()) + if(iter != mImpl->frameBufferContainer.End()) { frameBuffer->Destroy(); mImpl->frameBufferContainer.Erase(iter); // frameBuffer found; now destroy it @@ -317,10 +370,12 @@ void RenderManager::InitializeScene(SceneGraph::Scene* scene) { scene->Initialize(mImpl->graphicsController, mImpl->depthBufferAvailable, mImpl->stencilBufferAvailable); mImpl->sceneContainer.push_back(scene); + mImpl->uniformBufferManager->RegisterScene(scene); } void RenderManager::UninitializeScene(SceneGraph::Scene* scene) { + mImpl->uniformBufferManager->UnregisterScene(scene); auto iter = std::find(mImpl->sceneContainer.begin(), mImpl->sceneContainer.end(), scene); if(iter != mImpl->sceneContainer.end()) { @@ -348,6 +403,11 @@ void RenderManager::AttachDepthStencilTextureToFrameBuffer(Render::FrameBuffer* frameBuffer->AttachDepthStencilTexture(texture, mipmapLevel); } +void RenderManager::SetMultiSamplingLevelToFrameBuffer(Render::FrameBuffer* frameBuffer, uint8_t multiSamplingLevel) +{ + frameBuffer->SetMultiSamplingLevel(multiSamplingLevel); +} + void RenderManager::AddVertexBuffer(OwnerPointer& vertexBuffer) { mImpl->vertexBufferContainer.PushBack(vertexBuffer.Release()); @@ -368,7 +428,17 @@ void RenderManager::SetVertexBufferData(Render::VertexBuffer* vertexBuffer, Owne vertexBuffer->SetData(data.Release(), size); } -void RenderManager::SetIndexBuffer(Render::Geometry* geometry, Dali::Vector& indices) +void RenderManager::SetVertexBufferUpdateCallback(Render::VertexBuffer* vertexBuffer, Dali::VertexBufferUpdateCallback* callback) +{ + vertexBuffer->SetVertexBufferUpdateCallback(callback); +} + +void RenderManager::SetIndexBuffer(Render::Geometry* geometry, Render::Geometry::Uint16ContainerType& indices) +{ + geometry->SetIndexBuffer(indices); +} + +void RenderManager::SetIndexBuffer(Render::Geometry* geometry, Render::Geometry::Uint32ContainerType& indices) { geometry->SetIndexBuffer(indices); } @@ -380,42 +450,17 @@ void RenderManager::AddGeometry(OwnerPointer& geometry) void RenderManager::RemoveGeometry(Render::Geometry* geometry) { - auto iter = std::find(mImpl->geometryContainer.begin(), mImpl->geometryContainer.end(), geometry); - - if(iter != mImpl->geometryContainer.end()) - { - mImpl->geometryContainer.Erase(iter); - } + mImpl->geometryContainer.EraseObject(geometry); } void RenderManager::AttachVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer) { - DALI_ASSERT_DEBUG(nullptr != geometry); - - // Find the geometry - for(auto&& iter : mImpl->geometryContainer) - { - if(iter == geometry) - { - iter->AddVertexBuffer(vertexBuffer); - break; - } - } + geometry->AddVertexBuffer(vertexBuffer); } void RenderManager::RemoveVertexBuffer(Render::Geometry* geometry, Render::VertexBuffer* vertexBuffer) { - DALI_ASSERT_DEBUG(nullptr != geometry); - - // Find the geometry - for(auto&& iter : mImpl->geometryContainer) - { - if(iter == geometry) - { - iter->RemoveVertexBuffer(vertexBuffer); - break; - } - } + geometry->RemoveVertexBuffer(vertexBuffer); } void RenderManager::SetGeometryType(Render::Geometry* geometry, uint32_t geometryType) @@ -436,9 +481,7 @@ void RenderManager::RemoveRenderTracker(Render::RenderTracker* renderTracker) void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear) { DALI_PRINT_RENDER_START(mImpl->renderBufferIndex); - - // Rollback - mImpl->uniformBufferManager->GetUniformBufferViewPool(mImpl->renderBufferIndex)->Rollback(); + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "\n\nNewFrame %d\n", mImpl->frameCount); // Increment the frame count at the beginning of each frame ++mImpl->frameCount; @@ -446,13 +489,13 @@ void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear // Process messages queued during previous update mImpl->renderQueue.ProcessMessages(mImpl->renderBufferIndex); - uint32_t count = 0u; + uint32_t totalInstructionCount = 0u; for(auto& i : mImpl->sceneContainer) { - count += i->GetRenderInstructions().Count(mImpl->renderBufferIndex); + totalInstructionCount += i->GetRenderInstructions().Count(mImpl->renderBufferIndex); } - const bool haveInstructions = count > 0u; + const bool haveInstructions = totalInstructionCount > 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"); @@ -468,6 +511,9 @@ void RenderManager::PreRender(Integration::RenderStatus& status, bool forceClear } } + // Reset pipeline cache before rendering + mImpl->pipelineCache->PreRender(); + mImpl->commandBufferSubmitted = false; } @@ -481,7 +527,7 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& Internal::Scene& sceneInternal = GetImplementation(scene); SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); - if(sceneObject->IsRenderingSkipped()) + if(!sceneObject || sceneObject->IsRenderingSkipped()) { // We don't need to calculate dirty rects return; @@ -521,13 +567,22 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& // Clean collected dirty/damaged rects on exit if 3d layer or 3d node or other conditions. 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 = sceneObject->GetItemsDirtyRects(); - for(DirtyRect& dirtyRect : itemsDirtyRects) + Scene::ItemsDirtyRectsContainer& itemsDirtyRects = sceneObject->GetItemsDirtyRects(); + + if(!sceneObject->IsPartialUpdateEnabled()) + { + // Clear all dirty rects + // The rects will be added when partial updated is enabled again + itemsDirtyRects.clear(); + return; + } + + // Mark previous dirty rects in the std::unordered_map. + for(auto& dirtyRectPair : itemsDirtyRects) { - dirtyRect.visited = false; + dirtyRectPair.second.visited = false; } uint32_t instructionCount = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex); @@ -537,37 +592,36 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& 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; @@ -577,7 +631,8 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& 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 @@ -601,50 +656,59 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& for(uint32_t listIndex = 0u; listIndex < listCount; ++listIndex) { RenderItem& item = renderList->GetItem(listIndex); - // If the item does 3D transformation, do early exit and clean the damaged rect array + // If the item does 3D transformation, make full update if(item.mUpdateArea == Vector4::ZERO) { - return; + cleanDamagedRect = true; + + // 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 rect; - DirtyRect dirtyRect(item.mNode, item.mRenderer, rect); + 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, item.mNode))))) + (item.mNode->Updated() || (item.mRenderer && item.mRenderer->Updated())))) { item.mIsUpdated = false; - rect = RenderItem::CalculateViewportSpaceAABB(item.mModelViewMatrix, Vector3(item.mUpdateArea.x, item.mUpdateArea.y, 0.0f), Vector3(item.mUpdateArea.z, item.mUpdateArea.w, 0.0f), viewportRect.width, viewportRect.height); + rect = CalculateUpdateArea(item, mImpl->renderBufferIndex, viewportRect); 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; + AlignDamagedRect(rect); // Found valid dirty rect. - dirtyRect.rect = rect; - auto dirtyRectPos = std::lower_bound(itemsDirtyRects.begin(), itemsDirtyRects.end(), dirtyRect); - - if(dirtyRectPos != itemsDirtyRects.end() && dirtyRectPos->node == item.mNode && dirtyRectPos->renderer == item.mRenderer) + auto dirtyRectPos = itemsDirtyRects.find(dirtyRectKey); + if(dirtyRectPos != itemsDirtyRects.end()) { + Rect currentRect = rect; + // Same item, merge it with the previous rect - rect.Merge(dirtyRectPos->rect); + rect.Merge(dirtyRectPos->second.rect); - // Replace the rect - dirtyRectPos->visited = true; - dirtyRectPos->rect = dirtyRect.rect; + // Replace the rect as current + dirtyRectPos->second.visited = true; + dirtyRectPos->second.rect = currentRect; } else { - // Else, just insert the new dirtyrect in the correct position - itemsDirtyRects.insert(dirtyRectPos, dirtyRect); + // Else, just insert the new dirtyrect + itemsDirtyRects.insert({dirtyRectKey, rect}); } damagedRects.push_back(rect); @@ -654,10 +718,22 @@ void RenderManager::PreRender(Integration::Scene& scene, std::vector>& { // 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); - if(dirtyRectPos != itemsDirtyRects.end() && dirtyRectPos->node == item.mNode && dirtyRectPos->renderer == item.mRenderer) + auto dirtyRectPos = itemsDirtyRects.find(dirtyRectKey); + if(dirtyRectPos != itemsDirtyRects.end()) + { + dirtyRectPos->second.visited = true; + } + else { - dirtyRectPos->visited = true; + // The item is not in the list for some reason. Add the current rect! + rect = CalculateUpdateArea(item, mImpl->renderBufferIndex, viewportRect); + if(rect.IsValid() && rect.Intersect(viewportRect) && !rect.IsEmpty()) + { + AlignDamagedRect(rect); + + itemsDirtyRects.insert({dirtyRectKey, rect}); + } + cleanDamagedRect = true; // And make full update at this frame } } } @@ -668,38 +744,40 @@ 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(sceneObject->IsNeededFullUpdate()) + { + cleanDamagedRect = true; // And make full update at this frame + } - // Reset updated flag from the root - Layer* root = sceneObject->GetRoot(); - if(root) + if(!cleanDamagedRect) { - root->SetUpdatedTree(false); + damagedRectCleaner.SetCleanOnReturn(false); } } void RenderManager::RenderScene(Integration::RenderStatus& status, Integration::Scene& scene, bool renderToFbo) { - SceneGraph::Scene* sceneObject = GetImplementation(scene).GetSceneObject(); - Rect clippingRect = sceneObject->GetSurfaceRect(); + SceneGraph::Scene* sceneObject = GetImplementation(scene).GetSceneObject(); + if(!sceneObject) + { + return; + } + Rect clippingRect = sceneObject->GetSurfaceRect(); RenderScene(status, scene, renderToFbo, clippingRect); } @@ -718,8 +796,12 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: Internal::Scene& sceneInternal = GetImplementation(scene); SceneGraph::Scene* sceneObject = sceneInternal.GetSceneObject(); + if(!sceneObject) + { + return; + } - uint32_t count = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex); + uint32_t instructionCount = sceneObject->GetRenderInstructions().Count(mImpl->renderBufferIndex); std::vector targetstoPresent; @@ -732,10 +814,77 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: clippingRect = Rect(); } - // Prepare to lock and map standalone uniform buffer. - mImpl->uniformBufferManager->ReadyToLockUniformBuffer(mImpl->renderBufferIndex); + // Prefetch programs before we start rendering so reflection is + // ready, and we can pull exact size of UBO needed (no need to resize during drawing) + auto totalSizeCPU = 0u; + auto totalSizeGPU = 0u; + + for(uint32_t i = 0; i < instructionCount; ++i) + { + RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i); + + if((instruction.mFrameBuffer != nullptr && renderToFbo) || + (instruction.mFrameBuffer == nullptr && !renderToFbo)) + { + for(auto j = 0u; j < instruction.RenderListCount(); ++j) + { + const auto& renderList = instruction.GetRenderList(j); + for(auto k = 0u; k < renderList->Count(); ++k) + { + auto& item = renderList->GetItem(k); + if(item.mRenderer && item.mRenderer->NeedsProgram()) + { + // Prepare and store used programs for further processing + auto program = item.mRenderer->PrepareProgram(instruction); + if(program) + { + auto memoryRequirements = program->GetUniformBlocksMemoryRequirements(); + + totalSizeCPU += memoryRequirements.totalCpuSizeRequired; + totalSizeGPU += memoryRequirements.totalGpuSizeRequired; + } + } + } + } + } + } + + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Render scene (%s), CPU:%d GPU:%d\n", renderToFbo ? "Offscreen" : "Onscreen", totalSizeCPU, totalSizeGPU); + + auto& uboManager = mImpl->uniformBufferManager; + + uboManager->SetCurrentSceneRenderInfo(sceneObject, renderToFbo); + uboManager->Rollback(sceneObject, renderToFbo); - for(uint32_t i = 0; i < count; ++i) + // Respec UBOs for this frame (orphan buffers or double buffer in the GPU) + if(instructionCount) + { + uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, true)->ReSpecify(totalSizeCPU); + uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, false)->ReSpecify(totalSizeGPU); + } + +#if defined(DEBUG_ENABLED) + auto uniformBuffer1 = uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, true); + auto uniformBuffer2 = uboManager->GetUniformBufferForScene(sceneObject, renderToFbo, false); + if(uniformBuffer1) + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "CPU buffer: Offset(%d), Cap(%d)\n", uniformBuffer1->GetCurrentOffset(), uniformBuffer1->GetCurrentCapacity()); + } + else + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "CPU buffer: nil\n"); + } + if(uniformBuffer2) + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GPU buffer: Offset(%d), Cap(%d)\n", uniformBuffer2->GetCurrentOffset(), uniformBuffer2->GetCurrentCapacity()); + } + else + { + DALI_LOG_INFO(gLogFilter, Debug::Verbose, "GPU buffer: nil\n"); + } +#endif + + for(uint32_t i = 0; i < instructionCount; ++i) { RenderInstruction& instruction = sceneObject->GetRenderInstructions().At(mImpl->renderBufferIndex, i); @@ -749,7 +898,11 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: Rect viewportRect; - int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation(); + int32_t surfaceOrientation = sceneObject->GetSurfaceOrientation() + sceneObject->GetScreenOrientation(); + if(surfaceOrientation >= 360) + { + surfaceOrientation -= 360; + } // @todo Should these be part of scene? Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; @@ -832,15 +985,6 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: // this ensures we will set view and projection matrix once per program per camera mImpl->programController.ResetProgramMatrices(); - if(instruction.mFrameBuffer) - { - // 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->GetTexture(i0)); - } - } - if(!instruction.mIgnoreRenderToFbo && (instruction.mFrameBuffer != nullptr)) { // Offscreen buffer rendering @@ -908,7 +1052,7 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: // 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); + scissorArea = RecalculateScissorArea(scissorArea, surfaceOrientation, surfaceRect); // Begin render pass mainCommandBuffer->BeginRenderPass( @@ -922,18 +1066,15 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: float(viewportRect.width), float(viewportRect.height)}); - // Clear the list of bound textures - mImpl->boundTextures.Clear(); - mImpl->renderAlgorithms.ProcessRenderInstruction( instruction, mImpl->renderBufferIndex, depthBufferAvailable, stencilBufferAvailable, - mImpl->boundTextures, viewportRect, clippingRect, - surfaceOrientation); + surfaceOrientation, + Uint16Pair(surfaceRect.width, surfaceRect.height)); Graphics::SyncObject* syncObject{nullptr}; // If the render instruction has an associated render tracker (owned separately) @@ -947,8 +1088,8 @@ void RenderManager::RenderScene(Integration::RenderStatus& status, Integration:: mainCommandBuffer->EndRenderPass(syncObject); } - // Unlock standalone uniform buffer. - mImpl->uniformBufferManager->UnlockUniformBuffer(mImpl->renderBufferIndex); + // Flush UBOs + mImpl->uniformBufferManager->Flush(sceneObject, renderToFbo); mImpl->renderAlgorithms.SubmitCommandBuffer(); mImpl->commandBufferSubmitted = true; @@ -985,6 +1126,13 @@ void RenderManager::PostRender() iter->OnRenderFinished(); } + // Notify updated RenderTexture that rendering has finished + for(auto&& iter : mImpl->updatedTextures) + { + iter->OnRenderFinished(); + } + mImpl->updatedTextures.Clear(); + mImpl->UpdateTrackers(); uint32_t count = 0u;