From: adam.b Date: Tue, 18 Dec 2018 18:55:09 +0000 (+0000) Subject: Data buffer index centralized in the vulkan-graphics module, additional synchronizati... X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f3fa5d1ad5d213d39ff253fa2fadc511347dc41b;p=platform%2Fcore%2Fuifw%2Fdali-core.git Data buffer index centralized in the vulkan-graphics module, additional synchronization applied Currently, only vulkan-graphics module swaps data buffers. Anything else that has to use double buffering should query current data buffer index in order to stay in sync. The data buffers are swapped using Controller::SwapBuffers(). Signed-off-by: adam.b Change-Id: If4cdcd8e90ed519ca5381955322ec4b8184fdca1 --- diff --git a/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.cpp b/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.cpp index 7b120272b..c624969f8 100644 --- a/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.cpp +++ b/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.cpp @@ -59,33 +59,44 @@ void DescriptorSetAllocator::ResolveFreeDescriptorSets() { auto& graphics = mController.GetGraphics(); - for( auto& pool : mPoolSet[mBufferIndex] ) + const auto bufferIndex = mController.GetCurrentBufferIndex(); + for( auto& pool : mPoolSet[bufferIndex] ) { if( !pool.vkDescriptorSetsToBeFreed.empty() ) { // free unused descriptor sets - graphics.GetDevice().freeDescriptorSets( pool.vkPool, pool.vkDescriptorSetsToBeFreed ); - - // Update tracked descriptor sets - std::sort( pool.vkDescriptorSetsToBeFreed.begin(), pool.vkDescriptorSetsToBeFreed.end() ); - + std::vector existingDSToFree; auto freeIt = pool.vkDescriptorSetsToBeFreed.begin(); std::vector newList{}; std::for_each( pool.vkDescriptorSets.begin(), pool.vkDescriptorSets.end(), [&]( auto& item ) { - if( item != *freeIt ) + if( static_cast(item) <= static_cast(*freeIt) ) { - newList.emplace_back( item ); + if( item != *freeIt ) + { + newList.emplace_back( item ); + } + else + { + existingDSToFree.emplace_back( *freeIt ); + ++freeIt; + } } - else + else if( freeIt != pool.vkDescriptorSetsToBeFreed.end() ) { ++freeIt; } }); + + if( !existingDSToFree.empty() ) + { + graphics.GetDevice().freeDescriptorSets( pool.vkPool, existingDSToFree ); + } + pool.vkDescriptorSets = std::move( newList ); // update available number of descriptor - pool.available += uint32_t( pool.vkDescriptorSetsToBeFreed.size() ); + pool.available += uint32_t( existingDSToFree.size() ); // clear the free list pool.vkDescriptorSetsToBeFreed.clear(); @@ -136,7 +147,15 @@ void DescriptorSetAllocator::UpdateWithRequirements( { ResolveFreeDescriptorSets(); - auto& poolset = mPoolSet[mBufferIndex]; + const auto bufferIndex = mController.GetCurrentBufferIndex(); + + // clean pools dirty flags + for( auto& pool : mPoolSet[mController.GetCurrentBufferIndex()] ) + { + pool.dirty = false; + } + + auto& poolset = mPoolSet[bufferIndex]; // For each signature decide whether we should reallocate pool or not. // Newly created pool always reallocates @@ -268,7 +287,7 @@ bool DescriptorSetAllocator::AllocateDescriptorSets( DescriptorSetList& descriptorSets ) { // access correct pool - auto& poolset = mPoolSet[mBufferIndex]; + auto& poolset = mPoolSet[mController.GetCurrentBufferIndex()]; auto& retval = descriptorSets.descriptorSets; @@ -308,7 +327,7 @@ bool DescriptorSetAllocator::AllocateDescriptorSets( (*it).available -= uint32_t( result.size() ); descriptorSets.reserved.reset( new DescriptorSetList::Internal() ); descriptorSets.reserved->pool = (*it).vkPool; - descriptorSets.reserved->bufferIndex = mBufferIndex; + descriptorSets.reserved->bufferIndex = mController.GetCurrentBufferIndex(); descriptorSets.reserved->signature = (*it).signature; descriptorSets.reserved->poolUID = (*it).uid; @@ -354,7 +373,7 @@ void DescriptorSetAllocator::FreeDescriptorSets( std::vector& auto bufferIndex = list.reserved->bufferIndex; std::find_if( mPoolSet[bufferIndex].begin(), mPoolSet[bufferIndex].end(), [&]( Pool& pool ) { - if( pool.uid == list.reserved->poolUID ) + if( pool.uid == list.reserved->poolUID && pool.vkPool == list.reserved->pool ) { pool.vkDescriptorSetsToBeFreed.insert( pool.vkDescriptorSetsToBeFreed.end(), list.descriptorSets.begin(), list.descriptorSets.end() ); return true; @@ -364,33 +383,17 @@ void DescriptorSetAllocator::FreeDescriptorSets( std::vector& } } -void DescriptorSetAllocator::SwapBuffers() -{ - // clean pools dirty flags - for( auto& pools : mPoolSet ) - { - for( auto& pool : pools ) - { - pool.dirty = false; - } - } - mBufferIndex = (mBufferIndex+1) & 1; -} - void DescriptorSetAllocator::InvalidateAllDescriptorSets() { auto& graphics = mController.GetGraphics(); graphics.DeviceWaitIdle(); - for( auto& set : mPoolSet ) + for( auto& pool : mPoolSet[mController.GetCurrentBufferIndex()] ) { - for( auto& pool : set ) - { - graphics.GetDevice().destroyDescriptorPool( - pool.vkPool, - &mController.GetGraphics().GetAllocator("DESCRIPTORPOOL") ); - } - set.clear(); + graphics.GetDevice().destroyDescriptorPool( + pool.vkPool, + &mController.GetGraphics().GetAllocator("DESCRIPTORPOOL") ); } + mPoolSet[mController.GetCurrentBufferIndex()].clear(); } } // Namespace Internal diff --git a/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.h b/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.h index 9d599d7dd..c53a40f9f 100644 --- a/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.h +++ b/dali/graphics/vulkan/api/internal/vulkan-api-descriptor-set-allocator.h @@ -106,11 +106,6 @@ public: */ void FreeDescriptorSets( std::vector&& descriptorSets ); - /** - * Swaps internal buffers - */ - void SwapBuffers(); - /** * Invalidates and releases all descriptor sets forcing recreating pools. This may happen * due to DALi staying in idle state. @@ -186,8 +181,6 @@ private: using PoolSet = std::vector; std::array mPoolSet; - uint32_t mBufferIndex { 1u }; // Starts with 1 to match index of update thread in DALi - uint32_t mPoolUID { 0u }; }; diff --git a/dali/graphics/vulkan/api/vulkan-api-controller.cpp b/dali/graphics/vulkan/api/vulkan-api-controller.cpp index e2e2e6dba..5063aa2bc 100644 --- a/dali/graphics/vulkan/api/vulkan-api-controller.cpp +++ b/dali/graphics/vulkan/api/vulkan-api-controller.cpp @@ -720,7 +720,6 @@ struct Controller::Impl mGraphics.GetSwapchainForFBID(0)->ResetAllCommandBuffers(); - mGraphics.CollectGarbage(); mGraphics.CollectGarbage(); mDescriptorSetAllocator->InvalidateAllDescriptorSets(); @@ -733,8 +732,7 @@ struct Controller::Impl void SwapBuffers() { - mBufferIndex = (mBufferIndex+1)%1; - mDescriptorSetAllocator->SwapBuffers(); + mGraphics.SwapBuffers(); } uint32_t GetSwapchainBufferCount() @@ -1026,6 +1024,10 @@ uint32_t Controller::GetSwapchainBufferCount() return mImpl->GetSwapchainBufferCount(); } +uint32_t Controller::GetCurrentBufferIndex() +{ + return mImpl->mGraphics.GetCurrentBufferIndex(); +} } // namespace VulkanAPI } // namespace Graphics diff --git a/dali/graphics/vulkan/api/vulkan-api-controller.h b/dali/graphics/vulkan/api/vulkan-api-controller.h index 8e593958a..399bbef61 100644 --- a/dali/graphics/vulkan/api/vulkan-api-controller.h +++ b/dali/graphics/vulkan/api/vulkan-api-controller.h @@ -201,6 +201,8 @@ public: // VULKAN only + uint32_t GetCurrentBufferIndex(); + public: Vulkan::Graphics& GetGraphics() const; diff --git a/dali/graphics/vulkan/internal/vulkan-swapchain.cpp b/dali/graphics/vulkan/internal/vulkan-swapchain.cpp index 7eafed4aa..1abe0f511 100644 --- a/dali/graphics/vulkan/internal/vulkan-swapchain.cpp +++ b/dali/graphics/vulkan/internal/vulkan-swapchain.cpp @@ -133,9 +133,7 @@ RefCountedFramebuffer Swapchain::AcquireNextFramebuffer( bool shouldCollectGarba // if not created yet if( mSwapchainBuffers.empty() ) { - const auto MAX_SWAPCHAIN_BUFFERS { mFramebuffers.size() }; - - mSwapchainBuffers.resize( MAX_SWAPCHAIN_BUFFERS ); + mSwapchainBuffers.resize( MAX_SWAPCHAIN_RESOURCE_BUFFERS ); for( auto& buffer : mSwapchainBuffers ) { buffer.reset( new SwapchainBuffer( *mGraphics ) ); @@ -145,7 +143,7 @@ RefCountedFramebuffer Swapchain::AcquireNextFramebuffer( bool shouldCollectGarba DALI_LOG_INFO( gVulkanFilter, Debug::General, "Swapchain Image Index ( BEFORE Acquire ) = %d", int(mSwapchainImageIndex) ); auto result = device.acquireNextImageKHR( mSwapchainKHR, std::numeric_limits::max(), - mSwapchainBuffers[mBufferIndex]->acquireNextImageSemaphore, + mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]->acquireNextImageSemaphore, nullptr, &mSwapchainImageIndex ); DALI_LOG_INFO( gVulkanFilter, Debug::General, "Swapchain Image Index ( AFTER Acquire ) = %d", int(mSwapchainImageIndex) ); @@ -165,21 +163,19 @@ RefCountedFramebuffer Swapchain::AcquireNextFramebuffer( bool shouldCollectGarba } } - auto& swapBuffer = mSwapchainBuffers[mBufferIndex]; + auto& swapBuffer = mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]; // First frames don't need waiting as they haven't been submitted // yet. Note, that waiting on the fence without resetting it may // cause a stall ( nvidia, ubuntu ) if( mFrameCounter >= mSwapchainBuffers.size() ) { - mGraphics->WaitForFence( mSwapchainBuffers[mBufferIndex]->endOfFrameFence ); - mGraphics->ExecuteActions(); + mGraphics->WaitForFence( mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]->endOfFrameFence ); mGraphics->CollectGarbage(); } else { mGraphics->DeviceWaitIdle(); - mGraphics->ExecuteActions(); mGraphics->CollectGarbage(); } @@ -203,7 +199,7 @@ void Swapchain::Present() return; } - auto& swapBuffer = mSwapchainBuffers[mBufferIndex]; + auto& swapBuffer = mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]; // End any render pass command buffers size_t count = swapBuffer->commandBuffers.size(); @@ -268,7 +264,6 @@ void Swapchain::Present() } mFrameCounter++; - mBufferIndex = uint32_t( (mBufferIndex+1) % MAX_SWAPCHAIN_RESOURCE_BUFFERS ); } void Swapchain::Present( std::vector< vk::Semaphore > waitSemaphores ) @@ -407,7 +402,7 @@ void Swapchain::ResetAllCommandBuffers() void Swapchain::AllocateCommandBuffers( size_t renderPassCount ) { - size_t commandBuffersCount = mSwapchainBuffers[mBufferIndex]->commandBuffers.size(); + size_t commandBuffersCount = mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]->commandBuffers.size(); DALI_LOG_STREAM( gVulkanFilter, Debug::General, "AllocateCommandBuffers: cbCount:" << commandBuffersCount << " renderPassCount: " << renderPassCount ); @@ -419,19 +414,19 @@ void Swapchain::AllocateCommandBuffers( size_t renderPassCount ) // Create primary buffer for each render pass & begin recording auto commandBuffer = mGraphics->CreateCommandBuffer(true); commandBuffer->Begin( vk::CommandBufferUsageFlagBits::eOneTimeSubmit, nullptr ); - mSwapchainBuffers[mBufferIndex]->commandBuffers.emplace_back( commandBuffer ); + mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]->commandBuffers.emplace_back( commandBuffer ); } } } RefCountedCommandBuffer Swapchain::GetLastCommandBuffer() const { - return mSwapchainBuffers[mBufferIndex]->commandBuffers.back(); + return mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]->commandBuffers.back(); } std::vector& Swapchain::GetCommandBuffers() const { - return mSwapchainBuffers[mBufferIndex]->commandBuffers; + return mSwapchainBuffers[mGraphics->GetCurrentBufferIndex()]->commandBuffers; } uint32_t Swapchain::GetImageCount() const diff --git a/dali/graphics/vulkan/internal/vulkan-swapchain.h b/dali/graphics/vulkan/internal/vulkan-swapchain.h index f3a56510d..4930aba4b 100644 --- a/dali/graphics/vulkan/internal/vulkan-swapchain.h +++ b/dali/graphics/vulkan/internal/vulkan-swapchain.h @@ -161,7 +161,6 @@ private: RefCountedFence mBetweenRenderPassFence; uint32_t mFrameCounter { 0u }; ///< Current frame number - uint32_t mBufferIndex { 0u }; ///< Current buffer index number bool mIsValid; // indicates whether the swapchain is still valid or requires to be recreated }; diff --git a/dali/graphics/vulkan/vulkan-graphics.cpp b/dali/graphics/vulkan/vulkan-graphics.cpp index ec6e79af6..92307abf4 100644 --- a/dali/graphics/vulkan/vulkan-graphics.cpp +++ b/dali/graphics/vulkan/vulkan-graphics.cpp @@ -214,15 +214,12 @@ Graphics::~Graphics() // This call assumes that the cash only holds the last reference of every resource in the program. (As it should) mResourceRegister->Clear(); - // Execute any outstanding actions... - ExecuteActions(); - ExecuteActions(); - // Kill pipeline cache mDevice.destroyPipelineCache( mVulkanPipelineCache, mAllocator.get() ); // Collect the garbage ( for each buffer index ) and shut down gracefully... CollectGarbage(); + SwapBuffers(); CollectGarbage(); // We are done with all resources (technically... . If not we will get a ton of validation layer errors) @@ -1520,64 +1517,33 @@ void Graphics::RemoveSampler( Sampler& sampler ) void Graphics::CollectGarbage() { std::lock_guard< std::mutex > lock{ mMutex }; + auto bufferIndex = (mCurrentBufferIndex+1)&1; + DALI_LOG_STREAM( gVulkanFilter, Debug::General, - "Beginning graphics garbage collection---------------------------------------" ) - DALI_LOG_INFO( gVulkanFilter, Debug::General, "Discard queue size: %ld\n", mDiscardQueue[mCurrentGarbageBufferIndex].size() ) + "Beginning graphics garbage collection---------------------------------------" ); + DALI_LOG_INFO( gVulkanFilter, Debug::General, "Discard queue size: %ld\n", mDiscardQueue[bufferIndex].size() ); // swap buffer - mCurrentGarbageBufferIndex = ((mCurrentGarbageBufferIndex+1)&1); - - if( mDiscardQueue[mCurrentGarbageBufferIndex].empty() ) + if( mDiscardQueue[bufferIndex].empty() ) { return; } - for( const auto& deleter : mDiscardQueue[mCurrentGarbageBufferIndex] ) + for( const auto& deleter : mDiscardQueue[bufferIndex] ) { deleter(); } // collect what's in the queue - mDiscardQueue[mCurrentGarbageBufferIndex].clear(); + mDiscardQueue[bufferIndex].clear(); DALI_LOG_STREAM( gVulkanFilter, Debug::General, "Graphics garbage collection complete---------------------------------------" ) } -void Graphics::ExecuteActions() -{ - std::lock_guard< std::mutex > lock{ mMutex }; - DALI_LOG_STREAM( gVulkanFilter, Debug::General, - "Beginning graphics action execution---------------------------------------" ) - DALI_LOG_INFO( gVulkanFilter, Debug::General, "Action queue size: %ld\n", mActionQueue.size() ) - - mCurrentActionBufferIndex = ((mCurrentActionBufferIndex+1)&1); - - if( mActionQueue[mCurrentActionBufferIndex].empty() ) - { - return; - } - - // swap buffer - for( const auto& action : mActionQueue[mCurrentActionBufferIndex] ) - { - action(); - } - - mActionQueue[mCurrentActionBufferIndex].clear(); - DALI_LOG_STREAM( gVulkanFilter, Debug::General, - "Graphics action execution complete---------------------------------------" ) -} - void Graphics::DiscardResource( std::function< void() > deleter ) { std::lock_guard< std::mutex > lock( mMutex ); - mDiscardQueue[mCurrentGarbageBufferIndex].push_back( std::move( deleter ) ); -} - -void Graphics::EnqueueAction( std::function< void() > action ) -{ - std::lock_guard< std::mutex > lock( mMutex ); - mActionQueue[mCurrentActionBufferIndex].push_back( std::move( action ) ); + mDiscardQueue[mCurrentBufferIndex].push_back( std::move( deleter ) ); } const DiscardQueue& Graphics::GetDiscardQueue( uint32_t bufferIndex ) const @@ -1585,8 +1551,16 @@ const DiscardQueue& Graphics::GetDiscardQueue( uint32_t bufferIndex ) const return mDiscardQueue[bufferIndex]; } -// -------------------------------------------------------------------------------------------------------------- +uint32_t Graphics::SwapBuffers() +{ + mCurrentBufferIndex = (mCurrentBufferIndex+1)&1; + return mCurrentBufferIndex; +} +uint32_t Graphics::GetCurrentBufferIndex() +{ + return mCurrentBufferIndex; +} void Graphics::CreateInstance( const std::vector< const char* >& extensions, const std::vector< const char* >& validationLayers ) diff --git a/dali/graphics/vulkan/vulkan-graphics.h b/dali/graphics/vulkan/vulkan-graphics.h index 7726db5d8..fd3bf5aae 100644 --- a/dali/graphics/vulkan/vulkan-graphics.h +++ b/dali/graphics/vulkan/vulkan-graphics.h @@ -311,14 +311,14 @@ public: //Cache management methods void CollectGarbage(); - void ExecuteActions(); - void DiscardResource( std::function< void() > deleter ); - void EnqueueAction( std::function< void() > action ); - const DiscardQueue& GetDiscardQueue( uint32_t bufferIndex ) const; + uint32_t SwapBuffers(); + + uint32_t GetCurrentBufferIndex(); + private: // Methods void CreateInstance( const std::vector< const char* >& extensions, @@ -378,18 +378,16 @@ private: // Members // Command pool map using thread IDs as keys CommandPoolMap mCommandPools; - DiscardQueue mActionQueue[2u]; DiscardQueue mDiscardQueue[2u]; - uint32_t mCurrentGarbageBufferIndex { 0u }; - uint32_t mCurrentActionBufferIndex { 0u }; - bool mHasDepth { false }; bool mHasStencil { false }; vk::PipelineCache mVulkanPipelineCache; bool mSurfaceResized { false }; + + uint32_t mCurrentBufferIndex{ 0u }; }; } // namespace Vulkan diff --git a/dali/internal/update/graphics/graphics-algorithms.cpp b/dali/internal/update/graphics/graphics-algorithms.cpp index 3582d1bc3..48df6f1a6 100644 --- a/dali/internal/update/graphics/graphics-algorithms.cpp +++ b/dali/internal/update/graphics/graphics-algorithms.cpp @@ -515,7 +515,7 @@ void GraphicsAlgorithms::RecordRenderItemList( // pass shared UBO and offset, return new offset for next item to be used // don't process bindings if there are no uniform buffers allocated auto shader = renderer->GetShader().GetGfxObject(); - auto ubo = mUniformBuffer[mUniformBufferIndex].get(); + auto ubo = mUniformBuffer[bufferIndex].get(); if( ubo && shader ) { std::vector* bindings{ nullptr }; @@ -956,8 +956,6 @@ void GraphicsAlgorithms::SubmitRenderInstructions( bool usesDepth = false; bool usesStencil = false; - mUniformBufferIndex = bufferIndex; - PrepareRendererPipelines( controller, renderInstructions, usesDepth, usesStencil, bufferIndex ); // If state of depth/stencil has changed between frames then the pipelines must be @@ -976,25 +974,28 @@ void GraphicsAlgorithms::SubmitRenderInstructions( mGraphicsBufferManager.reset( new GraphicsBufferManager( &controller ) ); } - auto pagedAllocation = ( ( mUniformBlockAllocationBytes / UBO_PAGE_SIZE + 1u ) ) * UBO_PAGE_SIZE; - controller.BeginFrame(); + auto pagedAllocation = ( ( mUniformBlockAllocationBytes / UBO_PAGE_SIZE + 1u ) ) * UBO_PAGE_SIZE; + // Allocate twice memory as required by the uniform buffers // todo: memory usage backlog to use optimal allocation - if( mUniformBlockAllocationBytes && !mUniformBuffer[mUniformBufferIndex] ) + if( mUniformBlockAllocationBytes && !mUniformBuffer[bufferIndex] ) { - mUniformBuffer[mUniformBufferIndex] = std::move( mGraphicsBufferManager->AllocateUniformBuffer( pagedAllocation ) ); + mUniformBuffer[bufferIndex] = std::move( mGraphicsBufferManager->AllocateUniformBuffer( pagedAllocation ) ); } else if( mUniformBlockAllocationBytes && ( - mUniformBuffer[mUniformBufferIndex]->GetSize() < pagedAllocation || - (pagedAllocation < uint32_t(float(mUniformBuffer[mUniformBufferIndex]->GetSize()) * UBO_SHRINK_THRESHOLD )))) + mUniformBuffer[bufferIndex]->GetSize() < pagedAllocation || + (pagedAllocation < uint32_t(float(mUniformBuffer[bufferIndex]->GetSize()) * UBO_SHRINK_THRESHOLD )))) { - mUniformBuffer[mUniformBufferIndex]->Reserve( pagedAllocation, true ); + mUniformBuffer[bufferIndex]->Reserve( pagedAllocation, true ); } // Clear UBO - mUniformBuffer[mUniformBufferIndex]->Fill( 0, 0u, 0u ); + if( mUniformBuffer[bufferIndex] ) + { + mUniformBuffer[bufferIndex]->Fill( 0, 0u, 0u ); + } mUboOffset = 0u; @@ -1010,9 +1011,9 @@ void GraphicsAlgorithms::SubmitRenderInstructions( // Submit all render commands in one go controller.SubmitCommands( std::move(commandList) ); - if( mUniformBlockAllocationBytes && mUniformBuffer[mUniformBufferIndex] ) + if( mUniformBlockAllocationBytes && mUniformBuffer[bufferIndex] ) { - mUniformBuffer[mUniformBufferIndex]->Flush(); + mUniformBuffer[bufferIndex]->Flush(); } controller.EndFrame(); diff --git a/dali/internal/update/graphics/graphics-algorithms.h b/dali/internal/update/graphics/graphics-algorithms.h index 80a6c07aa..5a6df3e47 100644 --- a/dali/internal/update/graphics/graphics-algorithms.h +++ b/dali/internal/update/graphics/graphics-algorithms.h @@ -109,7 +109,6 @@ private: using UniformBufferList = std::array, 2u>; UniformBufferList mUniformBuffer; - uint32_t mUniformBufferIndex{0u}; uint32_t mUniformBlockAllocationCount; uint32_t mUniformBlockAllocationBytes;