Changing swapchain acquisition at frame start 67/319267/5
authorDavid Steele <david.steele@samsung.com>
Thu, 6 Feb 2025 18:11:37 +0000 (18:11 +0000)
committerDavid Steele <david.steele@samsung.com>
Wed, 12 Feb 2025 12:05:46 +0000 (12:05 +0000)
Need to ensure that we don't create end of frame fence if we're not
going to render anything.

But, we do want to have same pipelines for fbos and scene; so we need
to sync swapchain _before_ drawing to fbos.

Ensured that Swapchain owns it's external images.

Change-Id: I4cc64607ad964362cb793f435324110027b45740

15 files changed:
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-egl-application.h
dali/internal/adaptor/common/combined-update-render-controller.cpp
dali/internal/graphics/common/graphics-interface.h
dali/internal/graphics/gles/egl-graphics.cpp
dali/internal/graphics/gles/egl-graphics.h
dali/internal/graphics/vulkan-impl/vulkan-command-buffer.cpp
dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.cpp
dali/internal/graphics/vulkan-impl/vulkan-image-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h
dali/internal/graphics/vulkan/vulkan-device.cpp
dali/internal/graphics/vulkan/vulkan-device.h
dali/internal/graphics/vulkan/vulkan-graphics-impl.cpp
dali/internal/graphics/vulkan/vulkan-graphics-impl.h
dali/internal/window-system/common/window-render-surface.cpp

index 08c997cbf90165d91553263b24db3a3f64df2f30..4626f3d8ba7436aa57e774167c443f2c1f192c37 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 /*
- * 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.
@@ -146,6 +146,11 @@ public:
     mCallstack.PushCall("MakeContextCurrent()", "");
   }
 
+  void AcquireNextImage(Integration::RenderSurfaceInterface* surface) override
+  {
+    mCallstack.PushCall("AcquireNextImage()", "");
+  }
+
   void PostRender() override
   {
     mCallstack.PushCall("PostRender()", "");
index 1a7c17dc394695669bbb15e679e491bada20a4ad..8a11eeb54974cc5b1c78fcb87f447198b81ce8db 100644 (file)
@@ -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.
@@ -799,6 +799,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     //////////////////////////////
 
     graphics.FrameStart();
+
     mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
 
     if(mPreRenderCallback != NULL)
@@ -861,21 +862,23 @@ void CombinedUpdateRenderController::UpdateRenderThread()
           mDamagedRects.clear();
 
           // Collect damage rects
-          mCore.PreRender(scene, mDamagedRects);
+          bool willRender = mCore.PreRender(scene, mDamagedRects);
+          if(willRender)
+          {
+            graphics.AcquireNextImage(windowSurface);
+          }
 
           // Render off-screen frame buffers first if any
           mCore.RenderScene(windowRenderStatus, scene, true);
 
           Rect<int> clippingRect; // Empty for fbo rendering
 
-          // Switch to the context of the surface, merge damaged areas for previous frames
-          windowSurface->PreRender(sceneSurfaceResized > 0u, mDamagedRects, clippingRect); // Switch GL context
+          // Ensure surface can be drawn to; merge damaged areas for previous frames
+          windowSurface->PreRender(sceneSurfaceResized > 0u, mDamagedRects, clippingRect);
 
           // Render the surface
           mCore.RenderScene(windowRenderStatus, scene, false, clippingRect);
 
-          // Buffer swapping now happens when the surface render target is presented.
-
           // If surface is resized, the surface resized count is decreased.
           if(DALI_UNLIKELY(sceneSurfaceResized > 0u))
           {
index fc1f7df4503994b37228ad21f65bdbc199be2d21..8966f3733f0a52dfa41edd7a11ef7416dff7704e 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_BASE_GRAPHICS_INTERFACE_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.
@@ -217,6 +217,13 @@ public:
    */
   virtual void MakeContextCurrent(Graphics::SurfaceId surfaceId) = 0;
 
+  /**
+   * Acquire the next image to draw onto.
+   *
+   * @param surface The surface to acquire the next image for.
+   */
+  virtual void AcquireNextImage(Integration::RenderSurfaceInterface* surface) = 0;
+
   /**
    * Inform graphics interface that all the surfaces have been rendered.
    *
index eb6ab8571a4ace1bbd7bac1d9cce309f27a8ec73..a5f093531f756b1da9a4899090160382f5b9aac1 100644 (file)
@@ -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.
@@ -98,6 +98,11 @@ void EglGraphics::MakeContextCurrent(Graphics::SurfaceId surfaceId)
   mEglImplementation->MakeContextCurrent(search->second.surface, search->second.context);
 }
 
+void EglGraphics::AcquireNextImage(Integration::RenderSurfaceInterface* surface)
+{
+  // Nothing to do here (SwapBuffers does this under the hood)
+}
+
 void EglGraphics::PostRender()
 {
   ActivateResourceContext();
index c730875db020efa3f0d01507fd85cd3329132dab..bd9ec864b9584a17d81038663edec6979497a5b7 100644 (file)
@@ -121,6 +121,11 @@ public:
    */
   void MakeContextCurrent(Graphics::SurfaceId surfaceId) override;
 
+  /**
+   * @copydoc Graphics::GraphicsInterface::AcquireNextImage()
+   */
+  void AcquireNextImage(Integration::RenderSurfaceInterface* surface) override;
+
   /**
    * This is called after all the surfaces have been rendered.
    *
index 87acb158586a16d6c633677d932c043888c30695..471cdde6ef57dc53bffc56116406b9e8ad8f2191 100644 (file)
@@ -84,6 +84,7 @@ void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info)
   mDynamicStateMask    = CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE;
   mRenderTarget        = ConstGraphicsCast<Vulkan::RenderTarget, Graphics::RenderTarget>(info.renderTarget);
   uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size());
 
   if(mCommandBufferImpl[bufferIndex])
   {
@@ -110,10 +111,8 @@ void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info)
 void CommandBuffer::End()
 {
   uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->End();
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+  mCommandBufferImpl[bufferIndex]->End();
 }
 
 void CommandBuffer::Reset()
@@ -121,10 +120,9 @@ void CommandBuffer::Reset()
   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[bufferIndex]->Reset();
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+  mCommandBufferImpl[bufferIndex]->Reset();
+
   mDynamicStateMask = CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE;
   mRenderTarget     = nullptr;
 }
@@ -140,10 +138,8 @@ void CommandBuffer::BindVertexBuffers(uint32_t
   {
     buffers.push_back(ConstGraphicsCast<Buffer, Graphics::Buffer>(gfxBuffer)->GetImpl());
   }
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->BindVertexBuffers(firstBinding, buffers, offsets);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+  mCommandBufferImpl[bufferIndex]->BindVertexBuffers(firstBinding, buffers, offsets);
 }
 
 void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& gfxBuffer,
@@ -151,51 +147,47 @@ void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& gfxBuffer,
                                     Format                  format)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    auto indexBuffer = ConstGraphicsCast<Buffer, Graphics::Buffer>(&gfxBuffer);
-    DALI_ASSERT_DEBUG(indexBuffer && indexBuffer->GetImpl());
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
 
-    mCommandBufferImpl[bufferIndex]->BindIndexBuffer(*indexBuffer->GetImpl(), offset, format);
-  }
+  auto indexBuffer = ConstGraphicsCast<Buffer, Graphics::Buffer>(&gfxBuffer);
+  DALI_ASSERT_DEBUG(indexBuffer && indexBuffer->GetImpl());
+
+  mCommandBufferImpl[bufferIndex]->BindIndexBuffer(*indexBuffer->GetImpl(), offset, format);
 }
 
 void CommandBuffer::BindUniformBuffers(const std::vector<UniformBufferBinding>& bindings)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
 
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->BindUniformBuffers(bindings);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->BindUniformBuffers(bindings);
 }
 
 void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->BindPipeline(&pipeline);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->BindPipeline(&pipeline);
 }
 
 void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->BindTextures(textureBindings);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->BindTextures(textureBindings);
+
   mController.CheckTextureDependencies(textureBindings, mRenderTarget);
 }
 
 void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->BindSamplers(samplerBindings);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->BindSamplers(samplerBindings);
 }
 
 void CommandBuffer::BindPushConstants(void*    data,
@@ -211,90 +203,87 @@ void CommandBuffer::BeginRenderPass(Graphics::RenderPass*          gfxRenderPass
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
 
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  auto renderTarget = static_cast<Vulkan::RenderTarget*>(gfxRenderTarget);
+  DALI_ASSERT_DEBUG(mRenderTarget == renderTarget && "RenderPass has different render target to cmd buffer Begin");
+
+  auto             renderPass  = static_cast<Vulkan::RenderPass*>(gfxRenderPass);
+  auto             surface     = mRenderTarget->GetSurface();
+  auto&            device      = mController.GetGraphicsDevice();
+  FramebufferImpl* framebuffer = nullptr;
+  RenderPassHandle renderPassImpl;
+  if(surface)
   {
-    auto renderTarget = static_cast<Vulkan::RenderTarget*>(gfxRenderTarget);
-    DALI_ASSERT_DEBUG(mRenderTarget == renderTarget && "RenderPass has different render target to cmd buffer Begin");
-
-    auto             renderPass  = static_cast<Vulkan::RenderPass*>(gfxRenderPass);
-    auto             surface     = mRenderTarget->GetSurface();
-    auto&            device      = mController.GetGraphicsDevice();
-    FramebufferImpl* framebuffer = nullptr;
-    RenderPassHandle renderPassImpl;
-    if(surface)
-    {
-      auto window    = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface);
-      auto surfaceId = window->GetSurfaceId();
-      auto swapchain = device.GetSwapchainForSurfaceId(surfaceId);
-      framebuffer    = swapchain->GetCurrentFramebuffer();
-      renderPassImpl = framebuffer->GetImplFromRenderPass(renderPass);
-    }
-    else
-    {
-      auto framebufferHandle = mRenderTarget->GetFramebuffer();
-      framebuffer            = framebufferHandle->GetImpl();
-      renderPassImpl         = framebuffer->GetImplFromRenderPass(renderPass);
-      mController.AddTextureDependencies(renderTarget);
-    }
+    auto window    = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface);
+    auto surfaceId = window->GetSurfaceId();
+    auto swapchain = device.GetSwapchainForSurfaceId(surfaceId);
+    framebuffer    = swapchain->GetCurrentFramebuffer();
+    renderPassImpl = framebuffer->GetImplFromRenderPass(renderPass);
+  }
+  else
+  {
+    auto framebufferHandle = mRenderTarget->GetFramebuffer();
+    framebuffer            = framebufferHandle->GetImpl();
+    renderPassImpl         = framebuffer->GetImplFromRenderPass(renderPass);
+    mController.AddTextureDependencies(renderTarget);
+  }
 
-    std::vector<vk::ClearValue> vkClearValues;
+  std::vector<vk::ClearValue> vkClearValues;
 
-    auto attachments = renderPass->GetCreateInfo().attachments;
-    if(attachments != nullptr &&
-       !attachments->empty()) // Can specify clear color even if load op is not clear.
+  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)
     {
-      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);
-      }
+      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[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);
 }
 
 void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->EndRenderPass();
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->EndRenderPass();
 }
 
 void CommandBuffer::ReadPixels(uint8_t* buffer)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->ReadPixels(buffer);
-  }
+
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->ReadPixels(buffer);
 }
 
 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& gfxCommandBuffers)
 {
   uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  std::vector<vk::CommandBuffer> vkCommandBuffers;
+  vkCommandBuffers.reserve(gfxCommandBuffers.size());
+  for(auto& gfxCmdBuf : gfxCommandBuffers)
   {
-    std::vector<vk::CommandBuffer> vkCommandBuffers;
-    vkCommandBuffers.reserve(gfxCommandBuffers.size());
-    for(auto& gfxCmdBuf : gfxCommandBuffers)
-    {
-      vkCommandBuffers.push_back(ConstGraphicsCast<CommandBuffer, Graphics::CommandBuffer>(gfxCmdBuf)->GetImpl()->GetVkHandle());
-    }
-    mCommandBufferImpl[bufferIndex]->ExecuteCommandBuffers(vkCommandBuffers);
+    vkCommandBuffers.push_back(ConstGraphicsCast<CommandBuffer, Graphics::CommandBuffer>(gfxCmdBuf)->GetImpl()->GetVkHandle());
   }
+  mCommandBufferImpl[bufferIndex]->ExecuteCommandBuffers(vkCommandBuffers);
 }
 
 void CommandBuffer::Draw(uint32_t vertexCount,
@@ -303,10 +292,9 @@ void CommandBuffer::Draw(uint32_t vertexCount,
                          uint32_t firstInstance)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->Draw(vertexCount, instanceCount, firstVertex, firstInstance);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->Draw(vertexCount, instanceCount, firstVertex, firstInstance);
 }
 
 void CommandBuffer::DrawIndexed(uint32_t indexCount,
@@ -316,10 +304,9 @@ void CommandBuffer::DrawIndexed(uint32_t indexCount,
                                 uint32_t firstInstance)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    mCommandBufferImpl[bufferIndex]->DrawIndexed(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  mCommandBufferImpl[bufferIndex]->DrawIndexed(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
 }
 
 void CommandBuffer::DrawIndexedIndirect(Graphics::Buffer& gfxBuffer,
@@ -328,11 +315,10 @@ void CommandBuffer::DrawIndexedIndirect(Graphics::Buffer& gfxBuffer,
                                         uint32_t          stride)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    auto buffer = ConstGraphicsCast<Buffer, Graphics::Buffer>(&gfxBuffer)->GetImpl();
-    mCommandBufferImpl[bufferIndex]->DrawIndexedIndirect(*buffer, offset, drawCount, stride);
-  }
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  auto buffer = ConstGraphicsCast<Buffer, Graphics::Buffer>(&gfxBuffer)->GetImpl();
+  mCommandBufferImpl[bufferIndex]->DrawIndexedIndirect(*buffer, offset, drawCount, stride);
 }
 
 void CommandBuffer::DrawNative(const DrawNativeInfo* drawInfo)
@@ -342,14 +328,13 @@ void CommandBuffer::DrawNative(const DrawNativeInfo* drawInfo)
 void CommandBuffer::SetScissor(Rect2D value)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    // @todo Vulkan accepts array of scissors... add to API
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
 
-    if(SetDynamicState(mDynamicState.scissor, value, DynamicStateMaskBits::SCISSOR))
-    {
-      mCommandBufferImpl[bufferIndex]->SetScissor(value);
-    }
+  // @todo Vulkan accepts array of scissors... add to API
+
+  if(SetDynamicState(mDynamicState.scissor, value, DynamicStateMaskBits::SCISSOR))
+  {
+    mCommandBufferImpl[bufferIndex]->SetScissor(value);
   }
 }
 
@@ -370,12 +355,11 @@ void CommandBuffer::SetViewport(Viewport value)
   }
 
   uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  if(SetDynamicState(mDynamicState.viewport, correctedValue, DynamicStateMaskBits::VIEWPORT))
   {
-    if(SetDynamicState(mDynamicState.viewport, correctedValue, DynamicStateMaskBits::VIEWPORT))
-    {
-      mCommandBufferImpl[bufferIndex]->SetViewport(correctedValue);
-    }
+    mCommandBufferImpl[bufferIndex]->SetViewport(correctedValue);
   }
 }
 
@@ -402,24 +386,22 @@ void CommandBuffer::ClearDepthBuffer()
 void CommandBuffer::SetStencilTestEnable(bool stencilEnable)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  if(SetDynamicState(mDynamicState.stencilTest, stencilEnable, DynamicStateMaskBits::STENCIL_TEST))
   {
-    if(SetDynamicState(mDynamicState.stencilTest, stencilEnable, DynamicStateMaskBits::STENCIL_TEST))
-    {
-      mCommandBufferImpl[bufferIndex]->SetStencilTestEnable(stencilEnable);
-    }
+    mCommandBufferImpl[bufferIndex]->SetStencilTestEnable(stencilEnable);
   }
 }
 
 void CommandBuffer::SetStencilWriteMask(uint32_t writeMask)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
+  if(SetDynamicState(mDynamicState.stencilWriteMask, writeMask, DynamicStateMaskBits::STENCIL_WRITE_MASK))
   {
-    if(SetDynamicState(mDynamicState.stencilWriteMask, writeMask, DynamicStateMaskBits::STENCIL_WRITE_MASK))
-    {
-      mCommandBufferImpl[bufferIndex]->SetStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack, writeMask);
-    }
+    mCommandBufferImpl[bufferIndex]->SetStencilWriteMask(vk::StencilFaceFlagBits::eFrontAndBack, writeMask);
   }
 }
 
@@ -431,6 +413,8 @@ void CommandBuffer::SetStencilState(Graphics::CompareOp compareOp,
                                     Graphics::StencilOp depthFailOp)
 {
   uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+
   if(SetDynamicState(mDynamicState.stencilCompareMask, compareMask, DynamicStateMaskBits::STENCIL_COMP_MASK))
   {
     mCommandBufferImpl[bufferIndex]->SetStencilCompareMask(vk::StencilFaceFlagBits::eFrontAndBack, compareMask);
@@ -456,36 +440,30 @@ void CommandBuffer::SetStencilState(Graphics::CompareOp compareOp,
 void CommandBuffer::SetDepthCompareOp(Graphics::CompareOp compareOp)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+  if(SetDynamicState(mDynamicState.depthCompareOp, compareOp, DynamicStateMaskBits::DEPTH_OP_COMP))
   {
-    if(SetDynamicState(mDynamicState.depthCompareOp, compareOp, DynamicStateMaskBits::DEPTH_OP_COMP))
-    {
-      mCommandBufferImpl[bufferIndex]->SetDepthCompareOp(VkCompareOpType(compareOp).op);
-    }
+    mCommandBufferImpl[bufferIndex]->SetDepthCompareOp(VkCompareOpType(compareOp).op);
   }
 }
 
 void CommandBuffer::SetDepthTestEnable(bool depthTestEnable)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+  if(SetDynamicState(mDynamicState.depthTest, depthTestEnable, DynamicStateMaskBits::DEPTH_TEST))
   {
-    if(SetDynamicState(mDynamicState.depthTest, depthTestEnable, DynamicStateMaskBits::DEPTH_TEST))
-    {
-      mCommandBufferImpl[bufferIndex]->SetDepthTestEnable(depthTestEnable);
-    }
+    mCommandBufferImpl[bufferIndex]->SetDepthTestEnable(depthTestEnable);
   }
 }
 
 void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+  if(SetDynamicState(mDynamicState.depthWrite, depthWriteEnable, DynamicStateMaskBits::DEPTH_WRITE))
   {
-    if(SetDynamicState(mDynamicState.depthWrite, depthWriteEnable, DynamicStateMaskBits::DEPTH_WRITE))
-    {
-      mCommandBufferImpl[bufferIndex]->SetDepthWriteEnable(depthWriteEnable);
-    }
+    mCommandBufferImpl[bufferIndex]->SetDepthWriteEnable(depthWriteEnable);
   }
 }
 
@@ -498,11 +476,8 @@ Vulkan::RenderTarget* CommandBuffer::GetRenderTarget() const
 [[nodiscard]] Vulkan::CommandBufferImpl* CommandBuffer::GetImpl() const
 {
   const uint32_t bufferIndex = mController.GetGraphicsDevice().GetCurrentBufferIndex();
-  if(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex])
-  {
-    return mCommandBufferImpl[bufferIndex];
-  }
-  return nullptr;
+  DALI_ASSERT_ALWAYS(bufferIndex < mCommandBufferImpl.size() && mCommandBufferImpl[bufferIndex]);
+  return mCommandBufferImpl[bufferIndex];
 }
 
 } // namespace Dali::Graphics::Vulkan
index 21d7fde9e05e51ab2f9b7c228ed6db3428f75720..7c273caec02777b2dbd3dee4a30381f73329b73e 100644 (file)
@@ -219,8 +219,7 @@ 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);
@@ -310,8 +309,7 @@ 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);
@@ -566,8 +564,7 @@ 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;
 }
 
@@ -618,6 +615,7 @@ void VulkanGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo
       auto surface   = renderTarget->GetSurface();
       auto surfaceId = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface)->GetSurfaceId();
       auto swapchain = GetGraphicsDevice().GetSwapchainForSurfaceId(surfaceId);
+
       renderTarget->CreateSubmissionData(cmdBuffer, submitData);
       swapchain->GetQueue()->Submit(submitData, swapchain->GetEndOfFrameFence());
     }
@@ -745,8 +743,7 @@ 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)
@@ -781,8 +778,7 @@ 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<char*>(*ppStagingMemory);
 
             // Try to initialise` texture resources explicitly if they are not yet initialised
@@ -820,8 +816,7 @@ 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);
index 5a34b9bd515ec27c2ea0638df5aa6ebbbb2a8fbf..352d82a75577db27a8b018ca60648fc4f72329f6 100644 (file)
@@ -92,7 +92,7 @@ void Image::Destroy()
 {
   DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying image: %p\n", static_cast<VkImage>(mImage));
   auto device = mDevice.GetLogicalDevice();
-  if(mImage)
+  if(mImage && !mIsExternal)
   {
     device.destroyImage(mImage, mDevice.GetAllocator());
   }
index f6a58d0a2e10fee709785f33eeda4e236cd97a33..07b9d9c654e90ba85fede8154ac36dae8a340e28 100644 (file)
@@ -164,8 +164,7 @@ 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;
                             });
 
@@ -239,6 +238,8 @@ void Swapchain::CreateFramebuffers(FramebufferAttachmentHandle depthAttachment)
 
   mFramebuffers.clear();
   mFramebuffers.reserve(images.size());
+  mSwapchainImages.clear();
+  mSwapchainImages.reserve(images.size());
 
   auto clearColor = vk::ClearColorValue{}.setFloat32({1.0f, 0.0f, 1.0f, 1.0f});
 
@@ -251,6 +252,7 @@ void Swapchain::CreateFramebuffers(FramebufferAttachmentHandle depthAttachment)
     auto colorImage = mGraphicsDevice.CreateImageFromExternal(image,
                                                               mSwapchainCreateInfoKHR.imageFormat,
                                                               mSwapchainCreateInfoKHR.imageExtent);
+    mSwapchainImages.emplace_back(colorImage);
 
     std::unique_ptr<ImageView> colorImageView;
     colorImageView.reset(ImageView::NewFromImage(mGraphicsDevice, *colorImage));
@@ -269,8 +271,7 @@ void Swapchain::CreateFramebuffers(FramebufferAttachmentHandle depthAttachment)
                            depthAttachment,
                            mSwapchainCreateInfoKHR.imageExtent.width,
                            mSwapchainCreateInfoKHR.imageExtent.height),
-      [](FramebufferImpl* framebuffer1)
-      {
+      [](FramebufferImpl* framebuffer1) {
         framebuffer1->Destroy();
         delete framebuffer1;
       });
index c1064268ddafff653163abdf0d4cd23adae688dc..222cf474ef2e57620da9b490f761719d3a409052 100644 (file)
@@ -179,8 +179,9 @@ private:
    * FramebufferImpl object associated with the buffer
    */
   using OwnedFramebuffer = std::unique_ptr<FramebufferImpl, void (*)(FramebufferImpl*)>;
-  std::vector<OwnedFramebuffer> mFramebuffers;
-  std::unique_ptr<Image>        mDepthStencilBuffer;
+  std::vector<OwnedFramebuffer>       mFramebuffers;
+  std::vector<std::unique_ptr<Image>> mSwapchainImages;
+  std::unique_ptr<Image>              mDepthStencilBuffer;
 
   /**
    * Array of swapchain buffers
index 4e761bc1f6738fbcb902dba5f1eb011dbeed21a8..a93d8f70a88da8c1bc6a8d38450953e1daa4a187 100644 (file)
@@ -395,32 +395,29 @@ Swapchain* Device::CreateSwapchain(SurfaceImpl*       surface,
   return newSwapchain;
 }
 
-void Device::AcquireNextImage()
+void Device::AcquireNextImage(SurfaceId surfaceId)
 {
-  for(auto& s : mSurfaceMap)
+  auto swapchain = mSurfaceMap[surfaceId].swapchain;
+  if(swapchain != nullptr)
   {
-    auto swapchain = s.second.swapchain;
-    if(swapchain != nullptr)
-    {
-      FramebufferImpl* framebuffer = swapchain->AcquireNextFramebuffer(true);
+    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();
+    // 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));
+      // 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!");
+      // get new valid framebuffer
+      if(swapchain)
+      {
+        framebuffer = swapchain->AcquireNextFramebuffer(true);
       }
+      DALI_ASSERT_ALWAYS(framebuffer && "Replacing invalid swapchain unsuccessful! Goodbye!");
     }
   }
 }
index bbc934b311a8c5ce96c81863ee38a00a81ef4988..2b9c108fb6b323b157e596cb17cd8a0ea31c35c9 100644 (file)
@@ -75,7 +75,13 @@ public: // Create methods
 
   Swapchain* CreateSwapchain(SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, uint32_t& bufferCount, Swapchain*&& oldSwapchain);
 
-  void AcquireNextImage();
+  /**
+   * Ensures that the next available image is retrieved for drawing onto.
+   * Should only call this method if there is something to present, as this
+   * sets up a fence, and will cause a stall if nothing waits on it.
+   * @param surfaceId The id of the surface to get the next image for
+   */
+  void AcquireNextImage(SurfaceId surfaceId);
 
   vk::Result Present(Queue& queue, vk::PresentInfoKHR& presentInfo);
   vk::Result QueueWaitIdle(Queue& queue);
index b1abde1d752d488a654f5afd73dd53ef01235e27..b54e6660f5a5a85ea0a4d980bc89210447cdc91f 100644 (file)
@@ -23,6 +23,8 @@
 #include <dali/internal/system/common/configuration-manager.h>
 #include <vector>
 
+#include "dali/internal/window-system/common/window-render-surface.h"
+
 extern "C" std::vector<uint32_t> GraphicsGetBuiltinShader(const std::string& tag);
 
 namespace Dali
@@ -120,6 +122,12 @@ void VulkanGraphics::MakeContextCurrent(Graphics::SurfaceId surfaceId)
 {
 }
 
+void VulkanGraphics::AcquireNextImage(Integration::RenderSurfaceInterface* surface)
+{
+  auto surfaceId = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface)->GetSurfaceId();
+  mGraphicsDevice.AcquireNextImage(surfaceId);
+}
+
 void VulkanGraphics::PostRender()
 {
   mGraphicsDevice.SwapBuffers();
index 1f4a64dfbf7a1eff0bf52baa867421603c1cd55e..3bd7a7cf5fd1aa22ffca4e471b6926cbbaa5904c 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_VULKAN_GRAPHICS_IMPLEMENTATION_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.
@@ -82,6 +82,11 @@ public:
    */
   void MakeContextCurrent(Graphics::SurfaceId surfaceId) override;
 
+  /**
+   * @copydoc Graphics::GraphicsInterface::AcquireNextImage()
+   */
+  void AcquireNextImage(Integration::RenderSurfaceInterface* surface) override;
+
   /**
    * Inform graphics interface that all the surfaces have been rendered.
    *
index f96417b39ee6e75256550ac91cab510328b63c09..8ea6f1c22754a5dc90c1064d87d5ee7ff6d96067 100644 (file)
@@ -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.
@@ -543,7 +543,7 @@ bool WindowRenderSurface::PreRender(bool resizingSurface, const std::vector<Rect
     DALI_LOG_RELEASE_INFO("Window/Screen orientation ard changed, WinOrientation[%d],flag[%d], ScreenOrientation[%d],flag[%d], total[%d]\n", mWindowRotationAngle, mIsWindowOrientationChanging, mScreenRotationAngle, isScreenOrientationChanging, totalAngle);
 
     Rect<int> surfaceSize = scene.GetCurrentSurfaceRect();
-    //update surface size
+    // update surface size
     mPositionSize.width  = surfaceSize.width;
     mPositionSize.height = surfaceSize.height;
 
@@ -775,9 +775,8 @@ void WindowRenderSurface::OnFileDescriptorEventDispatched(FileDescriptorMonitor:
   {
     Dali::Mutex::ScopedLock lock(mMutex);
 
-    auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo) {
-      return callbackInfo->fileDescriptor == fileDescriptor;
-    });
+    auto frameCallbackInfo = std::find_if(mFrameCallbackInfoContainer.begin(), mFrameCallbackInfoContainer.end(), [fileDescriptor](std::unique_ptr<FrameCallbackInfo>& callbackInfo)
+                                          { return callbackInfo->fileDescriptor == fileDescriptor; });
     if(frameCallbackInfo != mFrameCallbackInfoContainer.end())
     {
       callbackInfo = std::move(*frameCallbackInfo);