Implementing framebuffer in vulkan backend 62/315762/14
authorDavid Steele <david.steele@samsung.com>
Thu, 12 Dec 2024 11:36:59 +0000 (11:36 +0000)
committerDavid Steele <david.steele@samsung.com>
Thu, 23 Jan 2025 16:45:17 +0000 (16:45 +0000)
High level:
----------
Added render pass constructors for fbo.

Added offscreen texture dependency graph.

FBO command submission requires texture dependencies to ensure that
syncing semaphores are correctly setup.

Added submission semaphore to RenderTarget

Detail
------
vulkan-command-buffer.h/.cpp
  - Added mRenderTarget member which is stored when Begin() cmd is issued on this buffer.
  - Added call to check texture dependencies when BindTextures() cmd is issued.
  - Added call to add texture dependencies when BeginRenderPass() cmd is issued.
  - Replaced GetLastSwapchain with GetRenderTarget() (More generic)

vulkan-framebuffer.h/.cpp
  - Added render pass generation

vulkan-framebuffer-attachment.h
  - Added AttachmentDescription to constructor/New

vulkan-framebuffer-impl.h/cpp
  - Add AddRenderPass() method
  - Changed Attachment constructor to copy AttachmentDescription if not null, or use "Clear"/"Store"
    for load / store ops, respectively.

vulkan-graphics-controller.h/cpp
  - Changed FrameStart() to reset texture dependency graph
  - Changed SubmitCommandBuffers() to submit for all render targets (not just swapchain)
  - Changed PresentRenderTarget() to only present swapchain target
  - Changed CreateRenderTarget() to add render target to dependency checker
  - Added CreateFramebuffer() implementation
  - Added texture dependency methods
    - AddTextureDependencies() goes thru each attachment of a render target and adds it to the
        dependency checker
    - CheckTextureDependencies() goes through each bound texture to determine if it needs to wait
        on a render target submission
    - RemoveRenderTarget() - removes render target from dependency graph

vulkan-render-pass-impl.h/cpp
  - Added new New factory fn to pass in CreateInfo
  - Separated out sub-pass dependency generation - different setup for offscreen/swapchain.
  - Storing attachment handles in CreateInfo

vulkan-render-target.h/.cpp
  - Added mSubmitSemaphore. This is used when Submitting offscreen command buffers to the graphics
    queue to handle synchronization between render targets - the submission can wait on dependent
    targets to finish drawing to offscreens.
  - Added Submit() method to submit for either offscreen / swapchain.

vulkan-swapchain-impl.h/.cpp
  - Changed to use Queue::Submit method

vulkan-texture.h
  - Addition of CreateImageView() which ensures the image is allocated, and creates
    separate image view using existing parameters.

vulkan-queue.h/cpp
  - Moved Submit() function from Device class to Queue as method.

Change-Id: I12dad2805e4a25f431878e0c3bf07bead1943694
Signed-off-by: David Steele <david.steele@samsung.com>
25 files changed:
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp
dali/internal/graphics/file.list
dali/internal/graphics/vulkan-impl/vulkan-command-buffer.cpp
dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h
dali/internal/graphics/vulkan-impl/vulkan-framebuffer-attachment.h
dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h
dali/internal/graphics/vulkan-impl/vulkan-framebuffer.cpp
dali/internal/graphics/vulkan-impl/vulkan-framebuffer.h
dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.cpp
dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h
dali/internal/graphics/vulkan-impl/vulkan-pipeline-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-queue-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-queue-impl.h
dali/internal/graphics/vulkan-impl/vulkan-render-pass-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-render-pass-impl.h
dali/internal/graphics/vulkan-impl/vulkan-render-target.cpp
dali/internal/graphics/vulkan-impl/vulkan-render-target.h
dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.cpp [new file with mode: 0644]
dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.h [new file with mode: 0644]
dali/internal/graphics/vulkan-impl/vulkan-texture.cpp
dali/internal/graphics/vulkan-impl/vulkan-texture.h
dali/internal/graphics/vulkan/vulkan-device.cpp
dali/internal/graphics/vulkan/vulkan-device.h

index 1fa33c453d6564af570d39350fef3527efa13d16..e5a943a51a052f1419b17f2124b86db19ac38150 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.
@@ -97,6 +97,7 @@ void TestApplication::InitializeCore()
 {
   mCore->SceneCreated();
   mCore->Initialize();
+  mCore->ProcessEvents(); // Ensure that scene messages are ready for next update/render.
 }
 
 TestApplication::~TestApplication()
index 7e20b1562c02096a5e7cf8dbf6375c757ea1d71d..f7191d66d8d8f0d50225fec1b36482ace0f4e22c 100644 (file)
@@ -50,6 +50,7 @@ SET( adaptor_graphics_vulkan_src_files
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-sampler.cpp
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-sampler-impl.cpp
     ${adaptor_graphics_dir}/vulkan-impl/vulkan-texture.cpp
+    ${adaptor_graphics_dir}/vulkan-impl/vulkan-texture-dependency-checker.cpp
 )
 
 # module: graphics, backend: vulkan/x11
index ebb4c6edd25180c485a6b774d2fe9e78296a00e2..e43253b2b55c356d9112afb8cf02dcc61361ce81 100644 (file)
@@ -80,15 +80,16 @@ void CommandBuffer::DiscardResource()
 void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info)
 {
   mDynamicStateMask = CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE;
+  mRenderTarget     = ConstGraphicsCast<Vulkan::RenderTarget, Graphics::RenderTarget>(info.renderTarget);
+
   if(mCommandBufferImpl)
   {
     vk::CommandBufferInheritanceInfo inheritanceInfo{};
     if(info.renderPass)
     {
-      auto renderTarget                  = ConstGraphicsCast<Vulkan::RenderTarget, Graphics::RenderTarget>(info.renderTarget);
-      inheritanceInfo.renderPass         = renderTarget->GetRenderPass(info.renderPass)->GetVkHandle();
+      inheritanceInfo.renderPass         = mRenderTarget->GetRenderPass(info.renderPass)->GetVkHandle();
       inheritanceInfo.subpass            = 0;
-      inheritanceInfo.framebuffer        = renderTarget->GetCurrentFramebufferImpl()->GetVkHandle();
+      inheritanceInfo.framebuffer        = mRenderTarget->GetCurrentFramebufferImpl()->GetVkHandle();
       inheritanceInfo.queryFlags         = static_cast<vk::QueryControlFlags>(0);
       inheritanceInfo.pipelineStatistics = static_cast<vk::QueryPipelineStatisticFlags>(0);
     }
@@ -117,7 +118,7 @@ void CommandBuffer::Reset()
     mCommandBufferImpl->Reset();
   }
   mDynamicStateMask = CommandBuffer::INITIAL_DYNAMIC_MASK_VALUE;
-  mLastSwapchain    = nullptr;
+  mRenderTarget     = nullptr;
 }
 
 void CommandBuffer::BindVertexBuffers(uint32_t                                    firstBinding,
@@ -155,6 +156,7 @@ void CommandBuffer::BindPipeline(const Graphics::Pipeline& pipeline)
 void CommandBuffer::BindTextures(const std::vector<TextureBinding>& textureBindings)
 {
   mCommandBufferImpl->BindTextures(textureBindings);
+  mController.CheckTextureDependencies(textureBindings, mRenderTarget);
 }
 
 void CommandBuffer::BindSamplers(const std::vector<SamplerBinding>& samplerBindings)
@@ -173,10 +175,12 @@ void CommandBuffer::BeginRenderPass(Graphics::RenderPass*          gfxRenderPass
                                     Rect2D                         renderArea,
                                     const std::vector<ClearValue>& clearValues)
 {
-  auto             renderPass   = static_cast<Vulkan::RenderPass*>(gfxRenderPass);
-  auto             renderTarget = static_cast<Vulkan::RenderTarget*>(gfxRenderTarget);
-  auto             surface      = renderTarget->GetSurface();
-  auto&            device       = mController.GetGraphicsDevice();
+  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)
@@ -217,16 +221,17 @@ void CommandBuffer::BeginRenderPass(Graphics::RenderPass*          gfxRenderPass
       {
         framebuffer = swapchain->AcquireNextFramebuffer(true);
       }
-      assert(framebuffer && "Replacing invalid swapchain unsuccessful! Goodbye!");
+      DALI_ASSERT_ALWAYS(framebuffer && "Replacing invalid swapchain unsuccessful! Goodbye!");
     }
 
     renderPassImpl = framebuffer->GetImplFromRenderPass(renderPass);
   }
   else
   {
-    auto coreFramebuffer = renderTarget->GetFramebuffer();
+    auto coreFramebuffer = mRenderTarget->GetFramebuffer();
     framebuffer          = coreFramebuffer->GetImpl();
     renderPassImpl       = framebuffer->GetImplFromRenderPass(renderPass);
+    mController.AddTextureDependencies(mRenderTarget);
   }
 
   std::vector<vk::ClearValue> vkClearValues;
@@ -420,9 +425,10 @@ void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
   }
 }
 
-Swapchain* CommandBuffer::GetLastSwapchain() const
+Vulkan::RenderTarget* CommandBuffer::GetRenderTarget() const
 {
-  return mLastSwapchain;
+  // Gets the render target from the Begin() cmd.
+  return mRenderTarget;
 }
 
 } // namespace Dali::Graphics::Vulkan
index 296faded5655d334f8455621089f5747bbe36fca..f50cdd41bb1358b4824307a6861164f9acbc4460 100644 (file)
@@ -25,6 +25,7 @@ namespace Dali::Graphics::Vulkan
 {
 class CommandBufferImpl;
 class Swapchain;
+class RenderTarget;
 
 using CommandBufferResource = Resource<Graphics::CommandBuffer, Graphics::CommandBufferCreateInfo>;
 
@@ -378,14 +379,12 @@ public: // VulkanResource API
 
 public: // API
   /**
-   * Get the last swapchain referenced by a BeginRenderPass command in this command buffer.
-   *
-   * @todo Should split the command buffer up into multiple buffers if there is more than one
-   * render target referenced in it.
+   * Get the last target referenced by a BeginRenderPass command in this command buffer.
+   * Core now splits up command buffers so that they contain 1 render target each.
    */
-  Swapchain* GetLastSwapchain() const;
+  RenderTarget* GetRenderTarget() const;
 
-  CommandBufferImpl* GetImpl() const
+  [[nodiscard]] CommandBufferImpl* GetImpl() const
   {
     return mCommandBufferImpl;
   }
@@ -425,6 +424,7 @@ private:
   }
 
   CommandBufferImpl* mCommandBufferImpl;
+  RenderTarget*      mRenderTarget{nullptr};
   Swapchain*         mLastSwapchain{nullptr};
 };
 
index ab0316790ae4f4cc756f16ec3ab4ef9a73f3012a..012834e810e3738d37d18fdf2537f019c9244c23 100644 (file)
@@ -42,33 +42,42 @@ public:
    *
    * @param[in] imageView The imageview of the attachment
    * @param[in] clearColor The color used to clear this attachment during CLEAR_OP
+   * @param[in] description Expected Load/Store ops
    * @param[in] type The attachment type (usually COLOR or DEPTH_STENCIL)
    * @param[in] presentable Whether the attachment is presentable (changes final layout)
    */
-  FramebufferAttachment(std::unique_ptr<ImageView>& imageView,
-                        vk::ClearValue              clearColor,
-                        AttachmentType              type,
-                        bool                        presentable);
+  FramebufferAttachment(
+    std::unique_ptr<ImageView>&            imageView,
+    vk::ClearValue                         clearColor,
+    const Graphics::AttachmentDescription* description,
+    AttachmentType                         type,
+    bool                                   presentable);
 
   /**
    * Creates a new color attachment.
    *
    * @param[in] imageView The imageview of the attachment
    * @param[in] clearColorValue The color used to clear this attachment during CLEAR_OP
+   * @param[in] description Expected Load/Store ops
    * @param[in] presentable Whether the attachment is presentable (changes final layout)
    */
-  static FramebufferAttachment* NewColorAttachment(std::unique_ptr<ImageView>& imageView,
-                                                   vk::ClearColorValue         clearColorValue,
-                                                   bool                        presentable);
+  static FramebufferAttachment* NewColorAttachment(
+    std::unique_ptr<ImageView>&            imageView,
+    vk::ClearColorValue                    clearColorValue,
+    const Graphics::AttachmentDescription* description,
+    bool                                   presentable);
 
   /**
    * Creates a new depth attachment.
    *
    * @param[in] imageView The imageview of the attachment
    * @param[in] clearDepthStencilValue The value used to clear this attachment during CLEAR_OP
+   * @param[in] description Expected Load/Store ops
    */
-  static FramebufferAttachment* NewDepthAttachment(std::unique_ptr<ImageView>& imageView,
-                                                   vk::ClearDepthStencilValue  clearDepthStencilValue);
+  static FramebufferAttachment* NewDepthAttachment(
+    std::unique_ptr<ImageView>&            imageView,
+    vk::ClearDepthStencilValue             clearDepthStencilValue,
+    const Graphics::AttachmentDescription* description);
 
   [[nodiscard]] ImageView* GetImageView() const;
 
@@ -86,7 +95,8 @@ private:
   std::unique_ptr<ImageView> mImageView;
   vk::AttachmentDescription  mDescription;
   vk::ClearValue             mClearValue;
-  AttachmentType             mType{AttachmentType::UNDEFINED};
+
+  AttachmentType mType{AttachmentType::UNDEFINED};
 };
 
 using FramebufferAttachmentHandle = Vulkan::Handle<FramebufferAttachment>; // Can share attachments
index b1bed3935b78e595d49d1f72e148ba2a7cb00dbf..be691e09b71700f3501955f17c6eb9de3ae40ffb 100644 (file)
@@ -33,37 +33,44 @@ extern Debug::Filter* gVulkanFilter;
 
 namespace Dali::Graphics::Vulkan
 {
-FramebufferAttachment* FramebufferAttachment::NewColorAttachment(std::unique_ptr<ImageView>& imageView,
-                                                                 vk::ClearColorValue         clearColorValue,
-                                                                 bool                        presentable)
+FramebufferAttachment* FramebufferAttachment::NewColorAttachment(
+  std::unique_ptr<ImageView>&            imageView,
+  vk::ClearColorValue                    clearColorValue,
+  const Graphics::AttachmentDescription* description,
+  bool                                   presentable)
 {
   assert(imageView->GetImage()->GetUsageFlags() & vk::ImageUsageFlagBits::eColorAttachment);
 
   auto attachment = new FramebufferAttachment(imageView,
                                               clearColorValue,
+                                              description,
                                               AttachmentType::COLOR,
                                               presentable);
   return attachment;
 }
 
 FramebufferAttachment* FramebufferAttachment::NewDepthAttachment(
-  std::unique_ptr<ImageView>& imageView,
-  vk::ClearDepthStencilValue  clearDepthStencilValue)
+  std::unique_ptr<ImageView>&            imageView,
+  vk::ClearDepthStencilValue             clearDepthStencilValue,
+  const Graphics::AttachmentDescription* description)
 {
   assert(imageView->GetImage()->GetUsageFlags() & vk::ImageUsageFlagBits::eDepthStencilAttachment);
 
   auto attachment = new FramebufferAttachment(imageView,
                                               clearDepthStencilValue,
+                                              description,
                                               AttachmentType::DEPTH_STENCIL,
                                               false /* presentable */);
 
   return attachment;
 }
 
-FramebufferAttachment::FramebufferAttachment(std::unique_ptr<ImageView>& imageView,
-                                             vk::ClearValue              clearColor,
-                                             AttachmentType              type,
-                                             bool                        presentable)
+FramebufferAttachment::FramebufferAttachment(
+  std::unique_ptr<ImageView>&            imageView,
+  vk::ClearValue                         clearColor,
+  const Graphics::AttachmentDescription* description,
+  AttachmentType                         type,
+  bool                                   presentable)
 : mClearValue(clearColor),
   mType(type)
 {
@@ -73,13 +80,22 @@ FramebufferAttachment::FramebufferAttachment(std::unique_ptr<ImageView>& imageVi
   auto sampleCountFlags = image->GetSampleCount();
 
   mDescription.setSamples(sampleCountFlags);
-
-  mDescription.setLoadOp(vk::AttachmentLoadOp::eClear);
-  mDescription.setStoreOp(vk::AttachmentStoreOp::eStore);
-  mDescription.setStencilLoadOp(vk::AttachmentLoadOp::eClear);
-  mDescription.setStencilStoreOp(vk::AttachmentStoreOp::eStore);
   mDescription.setFormat(image->GetFormat());
   mDescription.setInitialLayout(vk::ImageLayout::eUndefined);
+  if(description == nullptr)
+  {
+    mDescription.setLoadOp(vk::AttachmentLoadOp::eClear);
+    mDescription.setStoreOp(vk::AttachmentStoreOp::eStore);
+    mDescription.setStencilLoadOp(vk::AttachmentLoadOp::eClear);
+    mDescription.setStencilStoreOp(vk::AttachmentStoreOp::eStore);
+  }
+  else
+  {
+    mDescription.setLoadOp(VkLoadOpType(description->loadOp).loadOp);
+    mDescription.setStoreOp(VkStoreOpType(description->storeOp).storeOp);
+    mDescription.setStencilLoadOp(VkLoadOpType(description->stencilLoadOp).loadOp);
+    mDescription.setStencilStoreOp(VkStoreOpType(description->stencilStoreOp).storeOp);
+  }
 
   if(type == AttachmentType::DEPTH_STENCIL)
   {
@@ -366,7 +382,6 @@ RenderPassHandle FramebufferImpl::GetImplFromRenderPass(RenderPass* renderPass)
       if(createInfo.attachmentDescriptions[0].loadOp == VkLoadOpType(matchLoadOp).loadOp &&
          createInfo.attachmentDescriptions[0].storeOp == VkStoreOpType(matchStoreOp).storeOp)
       {
-        // Point at passed in render pass... should be a weak ptr... What's lifecycle?!
         element.renderPass = renderPass;
         return element.renderPassImpl;
       }
@@ -374,18 +389,28 @@ RenderPassHandle FramebufferImpl::GetImplFromRenderPass(RenderPass* renderPass)
   }
 
   // @todo create new render pass from existing + load/store op, add it to mRenderPasses, and return it.
-  // @todo Need to reconsider swapchain/fbo/renderpass creation model.
-  // This framebuffer may belong to a swapchain, in which case, there are multiple framebuffers
-  // that could share render passes.
-  // A) Need to detect this situation - keep owner info?
-  // B) Sharing render passes means we
-  //    1) need to ref-count to ensure safe ownership, or
-  //    2) move ownership of renderpass to swapchain.
-  //       Onus is on client to determine which interface to use, if it's a surface, use swapchain;
-  //       if it's an offscreen, use framebuffer. (Kinda need a core interface to wrap surface/offscreen)
+
   return mRenderPasses[0].renderPassImpl;
 }
 
+void FramebufferImpl::AddRenderPass(RenderPass* renderPass, Vulkan::RenderPassHandle renderPassImpl)
+{
+  bool found = false;
+  for(auto& element : mRenderPasses)
+  {
+    if(element.renderPassImpl == renderPassImpl && !element.renderPass)
+    {
+      element.renderPass = renderPass; // Update existing element with matched objects
+      found              = true;
+      break;
+    }
+  }
+  if(!found)
+  {
+    mRenderPasses.emplace_back(RenderPassMapElement{renderPass, renderPassImpl});
+  }
+}
+
 vk::Framebuffer FramebufferImpl::GetVkHandle() const
 {
   return mFramebuffer;
@@ -395,7 +420,6 @@ std::vector<vk::ClearValue> FramebufferImpl::GetClearValues() const
 {
   auto result = std::vector<vk::ClearValue>{};
 
-  // @todo & color clear enabled / depth clear enabled
   for(auto& attachment : mAttachments)
   {
     result.emplace_back(attachment->GetClearValue());
index da1b49209fcd76748ea439a3181df8812c382603..e00ac4687df1559a877f66debc66939055a62ea3 100644 (file)
@@ -26,8 +26,8 @@
 
 namespace Dali::Graphics::Vulkan
 {
-class RenderPass;
 class Device;
+class RenderPass;
 
 /**
  * FramebufferImpl encapsulates following objects:
@@ -110,7 +110,17 @@ public:
 
   [[nodiscard]] uint32_t GetAttachmentCount(AttachmentType type) const;
 
-  [[nodiscard]] RenderPassHandle GetImplFromRenderPass(RenderPass* renderPass); // May mutate mRenderPasses
+  /**
+   * Add a renderpass (load/store ops) + Impl (vk wrapper) to the framebuffer.
+   *
+   * The handle may point to the renderpass used to create the framebuffer.
+   * @param[in] renderPass A renderpass object (load/store ops)
+   * @param[in] renderPassImpl The vulkan wrapper to an actual render pass generated using
+   * the renderPass ops and framebuffer attachments.
+   */
+  void AddRenderPass(Vulkan::RenderPass* renderPass, Vulkan::RenderPassHandle renderPassImpl);
+
+  [[nodiscard]] RenderPassHandle GetImplFromRenderPass(Vulkan::RenderPass* renderPass); // May mutate mRenderPasses
 
   [[nodiscard]] RenderPassHandle GetRenderPass(uint32_t index) const;
 
index c95a952efb2efdda06d341495ba31bf810a62bc0..54ca921a560e5e7f710d11c4bedf1da0dd18feed 100644 (file)
 #include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-texture.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-types.h>
+
+template<class VulkanType, class GraphicsType>
+VulkanType* VulkanCast(GraphicsType* apiObject)
+{
+  return const_cast<VulkanType*>(static_cast<const VulkanType*>(apiObject));
+}
 
 namespace Dali::Graphics::Vulkan
 {
@@ -34,21 +42,73 @@ Framebuffer::~Framebuffer() = default;
 
 bool Framebuffer::InitializeResource()
 {
-  // Create attachments
-  SharedAttachments colorAttachments;
-  // for(auto& attachment : mCreateInfo.colorAttachments)
-  {
-    // auto graphicsTexture = static_cast<const Vulkan::Texture*>(attachment.texture);
-    // colorAttachments.push_back(FramebufferAttachment::NewColorAttachment(attachment.texture->GetVkHandle(), clearColor, AttachmentType::COLOR, false);
-  }
-  FramebufferAttachmentHandle depthStencilAttachment;
-  if(mCreateInfo.depthStencilAttachment.depthTexture || mCreateInfo.depthStencilAttachment.stencilTexture)
+  auto& device          = mController.GetGraphicsDevice();
+  bool  firstRenderPass = true;
+
+  // There are usually 2 render passes, Clear & Load.
+  // They only contain load/store ops for each of color / depth&stencil attachments.
+  for(auto& gfxRenderPass : mCreateInfo.renderPasses)
   {
-    // depthStencilAttachment = FramebufferAttachment::NewDepthAttachment();
-  }
+    auto* renderPass             = VulkanCast<Vulkan::RenderPass>(gfxRenderPass);
+    auto& attachmentDescriptions = *renderPass->GetCreateInfo().attachments;
+
+    // Each attachment description must match passed in attachments.
+    size_t attachmentDescriptionIndex = 0;
+
+    // Create attachments
+    SharedAttachments colorAttachments;
+
+    auto clearColor = vk::ClearColorValue{}.setFloat32({1.0f, 0.0f, 1.0f, 1.0f});
 
-  auto& device     = mController.GetGraphicsDevice();
-  mFramebufferImpl = FramebufferImpl::New(device, RenderPassHandle{}, colorAttachments, depthStencilAttachment, mCreateInfo.size.width, mCreateInfo.size.height);
+    for(auto& attachment : mCreateInfo.colorAttachments)
+    {
+      auto* graphicsTexture = VulkanCast<Vulkan::Texture>(attachment.texture);
+      DALI_ASSERT_DEBUG(attachmentDescriptionIndex < attachmentDescriptions.size() &&
+                        "Render pass attachment descriptions out of range");
+
+      // FramebufferAttachment takes ownership of the image view. So, create new view onto the image.
+      std::unique_ptr<ImageView> imageView = graphicsTexture->CreateImageView();
+      colorAttachments.emplace_back(FramebufferAttachment::NewColorAttachment(imageView, clearColor, &attachmentDescriptions[attachmentDescriptionIndex++], false));
+    }
+
+    FramebufferAttachmentHandle depthStencilAttachment;
+
+    auto depthClearValue = vk::ClearDepthStencilValue{}.setDepth(0.0).setStencil(STENCIL_DEFAULT_CLEAR_VALUE);
+
+    if(mCreateInfo.depthStencilAttachment.depthTexture)
+    {
+      DALI_ASSERT_DEBUG(attachmentDescriptionIndex < attachmentDescriptions.size() && "Render pass attachment descriptions out of range");
+
+      auto                       depthTexture = VulkanCast<Vulkan::Texture>(mCreateInfo.depthStencilAttachment.depthTexture);
+      std::unique_ptr<ImageView> imageView    = depthTexture->CreateImageView();
+      depthStencilAttachment                  = FramebufferAttachmentHandle(FramebufferAttachment::NewDepthAttachment(imageView, depthClearValue, &attachmentDescriptions[attachmentDescriptionIndex++]));
+    }
+    else if(mCreateInfo.depthStencilAttachment.stencilTexture)
+    {
+      DALI_ASSERT_DEBUG(attachmentDescriptionIndex < attachmentDescriptions.size() && "Render pass attachment descriptions out of range");
+      auto                       stencilTexture = VulkanCast<Vulkan::Texture>(mCreateInfo.depthStencilAttachment.stencilTexture);
+      std::unique_ptr<ImageView> imageView      = stencilTexture->CreateImageView();
+      depthStencilAttachment                    = FramebufferAttachmentHandle(FramebufferAttachment::NewDepthAttachment(imageView, depthClearValue, &attachmentDescriptions[attachmentDescriptionIndex++]));
+    }
+
+    RenderPassImpl::CreateInfo createInfo;
+    RenderPassImpl::CreateCompatibleCreateInfo(createInfo, colorAttachments, depthStencilAttachment, true);
+    auto renderPassImpl = RenderPassHandle(RenderPassImpl::New(device, createInfo));
+
+    if(firstRenderPass)
+    {
+      // Create a framebuffer using the first render pass. Subsequent render passes will be created that
+      // are compatible.
+      mFramebufferImpl = FramebufferImpl::New(device, renderPassImpl, colorAttachments, depthStencilAttachment, mCreateInfo.size.width, mCreateInfo.size.height);
+    }
+
+    // Add the renderPass/renderPassImpl pair to the framebuffer.
+    if(mFramebufferImpl)
+    {
+      mFramebufferImpl->AddRenderPass(renderPass, renderPassImpl);
+    }
+    firstRenderPass = false;
+  }
 
   return true;
 }
index 447422ad7eb8594a9ab39e3d9cfef7669cd5a312..227082642c3ae1f5452ed6ebf4f0292843b933ea 100644 (file)
@@ -19,6 +19,7 @@
  */
 
 #include <dali/internal/graphics/vulkan-impl/vulkan-graphics-resource.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-render-pass-impl.h>
 
 #include <dali/graphics-api/graphics-framebuffer-create-info.h>
 #include <dali/graphics-api/graphics-framebuffer.h>
@@ -80,7 +81,8 @@ public:
   }
 
 private:
-  FramebufferImpl* mFramebufferImpl;
+  FramebufferImpl*              mFramebufferImpl;
+  std::vector<RenderPassHandle> mRenderPasses;
 };
 
 } // namespace Vulkan
index 3ea17d5bc458091427aefc5c8df8e3680cacf675..9d4d8a4bbb05a2e807e85bd2d7494a3e801d7bc1 100644 (file)
@@ -36,6 +36,7 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-target.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-sampler.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-shader.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-texture.h>
 #include <dali/internal/window-system/common/window-render-surface.h>
 
@@ -151,7 +152,8 @@ using DepthStencilFlags = uint32_t;
 struct VulkanGraphicsController::Impl
 {
   explicit Impl(VulkanGraphicsController& controller)
-  : mGraphicsController(controller)
+  : mGraphicsController(controller),
+    mDependencyChecker(controller)
   {
   }
 
@@ -419,7 +421,7 @@ struct VulkanGraphicsController::Impl
         commandBuffer->End();
 
         // submit to the queue
-        mGraphicsDevice->Submit(mGraphicsDevice->GetTransferQueue(0u), {Vulkan::SubmissionData{{}, {}, {commandBuffer->GetImpl()}, {}}}, fence.get());
+        mGraphicsDevice->GetTransferQueue(0u).Submit({Vulkan::SubmissionData{{}, {}, {commandBuffer->GetImpl()}, {}}}, fence.get());
         fence->Wait();
         fence->Reset();
       }
@@ -514,6 +516,8 @@ struct VulkanGraphicsController::Impl
   VulkanGraphicsController& mGraphicsController;
   Vulkan::Device*           mGraphicsDevice{nullptr};
 
+  Vulkan::TextureDependencyChecker mDependencyChecker; ///< Dependencies between framebuffers/scene
+
   // used for texture<->buffer<->memory transfers
   std::vector<ResourceTransferRequest>     mResourceTransferRequests;
   std::recursive_mutex                     mResourceTransferMutex{};
@@ -559,6 +563,8 @@ Integration::GraphicsConfig& VulkanGraphicsController::GetGraphicsConfig()
 
 void VulkanGraphicsController::FrameStart()
 {
+  mImpl->mDependencyChecker.Reset(); // Clean down the dependency graph.
+
   mImpl->mCapacity = 0;
 }
 
@@ -582,14 +588,17 @@ void VulkanGraphicsController::SetResourceBindingHints(const std::vector<SceneRe
 
 void VulkanGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
 {
-  // Figure out where to submit each command buffer.
+  SubmissionData submitData;
   for(auto gfxCmdBuffer : submitInfo.cmdBuffer)
   {
-    auto cmdBuffer = static_cast<const CommandBuffer*>(gfxCmdBuffer);
-    auto swapchain = cmdBuffer->GetLastSwapchain();
-    if(swapchain)
+    auto cmdBuffer    = static_cast<const CommandBuffer*>(gfxCmdBuffer);
+    auto renderTarget = cmdBuffer->GetRenderTarget();
+    DALI_ASSERT_DEBUG(renderTarget && "Cmd buffer has no render target set.");
+    if(renderTarget)
     {
-      swapchain->Submit(cmdBuffer->GetImpl());
+      // Currently, this will call vkQueueSubmit per cmd buf.
+      // @todo Roll up each into single submission for fewer calls to driver
+      renderTarget->Submit(cmdBuffer);
     }
   }
 
@@ -602,11 +611,14 @@ void VulkanGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo
 
 void VulkanGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
 {
-  auto surface   = static_cast<Vulkan::RenderTarget*>(renderTarget)->GetSurface();
-  auto surfaceId = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface)->GetSurfaceId();
-  auto swapchain = mImpl->mGraphicsDevice->GetSwapchainForSurfaceId(surfaceId);
-
-  swapchain->Present();
+  auto surface = static_cast<Vulkan::RenderTarget*>(renderTarget)->GetSurface();
+  if(surface)
+  {
+    auto surfaceId = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface)->GetSurfaceId();
+    auto swapchain = mImpl->mGraphicsDevice->GetSwapchainForSurfaceId(surfaceId);
+    swapchain->Present();
+  }
+  // else no presentation required for framebuffer render target.
 }
 
 void VulkanGraphicsController::WaitIdle()
@@ -927,7 +939,9 @@ bool VulkanGraphicsController::IsDrawOnResumeRequired()
 
 UniquePtr<Graphics::RenderTarget> VulkanGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
 {
-  return NewGraphicsObject<Vulkan::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
+  auto renderTarget = NewGraphicsObject<Vulkan::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
+  mImpl->mDependencyChecker.AddRenderTarget(CastObject<Vulkan::RenderTarget>(renderTarget.get()));
+  return renderTarget;
 }
 
 UniquePtr<Graphics::CommandBuffer> VulkanGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
@@ -955,7 +969,7 @@ UniquePtr<Graphics::Texture> VulkanGraphicsController::CreateTexture(const Graph
 
 UniquePtr<Graphics::Framebuffer> VulkanGraphicsController::CreateFramebuffer(const Graphics::FramebufferCreateInfo& framebufferCreateInfo, UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
 {
-  return UniquePtr<Graphics::Framebuffer>{};
+  return NewGraphicsObject<Vulkan::Framebuffer>(framebufferCreateInfo, *this, std::move(oldFramebuffer));
 }
 
 UniquePtr<Graphics::Pipeline> VulkanGraphicsController::CreatePipeline(const Graphics::PipelineCreateInfo& pipelineCreateInfo, UniquePtr<Graphics::Pipeline>&& oldPipeline)
@@ -1209,4 +1223,44 @@ const Matrix& VulkanGraphicsController::GetClipMatrix() const
   return CLIP_MATRIX;
 }
 
+void VulkanGraphicsController::AddTextureDependencies(RenderTarget* renderTarget)
+{
+  auto framebuffer = renderTarget->GetFramebuffer();
+  DALI_ASSERT_DEBUG(framebuffer);
+
+  for(auto attachment : framebuffer->GetCreateInfo().colorAttachments)
+  {
+    auto texture = CastObject<Vulkan::Texture>(attachment.texture);
+    mImpl->mDependencyChecker.AddTexture(texture, renderTarget);
+  }
+  auto depthAttachment = framebuffer->GetCreateInfo().depthStencilAttachment;
+  if(depthAttachment.depthTexture)
+  {
+    mImpl->mDependencyChecker.AddTexture(CastObject<Vulkan::Texture>(depthAttachment.depthTexture), renderTarget);
+  }
+  if(depthAttachment.stencilTexture)
+  {
+    mImpl->mDependencyChecker.AddTexture(CastObject<Vulkan::Texture>(depthAttachment.stencilTexture), renderTarget);
+  }
+}
+
+void VulkanGraphicsController::CheckTextureDependencies(
+  const std::vector<Graphics::TextureBinding>& textureBindings,
+  RenderTarget*                                renderTarget)
+{
+  for(auto& binding : textureBindings)
+  {
+    if(binding.texture)
+    {
+      auto texture = CastObject<const Vulkan::Texture>(binding.texture);
+      mImpl->mDependencyChecker.CheckNeedsSync(texture, renderTarget);
+    }
+  }
+}
+
+void VulkanGraphicsController::RemoveRenderTarget(RenderTarget* renderTarget)
+{
+  mImpl->mDependencyChecker.RemoveRenderTarget(renderTarget);
+}
+
 } // namespace Dali::Graphics::Vulkan
index c5f69c37eaa25078b5ec3653ae5fbf6f3d8260a7..ca185a7f402b159dff2e49f4d5951c32040d0cfd 100644 (file)
@@ -40,6 +40,10 @@ class Buffer;
 class Sampler;
 class Texture;
 
+/**
+ * Class to manage the vulkan graphics backend. This is the main object that clients interact
+ * with to get work done on the GPU.
+ */
 class VulkanGraphicsController : public Graphics::Controller, public Integration::GraphicsConfig
 {
 public:
@@ -432,6 +436,23 @@ public: // ResourceId relative API.
    */
   const Matrix& GetClipMatrix() const override;
 
+public: // Other API
+  /**
+   * Adds the render-target's fbo attachments into the dependency graph.
+   */
+  void AddTextureDependencies(RenderTarget* renderTarget);
+
+  /**
+   * Check if any of the textures are fbo attachments and update dependency graph
+   */
+  void CheckTextureDependencies(const std::vector<Graphics::TextureBinding>& textureBindings,
+                                RenderTarget*                                renderTarget);
+
+  /**
+   * Remove the render target from dependency graph
+   */
+  void RemoveRenderTarget(RenderTarget* renderTarget);
+
 public: // For debug
   void FrameStart();
 
index aeec23643ebb097fbaec15fa194f7775d1216c6c..db20317baddc3032e2045c1aa6d73947479ebd30 100644 (file)
@@ -395,7 +395,7 @@ void PipelineImpl::InitializePipeline()
 
     if(gfxPipelineInfo.pColorBlendState)
     {
-      auto attachmentCount = impl->GetAttachments().size();
+      auto attachmentCount = impl->GetAttachmentCount();
       if(impl->HasDepthAttachment())
       {
         attachmentCount--;
index ada2e5e612734a56ed64843c7f517c30732e881c..c4740bb2ed63ee2ce7dcc02df96859b508da65df 100644 (file)
  */
 
 // INTERNAL INCLUDES
+#include <dali/internal/graphics/vulkan-impl/vulkan-command-buffer-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-fence-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-queue-impl.h>
 
 namespace Dali::Graphics::Vulkan
 {
-
 // submission
 SubmissionData::SubmissionData(const std::vector<vk::Semaphore>&      waitSemaphores_,
                                vk::PipelineStageFlags                 waitDestinationStageMask_,
@@ -93,9 +93,50 @@ vk::Result Queue::Present(vk::PresentInfoKHR& presentInfo)
   return mQueue.presentKHR(&presentInfo);
 }
 
-vk::Result Queue::Submit(std::vector<vk::SubmitInfo>& info, FenceImpl* fence)
+vk::Result Queue::Submit(const std::vector<SubmissionData>& submissionData, FenceImpl* fence)
 {
-  return VkAssert(mQueue.submit(info, fence ? fence->GetVkHandle() : nullptr));
+  auto lock(Lock());
+
+  auto submitInfos = std::vector<vk::SubmitInfo>{};
+  submitInfos.reserve(submissionData.size());
+  auto commandBufferHandles = std::vector<vk::CommandBuffer>{};
+
+  // prepare memory
+  auto bufferSize = 0u;
+  for(auto& data : submissionData)
+  {
+    bufferSize += uint32_t(data.commandBuffers.size());
+  }
+  commandBufferHandles.reserve(bufferSize);
+
+  // Transform SubmissionData to vk::SubmitInfo
+  for(const auto& subData : submissionData)
+  {
+    auto currentBufferIndex = commandBufferHandles.size();
+
+    // Extract the command buffer handles
+    std::transform(subData.commandBuffers.cbegin(),
+                   subData.commandBuffers.cend(),
+                   std::back_inserter(commandBufferHandles),
+                   [&](CommandBufferImpl* entry) {
+                     return entry->GetVkHandle();
+                   });
+
+    // clang-format=off
+    auto submitInfo = vk::SubmitInfo()
+                        .setWaitSemaphoreCount(U32(subData.waitSemaphores.size()))
+                        .setPWaitSemaphores(subData.waitSemaphores.data())
+                        .setPWaitDstStageMask(&subData.waitDestinationStageMask)
+                        .setCommandBufferCount(U32(subData.commandBuffers.size()))
+                        .setPCommandBuffers(&commandBufferHandles[currentBufferIndex])
+                        .setSignalSemaphoreCount(U32(subData.signalSemaphores.size()))
+                        .setPSignalSemaphores(subData.signalSemaphores.data());
+
+    submitInfos.push_back(submitInfo);
+    // clang-format=on
+  }
+
+  return VkAssert(mQueue.submit(submitInfos, fence ? fence->GetVkHandle() : nullptr));
 }
 
 } // namespace Dali::Graphics::Vulkan
index ca579c41e640863934b8ed2b92d45694c9327f27..f5b1fe52ced7cd4ee81e6dd2e89f192f451822bb 100644 (file)
@@ -70,7 +70,7 @@ public:
 
   vk::Result Present(vk::PresentInfoKHR& presentInfo);
 
-  vk::Result Submit(std::vector<vk::SubmitInfo>& info, FenceImpl* fence);
+  vk::Result Submit(const std::vector<SubmissionData>& submissionData, FenceImpl* fence);
 
 private:
   vk::Queue      mQueue;
index c3c0a6b6d72b3f82e878b2a8fea06f7246cc6ba8..dac6fb6f8731bbec8e3cf37247aa7faff086c73b 100644 (file)
@@ -38,13 +38,30 @@ RenderPassHandle RenderPassImpl::New(
   return RenderPassHandle(renderPass);
 }
 
+RenderPassHandle RenderPassImpl::New(
+  Vulkan::Device&                   device,
+  const RenderPassImpl::CreateInfo& createInfo)
+{
+  auto renderPass = new RenderPassImpl(device, createInfo);
+  return RenderPassHandle(renderPass);
+}
+
 RenderPassImpl::RenderPassImpl(Vulkan::Device&             device,
                                const SharedAttachments&    colorAttachments,
                                FramebufferAttachmentHandle depthAttachment)
 : mGraphicsDevice(&device),
   mHasDepthAttachment(bool(depthAttachment))
 {
-  CreateCompatibleCreateInfo(colorAttachments, depthAttachment);
+  // Default case is creating render pass for swapchain.
+  CreateCompatibleCreateInfo(mCreateInfo, colorAttachments, depthAttachment, false);
+  CreateRenderPass();
+}
+
+RenderPassImpl::RenderPassImpl(Vulkan::Device&                   device,
+                               const RenderPassImpl::CreateInfo& createInfo)
+: mGraphicsDevice(&device),
+  mCreateInfo(createInfo)
+{
   CreateRenderPass();
 }
 
@@ -71,14 +88,16 @@ vk::RenderPass RenderPassImpl::GetVkHandle()
   return mVkRenderPass;
 }
 
-std::vector<vk::ImageView>& RenderPassImpl::GetAttachments()
+size_t RenderPassImpl::GetAttachmentCount()
 {
-  return mAttachments;
+  return mHasDepthAttachment + mCreateInfo.colorAttachmentReferences.size();
 }
 
 void RenderPassImpl::CreateCompatibleCreateInfo(
-  const SharedAttachments&    colorAttachments,
-  FramebufferAttachmentHandle depthAttachment)
+  CreateInfo&                        createInfo,
+  const SharedAttachments&           colorAttachments,
+  const FramebufferAttachmentHandle& depthAttachment,
+  bool                               subpassForOffscreen)
 {
   auto hasDepth = false;
   if(depthAttachment)
@@ -89,14 +108,22 @@ void RenderPassImpl::CreateCompatibleCreateInfo(
 
   // The total number of attachments
   auto totalAttachmentCount = hasDepth ? colorAttachments.size() + 1 : colorAttachments.size();
-  mAttachments.clear();
-  mAttachments.reserve(totalAttachmentCount);
+
+  createInfo.attachmentHandles.reserve(colorAttachments.size() + depthAttachment);
+  for(auto& handle : colorAttachments)
+  {
+    createInfo.attachmentHandles.push_back(handle);
+  }
+  if(depthAttachment)
+  {
+    createInfo.attachmentHandles.push_back(depthAttachment);
+  }
 
   // This vector stores the attachment references
-  mCreateInfo.colorAttachmentReferences.reserve(colorAttachments.size());
+  createInfo.colorAttachmentReferences.reserve(colorAttachments.size());
 
   // This vector stores the attachment descriptions
-  mCreateInfo.attachmentDescriptions.reserve(totalAttachmentCount);
+  createInfo.attachmentDescriptions.reserve(totalAttachmentCount);
 
   // For each color attachment...
   for(auto i = 0u; i < colorAttachments.size(); ++i)
@@ -115,11 +142,9 @@ void RenderPassImpl::CreateCompatibleCreateInfo(
     assert(imageLayout == vk::ImageLayout::eColorAttachmentOptimal);
 
     // Add a reference and a descriptions and image views to their respective vectors
-    mCreateInfo.colorAttachmentReferences.push_back(vk::AttachmentReference{}.setLayout(imageLayout).setAttachment(U32(i)));
-
-    mCreateInfo.attachmentDescriptions.push_back(colorAttachments[i]->GetDescription());
+    createInfo.colorAttachmentReferences.push_back(vk::AttachmentReference{}.setLayout(imageLayout).setAttachment(U32(i)));
 
-    mAttachments.push_back(colorAttachments[i]->GetImageView()->GetVkHandle());
+    createInfo.attachmentDescriptions.push_back(colorAttachments[i]->GetDescription());
   }
 
   // Follow the exact same procedure as color attachments
@@ -134,59 +159,29 @@ void RenderPassImpl::CreateCompatibleCreateInfo(
 
     assert(imageLayout == vk::ImageLayout::eDepthStencilAttachmentOptimal);
 
-    mCreateInfo.depthAttachmentReference.setLayout(imageLayout);
-    mCreateInfo.depthAttachmentReference.setAttachment(U32(mCreateInfo.colorAttachmentReferences.size()));
-
-    mCreateInfo.attachmentDescriptions.push_back(depthAttachment->GetDescription());
+    createInfo.depthAttachmentReference.setLayout(imageLayout);
+    createInfo.depthAttachmentReference.setAttachment(U32(createInfo.colorAttachmentReferences.size()));
 
-    mAttachments.push_back(depthAttachment->GetImageView()->GetVkHandle());
+    createInfo.attachmentDescriptions.push_back(depthAttachment->GetDescription());
   }
 
-  // Creating a single subpass per framebuffer
-  mCreateInfo.subpassDesc.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics);
-  mCreateInfo.subpassDesc.setColorAttachmentCount(U32(colorAttachments.size()));
+  createInfo.subpassDesc.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics);
+  createInfo.subpassDesc.setColorAttachmentCount(U32(colorAttachments.size()));
   if(hasDepth)
   {
-    mCreateInfo.subpassDesc.setPDepthStencilAttachment(&mCreateInfo.depthAttachmentReference);
+    createInfo.subpassDesc.setPDepthStencilAttachment(&createInfo.depthAttachmentReference);
   }
-  mCreateInfo.subpassDesc.setPColorAttachments(mCreateInfo.colorAttachmentReferences.data());
+  createInfo.subpassDesc.setPColorAttachments(createInfo.colorAttachmentReferences.data());
 
-  // Creating 2 subpass dependencies using VK_SUBPASS_EXTERNAL to leverage the implicit image layout
-  // transitions provided by the driver
-  vk::AccessFlags        accessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite);
-  vk::PipelineStageFlags stageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput);
-  if(hasDepth)
-  {
-    accessMask |= vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
-    stageMask |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
-  }
+  auto dependencyCount = CreateSubPassDependencies(createInfo, hasDepth, subpassForOffscreen);
 
-  mCreateInfo.subpassDependencies = {
-    vk::SubpassDependency{}
-      .setSrcSubpass(VK_SUBPASS_EXTERNAL)
-      .setDstSubpass(0)
-      .setSrcStageMask(vk::PipelineStageFlagBits::eBottomOfPipe)
-      .setDstStageMask(stageMask)
-      .setSrcAccessMask(vk::AccessFlagBits::eMemoryRead)
-      .setDstAccessMask(accessMask)
-      .setDependencyFlags(vk::DependencyFlagBits::eByRegion),
-
-    vk::SubpassDependency{}
-      .setSrcSubpass(0)
-      .setDstSubpass(VK_SUBPASS_EXTERNAL)
-      .setSrcStageMask(stageMask)
-      .setDstStageMask(vk::PipelineStageFlagBits::eBottomOfPipe)
-      .setSrcAccessMask(accessMask)
-      .setDstAccessMask(vk::AccessFlagBits::eMemoryRead)
-      .setDependencyFlags(vk::DependencyFlagBits::eByRegion)};
-
-  mCreateInfo.createInfo
-    .setAttachmentCount(U32(mCreateInfo.attachmentDescriptions.size()))
-    .setPAttachments(mCreateInfo.attachmentDescriptions.data())
-    .setPSubpasses(&mCreateInfo.subpassDesc)
+  createInfo.createInfo
+    .setAttachmentCount(U32(createInfo.attachmentDescriptions.size()))
+    .setPAttachments(createInfo.attachmentDescriptions.data())
+    .setPSubpasses(&createInfo.subpassDesc)
     .setSubpassCount(1)
-    .setDependencyCount(2)
-    .setPDependencies(mCreateInfo.subpassDependencies.data());
+    .setDependencyCount(dependencyCount)
+    .setPDependencies(createInfo.subpassDependencies.data());
 }
 
 void RenderPassImpl::CreateRenderPass()
@@ -194,4 +189,62 @@ void RenderPassImpl::CreateRenderPass()
   mVkRenderPass = VkAssert(mGraphicsDevice->GetLogicalDevice().createRenderPass(mCreateInfo.createInfo, mGraphicsDevice->GetAllocator()));
 }
 
+int RenderPassImpl::CreateSubPassDependencies(CreateInfo& createInfo, bool hasDepth, bool subpassForOffscreen)
+{
+  int dependencyCount = 0;
+
+  if(subpassForOffscreen)
+  {
+    createInfo.subpassDependencies = {
+      vk::SubpassDependency{}
+        .setSrcSubpass(vk::SubpassExternal)
+        .setDstSubpass(0)
+        .setSrcStageMask(vk::PipelineStageFlagBits::eFragmentShader)
+        .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests)
+        .setSrcAccessMask(vk::AccessFlagBits::eNone)
+        .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite),
+      vk::SubpassDependency{}
+        .setSrcSubpass(0)
+        .setDstSubpass(vk::SubpassExternal)
+        .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests)
+        .setDstStageMask(vk::PipelineStageFlagBits::eFragmentShader)
+        .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite)
+        .setDstAccessMask(vk::AccessFlagBits::eMemoryRead)};
+    dependencyCount = 2;
+  }
+  else // Subpass for swapchain
+  {
+    // Creating 2 subpass dependencies using VK_SUBPASS_EXTERNAL to leverage the implicit image layout
+    // transitions provided by the driver
+    vk::AccessFlags        accessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite);
+    vk::PipelineStageFlags stageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput);
+    if(hasDepth)
+    {
+      accessMask |= vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
+      stageMask |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
+    }
+
+    createInfo.subpassDependencies = {
+      vk::SubpassDependency{}
+        .setSrcSubpass(VK_SUBPASS_EXTERNAL)
+        .setDstSubpass(0)
+        .setSrcStageMask(vk::PipelineStageFlagBits::eBottomOfPipe)
+        .setDstStageMask(stageMask)
+        .setSrcAccessMask(vk::AccessFlagBits::eMemoryRead)
+        .setDstAccessMask(accessMask)
+        .setDependencyFlags(vk::DependencyFlagBits::eByRegion),
+
+      vk::SubpassDependency{}
+        .setSrcSubpass(0)
+        .setDstSubpass(VK_SUBPASS_EXTERNAL)
+        .setSrcStageMask(stageMask)
+        .setDstStageMask(vk::PipelineStageFlagBits::eBottomOfPipe)
+        .setSrcAccessMask(accessMask)
+        .setDstAccessMask(vk::AccessFlagBits::eMemoryRead)
+        .setDependencyFlags(vk::DependencyFlagBits::eByRegion)};
+    dependencyCount = 2;
+  }
+  return dependencyCount;
+}
+
 } // namespace Dali::Graphics::Vulkan
index 2fe63d3d04ba6457c04047292d8073ef4b2933e2..4d379a872de225d3f3a85069ea5d444158e94e97 100644 (file)
@@ -49,8 +49,10 @@ using RenderPassHandle = Handle<class RenderPassImpl>;
 class RenderPassImpl : public VkSharedResource
 {
 public:
-  struct CreateInfo
+  class CreateInfo
   {
+  public:
+    SharedAttachments                      attachmentHandles;
     std::vector<vk::AttachmentReference>   colorAttachmentReferences;
     vk::AttachmentReference                depthAttachmentReference;
     std::vector<vk::AttachmentDescription> attachmentDescriptions;
@@ -63,15 +65,20 @@ public:
                               const SharedAttachments&    colorAttachments,
                               FramebufferAttachmentHandle depthAttachment);
 
+  static RenderPassHandle New(Vulkan::Device&                   device,
+                              const RenderPassImpl::CreateInfo& createInfo);
+
   RenderPassImpl(Vulkan::Device& device, const SharedAttachments& colorAttachments, FramebufferAttachmentHandle depthAttachment);
 
+  RenderPassImpl(Vulkan::Device& device, const RenderPassImpl::CreateInfo& createInfo);
+
   ~RenderPassImpl();
 
   bool OnDestroy() override;
 
   vk::RenderPass GetVkHandle();
 
-  std::vector<vk::ImageView>& GetAttachments();
+  size_t GetAttachmentCount();
 
   bool HasDepthAttachment()
   {
@@ -83,19 +90,21 @@ public:
     return mCreateInfo;
   }
 
-private:
-  void CreateCompatibleCreateInfo(
-    const SharedAttachments&    colorAttachments,
-    FramebufferAttachmentHandle depthAttachment);
+  static void CreateCompatibleCreateInfo(
+    CreateInfo&                        createInfo,
+    const SharedAttachments&           colorAttachments,
+    const FramebufferAttachmentHandle& depthAttachment,
+    bool                               subpassForOffscreen);
 
-  void CreateRenderPass();
+private:
+  void       CreateRenderPass();
+  static int CreateSubPassDependencies(CreateInfo& createInfo, bool hasDepth, bool subpassForOffscreen);
 
 private:
-  Device*                    mGraphicsDevice;
-  CreateInfo                 mCreateInfo;
-  vk::RenderPass             mVkRenderPass;
-  std::vector<vk::ImageView> mAttachments{};
-  bool                       mHasDepthAttachment;
+  Device*        mGraphicsDevice;
+  CreateInfo     mCreateInfo;
+  vk::RenderPass mVkRenderPass;
+  bool           mHasDepthAttachment{false};
 };
 
 } // namespace Dali::Graphics::Vulkan
index b69c3c4755e715cce38ec903ef1e90347df41539..2f93915d1f4a9d363f0f7a658fd6478a42224a89 100644 (file)
 
 // INTERNAL INCLUDES
 #include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-queue-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass.h>
 #include <dali/internal/graphics/vulkan/vulkan-device.h>
 #include <dali/internal/window-system/common/window-render-surface.h>
@@ -37,6 +39,12 @@ RenderTarget::RenderTarget(const Graphics::RenderTargetCreateInfo& createInfo, V
     // Do creation stuff!
     //   Create Swapchain?!
   }
+  else
+  {
+    // Non-surface render targets use own semaphore to signal cmd buffer completion.
+    auto& graphicsDevice = controller.GetGraphicsDevice();
+    mSubmitSemaphore     = graphicsDevice.GetLogicalDevice().createSemaphore({}, graphicsDevice.GetAllocator()).value;
+  }
 }
 
 RenderTarget::~RenderTarget() = default;
@@ -48,11 +56,11 @@ void RenderTarget::DestroyResource()
 void RenderTarget::DiscardResource()
 {
   mController.DiscardResource(this);
+  mController.RemoveRenderTarget(this); // Remove from dependency graph
 
   // The surface context should be deleted now
   if(mCreateInfo.surface)
   {
-    //mController.DeleteSurfaceContext(static_cast<Dali::RenderSurfaceInterface*>(mCreateInfo.surface));
     mCreateInfo.surface = nullptr;
   }
 }
@@ -94,4 +102,34 @@ Vulkan::RenderPassHandle RenderTarget::GetRenderPass(const Graphics::RenderPass*
   return framebufferImpl->GetImplFromRenderPass(renderPass);
 }
 
+void RenderTarget::Submit(const CommandBuffer* cmdBuffer)
+{
+  auto& graphicsDevice = mController.GetGraphicsDevice();
+  auto  surface        = GetSurface();
+
+  if(surface)
+  {
+    auto surfaceId = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface)->GetSurfaceId();
+    auto swapchain = graphicsDevice.GetSwapchainForSurfaceId(surfaceId);
+    swapchain->Submit(cmdBuffer->GetImpl());
+  }
+  else
+  {
+    std::vector<vk::Semaphore> waitSemaphores;
+    for(auto renderTarget : mDependencies)
+    {
+      waitSemaphores.push_back(renderTarget->mSubmitSemaphore);
+    }
+
+    std::vector<vk::Semaphore> signalSemaphores{mSubmitSemaphore};
+    graphicsDevice.GetGraphicsQueue(0).Submit(
+      {SubmissionData{
+        waitSemaphores,
+        {vk::PipelineStageFlagBits::eFragmentShader},
+        {cmdBuffer->GetImpl()},
+        signalSemaphores}},
+      nullptr);
+  }
+}
+
 } // namespace Dali::Graphics::Vulkan
index f08983e8b5e0993476873b07fed19c5554bfe567..caca3c881491bf8ab6a329e8892bca2c0ac8ea59 100644 (file)
@@ -29,6 +29,7 @@ namespace Dali::Graphics::Vulkan
 {
 class Framebuffer;
 class Surface;
+class CommandBuffer;
 
 using RenderTargetResource = Resource<Graphics::RenderTarget, Graphics::RenderTargetCreateInfo>;
 
@@ -100,6 +101,32 @@ public:
    * @return a matching render pass implementation from the current framebuffer
    */
   [[nodiscard]] Vulkan::RenderPassHandle GetRenderPass(const Graphics::RenderPass* renderPass) const;
+  /**
+   * Submit the command buffer to the graphics queue using the right sync.
+   */
+  void Submit(const CommandBuffer* commandBuffer);
+
+  void ResetDependencies()
+  {
+    mDependencies.clear();
+  }
+
+  void AddDependency(RenderTarget* dependency)
+  {
+    mDependencies.push_back(dependency);
+  }
+  void RemoveDependency(RenderTarget* dependency)
+  {
+    auto iter = std::find(mDependencies.begin(), mDependencies.end(), dependency);
+    if(iter != mDependencies.end())
+    {
+      mDependencies.erase(iter);
+    }
+  }
+
+private:
+  vk::Semaphore              mSubmitSemaphore; ///< Signaled when the command buffer for this target is processed
+  std::vector<RenderTarget*> mDependencies;    ///< Render targets whose output is used as input to this task.
 };
 
 } // namespace Dali::Graphics::Vulkan
index 2741183f3bf71c587920b9969a6fbf6310ee43d4..5d9a41a15678798a564784e70c9b4cb36cb0002e 100644 (file)
@@ -253,6 +253,7 @@ void Swapchain::CreateFramebuffers(FramebufferAttachmentHandle depthAttachment)
     SharedAttachments attachments;
     attachments.emplace_back(FramebufferAttachment::NewColorAttachment(colorImageView,
                                                                        clearColor,
+                                                                       nullptr,
                                                                        true));
 
     std::unique_ptr<FramebufferImpl, void (*)(FramebufferImpl*)> framebuffer(
@@ -376,16 +377,12 @@ void Swapchain::Submit(CommandBufferImpl* commandBuffer)
 
   swapchainBuffer->endOfFrameFence->Reset();
 
-  // @todo Should we allow multiple submits per swapchain per frame?
-  // If so, should change the fence, or at least wait for the fence
-  // prior to the reset above.
-  mGraphicsDevice.Submit(*mQueue,
-                         {Vulkan::SubmissionData{
-                           {swapchainBuffer->acquireNextImageSemaphore},
-                           {vk::PipelineStageFlagBits::eFragmentShader},
-                           {commandBuffer},
-                           {swapchainBuffer->submitSemaphore}}},
-                         swapchainBuffer->endOfFrameFence.get());
+  mQueue->Submit({Vulkan::SubmissionData{
+                   {swapchainBuffer->acquireNextImageSemaphore},
+                   {vk::PipelineStageFlagBits::eFragmentShader},
+                   {commandBuffer},
+                   {swapchainBuffer->submitSemaphore}}},
+                 swapchainBuffer->endOfFrameFence.get());
 }
 
 void Swapchain::Present()
@@ -465,7 +462,7 @@ void Swapchain::SetDepthStencil(vk::Format depthStencilFormat)
     auto depthClearValue       = vk::ClearDepthStencilValue{}.setDepth(0.0).setStencil(STENCIL_DEFAULT_CLEAR_VALUE);
 
     // A single depth attachment for the swapchain. Takes ownership of the image view
-    depthAttachment = FramebufferAttachmentHandle(FramebufferAttachment::NewDepthAttachment(depthStencilImageView, depthClearValue));
+    depthAttachment = FramebufferAttachmentHandle(FramebufferAttachment::NewDepthAttachment(depthStencilImageView, depthClearValue, nullptr));
   }
 
   // Before replacing framebuffers in the swapchain, wait until all is done
diff --git a/dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.cpp b/dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.cpp
new file mode 100644 (file)
index 0000000..aad1ec4
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/graphics/vulkan-impl/vulkan-render-target.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-texture.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali::Graphics::Vulkan
+{
+void TextureDependencyChecker::Reset()
+{
+  for(auto& dependency : mDependencies)
+  {
+    dependency.generator->ResetDependencies();
+  }
+
+  mDependencies.clear();
+  mCurrentIndex = 0;
+}
+
+void TextureDependencyChecker::AddTexture(const Vulkan::Texture* texture, Vulkan::RenderTarget* renderTarget)
+{
+  // We only push attachments into this struct, so total size should be low.
+  // Note, Textures may be written to more than once in a frame, so always add new target generator
+  mDependencies.push_back(TextureDependency{texture, renderTarget});
+}
+
+void TextureDependencyChecker::CheckNeedsSync(const Vulkan::Texture* texture, Vulkan::RenderTarget* renderTarget)
+{
+  // Check if this texture was generated as a dependency. It could be generated by more than one
+  // target in a frame, so work backwards from the latest render pass.
+  for(auto iter = mDependencies.rbegin(); iter < mDependencies.rend(); ++iter)
+  {
+    if(iter->texture == texture)
+    {
+      renderTarget->AddDependency(iter->generator);
+      break;
+    }
+  }
+}
+
+void TextureDependencyChecker::AddRenderTarget(Vulkan::RenderTarget* renderTarget)
+{
+  // We only add/remove on create/destroy, so guarantee uniqueness
+  mRenderTargets.push_back(renderTarget);
+}
+
+void TextureDependencyChecker::RemoveRenderTarget(Vulkan::RenderTarget* renderTarget)
+{
+  for(auto iter = mRenderTargets.begin(); iter != mRenderTargets.end(); ++iter)
+  {
+    if(*iter == renderTarget)
+    {
+      mRenderTargets.erase(iter);
+      break;
+    }
+    else
+    {
+      (*iter)->RemoveDependency(renderTarget);
+    }
+  }
+}
+
+} // namespace Dali::Graphics::Vulkan
diff --git a/dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.h b/dali/internal/graphics/vulkan-impl/vulkan-texture-dependency-checker.h
new file mode 100644 (file)
index 0000000..47364d1
--- /dev/null
@@ -0,0 +1,93 @@
+#pragma once
+
+/*
+ * Copyright (c) 2024 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <cstdint>
+
+namespace Dali::Graphics::Vulkan
+{
+class VulkanGraphicsController;
+class Texture;
+class RenderTarget;
+
+/**
+ * Class to handle dependency checks between textures from different render targets.
+ *
+ * When submitting a render target to generate a framebuffer attachment, the controller
+ * will create a signal semaphore that is triggered once the command buffer has completed
+ * execution.
+ * The dependency checker ensures that any dependent render targets that use the attachment
+ * texture listen to this semaphore on their cmd buffer submission.
+ */
+class TextureDependencyChecker
+{
+public:
+  explicit TextureDependencyChecker(VulkanGraphicsController& controller)
+  : mController(controller)
+  {
+  }
+  ~TextureDependencyChecker() = default;
+
+  /**
+   * Resets the dependency graph for regeneration this frame
+   */
+  void Reset();
+
+  /**
+   * Add Texture dependencies.
+   *
+   * @param[in] texture The texture that's output by this render target
+   * @param[in] renderTarget The render target that generates this texture
+   */
+  void AddTexture(const Vulkan::Texture* texture, Vulkan::RenderTarget* renderTarget);
+
+  /**
+   * Check if the given texture needs syncing before being read. This will add any
+   * existing dependencies to the given render target (will be used in command
+   * submission to set up waiting semaphores)
+   */
+  void CheckNeedsSync(const Vulkan::Texture* texture, Vulkan::RenderTarget* renderTarget);
+
+  const uint32_t INVALID_DEPENDENCY_INDEX = 0xffffffff;
+
+  /**
+   * Add render target.
+   *
+   * @param[in] renderTarget The render target to add to the dependency graph
+   */
+  void AddRenderTarget(Vulkan::RenderTarget* renderTarget);
+
+  /**
+   * Remove render target
+   * @param[in] renderTarget The render target to remove from the dependency graph
+   */
+  void RemoveRenderTarget(Vulkan::RenderTarget* renderTarget);
+
+private:
+  struct TextureDependency
+  {
+    const Vulkan::Texture* texture;
+    Vulkan::RenderTarget*  generator;
+  };
+  VulkanGraphicsController&      mController;
+  std::vector<TextureDependency> mDependencies;
+  std::vector<RenderTarget*>     mRenderTargets; ///< Maintained list of all current render targets
+  uint32_t                       mCurrentIndex{0};
+};
+
+} // namespace Dali::Graphics::Vulkan
index 2121f0b6868cb4119bcc9e9c63400417c92ae5f5..0306dc72da9145050b3827ff020745aa8ec94fbd 100644 (file)
@@ -1294,6 +1294,17 @@ void Texture::InitializeImageView()
   }
 }
 
+std::unique_ptr<Vulkan::ImageView> Texture::CreateImageView()
+{
+  if(!mImageView)
+  {
+    // Ensure we have initialized the image:
+    InitializeImageView();
+  }
+  std::unique_ptr<Vulkan::ImageView> imageView(ImageView::NewFromImage(mDevice, *mImage, mComponentMapping));
+  return imageView;
+}
+
 Vulkan::Image* Texture::GetImage() const
 {
   return mImage;
index d3d16beace846098cacd5b3db435ada5db91b804..2407c61fb79ee67ed699131a82dedc5c88f435c0 100644 (file)
@@ -79,6 +79,11 @@ public:
 
   ImageView* GetImageView() const;
 
+  /**
+   * Create a new image view onto the image.
+   */
+  std::unique_ptr<ImageView> CreateImageView();
+
   SamplerImpl* GetSampler() const;
 
   // @todo Temporary. We need to use the newer APIs
index e173abf3bff6fcbee0fa69d828d79dbfe7e609d4..ccdd2db0d676b52e0a287e0014f5d320d4251ba9 100644 (file)
@@ -870,52 +870,6 @@ std::vector<const char*> Device::PrepareDefaultInstanceExtensions()
   return extensions;
 }
 
-vk::Result Device::Submit(Queue& queue, const std::vector<SubmissionData>& submissionData, FenceImpl* fence)
-{
-  auto lock(queue.Lock());
-
-  auto submitInfos = std::vector<vk::SubmitInfo>{};
-  submitInfos.reserve(submissionData.size());
-  auto commandBufferHandles = std::vector<vk::CommandBuffer>{};
-
-  // prepare memory
-  auto bufferSize = 0u;
-  for(auto& data : submissionData)
-  {
-    bufferSize += uint32_t(data.commandBuffers.size());
-  }
-  commandBufferHandles.reserve(bufferSize);
-
-  // Transform SubmissionData to vk::SubmitInfo
-  for(const auto& subData : submissionData)
-  {
-    auto currentBufferIndex = commandBufferHandles.size();
-
-    // Extract the command buffer handles
-    std::transform(subData.commandBuffers.cbegin(),
-                   subData.commandBuffers.cend(),
-                   std::back_inserter(commandBufferHandles),
-                   [&](CommandBufferImpl* entry) {
-                     return entry->GetVkHandle();
-                   });
-
-    // clang-format=off
-    auto submitInfo = vk::SubmitInfo()
-                        .setWaitSemaphoreCount(U32(subData.waitSemaphores.size()))
-                        .setPWaitSemaphores(subData.waitSemaphores.data())
-                        .setPWaitDstStageMask(&subData.waitDestinationStageMask)
-                        .setCommandBufferCount(U32(subData.commandBuffers.size()))
-                        .setPCommandBuffers(&commandBufferHandles[currentBufferIndex])
-                        .setSignalSemaphoreCount(U32(subData.signalSemaphores.size()))
-                        .setPSignalSemaphores(subData.signalSemaphores.data());
-
-    submitInfos.push_back(submitInfo);
-    // clang-format=on
-  }
-
-  return VkAssert(queue.Submit(submitInfos, fence));
-}
-
 /**
  * Helper function which returns GPU heap index that can be used to allocate
  * particular type of resource
index 532a995ab47d6ba7a4a054ced794a3f79739b213..843ff2fd792b3035ae12ff816a1039b16f638b6c 100644 (file)
@@ -75,7 +75,6 @@ public: // Create methods
 
   Swapchain* CreateSwapchain(SurfaceImpl* surface, vk::Format requestedFormat, vk::PresentModeKHR presentMode, uint32_t bufferCount, Swapchain*&& oldSwapchain);
 
-  vk::Result Submit(Queue& queue, const std::vector<SubmissionData>& submissionData, FenceImpl* fence = nullptr);
   vk::Result Present(Queue& queue, vk::PresentInfoKHR presentInfo);
   vk::Result QueueWaitIdle(Queue& queue);
   vk::Result DeviceWaitIdle();