Implementing basic render pass through graphics API 04/314704/1
authorDavid Steele <david.steele@samsung.com>
Tue, 9 Jul 2024 18:02:55 +0000 (19:02 +0100)
committerDavid Steele <david.steele@samsung.com>
Wed, 17 Jul 2024 16:43:32 +0000 (17:43 +0100)
Rather than relying on test code in PresentRenderTarget, this instead
sets up basic command buffers properly, and expects Begin,
BeginRenderPass, EndRenderPass, End commands,
Controller::SubmitCommandBuffers and ::PresentRenderTarget to work in
the right way.

Suggested test code is to create an empty app with a single
actor/renderer pair that has a RenderCallback attached.

Change-Id: I828f37aa704bacd18487d9c0a516051b91f6e5fd

17 files changed:
automated-tests/.gitignore
automated-tests/.gitignore-with-autogenerated-files
automated-tests/.gitignore-without-autogenerated-files
dali/integration-api/adaptor-framework/render-surface-interface.h
dali/internal/adaptor/common/combined-update-render-controller.cpp
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-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-graphics-controller.cpp
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-pass.cpp
dali/internal/graphics/vulkan-impl/vulkan-render-pass.h
dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-types.h

index 34dc85b..3ada789 100644 (file)
@@ -2,4 +2,5 @@
 build
 build.log
 tct*core.h
-results_xml.*
\ No newline at end of file
+results_xml.*
+/CMakeLists.txt
index 7747374..e5ffe8f 100644 (file)
@@ -260,7 +260,7 @@ private:
 
 protected:
   Dali::Internal::Adaptor::AdaptorInternalServices* mAdaptor;
-  Dali::Graphics::GraphicsInterface*       mGraphics;
+  Dali::Graphics::GraphicsInterface*                mGraphics;
   Dali::DisplayConnection*                          mDisplayConnection;
   WeakHandle<Dali::Integration::Scene>              mScene;
   bool                                              mFullSwapNextFrame; ///< Whether the full surface swap is required
index 30ca2dc..85d5cb9 100644 (file)
@@ -545,7 +545,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
 
   NotifyGraphicsInitialised();
 
-  //@todo Vk swaps this around, but we need to support surfaceless context for multi-window
+  // Generate swapchains if needed
   graphics.ConfigureSurface(mAdaptorInterfaces.GetRenderSurfaceInterface());
 
   // Tell core it has a context
@@ -777,7 +777,7 @@ void CombinedUpdateRenderController::UpdateRenderThread()
     AddPerformanceMarker(PerformanceInterface::RENDER_START);
     TRACE_UPDATE_RENDER_BEGIN("DALI_RENDER");
 
-    // Upload shared resources
+    // Upload shared resources and process render messages
     TRACE_UPDATE_RENDER_BEGIN("DALI_PRE_RENDER");
     mCore.PreRender(renderStatus, mForceClear);
     TRACE_UPDATE_RENDER_END("DALI_PRE_RENDER");
index 274cfdf..c6dd727 100644 (file)
@@ -58,10 +58,27 @@ void CommandBuffer::DiscardResource()
 
 void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info)
 {
+  if(mCommandBufferImpl)
+  {
+    mCommandBufferImpl->Begin(static_cast<vk::CommandBufferUsageFlags>(info.usage), nullptr);
+  }
 }
 
 void CommandBuffer::End()
 {
+  if(mCommandBufferImpl)
+  {
+    mCommandBufferImpl->End();
+  }
+}
+
+void CommandBuffer::Reset()
+{
+  if(mCommandBufferImpl)
+  {
+    mCommandBufferImpl->Reset();
+  }
+  mLastSwapchain = nullptr;
 }
 
 void CommandBuffer::BindVertexBuffers(uint32_t                                    firstBinding,
@@ -98,59 +115,63 @@ void CommandBuffer::BindIndexBuffer(const Graphics::Buffer& buffer,
 {
 }
 
-void CommandBuffer::BeginRenderPass(Graphics::RenderPass*          renderPass,
-                                    Graphics::RenderTarget*        renderTarget,
+void CommandBuffer::BeginRenderPass(Graphics::RenderPass*          gfxRenderPass,
+                                    Graphics::RenderTarget*        gfxRenderTarget,
                                     Rect2D                         renderArea,
                                     const std::vector<ClearValue>& clearValues)
 {
-  //@todo Find a better place to auto-insert begin/end.
-  // mCommandBufferImpl->Begin(vk::CommandBufferUsageFlagBits::eOneTimeSubmit, nullptr );
-
-  auto             vulkanRenderPass   = static_cast<Vulkan::RenderPass*>(renderPass);
-  auto             vulkanRenderTarget = static_cast<Vulkan::RenderTarget*>(renderTarget);
-  auto             surface            = vulkanRenderTarget->GetSurface();
-  auto&            device             = mController.GetGraphicsDevice();
+  auto             renderPass   = static_cast<Vulkan::RenderPass*>(gfxRenderPass);
+  auto             renderTarget = static_cast<Vulkan::RenderTarget*>(gfxRenderTarget);
+  auto             surface      = renderTarget->GetSurface();
+  auto&            device       = mController.GetGraphicsDevice();
   FramebufferImpl* framebuffer;
-  vk::RenderPass   vkRenderPass;
+  RenderPassImpl*  renderPassImpl;
   if(surface)
   {
     auto window    = static_cast<Internal::Adaptor::WindowRenderSurface*>(surface);
     auto surfaceId = window->GetSurfaceId();
     auto swapchain = device.GetSwapchainForSurfaceId(surfaceId);
+    mLastSwapchain = swapchain;
     framebuffer    = swapchain->GetCurrentFramebuffer();
-    vkRenderPass   = framebuffer->GetRenderPass();
+    renderPassImpl = framebuffer->GetRenderPass(renderPass);
   }
   else
   {
-    auto coreFramebuffer = vulkanRenderTarget->GetFramebuffer();
+    auto coreFramebuffer = renderTarget->GetFramebuffer();
     framebuffer          = coreFramebuffer->GetImpl();
-    vkRenderPass         = vulkanRenderPass->GetImpl()->GetVkHandle();
+    renderPassImpl       = framebuffer->GetRenderPass(renderPass);
   }
 
   std::vector<vk::ClearValue> vkClearValues;
-  for(auto clearValue : clearValues)
+
+  auto attachments = renderPass->GetCreateInfo().attachments;
+  if(attachments != nullptr &&
+     !attachments->empty() &&
+     attachments->front().loadOp == Graphics::AttachmentLoadOp::CLEAR)
   {
-    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);
+    for(auto clearValue : clearValues)
+    {
+      vk::ClearColorValue color;
+      color.float32[0] = clearValue.color.r;
+      color.float32[1] = clearValue.color.g;
+      color.float32[2] = clearValue.color.b;
+      color.float32[3] = clearValue.color.a;
+      vkClearValues.emplace_back(color);
+    }
   }
-  /**
-  mCommandBufferImpl->BeginRenderPass( vk::RenderPassBeginInfo{}
-                                         .setFramebuffer( framebuffer->GetVkHandle() )
-                                         .setRenderPass( vkRenderPass )
-                                         .setRenderArea( { {0, 0}, { renderArea.width, renderArea.height } } )
-                                         .setPClearValues( vkClearValues.data() )
-                                         .setClearValueCount( uint32_t(framebuffer->GetClearValues().size()) ),
-                                      vk::SubpassContents::eInline );
-*/
+
+  mCommandBufferImpl->BeginRenderPass(vk::RenderPassBeginInfo{}
+                                        .setFramebuffer(framebuffer->GetVkHandle())
+                                        .setRenderPass(renderPassImpl->GetVkHandle())
+                                        .setRenderArea({{0, 0}, {renderArea.width, renderArea.height}})
+                                        .setPClearValues(vkClearValues.data())
+                                        .setClearValueCount(uint32_t(framebuffer->GetClearValues().size())),
+                                      vk::SubpassContents::eInline);
 }
 
 void CommandBuffer::EndRenderPass(Graphics::SyncObject* syncObject)
 {
-  // mCommandBufferImpl->EndRenderPass();
+  mCommandBufferImpl->EndRenderPass();
 }
 
 void CommandBuffer::ExecuteCommandBuffers(std::vector<const Graphics::CommandBuffer*>&& commandBuffers)
@@ -183,10 +204,6 @@ void CommandBuffer::DrawNative(const DrawNativeInfo* drawInfo)
 {
 }
 
-void CommandBuffer::Reset()
-{
-}
-
 void CommandBuffer::SetScissor(Rect2D value)
 {
 }
@@ -247,4 +264,9 @@ void CommandBuffer::SetDepthWriteEnable(bool depthWriteEnable)
 {
 }
 
+Swapchain* CommandBuffer::GetLastSwapchain() const
+{
+  return mLastSwapchain;
+}
+
 } // namespace Dali::Graphics::Vulkan
index ba73457..5bad086 100644 (file)
@@ -24,6 +24,7 @@
 namespace Dali::Graphics::Vulkan
 {
 class CommandBufferImpl;
+class Swapchain;
 
 using CommandBufferResource = Resource<Graphics::CommandBuffer, Graphics::CommandBufferCreateInfo>;
 
@@ -337,8 +338,23 @@ public:
    */
   void SetDepthWriteEnable(bool depthWriteEnable) override;
 
+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.
+   */
+  Swapchain* GetLastSwapchain() const;
+
+  CommandBufferImpl* GetImpl() const
+  {
+    return mCommandBufferImpl;
+  }
+
 private:
   CommandBufferImpl* mCommandBufferImpl;
+  Swapchain*         mLastSwapchain{nullptr};
 };
 
 } // namespace Dali::Graphics::Vulkan
index c0b8cdd..4810bf3 100644 (file)
@@ -20,6 +20,8 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-image-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-image-view-impl.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-types.h>
 #include <dali/internal/graphics/vulkan/vulkan-device.h>
 
 #include <dali/integration-api/debug.h>
@@ -122,11 +124,12 @@ FramebufferImpl* FramebufferImpl::New(
   std::vector<FramebufferAttachment*>& attachments,
   uint32_t                             width,
   uint32_t                             height,
-  bool                                 hasDepthAttachments,
-  bool                                 takeRenderPassOwnership)
+  bool                                 hasDepthAttachments)
 {
   std::vector<vk::ImageView> imageViewAttachments;
 
+  DALI_ASSERT_ALWAYS(renderPass != nullptr && "You require more render passes!");
+
   std::transform(attachments.cbegin(),
                  attachments.cend(),
                  std::back_inserter(imageViewAttachments),
@@ -142,11 +145,10 @@ FramebufferImpl* FramebufferImpl::New(
   return new FramebufferImpl(device,
                              attachments,
                              vkFramebuffer,
-                             renderPass->GetVkHandle(),
+                             *renderPass,
                              width,
                              height,
-                             hasDepthAttachments,
-                             takeRenderPassOwnership);
+                             hasDepthAttachments);
 }
 
 FramebufferImpl* FramebufferImpl::New(
@@ -183,11 +185,10 @@ FramebufferImpl* FramebufferImpl::New(
   auto attachments = std::vector<FramebufferAttachment*>{};
 
   // Flag that indicates if the render pass is externally provided
-  bool renderPassTakeOwnership = false;
   if(renderPass == nullptr)
   {
-    renderPass              = RenderPassImpl::New(device, colorAttachments, depthAttachment);
-    renderPassTakeOwnership = true;
+    // Create compatible render pass
+    renderPass = RenderPassImpl::New(device, colorAttachments, depthAttachment);
   }
   attachments.reserve(colorAttachments.size());
   attachments.insert(attachments.begin(), colorAttachments.begin(), colorAttachments.end());
@@ -195,26 +196,24 @@ FramebufferImpl* FramebufferImpl::New(
   {
     attachments.push_back(depthAttachment);
   }
-  return FramebufferImpl::New(device, renderPass, attachments, width, height, hasDepth, renderPassTakeOwnership);
+  return FramebufferImpl::New(device, renderPass, attachments, width, height, hasDepth);
 }
 
 FramebufferImpl::FramebufferImpl(Device&                                    graphicsDevice,
                                  const std::vector<FramebufferAttachment*>& attachments,
                                  vk::Framebuffer                            vkHandle,
-                                 vk::RenderPass                             renderPass,
+                                 const RenderPassImpl&                      renderPassImpl,
                                  uint32_t                                   width,
                                  uint32_t                                   height,
-                                 bool                                       hasDepthAttachment,
-                                 bool                                       takeRenderPassOwnership)
+                                 bool                                       hasDepthAttachment)
 : mGraphicsDevice(&graphicsDevice),
   mWidth(width),
   mHeight(height),
   mAttachments(attachments),
   mFramebuffer(vkHandle),
-  mRenderPass(renderPass),
-  mHasDepthAttachment(hasDepthAttachment),
-  mRenderPassOwned(takeRenderPassOwnership)
+  mHasDepthAttachment(hasDepthAttachment)
 {
+  mRenderPasses.push_back(RenderPassMapElement{nullptr, const_cast<RenderPassImpl*>(&renderPassImpl)});
 }
 
 uint32_t FramebufferImpl::GetWidth() const
@@ -303,9 +302,42 @@ uint32_t FramebufferImpl::GetAttachmentCount(AttachmentType type) const
   return 0u;
 }
 
-vk::RenderPass FramebufferImpl::GetRenderPass() const
+RenderPassImpl* FramebufferImpl::GetRenderPass(RenderPass* renderPass)
 {
-  return mRenderPass;
+  auto attachments  = renderPass->GetCreateInfo().attachments;
+  auto matchLoadOp  = attachments->front().loadOp;
+  auto matchStoreOp = attachments->front().storeOp;
+
+  for(auto& element : mRenderPasses)
+  {
+    // Test renderpass first
+    if(element.renderPass != nullptr)
+    {
+      auto firstAttachment = element.renderPass->GetCreateInfo().attachments->front();
+      if(firstAttachment.loadOp == matchLoadOp &&
+         firstAttachment.storeOp == matchStoreOp)
+      {
+        return element.renderPassImpl;
+      }
+    }
+    else
+    {
+      DALI_ASSERT_DEBUG(element.renderPassImpl != nullptr && "Render pass list doesn't contain impl");
+      auto createInfo = element.renderPassImpl->GetCreateInfo();
+
+      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;
+      }
+    }
+  }
+
+  // @todo create new render pass from existing + load/store op, add it to mRenderPasses, and return it.
+
+  return mRenderPasses[0].renderPassImpl;
 }
 
 vk::Framebuffer FramebufferImpl::GetVkHandle() const
@@ -333,7 +365,8 @@ bool FramebufferImpl::OnDestroy()
   auto device      = mGraphicsDevice->GetLogicalDevice();
   auto frameBuffer = mFramebuffer;
 
-  vk::RenderPass renderPass = mRenderPassOwned ? mRenderPass : vk::RenderPass{};
+  ///@todo Destroy all render passes.
+  vk::RenderPass renderPass = mRenderPasses[0].renderPassImpl->GetVkHandle();
 
   auto allocator = &mGraphicsDevice->GetAllocator();
 
@@ -346,8 +379,7 @@ bool FramebufferImpl::OnDestroy()
                                      {
                                        DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: render pass->%p\n", static_cast<VkRenderPass>(renderPass))
                                        device.destroyRenderPass(renderPass, allocator);
-                                     }
-                                   });
+                                     } });
 
   return false;
 }
index e0ccee5..bcf567d 100644 (file)
@@ -22,6 +22,7 @@
 
 namespace Dali::Graphics::Vulkan
 {
+class RenderPass;
 class RenderPassImpl;
 
 enum class AttachmentType
@@ -85,8 +86,7 @@ public:
     std::vector<FramebufferAttachment*>& attachments,
     uint32_t                             width,
     uint32_t                             height,
-    bool                                 hasDepthAttachment,
-    bool                                 takeRenderPassOwnership);
+    bool                                 hasDepthAttachment);
 
   static FramebufferImpl* New(
     Vulkan::Device&                            device,
@@ -99,11 +99,10 @@ public:
   FramebufferImpl(Device&                                    graphicsDevice,
                   const std::vector<FramebufferAttachment*>& attachments,
                   vk::Framebuffer                            vkHandle,
-                  vk::RenderPass                             renderPass,
+                  const RenderPassImpl&                      renderPass,
                   uint32_t                                   width,
                   uint32_t                                   height,
-                  bool                                       hasDepthAttachment,
-                  bool                                       takeRenderPassOwnership);
+                  bool                                       hasDepthAttachment);
 
   [[nodiscard]] uint32_t GetWidth() const;
 
@@ -115,7 +114,7 @@ public:
 
   [[nodiscard]] uint32_t GetAttachmentCount(AttachmentType type) const;
 
-  [[nodiscard]] vk::RenderPass GetRenderPass() const;
+  [[nodiscard]] RenderPassImpl* GetRenderPass(RenderPass* renderPass); // May mutate mRenderPasses
 
   [[nodiscard]] vk::Framebuffer GetVkHandle() const;
 
@@ -129,11 +128,20 @@ private:
   uint32_t mWidth;
   uint32_t mHeight;
 
+  /**
+   * Structure to map RenderPass to RenderPassImpl.
+   */
+  struct RenderPassMapElement
+  {
+    RenderPass*     renderPass{nullptr};
+    RenderPassImpl* renderPassImpl{nullptr};
+  };
+  using RenderPasses = std::vector<RenderPassMapElement>;
+
   std::vector<FramebufferAttachment*> mAttachments;
   vk::Framebuffer                     mFramebuffer;
-  vk::RenderPass                      mRenderPass;
+  RenderPasses                        mRenderPasses;
   bool                                mHasDepthAttachment{false};
-  bool                                mRenderPassOwned{false};
 };
 
 } // Namespace Dali::Graphics::Vulkan
index a98e484..bbea6b2 100644 (file)
@@ -39,29 +39,27 @@ Framebuffer::~Framebuffer() = default;
 
 bool Framebuffer::InitializeResource()
 {
-  /*
-   * Renderpass handling.
-   * We get passed VulkanRenderPass
-   * For actual framebuffer creation, we need at least the first VulkanRenderPass to have a VulkanRenderPassImpl created
-   * and for subsequent VulkanRenderPasses to be compatible with the first (and can be created on the fly)
-   */
-
   // Create attachments
-  auto renderPass = static_cast<Vulkan::RenderPass*>(mCreateInfo.renderPasses[0]);
-
-  auto renderPassImpl = renderPass->GetImpl(); // Only generate actual render pass if needed
-  if(!renderPassImpl)
+  std::vector<FramebufferAttachment*> colorAttachments;
+  // for(auto& attachment : mCreateInfo.colorAttachments)
   {
-    renderPass->InitializeResource();
+    // auto graphicsTexture = static_cast<const Vulkan::Texture*>(attachment.texture);
+    // colorAttachments.push_back(FramebufferAttachment::NewColorAttachment(attachment.texture->GetVkHandle(), clearColor, AttachmentType::COLOR, false);
+  }
+  FramebufferAttachment* depthStencilAttachment{nullptr};
+  if(mCreateInfo.depthStencilAttachment.depthTexture || mCreateInfo.depthStencilAttachment.stencilTexture)
+  {
+    // depthStencilAttachment = FramebufferAttachment::NewDepthAttachment();
   }
 
-  auto&                               device = mController.GetGraphicsDevice();
-  std::vector<FramebufferAttachment*> colorAttachments;
-  FramebufferAttachment*              depthStencilAttachment{nullptr};
-  //@todo FINISH ME! (Needs texture -> image view bindings)
+  // Create initial render pass.
+  auto renderPassImpl = RenderPassImpl::New(mController.GetGraphicsDevice(),
+                                            colorAttachments,
+                                            depthStencilAttachment);
+
+  auto& device     = mController.GetGraphicsDevice();
   mFramebufferImpl = FramebufferImpl::New(device, renderPassImpl, colorAttachments, depthStencilAttachment, mCreateInfo.size.width, mCreateInfo.size.height);
 
-  //@todo Store all the render passes here. Will be used later to generate compatible render pass impls.
   return true;
 }
 
index 3696eaa..8f808e8 100644 (file)
@@ -27,6 +27,7 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-target.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
 
 namespace Dali::Graphics::Vulkan
 {
@@ -121,7 +122,7 @@ struct VulkanGraphicsController::Impl
 
   void AcquireNextFramebuffer()
   {
-    // for all swapchains acquire new framebuffer
+    // @todo for all swapchains acquire new framebuffer
     auto surface   = mGraphicsDevice->GetSurface(0u);
     auto swapchain = mGraphicsDevice->GetSwapchainForSurfaceId(0u);
 
@@ -168,33 +169,31 @@ Integration::GraphicsConfig& VulkanGraphicsController::GetGraphicsConfig()
   return *this;
 }
 
+void VulkanGraphicsController::FrameStart()
+{
+  mImpl->mCapacity = 0;
+  mImpl->AcquireNextFramebuffer();
+}
+
 void VulkanGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo)
 {
+  // Figure out where to submit each command buffer.
+  for(auto gfxCmdBuffer : submitInfo.cmdBuffer)
+  {
+    auto cmdBuffer = static_cast<const CommandBuffer*>(gfxCmdBuffer);
+    auto swapchain = cmdBuffer->GetLastSwapchain();
+    if(swapchain)
+    {
+      swapchain->Submit(cmdBuffer->GetImpl());
+    }
+  }
 }
 
 void VulkanGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
 {
-  // Test code to create a render pass to clear the surface
-  mImpl->AcquireNextFramebuffer();
-
-  auto swapchain = mImpl->mGraphicsDevice->GetSwapchainForSurfaceId(0u);
-
-  CommandPool* commandPool          = mImpl->mGraphicsDevice->GetCommandPool(std::this_thread::get_id());
-  auto         primaryCommandBuffer = commandPool->NewCommandBuffer(true);
-
-  primaryCommandBuffer->Begin(vk::CommandBufferUsageFlagBits::eOneTimeSubmit, nullptr);
-  primaryCommandBuffer->BeginRenderPass(vk::RenderPassBeginInfo{}
-                                          .setFramebuffer(swapchain->GetCurrentFramebuffer()->GetVkHandle())
-                                          .setRenderPass(swapchain->GetCurrentFramebuffer()->GetRenderPass())
-                                          .setRenderArea({{0, 0}, {swapchain->GetCurrentFramebuffer()->GetWidth(), swapchain->GetCurrentFramebuffer()->GetHeight()}})
-                                          .setPClearValues(swapchain->GetCurrentFramebuffer()->GetClearValues().data())
-                                          .setClearValueCount(uint32_t(swapchain->GetCurrentFramebuffer()->GetClearValues().size())),
-                                        vk::SubpassContents::eInline);
-  primaryCommandBuffer->EndRenderPass();
-  primaryCommandBuffer->End();
-
-  // Submit command buffer
-  swapchain->Submit(primaryCommandBuffer);
+  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();
 }
@@ -265,15 +264,9 @@ UniquePtr<Graphics::CommandBuffer> VulkanGraphicsController::CreateCommandBuffer
 
 UniquePtr<Graphics::RenderPass> VulkanGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, UniquePtr<Graphics::RenderPass>&& oldRenderPass)
 {
-  // If this is for a surface, then we already have a render pass hidden inside the swapchain...
-  // The surface should have a GraphicsSurfaceId, which can be used to get the swapchain.
-  // But, we want to create multiple render passes in Core on a scene's surface...
-  // Now, renderPassCreateInfo contains renderTarget, so this implementation can decide to generate
-  // surface's swapchain framebuffers based on this new renderpass. Though, should be explicit about it!
-  auto renderPass = NewObject<Vulkan::RenderPass>(renderPassCreateInfo, *this, std::move(oldRenderPass));
+  auto renderPass = UniquePtr<Graphics::RenderPass>(new Vulkan::RenderPass(renderPassCreateInfo, *this));
 
-  //auto vkRenderPass = static_cast<Vulkan::RenderPass*>(renderPass.get());
-  //vkRenderPass->InitializeResource(); // This may create an actual resource.
+  // Don't create actual vulkan resource here. It will instead be done on demand. (e.g. framebuffer creation, CommandBuffer::BeginRenderPass())
   return renderPass;
 }
 
@@ -493,11 +486,6 @@ Graphics::UniquePtr<Graphics::Texture> VulkanGraphicsController::ReleaseTextureF
   return texture;
 }
 
-void VulkanGraphicsController::FrameStart()
-{
-  mImpl->mCapacity = 0;
-}
-
 std::size_t VulkanGraphicsController::GetCapacity() const
 {
   return mImpl->mCapacity;
index 2d3d40a..67a6f1f 100644 (file)
@@ -16,8 +16,6 @@
 
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass-impl.h>
 
-#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
-
 #include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-image-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-image-view-impl.h>
@@ -31,13 +29,57 @@ extern Debug::Filter* gVulkanFilter;
 
 namespace Dali::Graphics::Vulkan
 {
-namespace
-{
-vk::RenderPass CreateCompatibleRenderPass(
+
+RenderPassImpl* RenderPassImpl::New(
   Vulkan::Device&                            device,
   const std::vector<FramebufferAttachment*>& colorAttachments,
-  FramebufferAttachment*                     depthAttachment,
-  std::vector<vk::ImageView>&                attachments)
+  FramebufferAttachment*                     depthAttachment)
+{
+  auto renderPass = new RenderPassImpl(device, colorAttachments, depthAttachment);
+  return renderPass;
+}
+
+RenderPassImpl::RenderPassImpl(Vulkan::Device&                            device,
+                               const std::vector<FramebufferAttachment*>& colorAttachments,
+                               FramebufferAttachment*                     depthAttachment)
+: mGraphicsDevice(&device)
+{
+  CreateCompatibleCreateInfo(colorAttachments, depthAttachment);
+  CreateRenderPass();
+}
+
+RenderPassImpl::~RenderPassImpl() = default;
+
+vk::RenderPass RenderPassImpl::GetVkHandle()
+{
+  return mVkRenderPass;
+}
+
+bool RenderPassImpl::OnDestroy()
+{
+  if(mVkRenderPass)
+  {
+    auto device     = mGraphicsDevice->GetLogicalDevice();
+    auto allocator  = &mGraphicsDevice->GetAllocator();
+    auto renderPass = mVkRenderPass;
+    mGraphicsDevice->DiscardResource([device, renderPass, allocator]()
+                                     {
+      DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: swap chain->%p\n", static_cast<VkRenderPass>(renderPass))
+      device.destroyRenderPass(renderPass, allocator); });
+
+    mVkRenderPass = nullptr;
+  }
+  return false;
+}
+
+std::vector<vk::ImageView>& RenderPassImpl::GetAttachments()
+{
+  return mAttachments;
+}
+
+void RenderPassImpl::CreateCompatibleCreateInfo(
+  const std::vector<FramebufferAttachment*>& colorAttachments,
+  FramebufferAttachment*                     depthAttachment)
 {
   auto hasDepth = false;
   if(depthAttachment)
@@ -48,16 +90,14 @@ vk::RenderPass CreateCompatibleRenderPass(
 
   // The total number of attachments
   auto totalAttachmentCount = hasDepth ? colorAttachments.size() + 1 : colorAttachments.size();
-  attachments.clear();
-  attachments.reserve(totalAttachmentCount);
+  mAttachments.clear();
+  mAttachments.reserve(totalAttachmentCount);
 
   // This vector stores the attachment references
-  auto colorAttachmentReferences = std::vector<vk::AttachmentReference>{};
-  colorAttachmentReferences.reserve(colorAttachments.size());
+  mCreateInfo.colorAttachmentReferences.reserve(colorAttachments.size());
 
   // This vector stores the attachment descriptions
-  auto attachmentDescriptions = std::vector<vk::AttachmentDescription>{};
-  attachmentDescriptions.reserve(totalAttachmentCount);
+  mCreateInfo.attachmentDescriptions.reserve(totalAttachmentCount);
 
   // For each color attachment...
   for(auto i = 0u; i < colorAttachments.size(); ++i)
@@ -76,15 +116,14 @@ vk::RenderPass CreateCompatibleRenderPass(
     assert(imageLayout == vk::ImageLayout::eColorAttachmentOptimal);
 
     // Add a reference and a descriptions and image views to their respective vectors
-    colorAttachmentReferences.push_back(vk::AttachmentReference{}.setLayout(imageLayout).setAttachment(U32(i)));
+    mCreateInfo.colorAttachmentReferences.push_back(vk::AttachmentReference{}.setLayout(imageLayout).setAttachment(U32(i)));
 
-    attachmentDescriptions.push_back(colorAttachments[i]->GetDescription());
+    mCreateInfo.attachmentDescriptions.push_back(colorAttachments[i]->GetDescription());
 
-    attachments.push_back(colorAttachments[i]->GetImageView()->GetVkHandle());
+    mAttachments.push_back(colorAttachments[i]->GetImageView()->GetVkHandle());
   }
 
   // Follow the exact same procedure as color attachments
-  auto depthAttachmentReference = vk::AttachmentReference{};
   if(hasDepth)
   {
     auto imageLayout = depthAttachment->GetImageView()->GetImage()->GetImageLayout();
@@ -96,107 +135,54 @@ vk::RenderPass CreateCompatibleRenderPass(
 
     assert(imageLayout == vk::ImageLayout::eDepthStencilAttachmentOptimal);
 
-    depthAttachmentReference.setLayout(imageLayout);
-    depthAttachmentReference.setAttachment(U32(colorAttachmentReferences.size()));
+    mCreateInfo.depthAttachmentReference.setLayout(imageLayout);
+    mCreateInfo.depthAttachmentReference.setAttachment(U32(mCreateInfo.colorAttachmentReferences.size()));
 
-    attachmentDescriptions.push_back(depthAttachment->GetDescription());
+    mCreateInfo.attachmentDescriptions.push_back(depthAttachment->GetDescription());
 
-    attachments.push_back(depthAttachment->GetImageView()->GetVkHandle());
+    mAttachments.push_back(depthAttachment->GetImageView()->GetVkHandle());
   }
 
   // Creating a single subpass per framebuffer
-  auto subpassDesc = vk::SubpassDescription{};
-  subpassDesc.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics);
-  subpassDesc.setColorAttachmentCount(U32(colorAttachments.size()));
+  mCreateInfo.subpassDesc.setPipelineBindPoint(vk::PipelineBindPoint::eGraphics);
+  mCreateInfo.subpassDesc.setColorAttachmentCount(U32(colorAttachments.size()));
   if(hasDepth)
   {
-    subpassDesc.setPDepthStencilAttachment(&depthAttachmentReference);
+    mCreateInfo.subpassDesc.setPDepthStencilAttachment(&mCreateInfo.depthAttachmentReference);
   }
-  subpassDesc.setPColorAttachments(colorAttachmentReferences.data());
+  mCreateInfo.subpassDesc.setPColorAttachments(mCreateInfo.colorAttachmentReferences.data());
 
   // Creating 2 subpass dependencies using VK_SUBPASS_EXTERNAL to leverage the implicit image layout
   // transitions provided by the driver
-  std::array<vk::SubpassDependency, 2> subpassDependencies{
-
-    vk::SubpassDependency{}.setSrcSubpass(VK_SUBPASS_EXTERNAL).setDstSubpass(0).setSrcStageMask(vk::PipelineStageFlagBits::eBottomOfPipe).setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput).setSrcAccessMask(vk::AccessFlagBits::eMemoryRead).setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite).setDependencyFlags(vk::DependencyFlagBits::eByRegion),
-
-    vk::SubpassDependency{}.setSrcSubpass(0).setDstSubpass(VK_SUBPASS_EXTERNAL).setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput).setDstStageMask(vk::PipelineStageFlagBits::eBottomOfPipe).setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite).setDstAccessMask(vk::AccessFlagBits::eMemoryRead).setDependencyFlags(vk::DependencyFlagBits::eByRegion)
-
-  };
-
-  // Create the render pass
-  auto renderPassCreateInfo = vk::RenderPassCreateInfo{}.setAttachmentCount(U32(attachmentDescriptions.size())).setPAttachments(attachmentDescriptions.data()).setPSubpasses(&subpassDesc).setSubpassCount(1).setPDependencies(subpassDependencies.data());
-
-  auto vkRenderPass = VkAssert(device.GetLogicalDevice().createRenderPass(renderPassCreateInfo, device.GetAllocator()));
-  return vkRenderPass;
-}
-
-} // namespace
-
-RenderPassImpl* RenderPassImpl::New(
-  Vulkan::Device&                            device,
-  const std::vector<FramebufferAttachment*>& colorAttachments,
-  FramebufferAttachment*                     depthAttachment)
-{
-  std::vector<vk::ImageView> attachments{};
-  auto                       vkRenderPass = CreateCompatibleRenderPass(device, colorAttachments, depthAttachment, attachments);
-
-  auto renderPass = new RenderPassImpl(device, vkRenderPass);
-  renderPass->SetAttachments(attachments);
-  return renderPass;
-}
-
-RenderPassImpl::RenderPassImpl(Vulkan::Device& device, vk::RenderPass renderPass)
-: mGraphicsDevice(&device),
-  mVkRenderPass(renderPass)
-{
-}
-
-RenderPassImpl::RenderPassImpl(
-  Vulkan::Device&                       device,
-  const Graphics::RenderPassCreateInfo& createInfo,
-  std::vector<FramebufferAttachment*>&  colorAttachments,
-  FramebufferAttachment*                depthAttachment)
-: mGraphicsDevice(&device)
-{
-  // @todo Do mostly as CreateCompatibleRenderPass above, but instead, get the attachment
-  // descriptions from the createInfo passed in here.
-  mVkRenderPass = CreateCompatibleRenderPass(*mGraphicsDevice, colorAttachments, depthAttachment, mAttachments);
-}
-
-RenderPassImpl::~RenderPassImpl() = default;
-
-vk::RenderPass RenderPassImpl::GetVkHandle()
-{
-  return mVkRenderPass;
-}
-
-bool RenderPassImpl::OnDestroy()
-{
-  if(mVkRenderPass)
-  {
-    auto device     = mGraphicsDevice->GetLogicalDevice();
-    auto allocator  = &mGraphicsDevice->GetAllocator();
-    auto renderPass = mVkRenderPass;
-    mGraphicsDevice->DiscardResource([device, renderPass, allocator]()
-                                     {
-      DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: swap chain->%p\n", static_cast<VkRenderPass>(renderPass))
-      device.destroyRenderPass(renderPass, allocator); });
-
-    mVkRenderPass = nullptr;
-  }
-  return false;
-}
-
-std::vector<vk::ImageView>& RenderPassImpl::GetAttachments()
-{
-  return mAttachments;
+  mCreateInfo.subpassDependencies = {
+    vk::SubpassDependency{}
+      .setSrcSubpass(VK_SUBPASS_EXTERNAL)
+      .setDstSubpass(0)
+      .setSrcStageMask(vk::PipelineStageFlagBits::eBottomOfPipe)
+      .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
+      .setSrcAccessMask(vk::AccessFlagBits::eMemoryRead)
+      .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite)
+      .setDependencyFlags(vk::DependencyFlagBits::eByRegion),
+
+    vk::SubpassDependency{}
+      .setSrcSubpass(0)
+      .setDstSubpass(VK_SUBPASS_EXTERNAL)
+      .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
+      .setDstStageMask(vk::PipelineStageFlagBits::eBottomOfPipe)
+      .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite)
+      .setDstAccessMask(vk::AccessFlagBits::eMemoryRead)
+      .setDependencyFlags(vk::DependencyFlagBits::eByRegion)};
+
+  mCreateInfo.createInfo.setAttachmentCount(U32(mCreateInfo.attachmentDescriptions.size()))
+    .setPAttachments(mCreateInfo.attachmentDescriptions.data())
+    .setPSubpasses(&mCreateInfo.subpassDesc)
+    .setSubpassCount(1)
+    .setPDependencies(mCreateInfo.subpassDependencies.data());
 }
 
-void RenderPassImpl::SetAttachments(std::vector<vk::ImageView>& attachments)
+void RenderPassImpl::CreateRenderPass()
 {
-  // @todo Remove? How can we late bind attachments? Recreate the whole RP?
-  mAttachments = std::move(attachments);
+  mVkRenderPass = VkAssert(mGraphicsDevice->GetLogicalDevice().createRenderPass(mCreateInfo.createInfo, mGraphicsDevice->GetAllocator()));
 }
 
 } // namespace Dali::Graphics::Vulkan
index 58630a6..6122634 100644 (file)
@@ -27,30 +27,63 @@ class Device;
 class VulkanGraphicsController;
 class RenderTarget;
 
+/**
+ * Holder class for Vulkan RenderPass object.
+ *
+ * We need a render pass to create a Framebuffer; this can create a
+ * compatible render pass given the specific attachments.
+ *
+ * FramebufferImpl will own it's RenderPassImpl(s), NOT the Graphics::RenderPass
+ * implementation.
+ *
+ * When we want to use the FramebufferImpl (CommandBuffer::BeginRenderPass), then
+ * we try and match the supplied Graphics::RenderPass to the creating render pass.
+ * FramebufferImpl will create a separate compatible RenderPassImpl if a matching
+ * render pass is NOT found.
+ */
 class RenderPassImpl final : public Dali::Graphics::Vulkan::VkManaged
 {
 public:
+  struct CreateInfo
+  {
+    std::vector<vk::AttachmentReference>   colorAttachmentReferences;
+    vk::AttachmentReference                depthAttachmentReference;
+    std::vector<vk::AttachmentDescription> attachmentDescriptions;
+    vk::SubpassDescription                 subpassDesc;
+    std::array<vk::SubpassDependency, 2>   subpassDependencies;
+    vk::RenderPassCreateInfo               createInfo;
+  };
+
   static RenderPassImpl* New(
     Vulkan::Device&                            device,
     const std::vector<FramebufferAttachment*>& colorAttachments,
     FramebufferAttachment*                     depthAttachment);
 
-  RenderPassImpl(Vulkan::Device& device, vk::RenderPass renderPass);
-
-  RenderPassImpl(Vulkan::Device& device, const Graphics::RenderPassCreateInfo& createInfo, std::vector<FramebufferAttachment*>& colorAttachments, FramebufferAttachment* depthAttachment);
+  RenderPassImpl(Vulkan::Device& device, const std::vector<FramebufferAttachment*>& colorAttachments, FramebufferAttachment* depthAttachment);
 
   ~RenderPassImpl() override;
 
   vk::RenderPass GetVkHandle();
 
+  bool OnDestroy() override;
+
   std::vector<vk::ImageView>& GetAttachments();
 
-  void SetAttachments(std::vector<vk::ImageView>& attachments);
+  CreateInfo& GetCreateInfo()
+  {
+    return mCreateInfo;
+  }
 
-  bool OnDestroy() override;
+private:
+  void CreateCompatibleCreateInfo(
+    const std::vector<FramebufferAttachment*>& colorAttachments,
+    FramebufferAttachment*                     depthAttachment);
+
+  void CreateRenderPass();
 
 private:
   Device*                    mGraphicsDevice;
+  CreateInfo                 mCreateInfo;
   vk::RenderPass             mVkRenderPass;
   std::vector<vk::ImageView> mAttachments{};
 };
index b2f8faf..fd8a104 100644 (file)
 namespace Dali::Graphics::Vulkan
 {
 RenderPass::RenderPass(const Graphics::RenderPassCreateInfo& createInfo, VulkanGraphicsController& controller)
-: RenderPassResource(createInfo, controller),
-  mRenderPassImpl(nullptr)
+: mCreateInfo(createInfo),
+  mController(controller)
 {
-}
-
-RenderPass::~RenderPass() = default;
-
-bool RenderPass::InitializeResource()
-{
-  auto renderTarget = static_cast<RenderTarget*>(mCreateInfo.renderTarget);
-  auto framebuffer  = renderTarget->GetFramebuffer();
-  if(framebuffer)
-  {
-    auto vkFramebuffer = framebuffer->GetImpl();
-
-    // Note, Vulkan framebuffer can now be used with compatible render passes in vkBeginRenderPass.
-    // So we can create multiple render passes.
-
-    std::vector<FramebufferAttachment*> colorAttachments = vkFramebuffer->GetAttachments(AttachmentType::COLOR);
-    ;
-    std::vector<FramebufferAttachment*> depthAttachment = vkFramebuffer->GetAttachments(AttachmentType::DEPTH_STENCIL);
-    ;
-
-    mRenderPassImpl = new RenderPassImpl(mController.GetGraphicsDevice(), mCreateInfo, colorAttachments, depthAttachment[0]);
-  }
-  else
+  if(createInfo.attachments)
   {
-    // RenderTarget must be a surface.
-    // Create a new render pass that's compatible with the surface's framebuffer.
-    //
-    // Does that mean it has to use the fbo's color attachment? YES.
-    // I.e. should we generate separate RenderPassImpls for each of the surface's framebuffers?
-    // GetImpl() then needs bufferIndex
+    mAttachments.insert(mAttachments.end(), createInfo.attachments->begin(), createInfo.attachments->end());
+    mCreateInfo.attachments = &mAttachments;
   }
-  return true;
 }
 
-void RenderPass::DestroyResource()
-{
-}
-
-void RenderPass::DiscardResource()
-{
-}
-
-RenderPassImpl* RenderPass::GetImpl()
-{
-  return mRenderPassImpl;
-}
+RenderPass::~RenderPass() = default;
 
 } // namespace Dali::Graphics::Vulkan
index 897bf4e..e358493 100644 (file)
 
 #include <dali/internal/graphics/vulkan-impl/vulkan-graphics-resource.h>
 
-#include <dali/graphics-api/graphics-render-pass.h>
 #include <dali/graphics-api/graphics-render-pass-create-info.h>
+#include <dali/graphics-api/graphics-render-pass.h>
 
 namespace Dali::Graphics::Vulkan
 {
 class RenderPassImpl;
 
-using RenderPassResource = Resource<Graphics::RenderPass, Graphics::RenderPassCreateInfo>;
-class RenderPass : public RenderPassResource
+/**
+ * This class represents a set of render pass operations.
+ *
+ * This class is not directly associated with a graphics resource, and is not
+ * responsible for the lifetime of actual vulkan render pass objects. That is
+ * instead the responsibility of the Framebuffer implementation.
+ *
+ * When this render pass is used, the Framebuffer will find or create a compatible
+ * render pass implementation, and cache it.
+ */
+class RenderPass : public Graphics::RenderPass
 {
 public:
   RenderPass(const Graphics::RenderPassCreateInfo& createInfo, VulkanGraphicsController& controller);
 
   ~RenderPass() override;
 
-  /**
-   * @brief Called when GL resources are destroyed
-   */
-  void DestroyResource() override;
-
-  /**
-   * @brief Called when initializing the resource
-   *
-   * @return True on success
-   */
-  bool InitializeResource() override;
-
-  /**
-   * @brief Called when UniquePtr<> on client-side dies
-   */
-  void DiscardResource() override;
-
-  RenderPassImpl* GetImpl();
+  [[nodiscard]] const Graphics::RenderPassCreateInfo& GetCreateInfo() const
+  {
+    return mCreateInfo;
+  }
 
 private:
-  RenderPassImpl* mRenderPassImpl;
+  Graphics::RenderPassCreateInfo               mCreateInfo;
+  VulkanGraphicsController&                    mController;
+  std::vector<Graphics::AttachmentDescription> mAttachments;
 };
 
 } // namespace Dali::Graphics::Vulkan
index d9f98f0..53e321a 100644 (file)
 #include <dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h>
 #include <dali/internal/graphics/vulkan/vulkan-device.h>
 
-#if 0
-#include <dali/internal/graphics/vulkan-impl/vulkan-debug.h>
-#include <dali/internal/graphics/vulkan-impl/vulkan-image-view.h>
-#include <dali/internal/graphics/vulkan-impl/vulkan-image.h>
-#include <dali/internal/graphics/vulkan-impl/vulkan-queue.h>
-#endif
-
 #include <dali/integration-api/debug.h>
 
 #if defined(DEBUG_ENABLED)
@@ -167,8 +160,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;
                             });
 
@@ -394,8 +386,7 @@ bool Swapchain::OnDestroy()
     auto swapchain = mSwapchainKHR;
     auto allocator = &mGraphicsDevice.GetAllocator();
 
-    mGraphicsDevice.DiscardResource([device, swapchain, allocator]()
-                                    {
+    mGraphicsDevice.DiscardResource([device, swapchain, allocator]() {
       DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: swap chain->%p\n", static_cast<VkSwapchainKHR>(swapchain))
       device.destroySwapchainKHR(swapchain, allocator); });
 
index 785fb44..cc31808 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <atomic>
-#include <unordered_map>
-#include <memory>
 #include <bitset>
+#include <memory>
+#include <unordered_map>
 
+#include <dali/graphics-api/graphics-types.h>
 #include <dali/internal/graphics/vulkan/vulkan-hpp-wrapper.h>
 
 // Ensure we can use this type name safely.
@@ -32,7 +33,6 @@
 #undef WAYLAND
 #endif
 
-
 namespace Dali::Graphics
 {
 
@@ -40,12 +40,12 @@ namespace
 {
 // Default value use to clear the stencil buffer
 constexpr auto STENCIL_DEFAULT_CLEAR_VALUE = 255u;
-}
+} // namespace
 
-template< typename T, typename... Args >
-std::unique_ptr< T > MakeUnique( Args&& ... args )
+template<typename T, typename... Args>
+std::unique_ptr<T> MakeUnique(Args&&... args)
 {
-  return std::unique_ptr< T >( new T( std::forward< Args >( args )... ) );
+  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
 }
 
 namespace Vulkan
@@ -78,54 +78,54 @@ class Texture;
 /**
  * Unique pointers to Vulkan types
  */
-using UniqueQueue = std::unique_ptr< Queue >;
+using UniqueQueue = std::unique_ptr<Queue>;
 
 /**
  * Reference wrappers
  */
-using QueueRef = std::reference_wrapper< Queue >;
+using QueueRef = std::reference_wrapper<Queue>;
 
-template< typename T >
-T VkAssert( const vk::ResultValue< T >& result, vk::Result expected = vk::Result::eSuccess )
+template<typename T>
+T VkAssert(const vk::ResultValue<T>& result, vk::Result expected = vk::Result::eSuccess)
 {
-  assert( result.result == expected );
+  assert(result.result == expected);
   return result.value;
 }
 
-inline vk::Result VkAssert( vk::Result result, vk::Result expected = vk::Result::eSuccess )
+inline vk::Result VkAssert(vk::Result result, vk::Result expected = vk::Result::eSuccess)
 {
-  assert( result == expected );
+  assert(result == expected);
   return result;
 }
 
-inline vk::Result VkTest( vk::Result result, vk::Result expected = vk::Result::eSuccess )
+inline vk::Result VkTest(vk::Result result, vk::Result expected = vk::Result::eSuccess)
 {
   // todo: log if result different than expected?
   return result;
 }
 
-template< typename T >
-inline uint32_t U32( T value )
+template<typename T>
+inline uint32_t U32(T value)
 {
-  return static_cast< uint32_t >(value);
+  return static_cast<uint32_t>(value);
 }
 
-template <typename T>
-inline int32_t I32( T value )
+template<typename T>
+inline int32_t I32(T value)
 {
-  return static_cast< int32_t >( value );
+  return static_cast<int32_t>(value);
 }
 
-template <typename T>
-inline float F32( T value )
+template<typename T>
+inline float F32(T value)
 {
-  return static_cast< float >( value );
+  return static_cast<float>(value);
 }
 
-template <typename T>
-inline double F64( T value )
+template<typename T>
+inline double F64(T value)
 {
-  return static_cast< double >( value );
+  return static_cast<double>(value);
 }
 
 enum class Platform
@@ -136,22 +136,72 @@ enum class Platform
   WAYLAND,
 };
 
+struct VkLoadOpType
+{
+  constexpr explicit VkLoadOpType(Graphics::AttachmentLoadOp op)
+  {
+    switch(op)
+    {
+      case Graphics::AttachmentLoadOp::LOAD:
+      {
+        loadOp = vk::AttachmentLoadOp::eLoad;
+        break;
+      }
+      case Graphics::AttachmentLoadOp::CLEAR:
+      {
+        loadOp = vk::AttachmentLoadOp::eClear;
+        break;
+      }
+      case Graphics::AttachmentLoadOp::DONT_CARE:
+      {
+        loadOp = vk::AttachmentLoadOp::eDontCare;
+        break;
+      }
+    }
+  }
+  vk::AttachmentLoadOp loadOp{vk::AttachmentLoadOp::eDontCare};
+};
+
+struct VkStoreOpType
+{
+  constexpr explicit VkStoreOpType(Graphics::AttachmentStoreOp op)
+  {
+    switch(op)
+    {
+      case Graphics::AttachmentStoreOp::STORE:
+      {
+        Assign(vk::AttachmentStoreOp::eStore);
+        break;
+      }
+      case Graphics::AttachmentStoreOp::DONT_CARE:
+      {
+        Assign(vk::AttachmentStoreOp::eDontCare);
+        break;
+      }
+    }
+  }
+  constexpr inline void Assign(vk::AttachmentStoreOp op)
+  {
+    storeOp = op;
+  }
+  vk::AttachmentStoreOp storeOp{vk::AttachmentStoreOp::eDontCare};
+};
+
 class VkManaged
 {
 public:
-
   VkManaged() = default;
 
   virtual ~VkManaged() = default;
 
   void Release()
   {
-    OnRelease( --mRefCount );
+    OnRelease(--mRefCount);
 
-    if( mRefCount == 0 )
+    if(mRefCount == 0)
     {
       // orphaned
-      if( !Destroy() )
+      if(!Destroy())
       {
         delete this;
       }
@@ -160,7 +210,7 @@ public:
 
   void Retain()
   {
-    OnRetain( ++mRefCount );
+    OnRetain(++mRefCount);
   }
 
   uint32_t GetRefCount()
@@ -173,11 +223,11 @@ public:
     return OnDestroy();
   }
 
-  virtual void OnRetain( uint32_t refcount )
+  virtual void OnRetain(uint32_t refcount)
   {
   }
 
-  virtual void OnRelease( uint32_t refcount )
+  virtual void OnRelease(uint32_t refcount)
   {
   }
 
@@ -187,13 +237,10 @@ public:
   }
 
 private:
-
-  std::atomic_uint mRefCount{ 0u };
+  std::atomic_uint mRefCount{0u};
 };
 
-
 } // namespace Vulkan
 } // namespace Dali::Graphics
 
-
 #endif // DALI_GRAPHICS_VULKAN_TYPES