From: David Steele Date: Fri, 24 Jan 2025 11:49:08 +0000 (+0000) Subject: Removing DeviceWaitIdle from Vk::SwapBuffers X-Git-Tag: dali_2.4.6~5^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=da3a84a223bb5208eab394f87708f19e88db95bf;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git Removing DeviceWaitIdle from Vk::SwapBuffers Rather than a hard wait each frame, should instead leverage the exising end of frame fence that's owned by the swapchain buffer. Moved the AcquireNextImage functions out of BeginRenderPass, and into the VulkanGraphicsController::FrameStart method; this will now wait on the current buffer's end of frame fence before trying to get the next image (for this buffer index). SwapBuffers() now just increases the buffer index modulo the buffer count (aka the number of swapchain images that are available for this device). Changed CommandBuffer to contain up to BufferCount() Impls; the relevant impl is selected for each command by getting the current buffer index from the device. Changed DescriptorPool implementation to use the current buffer index rather than trying to manage it's own pool index. This was quite broken! It now grows the poolList to match the buffer index, which will never go past the BufferCount. (usually 2 or 3). Change-Id: I994046805bfb38285063e87f8409e856f14b3459 --- diff --git a/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.cpp b/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.cpp index 4c31dee5a..87acb1585 100644 --- a/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.cpp +++ b/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.cpp @@ -45,8 +45,7 @@ VT* ConstGraphicsCast(const GT* object) CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, VulkanGraphicsController& controller) : CommandBufferResource(createInfo, controller), - mDynamicStateMask(CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE), - mCommandBufferImpl(nullptr) + mDynamicStateMask(CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE) { auto& device = controller.GetGraphicsDevice(); bool isPrimary = true; @@ -54,8 +53,11 @@ CommandBuffer::CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo { isPrimary = false; } - auto commandPool = device.GetCommandPool(std::this_thread::get_id()); - mCommandBufferImpl = commandPool->NewCommandBuffer(isPrimary); + auto commandPool = device.GetCommandPool(std::this_thread::get_id()); + for(uint32_t i = 0; i < device.GetBufferCount(); ++i) + { + mCommandBufferImpl.emplace_back(commandPool->NewCommandBuffer(isPrimary)); + } } CommandBuffer::~CommandBuffer() = default; @@ -64,7 +66,7 @@ void CommandBuffer::DestroyResource() { // Don't delete the impl, it's pool allocated and should have been // returned to the command pool for re-use. - mCommandBufferImpl = nullptr; + mCommandBufferImpl.clear(); } bool CommandBuffer::InitializeResource() @@ -79,11 +81,13 @@ void CommandBuffer::DiscardResource() void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info) { - mDynamicStateMask = CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE; - mRenderTarget = ConstGraphicsCast(info.renderTarget); + mDynamicStateMask = CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE; + mRenderTarget = ConstGraphicsCast(info.renderTarget); + uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); - if(mCommandBufferImpl) + if(mCommandBufferImpl[bufferIndex]) { + DALI_LOG_INFO(gLogCmdBufferFilter, Debug::Verbose, "CommandBuffer::Begin: ptr:%p bufferIndex=%d", this, bufferIndex); vk::CommandBufferInheritanceInfo inheritanceInfo{}; if(info.renderPass) { @@ -93,7 +97,7 @@ void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info) inheritanceInfo.queryFlags = static_cast(0); inheritanceInfo.pipelineStatistics = static_cast(0); } - mCommandBufferImpl->Begin(static_cast(info.usage), &inheritanceInfo); + mCommandBufferImpl[bufferIndex]->Begin(static_cast(info.usage), &inheritanceInfo); // Default depth/stencil should be off: SetDepthTestEnable(false); @@ -105,17 +109,21 @@ void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info) void CommandBuffer::End() { - if(mCommandBufferImpl) + uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->End(); + mCommandBufferImpl[bufferIndex]->End(); } } void CommandBuffer::Reset() { - if(mCommandBufferImpl) + uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + DALI_LOG_INFO(gLogCmdBufferFilter, Debug::Verbose, "CommandBuffer::Reset: ptr:%p bufferIndex=%d", this, bufferIndex); + + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->Reset(); + mCommandBufferImpl[bufferIndex]->Reset(); } mDynamicStateMask = CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE; mRenderTarget = nullptr; @@ -125,43 +133,69 @@ void CommandBuffer::BindVertexBuffers(uint32_t const std::vector& gfxBuffers, const std::vector& offsets) { + uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); std::vector buffers; buffers.reserve(gfxBuffers.size()); for(auto& gfxBuffer : gfxBuffers) { buffers.push_back(ConstGraphicsCast(gfxBuffer)->GetImpl()); } - mCommandBufferImpl->BindVertexBuffers(firstBinding, buffers, offsets); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->BindVertexBuffers(firstBinding, buffers, offsets); + } } void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& gfxBuffer, uint32_t offset, Format format) { - auto indexBuffer = ConstGraphicsCast(&gfxBuffer); - DALI_ASSERT_DEBUG(indexBuffer && indexBuffer->GetImpl()); - mCommandBufferImpl->BindIndexBuffer(*indexBuffer->GetImpl(), offset, format); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + auto indexBuffer = ConstGraphicsCast(&gfxBuffer); + DALI_ASSERT_DEBUG(indexBuffer && indexBuffer->GetImpl()); + + mCommandBufferImpl[bufferIndex]->BindIndexBuffer(*indexBuffer->GetImpl(), offset, format); + } } void CommandBuffer::BindUniformBuffers(const std::vector& bindings) { - mCommandBufferImpl->BindUniformBuffers(bindings); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->BindUniformBuffers(bindings); + } } void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline) { - mCommandBufferImpl->BindPipeline(&pipeline); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->BindPipeline(&pipeline); + } } void CommandBuffer::BindTextures(const std::vector& textureBindings) { - mCommandBufferImpl->BindTextures(textureBindings); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->BindTextures(textureBindings); + } mController.CheckTextureDependencies(textureBindings, mRenderTarget); } void CommandBuffer::BindSamplers(const std::vector& samplerBindings) { - mCommandBufferImpl->BindSamplers(samplerBindings); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->BindSamplers(samplerBindings); + } } void CommandBuffer::BindPushConstants(void* data, @@ -175,110 +209,92 @@ void CommandBuffer::BeginRenderPass(Graphics::RenderPass* gfxRenderPass Rect2D renderArea, const std::vector& clearValues) { - auto renderTarget = static_cast(gfxRenderTarget); - DALI_ASSERT_DEBUG(mRenderTarget == renderTarget && "RenderPass has different render target to cmd buffer Begin"); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); - auto renderPass = static_cast(gfxRenderPass); - auto surface = renderTarget->GetSurface(); - auto& device = mController.GetGraphicsDevice(); - FramebufferImpl* framebuffer = nullptr; - RenderPassHandle renderPassImpl; - if(surface) + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - auto window = static_cast(surface); - auto surfaceId = window->GetSurfaceId(); - auto swapchain = device.GetSwapchainForSurfaceId(surfaceId); - - // If we have swapchain then we need to acquire image - // This is a special case: - // We assume that: - // - only one BeginRenderPass() happens per surface so we can acquire image here - // - swapchain shouldn't change but in case it does hence the condition below (?) - if(mLastSwapchain != swapchain) + auto renderTarget = static_cast(gfxRenderTarget); + DALI_ASSERT_DEBUG(mRenderTarget == renderTarget && "RenderPass has different render target to cmd buffer Begin"); + + auto renderPass = static_cast(gfxRenderPass); + auto surface = mRenderTarget->GetSurface(); + auto& device = mController.GetGraphicsDevice(); + FramebufferImpl* framebuffer = nullptr; + RenderPassHandle renderPassImpl; + if(surface) { - mLastSwapchain = swapchain; + auto window = static_cast(surface); + auto surfaceId = window->GetSurfaceId(); + auto swapchain = device.GetSwapchainForSurfaceId(surfaceId); + framebuffer = swapchain->GetCurrentFramebuffer(); + renderPassImpl = framebuffer->GetImplFromRenderPass(renderPass); } - - if(mLastSwapchain) + else { - framebuffer = mLastSwapchain->AcquireNextFramebuffer(true); + auto framebufferHandle = mRenderTarget->GetFramebuffer(); + framebuffer = framebufferHandle->GetImpl(); + renderPassImpl = framebuffer->GetImplFromRenderPass(renderPass); + mController.AddTextureDependencies(renderTarget); } - // In case something went wrong we will try to replace swapchain once - // before calling it a day. - if(!framebuffer || !swapchain->IsValid()) - { - // make sure device doesn't do any work before replacing swapchain - device.DeviceWaitIdle(); - - // replace swapchain (only once) - swapchain = device.ReplaceSwapchainForSurface(swapchain->GetSurface(), std::move(swapchain)); + std::vector vkClearValues; - mLastSwapchain = swapchain; - - // get new valid framebuffer - if(mLastSwapchain) + auto attachments = renderPass->GetCreateInfo().attachments; + if(attachments != nullptr && + !attachments->empty()) // Can specify clear color even if load op is not clear. + { + for(auto clearValue : clearValues) { - framebuffer = swapchain->AcquireNextFramebuffer(true); + vk::ClearColorValue color; + color.float32[0] = clearValue.color.r; + color.float32[1] = clearValue.color.g; + color.float32[2] = clearValue.color.b; + color.float32[3] = clearValue.color.a; + vkClearValues.emplace_back(color); } - DALI_ASSERT_ALWAYS(framebuffer && "Replacing invalid swapchain unsuccessful! Goodbye!"); } - renderPassImpl = framebuffer->GetImplFromRenderPass(renderPass); - } - else - { - auto coreFramebuffer = renderTarget->GetFramebuffer(); - framebuffer = coreFramebuffer->GetImpl(); - renderPassImpl = framebuffer->GetImplFromRenderPass(renderPass); - mController.AddTextureDependencies(renderTarget); - } - - std::vector vkClearValues; - - auto attachments = renderPass->GetCreateInfo().attachments; - if(attachments != nullptr && - !attachments->empty()) // Can specify clear color even if load op is not clear. - { - for(auto clearValue : clearValues) - { - vk::ClearColorValue color; - color.float32[0] = clearValue.color.r; - color.float32[1] = clearValue.color.g; - color.float32[2] = clearValue.color.b; - color.float32[3] = clearValue.color.a; - vkClearValues.emplace_back(color); - } + mCommandBufferImpl[bufferIndex]->BeginRenderPass(vk::RenderPassBeginInfo{} + .setFramebuffer(framebuffer->GetVkHandle()) + .setRenderPass(renderPassImpl->GetVkHandle()) + .setRenderArea({{0, 0}, {renderArea.width, renderArea.height}}) + .setPClearValues(vkClearValues.data()) + .setClearValueCount(uint32_t(vkClearValues.size())), + vk::SubpassContents::eSecondaryCommandBuffers); } - - mCommandBufferImpl->BeginRenderPass(vk::RenderPassBeginInfo{} - .setFramebuffer(framebuffer->GetVkHandle()) - .setRenderPass(renderPassImpl->GetVkHandle()) - .setRenderArea({{0, 0}, {renderArea.width, renderArea.height}}) - .setPClearValues(vkClearValues.data()) - .setClearValueCount(uint32_t(vkClearValues.size())), - vk::SubpassContents::eSecondaryCommandBuffers); } void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject) { - mCommandBufferImpl->EndRenderPass(); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->EndRenderPass(); + } } void CommandBuffer::ReadPixels(uint8_t* buffer) { - mCommandBufferImpl->ReadPixels(buffer); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->ReadPixels(buffer); + } } void CommandBuffer::ExecuteCommandBuffers(std::vector&& gfxCommandBuffers) { - std::vector vkCommandBuffers; - vkCommandBuffers.reserve(gfxCommandBuffers.size()); - for(auto& gfxCmdBuf : gfxCommandBuffers) + uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - vkCommandBuffers.push_back(ConstGraphicsCast(gfxCmdBuf)->GetImpl()->GetVkHandle()); + std::vector vkCommandBuffers; + vkCommandBuffers.reserve(gfxCommandBuffers.size()); + for(auto& gfxCmdBuf : gfxCommandBuffers) + { + vkCommandBuffers.push_back(ConstGraphicsCast(gfxCmdBuf)->GetImpl()->GetVkHandle()); + } + mCommandBufferImpl[bufferIndex]->ExecuteCommandBuffers(vkCommandBuffers); } - mCommandBufferImpl->ExecuteCommandBuffers(vkCommandBuffers); } void CommandBuffer::Draw(uint32_t vertexCount, @@ -286,7 +302,11 @@ void CommandBuffer::Draw(uint32_t vertexCount, uint32_t firstVertex, uint32_t firstInstance) { - mCommandBufferImpl->Draw(vertexCount, instanceCount, firstVertex, firstInstance); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->Draw(vertexCount, instanceCount, firstVertex, firstInstance); + } } void CommandBuffer::DrawIndexed(uint32_t indexCount, @@ -295,7 +315,11 @@ void CommandBuffer::DrawIndexed(uint32_t indexCount, int32_t vertexOffset, uint32_t firstInstance) { - mCommandBufferImpl->DrawIndexed(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + mCommandBufferImpl[bufferIndex]->DrawIndexed(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); + } } void CommandBuffer::DrawIndexedIndirect(Graphics::Buffer& gfxBuffer, @@ -303,9 +327,12 @@ void CommandBuffer::DrawIndexedIndirect(Graphics::Buffer& gfxBuffer, uint32_t drawCount, uint32_t stride) { - auto buffer = ConstGraphicsCast(&gfxBuffer)->GetImpl(); - - mCommandBufferImpl->DrawIndexedIndirect(*buffer, offset, drawCount, stride); + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + auto buffer = ConstGraphicsCast(&gfxBuffer)->GetImpl(); + mCommandBufferImpl[bufferIndex]->DrawIndexedIndirect(*buffer, offset, drawCount, stride); + } } void CommandBuffer::DrawNative(const DrawNativeInfo* drawInfo) @@ -314,11 +341,15 @@ void CommandBuffer::DrawNative(const DrawNativeInfo* drawInfo) void CommandBuffer::SetScissor(Rect2D value) { - // @todo Vulkan accepts array of scissors... add to API - - if(SetDynamicState(mDynamicState.scissor, value, DynamicStateMaskBits::SCISSOR)) + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->SetScissor(value); + // @todo Vulkan accepts array of scissors... add to API + + if(SetDynamicState(mDynamicState.scissor, value, DynamicStateMaskBits::SCISSOR)) + { + mCommandBufferImpl[bufferIndex]->SetScissor(value); + } } } @@ -338,9 +369,13 @@ void CommandBuffer::SetViewport(Viewport value) correctedValue.y = value.height; } - if(SetDynamicState(mDynamicState.viewport, correctedValue, DynamicStateMaskBits::VIEWPORT)) + uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->SetViewport(correctedValue); + if(SetDynamicState(mDynamicState.viewport, correctedValue, DynamicStateMaskBits::VIEWPORT)) + { + mCommandBufferImpl[bufferIndex]->SetViewport(correctedValue); + } } } @@ -366,17 +401,25 @@ void CommandBuffer::ClearDepthBuffer() void CommandBuffer::SetStencilTestEnable(bool stencilEnable) { - if(SetDynamicState(mDynamicState.stencilTest, stencilEnable, DynamicStateMaskBits::STENCIL_TEST)) + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->SetStencilTestEnable(stencilEnable); + if(SetDynamicState(mDynamicState.stencilTest, stencilEnable, DynamicStateMaskBits::STENCIL_TEST)) + { + mCommandBufferImpl[bufferIndex]->SetStencilTestEnable(stencilEnable); + } } } void CommandBuffer::SetStencilWriteMask(uint32_t writeMask) { - if(SetDynamicState(mDynamicState.stencilWriteMask, writeMask, DynamicStateMaskBits::STENCIL_WRITE_MASK)) + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->SetStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack, writeMask); + if(SetDynamicState(mDynamicState.stencilWriteMask, writeMask, DynamicStateMaskBits::STENCIL_WRITE_MASK)) + { + mCommandBufferImpl[bufferIndex]->SetStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack, writeMask); + } } } @@ -387,13 +430,14 @@ void CommandBuffer::SetStencilState(Graphics::CompareOp compareOp, Graphics::StencilOp passOp, Graphics::StencilOp depthFailOp) { + uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); if(SetDynamicState(mDynamicState.stencilCompareMask, compareMask, DynamicStateMaskBits::STENCIL_COMP_MASK)) { - mCommandBufferImpl->SetStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, compareMask); + mCommandBufferImpl[bufferIndex]->SetStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, compareMask); } if(SetDynamicState(mDynamicState.stencilReference, reference, DynamicStateMaskBits::STENCIL_REF)) { - mCommandBufferImpl->SetStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, reference); + mCommandBufferImpl[bufferIndex]->SetStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, reference); } if(SetDynamicState(mDynamicState.stencilFailOp, failOp, DynamicStateMaskBits::STENCIL_OP_FAIL) || @@ -401,35 +445,47 @@ void CommandBuffer::SetStencilState(Graphics::CompareOp compareOp, SetDynamicState(mDynamicState.stencilDepthFailOp, depthFailOp, DynamicStateMaskBits::STENCIL_OP_DEPTH_FAIL) || SetDynamicState(mDynamicState.stencilCompareOp, compareOp, DynamicStateMaskBits::STENCIL_OP_COMP)) { - mCommandBufferImpl->SetStencilOp(vk::StencilFaceFlagBits::eFrontAndBack, - VkStencilOpType(failOp).op, - VkStencilOpType(passOp).op, - VkStencilOpType(depthFailOp).op, - VkCompareOpType(compareOp).op); + mCommandBufferImpl[bufferIndex]->SetStencilOp(vk::StencilFaceFlagBits::eFrontAndBack, + VkStencilOpType(failOp).op, + VkStencilOpType(passOp).op, + VkStencilOpType(depthFailOp).op, + VkCompareOpType(compareOp).op); } } void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp) { - if(SetDynamicState(mDynamicState.depthCompareOp, compareOp, DynamicStateMaskBits::DEPTH_OP_COMP)) + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->SetDepthCompareOp(VkCompareOpType(compareOp).op); + if(SetDynamicState(mDynamicState.depthCompareOp, compareOp, DynamicStateMaskBits::DEPTH_OP_COMP)) + { + mCommandBufferImpl[bufferIndex]->SetDepthCompareOp(VkCompareOpType(compareOp).op); + } } } void CommandBuffer::SetDepthTestEnable(bool depthTestEnable) { - if(SetDynamicState(mDynamicState.depthTest, depthTestEnable, DynamicStateMaskBits::DEPTH_TEST)) + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->SetDepthTestEnable(depthTestEnable); + if(SetDynamicState(mDynamicState.depthTest, depthTestEnable, DynamicStateMaskBits::DEPTH_TEST)) + { + mCommandBufferImpl[bufferIndex]->SetDepthTestEnable(depthTestEnable); + } } } void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable) { - if(SetDynamicState(mDynamicState.depthWrite, depthWriteEnable, DynamicStateMaskBits::DEPTH_WRITE)) + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) { - mCommandBufferImpl->SetDepthWriteEnable(depthWriteEnable); + if(SetDynamicState(mDynamicState.depthWrite, depthWriteEnable, DynamicStateMaskBits::DEPTH_WRITE)) + { + mCommandBufferImpl[bufferIndex]->SetDepthWriteEnable(depthWriteEnable); + } } } @@ -439,4 +495,14 @@ Vulkan::RenderTarget* CommandBuffer::GetRenderTarget() const return mRenderTarget; } +[[nodiscard]] Vulkan::CommandBufferImpl* CommandBuffer::GetImpl() const +{ + const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex(); + if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]) + { + return mCommandBufferImpl[bufferIndex]; + } + return nullptr; +} + } // namespace Dali::Graphics::Vulkan diff --git a/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h b/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h index f50cdd41b..9d8916fa8 100644 --- a/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h +++ b/dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_VULKAN_COMMAND_BUFFER_H /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -384,10 +384,7 @@ public: // API */ RenderTarget* GetRenderTarget() const; - [[nodiscard]] CommandBufferImpl* GetImpl() const - { - return mCommandBufferImpl; - } + [[nodiscard]] CommandBufferImpl* GetImpl() const; private: static const DynamicStateMask INITIAL_DYNAMIC_MASK_VALUE{0xFFFFFFFF}; @@ -423,9 +420,9 @@ private: return false; } - CommandBufferImpl* mCommandBufferImpl; - RenderTarget* mRenderTarget{nullptr}; - Swapchain* mLastSwapchain{nullptr}; + std::vector mCommandBufferImpl; ///< There are as many elements as there are swapchain images + RenderTarget* mRenderTarget{nullptr}; + Swapchain* mLastSwapchain{nullptr}; }; } // namespace Dali::Graphics::Vulkan diff --git a/dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.cpp b/dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.cpp index 9d4d8a4bb..e468d48ad 100644 --- a/dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.cpp +++ b/dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -219,7 +219,8 @@ struct VulkanGraphicsController::Impl if(!mTextureStagingBuffer || mTextureStagingBuffer->GetImpl()->GetSize() < size) { - auto workerFunc = [&, size](auto workerIndex) { + auto workerFunc = [&, size](auto workerIndex) + { Graphics::BufferCreateInfo createInfo{}; createInfo.SetSize(size) .SetUsage(0u | Dali::Graphics::BufferUsage::TRANSFER_SRC); @@ -309,7 +310,8 @@ struct VulkanGraphicsController::Impl } assert(image); - auto predicate = [&](auto& item) -> bool { + auto predicate = [&](auto& item) -> bool + { return image->GetVkHandle() == item.image.GetVkHandle(); }; auto it = std::find_if(requestMap.begin(), requestMap.end(), predicate); @@ -564,7 +566,8 @@ Integration::GraphicsConfig& VulkanGraphicsController::GetGraphicsConfig() void VulkanGraphicsController::FrameStart() { mImpl->mDependencyChecker.Reset(); // Clean down the dependency graph. - + // Wait for end of frame sync for this buffer, and get next swapchain image for each window. + mImpl->mGraphicsDevice->AcquireNextImage(); mImpl->mCapacity = 0; } @@ -611,11 +614,10 @@ void VulkanGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo void VulkanGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget) { - auto surface = static_cast(renderTarget)->GetSurface(); - if(surface) + if(const auto surface = static_cast(renderTarget)->GetSurface()) { - auto surfaceId = static_cast(surface)->GetSurfaceId(); - auto swapchain = mImpl->mGraphicsDevice->GetSwapchainForSurfaceId(surfaceId); + const auto surfaceId = static_cast(surface)->GetSurfaceId(); + auto swapchain = mImpl->mGraphicsDevice->GetSwapchainForSurfaceId(surfaceId); swapchain->Present(); } // else no presentation required for framebuffer render target. @@ -725,7 +727,8 @@ void VulkanGraphicsController::UpdateTextures( if(destTexture->GetProperties().directWriteAccessEnabled) { - auto taskLambda = [pInfo, sourcePtr, sourceInfoPtr, texture](auto workerIndex) { + auto taskLambda = [pInfo, sourcePtr, sourceInfoPtr, texture](auto workerIndex) + { const auto& properties = texture->GetProperties(); if(properties.emulated) @@ -760,7 +763,8 @@ void VulkanGraphicsController::UpdateTextures( // The staging buffer is not allocated yet. The task knows pointer to the pointer which will point // at staging buffer right before executing tasks. The function will either perform direct copy // or will do suitable conversion if source format isn't supported and emulation is available. - auto taskLambda = [ppStagingMemory, currentOffset, pInfo, sourcePtr, texture](auto workerThread) { + auto taskLambda = [ppStagingMemory, currentOffset, pInfo, sourcePtr, texture](auto workerThread) + { char* pStagingMemory = reinterpret_cast(*ppStagingMemory); // Try to initialise` texture resources explicitly if they are not yet initialised @@ -798,7 +802,8 @@ void VulkanGraphicsController::UpdateTextures( for(auto& item : updateMap) { auto pUpdates = &item.second; - auto task = [pUpdates](auto workerIndex) { + auto task = [pUpdates](auto workerIndex) + { for(auto& update : *pUpdates) { update.copyTask(workerIndex); @@ -946,7 +951,8 @@ UniquePtr VulkanGraphicsController::CreateRenderTarget(c UniquePtr VulkanGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, UniquePtr&& oldCommandBuffer) { - return NewGraphicsObject(commandBufferCreateInfo, *this, std::move(oldCommandBuffer)); + auto commandBuffer = NewGraphicsObject(commandBufferCreateInfo, *this, std::move(oldCommandBuffer)); + return commandBuffer; } UniquePtr VulkanGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, UniquePtr&& oldRenderPass) diff --git a/dali/internal/graphics/vulkan-impl/vulkan-program-impl.cpp b/dali/internal/graphics/vulkan-impl/vulkan-program-impl.cpp index add5e8a12..af01d72f2 100644 --- a/dali/internal/graphics/vulkan-impl/vulkan-program-impl.cpp +++ b/dali/internal/graphics/vulkan-impl/vulkan-program-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -71,8 +71,8 @@ struct ProgramImpl::Impl vk::DescriptorPool vkPool; }; - std::vector poolList; - int32_t currentPoolIndex{-1}; + std::vector poolList; ///< List of descriptor pools. Each element corresponds to overall bufferIndex. + uint32_t currentPoolIndex{0}; ///< Current pool index matches bufferIndex }; ProgramImpl::ProgramImpl(const Graphics::ProgramCreateInfo& createInfo, VulkanGraphicsController& controller) @@ -262,22 +262,22 @@ const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const [[nodiscard]] int ProgramImpl::AddDescriptorPool(uint32_t poolCapacity, uint32_t maxPoolCounts) { - auto& poolList = mImpl->poolList; - auto& poolIndex = mImpl->currentPoolIndex; - poolIndex %= maxPoolCounts; + auto& poolList = mImpl->poolList; auto& gfxDevice = mImpl->controller.GetGraphicsDevice(); auto& allocator = gfxDevice.GetAllocator(); auto vkDevice = gfxDevice.GetLogicalDevice(); - if(poolCapacity != poolList.size()) + uint32_t bufferIndex = gfxDevice.GetCurrentBufferIndex(); + mImpl->currentPoolIndex = bufferIndex % maxPoolCounts; + + if(mImpl->currentPoolIndex >= poolList.size()) { - poolList.resize(poolCapacity); - // should error if pool index exceeds pool capacity + poolList.resize(mImpl->currentPoolIndex + 1); } // round-robin the pool index - Impl::DescriptorPool& descriptorPool = mImpl->poolList[poolIndex]; + Impl::DescriptorPool& descriptorPool = mImpl->poolList[mImpl->currentPoolIndex]; // if pool exists at index... if(descriptorPool.vkPool) @@ -286,13 +286,14 @@ const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const if(descriptorPool.createInfo.maxSets >= poolCapacity) { vkDevice.resetDescriptorPool(descriptorPool.vkPool, vk::DescriptorPoolResetFlags{}); - return poolIndex; + return mImpl->currentPoolIndex; } - // ... else, destroy vulkan object + // ... else, destroy vulkan object, and re-create it below vkDevice.destroyDescriptorPool(descriptorPool.vkPool, &allocator); } + // Create new descriptor pool for the required capacity descriptorPool.createInfo.setMaxSets(poolCapacity); std::vector poolSizes; @@ -321,7 +322,7 @@ const ProgramCreateInfo& ProgramImpl::GetCreateInfo() const // create pool VkAssert(vkDevice.createDescriptorPool(&descriptorPool.createInfo, &allocator, &descriptorPool.vkPool)); - return poolIndex; + return mImpl->currentPoolIndex; } [[nodiscard]] vk::DescriptorSet ProgramImpl::AllocateDescriptorSet(int poolIndex) diff --git a/dali/internal/graphics/vulkan-impl/vulkan-program-impl.h b/dali/internal/graphics/vulkan-impl/vulkan-program-impl.h index be7b09c8d..376d33538 100644 --- a/dali/internal/graphics/vulkan-impl/vulkan-program-impl.h +++ b/dali/internal/graphics/vulkan-impl/vulkan-program-impl.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_VULKAN_PROGRAM_IMPL_H /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -30,7 +30,7 @@ namespace Dali::Graphics::Vulkan class Reflection; /** - * @brief Program implementation + * @brief Program implementation. * * Program implementation is owned only by the PipelineCache * @@ -161,4 +161,4 @@ private: } // namespace Dali::Graphics::Vulkan -#endif //DALI_GRAPHICS_VULKAN_PROGRAM_IMPL_H +#endif // DALI_GRAPHICS_VULKAN_PROGRAM_IMPL_H diff --git a/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp b/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp index 6df00820d..6fc871745 100644 --- a/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp +++ b/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp @@ -86,7 +86,7 @@ Swapchain* Swapchain::NewSwapchain( SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, - uint32_t bufferCount) + uint32_t& bufferCount) { auto swapchain = new Swapchain(device, presentationQueue); swapchain->CreateVkSwapchain(oldSwapchain, surface, requestedFormat, presentMode, bufferCount); @@ -110,7 +110,7 @@ void Swapchain::CreateVkSwapchain( SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, - uint32_t bufferCount) + uint32_t& bufferCount) { mSurface = surface; vk::Format swapchainImageFormat{}; @@ -164,7 +164,8 @@ void Swapchain::CreateVkSwapchain( auto presentModes = surface->GetSurfacePresentModes(); auto found = std::find_if(presentModes.begin(), presentModes.end(), - [&](vk::PresentModeKHR mode) { + [&](vk::PresentModeKHR mode) + { return presentMode == mode; }); @@ -268,7 +269,8 @@ void Swapchain::CreateFramebuffers(FramebufferAttachmentHandle depthAttachment) depthAttachment, mSwapchainCreateInfoKHR.imageExtent.width, mSwapchainCreateInfoKHR.imageExtent.height), - [](FramebufferImpl* framebuffer1) { + [](FramebufferImpl* framebuffer1) + { framebuffer1->Destroy(); delete framebuffer1; }); @@ -325,6 +327,19 @@ FramebufferImpl* Swapchain::AcquireNextFramebuffer(bool shouldCollectGarbageNow) auto& swapchainBuffer = mSwapchainBuffers[mGraphicsDevice.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()) + { + vk::Result status = swapchainBuffer->endOfFrameFence->GetStatus(); + if(status == vk::Result::eNotReady) + { + swapchainBuffer->endOfFrameFence->Wait(); + swapchainBuffer->endOfFrameFence->Reset(); + } + } + auto result = device.acquireNextImageKHR(mSwapchainKHR, TIMEOUT, swapchainBuffer->acquireNextImageSemaphore, @@ -355,24 +370,6 @@ FramebufferImpl* Swapchain::AcquireNextFramebuffer(bool shouldCollectGarbageNow) } } - // 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()) - { - vk::Result status = swapchainBuffer->endOfFrameFence->GetStatus(); - if(status == vk::Result::eNotReady) - { - swapchainBuffer->endOfFrameFence->Wait(); - swapchainBuffer->endOfFrameFence->Reset(); - } - } - else - { - mGraphicsDevice.DeviceWaitIdle(); - } - // mGraphicsDevice.CollectGarbage(); - return mFramebuffers[mSwapchainImageIndex].get(); } diff --git a/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h b/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h index 41c60e505..04a8d60cc 100644 --- a/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h +++ b/dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_GRAPHICS_VULKAN_SWAPCHAIN_IMPL_H /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -37,6 +37,18 @@ struct SwapchainBuffer; class Swapchain { public: + /** + * @brief Create a new swapchain for the given surface. + * + * @param device The vulkan device + * @param presentationQueue The queue to use for presenting the swapchain + * @param oldSwapchain Any old swapchain we're recyclying + * @param surface The surface to create the swapchain images for + * @param requestedFormat The desired image format + * @param presentMode Usually eFifo or eMailbox + * @param[out] bufferCount Number of available swapchain buffers + * @return A new swapchain + */ static Swapchain* NewSwapchain( Device& device, Queue& presentationQueue, @@ -44,13 +56,13 @@ public: SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, - uint32_t bufferCount); + uint32_t& bufferCount); Swapchain(Device& graphicsDevice, Queue& presentationQueue); ~Swapchain(); - Swapchain(const Swapchain&) = delete; + Swapchain(const Swapchain&) = delete; Swapchain& operator=(const Swapchain&) = delete; void Destroy(); @@ -140,7 +152,7 @@ private: SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, - uint32_t bufferCount); + uint32_t& bufferCount); private: Device& mGraphicsDevice; diff --git a/dali/internal/graphics/vulkan/vulkan-device.cpp b/dali/internal/graphics/vulkan/vulkan-device.cpp index ccdd2db0d..243e8f7de 100644 --- a/dali/internal/graphics/vulkan/vulkan-device.cpp +++ b/dali/internal/graphics/vulkan/vulkan-device.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -360,10 +360,10 @@ Swapchain* Device::ReplaceSwapchainForSurface(SurfaceImpl* surface, Swapchain*&& Swapchain* Device::CreateSwapchain(SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, - uint32_t bufferCount, + uint32_t& bufferCount, Swapchain*&& oldSwapchain) { - auto newSwapchain = Swapchain::NewSwapchain(*this, GetPresentQueue(), oldSwapchain ? oldSwapchain->GetVkHandle() : nullptr, surface, requestedFormat, presentMode, bufferCount); + auto newSwapchain = Swapchain::NewSwapchain(*this, GetPresentQueue(), oldSwapchain ? oldSwapchain->GetVkHandle() : nullptr, surface, requestedFormat, presentMode, mBufferCount); if(oldSwapchain) { @@ -395,6 +395,36 @@ Swapchain* Device::CreateSwapchain(SurfaceImpl* surface, return newSwapchain; } +void Device::AcquireNextImage() +{ + for(auto& s : mSurfaceMap) + { + auto swapchain = s.second.swapchain; + if(swapchain != nullptr) + { + FramebufferImpl* framebuffer = swapchain->AcquireNextFramebuffer(true); + + // In case something went wrong we will try to replace swapchain once + // before calling it a day. + if(!framebuffer || !swapchain->IsValid()) + { + // make sure device doesn't do any work before replacing swapchain + DeviceWaitIdle(); + + // replace swapchain (only once) + swapchain = ReplaceSwapchainForSurface(swapchain->GetSurface(), std::move(swapchain)); + + // get new valid framebuffer + if(swapchain) + { + framebuffer = swapchain->AcquireNextFramebuffer(true); + } + DALI_ASSERT_ALWAYS(framebuffer && "Replacing invalid swapchain unsuccessful! Goodbye!"); + } + } + } +} + vk::Result Device::Present(Queue& queue, vk::PresentInfoKHR presentInfo) { auto lock(queue.Lock()); @@ -577,15 +607,20 @@ void Device::SurfaceResized(unsigned int width, unsigned int height) } } -uint32_t Device::SwapBuffers() +uint32_t Device::GetCurrentBufferIndex() const { - DeviceWaitIdle(); - mCurrentBufferIndex = (mCurrentBufferIndex + 1) & 1; return mCurrentBufferIndex; } -uint32_t Device::GetCurrentBufferIndex() const +uint32_t Device::GetBufferCount() const +{ + return mBufferCount; +} + +uint32_t Device::SwapBuffers() { + // Increase the current buffer index. This should match the number of swapchain images in the main window. + mCurrentBufferIndex = (mCurrentBufferIndex + 1) % mBufferCount; return mCurrentBufferIndex; } diff --git a/dali/internal/graphics/vulkan/vulkan-device.h b/dali/internal/graphics/vulkan/vulkan-device.h index 843ff2fd7..9be0e2509 100644 --- a/dali/internal/graphics/vulkan/vulkan-device.h +++ b/dali/internal/graphics/vulkan/vulkan-device.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_VULKAN_DEVICE_H /* - * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * Copyright (c) 2025 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. @@ -73,7 +73,9 @@ public: // Create methods Swapchain* ReplaceSwapchainForSurface(SurfaceImpl* surface, Swapchain*&& oldSwapchain); - Swapchain* CreateSwapchain(SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, uint32_t bufferCount, Swapchain*&& oldSwapchain); + Swapchain* CreateSwapchain(SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, uint32_t& bufferCount, Swapchain*&& oldSwapchain); + + void AcquireNextImage(); vk::Result Present(Queue& queue, vk::PresentInfoKHR presentInfo); vk::Result QueueWaitIdle(Queue& queue); @@ -118,6 +120,8 @@ public: // Getters uint32_t GetCurrentBufferIndex() const; + uint32_t GetBufferCount() const; + uint32_t SwapBuffers(); const vk::PhysicalDeviceMemoryProperties& GetMemoryProperties() const @@ -176,6 +180,7 @@ private: // Members Platform mPlatform{Platform::UNDEFINED}; uint32_t mCurrentBufferIndex{0u}; + uint32_t mBufferCount{2}; std::mutex mMutex; bool mHasDepth{false};