Vulkan resource lifecycle management 68/316868/7
authorDavid Steele <david.steele@samsung.com>
Wed, 28 Aug 2024 16:18:56 +0000 (17:18 +0100)
committerDavid Steele <david.steele@samsung.com>
Mon, 30 Sep 2024 16:57:25 +0000 (17:57 +0100)
For Vulkan implementation of graphics resources:
  Added discard queue, that's cleaned down during Flush().

Added ResourceWithDeleter as a secondary interface on top of ResourceBase, to allow
Program/Pipeline to inherit solely from ResourceBase, and not have to utilize the
same resource deleters that the main graphics objects require.

Removed VkResource inheritance completely from Impl classes.
Kept VkResource as VkSharedResource, as we may still use this on RenderPassImpl

All Impl classes now have a public Destroy method which is called from their
destructor, but may also be called earlier if needed. Note, CommandBuffers should
not be deleted directly, but instead returned to the command pool for re-use.

Implemented owned containers for some Impl objects using
std::unique_ptr. Framebuffer owns it's attachments, Swapchain owns
it's framebuffers.

Change-Id: I651ed4d041cd2fb3e7698304eeede66625031945

47 files changed:
dali/internal/graphics/vulkan-impl/vulkan-buffer-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-buffer-impl.h
dali/internal/graphics/vulkan-impl/vulkan-buffer.cpp
dali/internal/graphics/vulkan-impl/vulkan-buffer.h
dali/internal/graphics/vulkan-impl/vulkan-command-buffer-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-command-buffer-impl.h
dali/internal/graphics/vulkan-impl/vulkan-command-buffer.cpp
dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h
dali/internal/graphics/vulkan-impl/vulkan-command-pool-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-command-pool-impl.h
dali/internal/graphics/vulkan-impl/vulkan-fence-impl.cpp
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-graphics-resource.h
dali/internal/graphics/vulkan-impl/vulkan-image-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-image-impl.h
dali/internal/graphics/vulkan-impl/vulkan-image-view-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-image-view-impl.h
dali/internal/graphics/vulkan-impl/vulkan-memory-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-memory-impl.h
dali/internal/graphics/vulkan-impl/vulkan-pipeline.cpp
dali/internal/graphics/vulkan-impl/vulkan-pipeline.h
dali/internal/graphics/vulkan-impl/vulkan-program.cpp
dali/internal/graphics/vulkan-impl/vulkan-program.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.h
dali/internal/graphics/vulkan-impl/vulkan-sampler-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-sampler-impl.h
dali/internal/graphics/vulkan-impl/vulkan-sampler.cpp
dali/internal/graphics/vulkan-impl/vulkan-sampler.h
dali/internal/graphics/vulkan-impl/vulkan-shader-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-shader-impl.h
dali/internal/graphics/vulkan-impl/vulkan-surface-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-surface-impl.h
dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.cpp
dali/internal/graphics/vulkan-impl/vulkan-swapchain-impl.h
dali/internal/graphics/vulkan-impl/vulkan-texture.cpp
dali/internal/graphics/vulkan-impl/vulkan-texture.h
dali/internal/graphics/vulkan-impl/vulkan-types.h
dali/internal/graphics/vulkan/vulkan-device.cpp
dali/internal/graphics/vulkan/vulkan-device.h
dali/internal/graphics/vulkan/vulkan-graphics-impl.cpp

index 48a952d..1ffcbf6 100644 (file)
@@ -54,6 +54,11 @@ BufferImpl::BufferImpl(Device& device, const vk::BufferCreateInfo& createInfo)
 {
 }
 
+BufferImpl::~BufferImpl()
+{
+  Destroy();
+}
+
 void BufferImpl::Initialize(vk::MemoryPropertyFlags memoryProperties)
 {
   // Allocate
@@ -84,19 +89,16 @@ void BufferImpl::Initialize(vk::MemoryPropertyFlags memoryProperties)
   }
 }
 
-void BufferImpl::DestroyNow()
+void BufferImpl::Destroy()
 {
-  DestroyVulkanResources(mDevice.GetLogicalDevice(), mBuffer, mMemory->ReleaseVkObject(), &mDevice.GetAllocator());
-  mBuffer = nullptr;
-  mMemory = nullptr;
-}
+  DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying buffer: %p\n", static_cast<VkBuffer>(mBuffer));
 
-void BufferImpl::DestroyVulkanResources(vk::Device device, vk::Buffer buffer, vk::DeviceMemory memory, const vk::AllocationCallbacks* allocator)
-{
-  DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: buffer->%p\n", static_cast<VkBuffer>(buffer));
+  auto device = mDevice.GetLogicalDevice();
+  device.destroyBuffer(mBuffer, mDevice.GetAllocator());
 
-  device.destroyBuffer(buffer, allocator);
-  device.freeMemory(memory, allocator);
+  mMemory.reset();
+  mBuffer = nullptr;
+  mMemory = nullptr;
 }
 
 Graphics::MemoryRequirements BufferImpl::GetMemoryRequirements()
index 9e59418..0a09ef9 100644 (file)
 
 #include <dali/graphics-api/graphics-types.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-memory-impl.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-types.h>
 #include <dali/internal/graphics/vulkan/vulkan-device.h>
 
 #include <cstdint>
 
 namespace Dali::Graphics::Vulkan
 {
-class BufferImpl // : public VkManaged
+class BufferImpl
 {
 public:
   static BufferImpl* New(Vulkan::Device& device, size_t size, vk::BufferUsageFlags usageFlags);
 
   static BufferImpl* New(Vulkan::Device& device, size_t size, vk::SharingMode sharingMode, vk::BufferUsageFlags usageFlags, vk::MemoryPropertyFlags memoryProperties);
 
+  /** Destructor */
+  ~BufferImpl();
+
   /**
    * Returns buffer usage flags
    * @return
@@ -75,7 +79,7 @@ public:
    * @note Calling this function is unsafe and makes any further use of
    * buffer invalid.
    */
-  void DestroyNow();
+  void Destroy();
 
   BufferImpl(const Buffer&)            = delete;
   BufferImpl& operator=(const Buffer&) = delete;
index e725d77..075f7b7 100644 (file)
 #include <dali/public-api/common/dali-common.h>
 
 // EXTERNAL INCLUDES
-#include <cstdint>
 
 namespace Dali::Graphics::Vulkan
 {
-
 Buffer::Buffer(const Graphics::BufferCreateInfo& createInfo, VulkanGraphicsController& controller)
 : BufferResource(createInfo, controller)
 {
@@ -121,8 +119,7 @@ void Buffer::DestroyResource()
     }
     mBufferPtr = nullptr;
   }
-  // Deestroy GPU allocation
-  else
+  else // Destroy GPU allocation
   {
     delete(mBufferImpl);
     mBufferImpl = nullptr;
index 72caa86..a6fb0eb 100644 (file)
@@ -45,8 +45,6 @@ public:
    * @copydoc Graphics::Vulkan::Resource::InitializeResource();
    */
   bool InitializeResource() override;
-  void InitializeCPUBuffer();
-  void InitializeGPUBuffer();
 
   /**
    * @return false - Vulkan should always allocate GPU buffers
@@ -59,6 +57,23 @@ public:
    */
   void DiscardResource() override;
 
+  /**
+   * @copydoc Graphics::Vulkan::Resource::GetAllocationCallbacks()
+   */
+  [[nodiscard]] const Graphics::AllocationCallbacks* GetAllocationCallbacks() const override
+  {
+    return mCreateInfo.allocationCallbacks;
+  }
+
+  /**
+   * @copydoc Graphics::Vulkan::Resource::InvokeDeleter()
+   * Only intended for use by discard queue.
+   */
+  void InvokeDeleter() override
+  {
+    this->~Buffer();
+  }
+
   void Bind(Graphics::BufferUsage bindingTarget) const;
 
   BufferImpl* GetImpl()
@@ -71,6 +86,10 @@ public:
   }
 
 private:
+  void InitializeCPUBuffer();
+  void InitializeGPUBuffer();
+
+private:
   union
   {
     BufferImpl* mBufferImpl{nullptr};
index 85e869e..200f3f8 100644 (file)
@@ -58,7 +58,15 @@ CommandBufferImpl::CommandBufferImpl(CommandPool&                         comman
 {
 }
 
-CommandBufferImpl::~CommandBufferImpl() = default;
+CommandBufferImpl::~CommandBufferImpl()
+{
+  Destroy();
+}
+
+void CommandBufferImpl::Destroy()
+{
+  // Command buffer Pool cleanup will remove the vulkan command buffer
+}
 
 /** Begin recording */
 void CommandBufferImpl::Begin(vk::CommandBufferUsageFlags       usageFlags,
@@ -68,7 +76,6 @@ void CommandBufferImpl::Begin(vk::CommandBufferUsageFlags       usageFlags,
   auto info = vk::CommandBufferBeginInfo{};
 
   vk::CommandBufferInheritanceInfo defaultInheritanceInfo{};
-  defaultInheritanceInfo.sType                = vk::StructureType::eCommandBufferInheritanceInfo;
   defaultInheritanceInfo.pNext                = nullptr;
   defaultInheritanceInfo.subpass              = 0;
   defaultInheritanceInfo.occlusionQueryEnable = false;
@@ -289,12 +296,6 @@ uint32_t CommandBufferImpl::GetPoolAllocationIndex() const
   return mPoolAllocationIndex;
 }
 
-bool CommandBufferImpl::OnDestroy()
-{
-  mOwnerCommandPool->ReleaseCommandBuffer(*this);
-  return true;
-}
-
 void CommandBufferImpl::Draw(uint32_t vertexCount,
                              uint32_t instanceCount,
                              uint32_t firstVertex,
index 5f05d5d..73c0323 100644 (file)
@@ -32,7 +32,7 @@ class Device;
 class CommandPool;
 class PipelineImpl;
 
-class CommandBufferImpl : public VkManaged
+class CommandBufferImpl
 {
   friend class CommandPool;
 
@@ -41,7 +41,9 @@ class CommandBufferImpl : public VkManaged
 public:
   CommandBufferImpl() = delete;
 
-  ~CommandBufferImpl() override;
+  ~CommandBufferImpl();
+
+  void Destroy();
 
   /** Begin recording */
   void Begin(vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo);
@@ -101,12 +103,6 @@ public:
 
   void CopyImage(Vulkan::Image* srcImage, vk::ImageLayout srcLayout, Image* dstImage, vk::ImageLayout dstLayout, const std::vector<vk::ImageCopy>& regions);
 
-  /**
-   * Implements VkManaged::OnDestroy
-   * @return
-   */
-  bool OnDestroy() override;
-
   void SetScissor(Rect2D value);
   void SetViewport(Viewport value);
 
index 8d085cf..1cba175 100644 (file)
@@ -61,6 +61,9 @@ CommandBuffer::~CommandBuffer() = default;
 
 void CommandBuffer::DestroyResource()
 {
+  // Don't delete the impl, it's pool allocated and should have been
+  // returned to the command pool for re-use.
+  mCommandBufferImpl = nullptr;
 }
 
 bool CommandBuffer::InitializeResource()
@@ -70,6 +73,7 @@ bool CommandBuffer::InitializeResource()
 
 void CommandBuffer::DiscardResource()
 {
+  mController.DiscardResource(this);
 }
 
 void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info)
index 5bad086..fe6f425 100644 (file)
@@ -33,22 +33,6 @@ class CommandBuffer : public CommandBufferResource
 public:
   CommandBuffer(const Graphics::CommandBufferCreateInfo& createInfo, VulkanGraphicsController& controller);
   ~CommandBuffer() 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;
 
   void Begin(const Graphics::CommandBufferBeginInfo& info) override;
 
@@ -338,7 +322,42 @@ public:
    */
   void SetDepthWriteEnable(bool depthWriteEnable) override;
 
-public: //API
+public: // VulkanResource API
+  /**
+   * @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;
+
+  /**
+   * @copydoc Graphics::Vulkan::Resource::GetAllocationCallbacks()
+   */
+  [[nodiscard]] const Graphics::AllocationCallbacks* GetAllocationCallbacks() const override
+  {
+    return mCreateInfo.allocationCallbacks;
+  }
+
+  /**
+   * @copydoc Graphics::Vulkan::Resource::InvokeDeleter()
+   * Only intended for use by discard queue.
+   */
+  void InvokeDeleter() override
+  {
+    this->~CommandBuffer();
+  }
+
+public: // API
   /**
    * Get the last swapchain referenced by a BeginRenderPass command in this command buffer.
    *
index ddc6d04..8bc279e 100644 (file)
@@ -19,8 +19,8 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-command-pool-impl.h>
 
 // INTERNAL INCLUDES
-#include <dali/internal/graphics/vulkan/vulkan-device.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-command-buffer-impl.h>
+#include <dali/internal/graphics/vulkan/vulkan-device.h>
 
 #include <dali/integration-api/debug.h>
 
@@ -34,47 +34,46 @@ namespace Dali::Graphics::Vulkan
  *
  * Struct: InternalPool
  */
-CommandPool::InternalPool::Node::Node( uint32_t _nextFreeIndex, CommandBufferImpl* _commandBuffer )
-: nextFreeIndex( _nextFreeIndex ),
-  commandBuffer( _commandBuffer )
+CommandPool::InternalPool::Node::Node(uint32_t _nextFreeIndex, CommandBufferImpl* _commandBuffer)
+: nextFreeIndex(_nextFreeIndex),
+  commandBuffer(_commandBuffer)
 {
 }
 
-CommandPool::InternalPool::InternalPool( CommandPool& owner, Vulkan::Device* graphics,
-                                         uint32_t initialCapacity, bool isPrimary )
-: mOwner( owner ),
-  mGraphicsDevice( graphics ),
+CommandPool::InternalPool::InternalPool(CommandPool& owner, Vulkan::Device* graphics, uint32_t initialCapacity, bool isPrimary)
+: mOwner(owner),
+  mGraphicsDevice(graphics),
   mPoolData{},
-  mFirstFree( INVALID_NODE_INDEX ),
-  mCapacity( initialCapacity ),
-  mAllocationCount( 0u ),
-  mIsPrimary( isPrimary )
+  mFirstFree(INVALID_NODE_INDEX),
+  mCapacity(initialCapacity),
+  mAllocationCount(0u),
+  mIsPrimary(isPrimary)
 {
   // don't allocate anything if initial capacity is 0
-  if( initialCapacity )
+  if(initialCapacity)
   {
-    Resize( initialCapacity );
+    Resize(initialCapacity);
   }
 }
 
 CommandPool::InternalPool::~InternalPool()
 {
   // free all buffers here
-  for( auto&& cmd : mPoolData )
+  for(auto&& cmd : mPoolData)
   {
     delete cmd.commandBuffer;
   }
 }
 
-std::vector< vk::CommandBuffer >
-CommandPool::InternalPool::AllocateVkCommandBuffers( vk::CommandBufferAllocateInfo allocateInfo )
+std::vector<vk::CommandBuffer>
+CommandPool::InternalPool::AllocateVkCommandBuffers(vk::CommandBufferAllocateInfo allocateInfo)
 {
-  return VkAssert( mGraphicsDevice->GetLogicalDevice().allocateCommandBuffers( allocateInfo ) );
+  return VkAssert(mGraphicsDevice->GetLogicalDevice().allocateCommandBuffers(allocateInfo));
 }
 
-void CommandPool::InternalPool::Resize( uint32_t newCapacity )
+void CommandPool::InternalPool::Resize(uint32_t newCapacity)
 {
-  if( newCapacity <= mPoolData.size() )
+  if(newCapacity <= mPoolData.size())
   {
     return;
   }
@@ -82,42 +81,42 @@ void CommandPool::InternalPool::Resize( uint32_t newCapacity )
   auto diff = newCapacity - mPoolData.size();
 
   auto allocateInfo = vk::CommandBufferAllocateInfo{}
-          .setCommandBufferCount( U32( diff ) )
-          .setCommandPool( mOwner.GetVkHandle() )
-          .setLevel( mIsPrimary ? vk::CommandBufferLevel::ePrimary : vk::CommandBufferLevel::eSecondary );
-  auto newBuffers = AllocateVkCommandBuffers( allocateInfo );
+                        .setCommandBufferCount(U32(diff))
+                        .setCommandPool(mOwner.GetVkHandle())
+                        .setLevel(mIsPrimary ? vk::CommandBufferLevel::ePrimary : vk::CommandBufferLevel::eSecondary);
+  auto newBuffers = AllocateVkCommandBuffers(allocateInfo);
 
-  uint32_t i = U32( mPoolData.size() + 1 );
+  uint32_t i = U32(mPoolData.size() + 1);
 
-  mFirstFree = U32( mPoolData.size() );
-  if( !mPoolData.empty() )
+  mFirstFree = U32(mPoolData.size());
+  if(!mPoolData.empty())
   {
     mPoolData.back()
-             .nextFreeIndex = U32( mPoolData.size() );
+      .nextFreeIndex = U32(mPoolData.size());
   }
-  for( auto&& cmdbuf : newBuffers )
+  for(auto&& cmdbuf : newBuffers)
   {
-    auto commandBuffer = new CommandBufferImpl( mOwner, i - 1, allocateInfo, cmdbuf );
-    mPoolData.emplace_back( i, commandBuffer );
+    auto commandBuffer = new CommandBufferImpl(mOwner, i - 1, allocateInfo, cmdbuf);
+    mPoolData.emplace_back(i, commandBuffer);
     ++i;
   }
   mPoolData.back().nextFreeIndex = INVALID_NODE_INDEX;
-  mCapacity = U32( mPoolData.size() );
+  mCapacity                      = U32(mPoolData.size());
 }
 
-CommandBufferImpl* CommandPool::InternalPool::AllocateCommandBuffer( bool reset )
+CommandBufferImpl* CommandPool::InternalPool::AllocateCommandBuffer(bool reset)
 {
   // resize if no more nodes
-  if( mFirstFree == INVALID_NODE_INDEX )
+  if(mFirstFree == INVALID_NODE_INDEX)
   {
     auto newSize = static_cast<uint32_t>(mPoolData.empty() ? 1 : 2 * mPoolData.size());
-    Resize( U32( newSize ) );
+    Resize(U32(newSize));
   }
 
   auto& node = mPoolData[mFirstFree];
   mFirstFree = node.nextFreeIndex;
 
-  if( reset )
+  if(reset)
   {
     node.commandBuffer->Reset();
   }
@@ -126,13 +125,13 @@ CommandBufferImpl* CommandPool::InternalPool::AllocateCommandBuffer( bool reset
   return node.commandBuffer;
 }
 
-void CommandPool::InternalPool::ReleaseCommandBuffer(CommandBufferImpl& buffer, bool reset )
+void CommandPool::InternalPool::ReleaseCommandBuffer(CommandBufferImpl& buffer, bool reset)
 {
-  auto indexInPool = buffer.GetPoolAllocationIndex();
+  auto indexInPool                     = buffer.GetPoolAllocationIndex();
   mPoolData[indexInPool].nextFreeIndex = mFirstFree;
-  mFirstFree = indexInPool;
+  mFirstFree                           = indexInPool;
 
-  if( reset )
+  if(reset)
   {
     buffer.Reset();
   }
@@ -149,9 +148,9 @@ uint32_t CommandPool::InternalPool::GetAllocationCount() const
   return mAllocationCount;
 }
 
-CommandPool* CommandPool::New( Device& graphics, const vk::CommandPoolCreateInfo& createInfo )
+CommandPool* CommandPool::New(Device& graphics, const vk::CommandPoolCreateInfo& createInfo)
 {
-  auto pool = new CommandPool( graphics, createInfo );
+  auto pool = new CommandPool(graphics, createInfo);
 
   if(pool)
   {
@@ -161,27 +160,30 @@ CommandPool* CommandPool::New( Device& graphics, const vk::CommandPoolCreateInfo
   return pool;
 }
 
-CommandPool* CommandPool::New( Device& graphics )
+CommandPool* CommandPool::New(Device& graphics)
 {
-  return New( graphics, vk::CommandPoolCreateInfo{} );
+  return New(graphics, vk::CommandPoolCreateInfo{});
 }
 
 bool CommandPool::Initialize()
 {
-  mCreateInfo.setFlags( vk::CommandPoolCreateFlagBits::eResetCommandBuffer );
-  mCommandPool = VkAssert( mGraphicsDevice->GetLogicalDevice().createCommandPool( mCreateInfo, mGraphicsDevice->GetAllocator() ) );
-  mInternalPoolPrimary = std::make_unique< InternalPool >( *this, mGraphicsDevice, 0, true );
-  mInternalPoolSecondary = std::make_unique< InternalPool >( *this, mGraphicsDevice, 0, false );
+  mCreateInfo.setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer);
+  mCommandPool           = VkAssert(mGraphicsDevice->GetLogicalDevice().createCommandPool(mCreateInfo, mGraphicsDevice->GetAllocator()));
+  mInternalPoolPrimary   = std::make_unique<InternalPool>(*this, mGraphicsDevice, 0, true);
+  mInternalPoolSecondary = std::make_unique<InternalPool>(*this, mGraphicsDevice, 0, false);
   return true;
 }
 
-CommandPool::CommandPool( Device& graphics, const vk::CommandPoolCreateInfo& createInfo )
-: mGraphicsDevice( &graphics ),
-  mCreateInfo( createInfo )
+CommandPool::CommandPool(Device& graphics, const vk::CommandPoolCreateInfo& createInfo)
+: mGraphicsDevice(&graphics),
+  mCreateInfo(createInfo)
 {
 }
 
-CommandPool::~CommandPool() = default;
+CommandPool::~CommandPool()
+{
+  Destroy();
+}
 
 vk::CommandPool CommandPool::GetVkHandle() const
 {
@@ -193,34 +195,34 @@ Device& CommandPool::GetGraphicsDevice() const
   return *mGraphicsDevice;
 }
 
-CommandBufferImpl* CommandPool::NewCommandBuffer( const vk::CommandBufferAllocateInfo& allocateInfo )
+CommandBufferImpl* CommandPool::NewCommandBuffer(const vk::CommandBufferAllocateInfo& allocateInfo)
 {
-  return NewCommandBuffer( allocateInfo.level == vk::CommandBufferLevel::ePrimary );
+  return NewCommandBuffer(allocateInfo.level == vk::CommandBufferLevel::ePrimary);
 }
 
-CommandBufferImpl* CommandPool::NewCommandBuffer( bool isPrimary )
+CommandBufferImpl* CommandPool::NewCommandBuffer(bool isPrimary)
 {
   auto& usedPool = isPrimary ? *mInternalPoolPrimary : *mInternalPoolSecondary;
-  return usedPool.AllocateCommandBuffer( false );
+  return usedPool.AllocateCommandBuffer(false);
 }
 
-void CommandPool::Reset( bool releaseResources )
+void CommandPool::Reset(bool releaseResources)
 {
   mGraphicsDevice->GetLogicalDevice()
-           .resetCommandPool( mCommandPool,
-                              releaseResources ? vk::CommandPoolResetFlagBits::eReleaseResources
-                                               : vk::CommandPoolResetFlags{} );
+    .resetCommandPool(mCommandPool,
+                      releaseResources ? vk::CommandPoolResetFlagBits::eReleaseResources
+                                       : vk::CommandPoolResetFlags{});
 }
 
-bool CommandPool::ReleaseCommandBuffer(CommandBufferImpl& buffer )
+bool CommandPool::ReleaseCommandBuffer(CommandBufferImpl& buffer)
 {
-  if( buffer.IsPrimary() )
+  if(buffer.IsPrimary() && mInternalPoolPrimary)
   {
-    mInternalPoolPrimary->ReleaseCommandBuffer( buffer );
+    mInternalPoolPrimary->ReleaseCommandBuffer(buffer);
   }
-  else
+  else if(mInternalPoolSecondary)
   {
-    mInternalPoolSecondary->ReleaseCommandBuffer( buffer );
+    mInternalPoolSecondary->ReleaseCommandBuffer(buffer);
   }
   return false;
 }
@@ -237,26 +239,23 @@ uint32_t CommandPool::GetAllocationCount() const
          mInternalPoolSecondary->GetAllocationCount();
 }
 
-uint32_t CommandPool::GetAllocationCount( vk::CommandBufferLevel level ) const
+uint32_t CommandPool::GetAllocationCount(vk::CommandBufferLevel level) const
 {
-  return level == vk::CommandBufferLevel::ePrimary ?
-         mInternalPoolPrimary->GetAllocationCount() :
-         mInternalPoolSecondary->GetAllocationCount();
+  return level == vk::CommandBufferLevel::ePrimary ? mInternalPoolPrimary->GetAllocationCount() : mInternalPoolSecondary->GetAllocationCount();
 }
 
-bool CommandPool::OnDestroy()
+void CommandPool::Destroy()
 {
-  auto device = mGraphicsDevice->GetLogicalDevice();
-  auto commandPool = mCommandPool;
+  auto device    = mGraphicsDevice->GetLogicalDevice();
   auto allocator = &mGraphicsDevice->GetAllocator();
 
-  mGraphicsDevice->DiscardResource( [ device, commandPool, allocator ]() {
-    DALI_LOG_INFO( gVulkanFilter, Debug::General, "Invoking deleter function: command pool->%p\n",
-                   static_cast< VkCommandPool >( commandPool ) )
-    device.destroyCommandPool( commandPool, allocator );
-  } );
+  if(mCommandPool)
+  {
+    DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying command pool: %p\n", static_cast<VkCommandPool>(mCommandPool));
+    device.destroyCommandPool(mCommandPool, allocator);
 
-  return false;
+    mCommandPool = nullptr;
+  }
 }
 
 } // namespace Dali::Graphics::Vulkan
index 497991e..dcf17b5 100644 (file)
@@ -24,7 +24,7 @@ namespace Dali::Graphics::Vulkan
 class Device;
 class CommandBufferImpl;
 
-class CommandPool : public VkManaged
+class CommandPool
 {
 public: // Construction, destruction
   /**
@@ -46,7 +46,7 @@ public: // Construction, destruction
 
   CommandPool(Device& graphicsDevice, const vk::CommandPoolCreateInfo& createInfo);
 
-  ~CommandPool() override;
+  ~CommandPool();
 
   vk::CommandPool GetVkHandle() const;
 
@@ -54,7 +54,7 @@ public: // Construction, destruction
 
   bool Initialize();
 
-  bool OnDestroy() override; // TODO: Queue deleter for destruction
+  void Destroy();
 
   /**
    * Resets command pool
index 38c15ef..3019e4d 100644 (file)
@@ -27,7 +27,6 @@ extern Debug::Filter* gVulkanFilter;
 
 namespace Dali::Graphics::Vulkan
 {
-
 FenceImpl* FenceImpl::New(Device& graphicsDevice, const vk::FenceCreateInfo& fenceCreateInfo)
 {
   auto fence = new FenceImpl(graphicsDevice);
index 933cbf5..6c281e7 100644 (file)
@@ -32,9 +32,9 @@ extern Debug::Filter* gVulkanFilter;
 
 namespace Dali::Graphics::Vulkan
 {
-FramebufferAttachment* FramebufferAttachment::NewColorAttachment(ImageView*          imageView,
-                                                                 vk::ClearColorValue clearColorValue,
-                                                                 bool                presentable)
+FramebufferAttachment* FramebufferAttachment::NewColorAttachment(std::unique_ptr<ImageView>& imageView,
+                                                                 vk::ClearColorValue         clearColorValue,
+                                                                 bool                        presentable)
 {
   assert(imageView->GetImage()->GetUsageFlags() & vk::ImageUsageFlagBits::eColorAttachment);
 
@@ -46,8 +46,8 @@ FramebufferAttachment* FramebufferAttachment::NewColorAttachment(ImageView*
 }
 
 FramebufferAttachment* FramebufferAttachment::NewDepthAttachment(
-  ImageView*                 imageView,
-  vk::ClearDepthStencilValue clearDepthStencilValue)
+  std::unique_ptr<ImageView>& imageView,
+  vk::ClearDepthStencilValue  clearDepthStencilValue)
 {
   assert(imageView->GetImage()->GetUsageFlags() & vk::ImageUsageFlagBits::eDepthStencilAttachment);
 
@@ -59,15 +59,15 @@ FramebufferAttachment* FramebufferAttachment::NewDepthAttachment(
   return attachment;
 }
 
-FramebufferAttachment::FramebufferAttachment(ImageView*     imageView,
-                                             vk::ClearValue clearColor,
-                                             AttachmentType type,
-                                             bool           presentable)
-: mImageView(imageView),
-  mClearValue(clearColor),
+FramebufferAttachment::FramebufferAttachment(std::unique_ptr<ImageView>& imageView,
+                                             vk::ClearValue              clearColor,
+                                             AttachmentType              type,
+                                             bool                        presentable)
+: mClearValue(clearColor),
   mType(type)
 {
-  auto image = imageView->GetImage();
+  mImageView.swap(imageView);
+  auto image = mImageView->GetImage();
 
   auto sampleCountFlags = image->GetSampleCount();
 
@@ -92,7 +92,7 @@ FramebufferAttachment::FramebufferAttachment(ImageView*     imageView,
 
 ImageView* FramebufferAttachment::GetImageView() const
 {
-  return mImageView;
+  return mImageView.get();
 }
 
 const vk::AttachmentDescription& FramebufferAttachment::GetDescription() const
@@ -112,31 +112,34 @@ AttachmentType FramebufferAttachment::GetType() const
 
 bool FramebufferAttachment::IsValid() const
 {
-  return mImageView;
+  return mImageView != nullptr;
 }
 
 // FramebufferImpl -------------------------------
 
 FramebufferImpl* FramebufferImpl::New(
-  Vulkan::Device&                      device,
-  RenderPassImpl*                      renderPass,
-  std::vector<FramebufferAttachment*>& attachments,
-  uint32_t                             width,
-  uint32_t                             height,
-  bool                                 hasDepthAttachments)
+  Vulkan::Device&   device,
+  RenderPassImpl*   renderPass,
+  OwnedAttachments& attachments,
+  uint32_t          width,
+  uint32_t          height,
+  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),
-                 [&](FramebufferAttachment* entry) {
-                   return entry->GetImageView()->GetVkHandle();
-                 });
+  std::vector<vk::ImageView> imageViewAttachments;
+  for(auto& attachment : attachments)
+  {
+    imageViewAttachments.emplace_back(attachment->GetImageView()->GetVkHandle());
+  }
 
-  auto framebufferCreateInfo = vk::FramebufferCreateInfo{}.setRenderPass(renderPass->GetVkHandle()).setPAttachments(imageViewAttachments.data()).setLayers(1).setWidth(width).setHeight(height).setAttachmentCount(U32(attachments.size()));
+  auto framebufferCreateInfo = vk::FramebufferCreateInfo{}
+                                 .setRenderPass(renderPass->GetVkHandle())
+                                 .setPAttachments(imageViewAttachments.data())
+                                 .setLayers(1)
+                                 .setWidth(width)
+                                 .setHeight(height)
+                                 .setAttachmentCount(U32(attachments.size()));
 
   auto vkFramebuffer = VkAssert(device.GetLogicalDevice().createFramebuffer(framebufferCreateInfo, device.GetAllocator()));
 
@@ -150,18 +153,20 @@ FramebufferImpl* FramebufferImpl::New(
 }
 
 FramebufferImpl* FramebufferImpl::New(
-  Vulkan::Device&                            device,
-  RenderPassImpl*                            renderPass,
-  const std::vector<FramebufferAttachment*>& colorAttachments,
-  FramebufferAttachment*                     depthAttachment,
-  uint32_t                                   width,
-  uint32_t                                   height)
+  Vulkan::Device&                         device,
+  RenderPassImpl*                         renderPass,
+  OwnedAttachments&                       colorAttachments,
+  std::unique_ptr<FramebufferAttachment>& depthAttachment,
+  uint32_t                                width,
+  uint32_t                                height)
 {
   assert((!colorAttachments.empty() || depthAttachment) && "Cannot create framebuffer. Please provide at least one attachment");
 
-  auto colorAttachmentsValid = true;
+  auto                                colorAttachmentsValid = true;
+  std::vector<FramebufferAttachment*> attachments;
   for(auto& attachment : colorAttachments)
   {
+    attachments.emplace_back(attachment.get());
     if(!attachment->IsValid())
     {
       colorAttachmentsValid = false;
@@ -180,40 +185,56 @@ FramebufferImpl* FramebufferImpl::New(
   }
 
   // This vector stores the attachments (vk::ImageViews)
-  auto attachments = std::vector<FramebufferAttachment*>{};
 
   // Flag that indicates if the render pass is externally provided
   if(renderPass == nullptr)
   {
     // Create compatible vulkan render pass
-    renderPass = RenderPassImpl::New(device, colorAttachments, depthAttachment);
+    renderPass = RenderPassImpl::New(device, attachments, depthAttachment.get());
   }
-  attachments.reserve(colorAttachments.size());
-  attachments.insert(attachments.begin(), colorAttachments.begin(), colorAttachments.end());
+
+  OwnedAttachments ownedAttachments(std::move(colorAttachments));
   if(hasDepth)
   {
-    attachments.push_back(depthAttachment);
+    ownedAttachments.emplace_back(std::move(depthAttachment));
   }
-  return FramebufferImpl::New(device, renderPass, attachments, width, height, hasDepth);
+  return FramebufferImpl::New(device, renderPass, ownedAttachments, width, height, hasDepth);
 }
 
-FramebufferImpl::FramebufferImpl(Device&                                    graphicsDevice,
-                                 const std::vector<FramebufferAttachment*>& attachments,
-                                 vk::Framebuffer                            vkHandle,
-                                 const RenderPassImpl&                      renderPassImpl,
-                                 uint32_t                                   width,
-                                 uint32_t                                   height,
-                                 bool                                       hasDepthAttachment)
+FramebufferImpl::FramebufferImpl(Device&               graphicsDevice,
+                                 OwnedAttachments&     attachments,
+                                 vk::Framebuffer       vkHandle,
+                                 const RenderPassImpl& renderPassImpl,
+                                 uint32_t              width,
+                                 uint32_t              height,
+                                 bool                  hasDepthAttachment)
 : mGraphicsDevice(&graphicsDevice),
   mWidth(width),
   mHeight(height),
-  mAttachments(attachments),
+  mAttachments(std::move(attachments)),
   mFramebuffer(vkHandle),
   mHasDepthAttachment(hasDepthAttachment)
 {
   mRenderPasses.push_back(RenderPassMapElement{nullptr, const_cast<RenderPassImpl*>(&renderPassImpl)});
 }
 
+void FramebufferImpl::Destroy()
+{
+  auto device = mGraphicsDevice->GetLogicalDevice();
+
+  mRenderPasses.clear();
+  mAttachments.clear();
+
+  if(mFramebuffer)
+  {
+    auto allocator = &mGraphicsDevice->GetAllocator();
+
+    DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying Framebuffer: %p\n", static_cast<VkFramebuffer>(mFramebuffer));
+    device.destroyFramebuffer(mFramebuffer, allocator);
+  }
+  mFramebuffer = nullptr;
+}
+
 uint32_t FramebufferImpl::GetWidth() const
 {
   return mWidth;
@@ -230,12 +251,14 @@ FramebufferAttachment* FramebufferImpl::GetAttachment(AttachmentType type, uint3
   {
     case AttachmentType::COLOR:
     {
-      return mAttachments[index];
+      return mAttachments[index].get();
     }
     case AttachmentType::DEPTH_STENCIL:
     {
       if(mHasDepthAttachment)
-        return mAttachments.back();
+      {
+        return mAttachments.back().get();
+      }
     }
     case AttachmentType::INPUT:
     case AttachmentType::RESOLVE:
@@ -256,7 +279,10 @@ std::vector<FramebufferAttachment*> FramebufferImpl::GetAttachments(AttachmentTy
     {
       auto numColorAttachments = mHasDepthAttachment ? mAttachments.size() - 1 : mAttachments.size();
       retval.reserve(numColorAttachments);
-      retval.insert(retval.end(), mAttachments.begin(), mAttachments.begin() + numColorAttachments);
+      for(size_t i = 0; i < numColorAttachments; ++i)
+      {
+        retval.emplace_back(mAttachments[i].get());
+      }
       break;
     }
     case AttachmentType::DEPTH_STENCIL:
@@ -264,7 +290,7 @@ std::vector<FramebufferAttachment*> FramebufferImpl::GetAttachments(AttachmentTy
       if(mHasDepthAttachment)
       {
         retval.reserve(1);
-        retval.push_back(mAttachments.back());
+        retval.emplace_back(mAttachments.back().get());
       }
       break;
     }
@@ -369,39 +395,15 @@ std::vector<vk::ClearValue> FramebufferImpl::GetClearValues() const
 {
   auto result = std::vector<vk::ClearValue>{};
 
-  std::transform(mAttachments.begin(), // @todo & color clear enabled / depth clear enabled
-                 mAttachments.end(),
-                 std::back_inserter(result),
-                 [](FramebufferAttachment* attachment) {
-                   return attachment->GetClearValue();
-                 });
+  // @todo & color clear enabled / depth clear enabled
+  for(auto& attachment : mAttachments)
+  {
+    result.emplace_back(attachment->GetClearValue());
+  }
 
   return result;
 }
 
-bool FramebufferImpl::OnDestroy()
-{
-  auto device      = mGraphicsDevice->GetLogicalDevice();
-  auto frameBuffer = mFramebuffer;
-
-  ///@todo Destroy all render passes.
-  vk::RenderPass renderPass = mRenderPasses[0].renderPassImpl->GetVkHandle();
-
-  auto allocator = &mGraphicsDevice->GetAllocator();
-
-  mGraphicsDevice->DiscardResource([device, frameBuffer, renderPass, allocator]() {
-                                     DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: framebuffer->%p\n", static_cast<VkFramebuffer>(frameBuffer))
-                                     device.destroyFramebuffer(frameBuffer, allocator);
-
-                                     if(renderPass)
-                                     {
-                                       DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: render pass->%p\n", static_cast<VkRenderPass>(renderPass))
-                                       device.destroyRenderPass(renderPass, allocator);
-                                     } });
-
-  return false;
-}
-
 } // namespace Dali::Graphics::Vulkan
 
 // Namespace Graphics
index 63782b2..2d10f0c 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <dali/internal/graphics/vulkan-impl/vulkan-types.h>
 
+#include <dali/internal/graphics/vulkan-impl/vulkan-image-view-impl.h>
+
 namespace Dali::Graphics::Vulkan
 {
 class RenderPass;
@@ -37,20 +39,41 @@ enum class AttachmentType
 
 class Device;
 
-class FramebufferAttachment : public VkManaged
+class FramebufferAttachment
 {
 public:
-  FramebufferAttachment(ImageView*     imageView,
-                        vk::ClearValue clearColor,
-                        AttachmentType type,
-                        bool           presentable);
+  /**
+   * Constructor
+   *
+   * @param[in] imageView The imageview of the attachment
+   * @param[in] clearColor The color used to clear this attachment during CLEAR_OP
+   * @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);
 
-  static FramebufferAttachment* NewColorAttachment(ImageView*          imageView,
-                                                   vk::ClearColorValue clearColorValue,
-                                                   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] presentable Whether the attachment is presentable (changes final layout)
+   */
+  static FramebufferAttachment* NewColorAttachment(std::unique_ptr<ImageView>& imageView,
+                                                   vk::ClearColorValue         clearColorValue,
+                                                   bool                        presentable);
 
-  static FramebufferAttachment* NewDepthAttachment(ImageView*                 imageView,
-                                                   vk::ClearDepthStencilValue clearDepthStencilValue);
+  /**
+   * 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
+   */
+  static FramebufferAttachment* NewDepthAttachment(std::unique_ptr<ImageView>& imageView,
+                                                   vk::ClearDepthStencilValue  clearDepthStencilValue);
 
   [[nodiscard]] ImageView* GetImageView() const;
 
@@ -65,44 +88,84 @@ public:
 private:
   FramebufferAttachment() = default;
 
-  ImageView*                mImageView{nullptr};
-  vk::AttachmentDescription mDescription;
-  vk::ClearValue            mClearValue;
-  AttachmentType            mType{AttachmentType::UNDEFINED};
+  std::unique_ptr<ImageView> mImageView;
+  vk::AttachmentDescription  mDescription;
+  vk::ClearValue             mClearValue;
+  AttachmentType             mType{AttachmentType::UNDEFINED};
 };
 
+using OwnedAttachments = std::vector<std::unique_ptr<FramebufferAttachment>>;
+
 /**
  * FramebufferImpl encapsulates following objects:
  * - Images ( attachments )
  * - FramebufferImpl
  * - ImageViews
+ * - RenderPasses
  */
-class FramebufferImpl : public VkManaged
+class FramebufferImpl
 {
 public:
+  /**
+   * @brief Create a new Framebuffer
+   *
+   * @param[in] device The vulkan device
+   * @param[in] renderPass A shared handle to a compatible render pass.
+   * @param[in] attachments The attachments. Framebuffer takes ownership of these
+   * @param[in] width Width of the framebuffer
+   * @param[in] height Height of the framebuffer
+   * @param[in] hasDepthAttachment True if the last attachment is a depth buffer
+   *
+   * @return A new framebuffer object
+   */
   static FramebufferImpl* New(
-    Vulkan::Device&                      device,
-    RenderPassImpl*                      renderPass,
-    std::vector<FramebufferAttachment*>& attachments,
-    uint32_t                             width,
-    uint32_t                             height,
-    bool                                 hasDepthAttachment);
+    Vulkan::Device&   device,
+    RenderPassImpl*   renderPass,
+    OwnedAttachments& attachments,
+    uint32_t          width,
+    uint32_t          height,
+    bool              hasDepthAttachment);
 
+  /**
+   * @brief Create a new Framebuffer
+   *
+   * @param[in] device The vulkan device
+   * @param[in] renderPass A shared handle to a compatible render pass.
+   * @param[in] attachments The attachments. Framebuffer takes ownership of these
+   * @param[in] width Width of the framebuffer
+   * @param[in] height Height of the framebuffer
+   * @param[in] hasDepthAttachment True if the last attachment is a depth buffer
+   *
+   * @return A new framebuffer object
+   */
   static FramebufferImpl* New(
-    Vulkan::Device&                            device,
-    RenderPassImpl*                            renderPass,
-    const std::vector<FramebufferAttachment*>& colorAttachments,
-    FramebufferAttachment*                     depthAttachment,
-    uint32_t                                   width,
-    uint32_t                                   height);
-
-  FramebufferImpl(Device&                                    graphicsDevice,
-                  const std::vector<FramebufferAttachment*>& attachments,
-                  vk::Framebuffer                            vkHandle,
-                  const RenderPassImpl&                      renderPass,
-                  uint32_t                                   width,
-                  uint32_t                                   height,
-                  bool                                       hasDepthAttachment);
+    Vulkan::Device&                         device,
+    RenderPassImpl*                         renderPass,
+    OwnedAttachments&                       colorAttachments,
+    std::unique_ptr<FramebufferAttachment>& depthAttachment,
+    uint32_t                                width,
+    uint32_t                                height);
+
+  /**
+   * @brief Constructor
+   *
+   * @param[in] graphicsDevice The vulkan device
+   * @param[in] attachments The attachments - framebuffer takes ownership
+   * @param[in] vkHandle a handle to a created framebuffer
+   * @param[in] renderPass a handle to a compatible render pass
+   * @param[in] width Width of the framebuffer
+   * @param[in] height Height of the framebuffer
+   * @param[in] hasDepthAttachment True if the last attachment is a depth buffer
+   */
+  FramebufferImpl(Device&               graphicsDevice,
+                  OwnedAttachments&     attachments,
+                  vk::Framebuffer       vkHandle,
+                  const RenderPassImpl& renderPass,
+                  uint32_t              width,
+                  uint32_t              height,
+                  bool                  hasDepthAttachment);
+
+  void Destroy();
 
   [[nodiscard]] uint32_t GetWidth() const;
 
@@ -124,8 +187,6 @@ public:
 
   [[nodiscard]] std::vector<vk::ClearValue> GetClearValues() const;
 
-  bool OnDestroy() override;
-
 private:
   Device* mGraphicsDevice;
 
@@ -142,10 +203,10 @@ private:
   };
   using RenderPasses = std::vector<RenderPassMapElement>;
 
-  std::vector<FramebufferAttachment*> mAttachments;
-  vk::Framebuffer                     mFramebuffer;
-  RenderPasses                        mRenderPasses;
-  bool                                mHasDepthAttachment{false};
+  OwnedAttachments mAttachments;
+  vk::Framebuffer  mFramebuffer;
+  RenderPasses     mRenderPasses;
+  bool             mHasDepthAttachment{false};
 };
 
 } // Namespace Dali::Graphics::Vulkan
index 70f1817..18d4072 100644 (file)
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-render-pass.h>
 
-namespace Dali
-{
-namespace Graphics
-{
-namespace Vulkan
+namespace Dali::Graphics::Vulkan
 {
 Framebuffer::Framebuffer(const FramebufferCreateInfo& createInfo, VulkanGraphicsController& controller)
 : Resource(createInfo, controller),
@@ -39,25 +35,20 @@ Framebuffer::~Framebuffer() = default;
 bool Framebuffer::InitializeResource()
 {
   // Create attachments
-  std::vector<FramebufferAttachment*> colorAttachments;
+  OwnedAttachments 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);
   }
-  FramebufferAttachment* depthStencilAttachment{nullptr};
+  std::unique_ptr<FramebufferAttachment> depthStencilAttachment;
   if(mCreateInfo.depthStencilAttachment.depthTexture || mCreateInfo.depthStencilAttachment.stencilTexture)
   {
     // depthStencilAttachment = FramebufferAttachment::NewDepthAttachment();
   }
 
-  // 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);
+  mFramebufferImpl = FramebufferImpl::New(device, nullptr, colorAttachments, depthStencilAttachment, mCreateInfo.size.width, mCreateInfo.size.height);
 
   return true;
 }
@@ -70,6 +61,4 @@ void Framebuffer::DiscardResource()
 {
 }
 
-} // namespace Vulkan
-} // namespace Graphics
-} // namespace Dali
+} // namespace Dali::Graphics::Vulkan
index 11b86e5..447422a 100644 (file)
@@ -20,8 +20,8 @@
 
 #include <dali/internal/graphics/vulkan-impl/vulkan-graphics-resource.h>
 
-#include <dali/graphics-api/graphics-framebuffer.h>
 #include <dali/graphics-api/graphics-framebuffer-create-info.h>
+#include <dali/graphics-api/graphics-framebuffer.h>
 
 namespace Dali
 {
@@ -32,6 +32,7 @@ namespace Vulkan
 class FramebufferImpl;
 
 using FramebufferResource = Resource<Graphics::Framebuffer, Graphics::FramebufferCreateInfo>;
+
 class Framebuffer : public FramebufferResource
 {
 public:
@@ -40,7 +41,7 @@ public:
   ~Framebuffer() override;
 
   /**
-   * @brief Called when GL resources are destroyed
+   * @brief Called when resources are destroyed
    */
   void DestroyResource() override;
 
@@ -56,10 +57,28 @@ public:
    */
   void DiscardResource() override;
 
+  /**
+   * @copydoc Graphics::Vulkan::ResourceBase::GetAllocationCallbacks()
+   */
+  [[nodiscard]] const Graphics::AllocationCallbacks* GetAllocationCallbacks() const override
+  {
+    return mCreateInfo.allocationCallbacks;
+  }
+
+  /**
+   * @copydoc Graphics::Vulkan::ResourceBase::InvokeDeleter()
+   * Only intended for use by discard queue.
+   */
+  void InvokeDeleter() override
+  {
+    this->~Framebuffer();
+  }
+
   FramebufferImpl* GetImpl()
   {
     return mFramebufferImpl;
   }
+
 private:
   FramebufferImpl* mFramebufferImpl;
 };
index 7087748..f2a717b 100644 (file)
@@ -71,13 +71,13 @@ static bool TestCopyRectIntersection(const ResourceTransferRequest* srcRequest,
  *
  * When Graphics object dies the unique pointer (Graphics::UniquePtr)
  * doesn't destroy it directly but passes the ownership back
- * to the Controller. The VKDeleter is responsible for passing
- * the object to the discard queue (by calling Resource::DiscardResource()).
+ * to the Controller. The GraphicsDeleter is responsible for passing
+ * the graphics object to the discard queue (by calling Resource::DiscardResource()).
  */
 template<typename T>
-struct VKDeleter
+struct GraphicsDeleter
 {
-  VKDeleter() = default;
+  GraphicsDeleter() = default;
 
   void operator()(T* object)
   {
@@ -94,7 +94,7 @@ struct VKDeleter
  * @param[out] out Unique pointer to the return object
  */
 template<class VKType, class GfxCreateInfo, class T>
-auto NewObject(const GfxCreateInfo& info, VulkanGraphicsController& controller, T&& oldObject)
+auto NewGraphicsObject(const GfxCreateInfo& info, VulkanGraphicsController& controller, T&& oldObject)
 {
   // Use allocator
   using Type = typename T::element_type;
@@ -105,7 +105,7 @@ auto NewObject(const GfxCreateInfo& info, VulkanGraphicsController& controller,
       sizeof(VKType),
       0,
       info.allocationCallbacks->userData);
-    return UPtr(new(memory) VKType(info, controller), VKDeleter<VKType>());
+    return UPtr(new(memory) VKType(info, controller), GraphicsDeleter<VKType>());
   }
   else // Use standard allocator
   {
@@ -116,7 +116,7 @@ auto NewObject(const GfxCreateInfo& info, VulkanGraphicsController& controller,
       // If succeeded, attach the object to the unique_ptr and return it back
       if(static_cast<VKType*>(reusedObject)->TryRecycle(info, controller))
       {
-        return UPtr(reusedObject, VKDeleter<VKType>());
+        return UPtr(reusedObject, GraphicsDeleter<VKType>());
       }
       else
       {
@@ -126,8 +126,8 @@ auto NewObject(const GfxCreateInfo& info, VulkanGraphicsController& controller,
       }
     }
 
-    // Create brand new object
-    UPtr gfxObject(new VKType(info, controller), VKDeleter<VKType>());
+    // Create brand-new object
+    UPtr gfxObject(new VKType(info, controller), GraphicsDeleter<VKType>());
     static_cast<VKType*>(gfxObject.get())->InitializeResource(); // @todo Consider using create queues?
     return gfxObject;
   }
@@ -410,7 +410,7 @@ struct VulkanGraphicsController::Impl
           // Do not destroy
           if(buffer != mTextureStagingBuffer->GetImpl())
           {
-            buffer->DestroyNow();
+            buffer->Destroy();
           }
         }
         else if(request.requestType == TransferRequestType::IMAGE_TO_IMAGE)
@@ -418,7 +418,7 @@ struct VulkanGraphicsController::Impl
           auto& image = request.imageToImageInfo.srcImage;
           if(image->GetVkHandle())
           {
-            image->DestroyNow();
+            image->Destroy();
           }
         }
       }
@@ -428,12 +428,74 @@ struct VulkanGraphicsController::Impl
     }
   }
 
+  /**
+   * @brief Processes a discard queue for objects created with NewObject
+   *
+   * @param[in,out] queue Reference to the queue
+   */
+  template<class ResourceType>
+  void ProcessResourceDiscardQueue(std::queue<ResourceType*>& queue)
+  {
+    while(!queue.empty())
+    {
+      auto* object = const_cast<ResourceType*>(queue.front());
+
+      // Destroy
+      object->DestroyResource();
+
+      auto* allocationCallbacks = object->GetAllocationCallbacks();
+      if(allocationCallbacks)
+      {
+        object->InvokeDeleter();
+        allocationCallbacks->freeCallback(object, allocationCallbacks->userData);
+      }
+      else
+      {
+        delete object;
+      }
+      queue.pop();
+    }
+  }
+
+  /**
+   * Processes a discard queue for direct instantiated objects
+   */
+  template<class ResourceType>
+  void ProcessDiscardQueue(std::queue<ResourceType*>& queue)
+  {
+    while(!queue.empty())
+    {
+      auto* object = queue.front();
+
+      // Destroy
+      object->DestroyResource();
+      delete object;
+
+      queue.pop();
+    }
+  }
+
+  void GarbageCollect()
+  {
+    ProcessResourceDiscardQueue<ResourceWithDeleter>(mResourceDiscardQueue);
+    ProcessDiscardQueue<ResourceBase>(mDiscardQueue);
+  }
+
+  void Flush()
+  {
+    // Flush any outstanding queues.
+
+    GarbageCollect();
+  }
+
   VulkanGraphicsController& mGraphicsController;
   Vulkan::Device*           mGraphicsDevice{nullptr};
 
   // used for texture<->buffer<->memory transfers
-  std::vector<ResourceTransferRequest> mResourceTransferRequests;
-  std::recursive_mutex                 mResourceTransferMutex{};
+  std::vector<ResourceTransferRequest>     mResourceTransferRequests;
+  std::recursive_mutex                     mResourceTransferMutex{};
+  std::queue<Vulkan::ResourceBase*>        mDiscardQueue;
+  std::queue<Vulkan::ResourceWithDeleter*> mResourceDiscardQueue;
 
   std::unique_ptr<Vulkan::Buffer>       mTextureStagingBuffer{};
   Dali::SharedFuture                    mTextureStagingBufferFuture{};
@@ -453,7 +515,10 @@ VulkanGraphicsController::VulkanGraphicsController()
 {
 }
 
-VulkanGraphicsController::~VulkanGraphicsController() = default;
+VulkanGraphicsController::~VulkanGraphicsController()
+{
+  mImpl->GarbageCollect();
+}
 
 void VulkanGraphicsController::Initialize(Dali::Graphics::VulkanGraphics& graphicsImplementation,
                                           Vulkan::Device&                 graphicsDevice)
@@ -484,6 +549,12 @@ void VulkanGraphicsController::SubmitCommandBuffers(const SubmitInfo& submitInfo
       swapchain->Submit(cmdBuffer->GetImpl());
     }
   }
+
+  // If flush bit set, flush all pending tasks
+  if(submitInfo.flags & (0 | SubmitFlagBits::FLUSH))
+  {
+    Flush();
+  }
 }
 
 void VulkanGraphicsController::PresentRenderTarget(Graphics::RenderTarget* renderTarget)
@@ -792,6 +863,7 @@ bool VulkanGraphicsController::EnableDepthStencilBuffer(bool enableDepth, bool e
 
 void VulkanGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
 {
+  mImpl->GarbageCollect();
 }
 
 void VulkanGraphicsController::DiscardUnusedResources()
@@ -810,12 +882,12 @@ bool VulkanGraphicsController::IsDrawOnResumeRequired()
 
 UniquePtr<Graphics::RenderTarget> VulkanGraphicsController::CreateRenderTarget(const Graphics::RenderTargetCreateInfo& renderTargetCreateInfo, UniquePtr<Graphics::RenderTarget>&& oldRenderTarget)
 {
-  return NewObject<Vulkan::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
+  return NewGraphicsObject<Vulkan::RenderTarget>(renderTargetCreateInfo, *this, std::move(oldRenderTarget));
 }
 
 UniquePtr<Graphics::CommandBuffer> VulkanGraphicsController::CreateCommandBuffer(const Graphics::CommandBufferCreateInfo& commandBufferCreateInfo, UniquePtr<Graphics::CommandBuffer>&& oldCommandBuffer)
 {
-  return NewObject<Vulkan::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
+  return NewGraphicsObject<Vulkan::CommandBuffer>(commandBufferCreateInfo, *this, std::move(oldCommandBuffer));
 }
 
 UniquePtr<Graphics::RenderPass> VulkanGraphicsController::CreateRenderPass(const Graphics::RenderPassCreateInfo& renderPassCreateInfo, UniquePtr<Graphics::RenderPass>&& oldRenderPass)
@@ -828,12 +900,12 @@ UniquePtr<Graphics::RenderPass> VulkanGraphicsController::CreateRenderPass(const
 
 UniquePtr<Graphics::Buffer> VulkanGraphicsController::CreateBuffer(const Graphics::BufferCreateInfo& bufferCreateInfo, UniquePtr<Graphics::Buffer>&& oldBuffer)
 {
-  return NewObject<Vulkan::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
+  return NewGraphicsObject<Vulkan::Buffer>(bufferCreateInfo, *this, std::move(oldBuffer));
 }
 
 UniquePtr<Graphics::Texture> VulkanGraphicsController::CreateTexture(const Graphics::TextureCreateInfo& textureCreateInfo, UniquePtr<Graphics::Texture>&& oldTexture)
 {
-  return NewObject<Vulkan::Texture>(textureCreateInfo, *this, std::move(oldTexture));
+  return NewGraphicsObject<Vulkan::Texture>(textureCreateInfo, *this, std::move(oldTexture));
 }
 
 UniquePtr<Graphics::Framebuffer> VulkanGraphicsController::CreateFramebuffer(const Graphics::FramebufferCreateInfo& framebufferCreateInfo, UniquePtr<Graphics::Framebuffer>&& oldFramebuffer)
@@ -858,7 +930,7 @@ UniquePtr<Graphics::Shader> VulkanGraphicsController::CreateShader(const Graphic
 
 UniquePtr<Graphics::Sampler> VulkanGraphicsController::CreateSampler(const Graphics::SamplerCreateInfo& samplerCreateInfo, UniquePtr<Graphics::Sampler>&& oldSampler)
 {
-  return NewObject<Vulkan::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
+  return NewGraphicsObject<Vulkan::Sampler>(samplerCreateInfo, *this, std::move(oldSampler));
 }
 
 UniquePtr<Graphics::SyncObject> VulkanGraphicsController::CreateSyncObject(const Graphics::SyncObjectCreateInfo& syncObjectCreateInfo,
@@ -867,6 +939,16 @@ UniquePtr<Graphics::SyncObject> VulkanGraphicsController::CreateSyncObject(const
   return UniquePtr<Graphics::SyncObject>{};
 }
 
+void VulkanGraphicsController::DiscardResource(Vulkan::ResourceBase* resource)
+{
+  mImpl->mDiscardQueue.push(resource);
+}
+
+void VulkanGraphicsController::DiscardResource(Vulkan::ResourceWithDeleter* resource)
+{
+  mImpl->mResourceDiscardQueue.push(resource);
+}
+
 UniquePtr<Graphics::Memory> VulkanGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
 {
   // @todo: Process create queues
@@ -909,7 +991,7 @@ MemoryRequirements VulkanGraphicsController::GetTextureMemoryRequirements(Graphi
 
 TextureProperties VulkanGraphicsController::GetTextureProperties(const Graphics::Texture& gfxTexture)
 {
-  Vulkan::Texture* texture = const_cast<Vulkan::Texture*>(static_cast<const Vulkan::Texture*>(&gfxTexture));
+  auto* texture = const_cast<Vulkan::Texture*>(static_cast<const Vulkan::Texture*>(&gfxTexture));
   return texture->GetProperties();
 }
 
@@ -992,40 +1074,6 @@ std::string VulkanGraphicsController::GetFragmentShaderPrefix()
   return "";
 }
 
-void VulkanGraphicsController::Add(Vulkan::RenderTarget* renderTarget)
-{
-  // @todo Add create resource queues?
-  renderTarget->InitializeResource();
-}
-
-void VulkanGraphicsController::DiscardResource(Vulkan::RenderTarget* renderTarget)
-{
-  // @todo Add discard queues
-}
-
-void VulkanGraphicsController::DiscardResource(Vulkan::Buffer* buffer)
-{
-  // @todo Add discard queues
-}
-
-void VulkanGraphicsController::DiscardResource(Vulkan::Pipeline* buffer)
-{
-  // @todo Add discard queues
-}
-
-void VulkanGraphicsController::DiscardResource(Vulkan::Program* program)
-{
-  // @todo Add discard queues
-}
-
-void VulkanGraphicsController::DiscardResource(Vulkan::Sampler* sampler)
-{
-}
-
-void VulkanGraphicsController::DiscardResource(Vulkan::Texture* texture)
-{
-}
-
 Vulkan::Device& VulkanGraphicsController::GetGraphicsDevice()
 {
   return *mImpl->mGraphicsDevice;
@@ -1083,6 +1131,11 @@ Graphics::UniquePtr<Graphics::Texture> VulkanGraphicsController::ReleaseTextureF
   return gfxTexture;
 }
 
+void VulkanGraphicsController::Flush()
+{
+  mImpl->Flush();
+}
+
 std::size_t VulkanGraphicsController::GetCapacity() const
 {
   return mImpl->mCapacity;
index a21f735..0e10695 100644 (file)
@@ -270,6 +270,14 @@ public:
                                                    UniquePtr<Graphics::SyncObject>&&     oldSyncObject) override;
 
   /**
+   * Add the graphics resource to a discard queue for later destruction
+   * @param[in] resource The graphics resource to discard.
+   */
+  void DiscardResource(Vulkan::ResourceBase* resource);
+
+  void DiscardResource(Vulkan::ResourceWithDeleter* program);
+
+  /**
    * @brief Maps memory associated with Buffer object
    *
    * @param[in] mapInfo Filled details of mapped resource
@@ -365,14 +373,6 @@ public:
    */
   bool GetProgramParameter(Graphics::Program& program, uint32_t parameterId, void* outData) override;
 
-  void Add(Vulkan::RenderTarget* renderTarget);
-  void DiscardResource(Vulkan::RenderTarget* renderTarget);
-  void DiscardResource(Vulkan::Buffer* buffer);
-  void DiscardResource(Vulkan::Pipeline* buffer);
-  void DiscardResource(Vulkan::Program* renderProgram);
-  void DiscardResource(Vulkan::Sampler* sampler);
-  void DiscardResource(Vulkan::Texture* texture);
-
 public: // Integration::GraphicsConfig
   bool        IsBlendEquationSupported(DevelBlendEquation::Type blendEquation) override;
   uint32_t    GetShaderLanguageVersion() override;
@@ -433,6 +433,11 @@ public: // For debug
   std::size_t GetCapacity() const;
 
 private:
+  /**
+   * Flush all outstanding queues.
+   */
+  void Flush();
+
   bool IsAdvancedBlendEquationSupported();
 
   struct Impl;
index e1d0f11..4d145c9 100644 (file)
  *
  */
 
+#include <dali/graphics-api/graphics-types.h>
+
 namespace Dali::Graphics::Vulkan
 {
 class VulkanGraphicsController;
 
 /**
+ * Interface class for graphics resources
+ */
+class ResourceBase
+{
+public:
+  /**
+   * @brief Destroys resource
+   *
+   * This function must be implemented by the derived class.
+   * It should perform final destruction of used GL resources.
+   */
+  virtual void DestroyResource() = 0;
+
+  /**
+   * @brief Initializes resource
+   *
+   * This function must be implemented by the derived class.
+   * It should initialize all necessary GL resources.
+   *
+   * @return True on success
+   */
+  virtual bool InitializeResource() = 0;
+
+  /**
+   * @brief Discards resource by adding it to the discard queue
+   */
+  virtual void DiscardResource() = 0;
+
+  virtual ~ResourceBase() = default;
+};
+
+class ResourceWithDeleter : public ResourceBase
+{
+public:
+  /**
+   * @brief Get the allocation callbacks for this object
+   */
+  [[nodiscard]] virtual const Graphics::AllocationCallbacks* GetAllocationCallbacks() const = 0;
+
+  /**
+   * @brief Invoke the deleter of the derived type.
+   */
+  virtual void InvokeDeleter() = 0;
+
+  ~ResourceWithDeleter() override = default;
+};
+
+/**
  * @brief Base class for the Graphics resource.
+ * A graphics resource is any Graphics API object created by the controller that
+ * requires lifecycle management.
+ * It explicitly does not include Vulkan Impl objects that wrap a vkHandle.
  */
-template<class BASE, class CreateInfo>
-class Resource : public BASE
+template<class GraphicsType, class CreateInfo>
+class Resource : public GraphicsType, public ResourceWithDeleter
 {
 public:
   /**
@@ -80,33 +133,10 @@ public:
   }
 
   /**
-   * @brief Destroys resource
-   *
-   * This function must be implemented by the derived class.
-   * It should perform final destruction of used GL resources.
-   */
-  virtual void DestroyResource() = 0;
-
-  /**
-   * @brief Initializes resource
-   *
-   * This function must be implemented by the derived class.
-   * It should initialize all necessary GL resources.
-   *
-   * @return True on success
-   */
-  virtual bool InitializeResource() = 0;
-
-  /**
-   * @brief Discards resource by adding it to the discard queue
-   */
-  virtual void DiscardResource() = 0;
-
-  /**
    * @brief returns pointer to base
    * @return
    */
-  BASE* GetBase()
+  GraphicsType* GetBase()
   {
     return this;
   }
index 20b95d1..470d1bd 100644 (file)
@@ -83,6 +83,18 @@ void Image::Initialize()
   VkAssert(mDevice.GetLogicalDevice().createImage(&mCreateInfo, &mDevice.GetAllocator("IMAGE"), &mImage));
 }
 
+void Image::Destroy()
+{
+  DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying image: %p\n", static_cast<VkImage>(mImage));
+  auto device = mDevice.GetLogicalDevice();
+  if(mImage)
+  {
+    device.destroyImage(mImage, mDevice.GetAllocator());
+  }
+  mImage = nullptr;
+  mMemory.reset();
+}
+
 void Image::AllocateAndBind(vk::MemoryPropertyFlags memoryProperties)
 {
   auto requirements    = mDevice.GetLogicalDevice().getImageMemoryRequirements(mImage);
@@ -255,38 +267,6 @@ vk::SampleCountFlagBits Image::GetSampleCount() const
   return mCreateInfo.samples;
 }
 
-void Image::DestroyNow()
-{
-  DestroyVulkanResources(mDevice.GetLogicalDevice(), mImage, mMemory->ReleaseVkObject(), &mDevice.GetAllocator());
-  mImage  = nullptr;
-  mMemory = nullptr;
-}
-
-bool Image::OnDestroy()
-{
-  if(!mIsExternal)
-  {
-    if(mImage)
-    {
-      auto device    = mDevice.GetLogicalDevice();
-      auto image     = mImage;
-      auto allocator = &mDevice.GetAllocator();
-      auto memory    = mMemory->ReleaseVkObject();
-
-      mDevice.DiscardResource([device, image, memory, allocator]() { DestroyVulkanResources(device, image, memory, allocator); });
-    }
-  }
-
-  return false;
-}
-
-void Image::DestroyVulkanResources(vk::Device device, vk::Image image, vk::DeviceMemory memory, const vk::AllocationCallbacks* allocator)
-{
-  DALI_LOG_INFO(gVulkanFilter, Debug::General, "Invoking deleter function: image->%p\n", static_cast<VkImage>(image))
-  device.destroyImage(image, allocator);
-  device.freeMemory(memory, allocator);
-}
-
 } // namespace Vulkan
 
 } // namespace Graphics
index 8454583..dc9ea51 100644 (file)
@@ -54,6 +54,14 @@ public:
   void Initialize();
 
   /**
+   * Destroys underlying Vulkan resources on the caller thread.
+   *
+   * @note Calling this function is unsafe and makes any further use of
+   * image invalid.
+   */
+  void Destroy();
+
+  /**
    * Allocate memory for the image and bind it.
    * Kept separate from Initialize because reasons. ?!?!
    *
@@ -149,32 +157,12 @@ public:
     return mMemory.get();
   }
 
-  bool OnDestroy();
-
-  /**
-   * Destroys underlying Vulkan resources on the caller thread.
-   *
-   * @note Calling this function is unsafe and makes any further use of
-   * image invalid.
-   */
-  void DestroyNow();
-
-  /**
-   * Destroys used Vulkan resource objects
-   * @param device Vulkan device
-   * @param image Vulkan image
-   * @param memory Vulkan device memory
-   * @param allocator Pointer to the Vulkan allocator callbacks
-   */
-  static void DestroyVulkanResources(vk::Device device, vk::Image image, vk::DeviceMemory memory, const vk::AllocationCallbacks* allocator);
-
 private:
-  Device&              mDevice;
-  vk::ImageCreateInfo  mCreateInfo;
-  vk::Image            mImage;
-  vk::ImageLayout      mImageLayout;
-  vk::ImageAspectFlags mAspectFlags;
-
+  Device&                     mDevice;
+  vk::ImageCreateInfo         mCreateInfo;
+  vk::Image                   mImage;
+  vk::ImageLayout             mImageLayout;
+  vk::ImageAspectFlags        mAspectFlags;
   std::unique_ptr<MemoryImpl> mMemory;
   bool                        mIsExternal;
 };
index 15fb6fd..9d921c0 100644 (file)
@@ -110,6 +110,13 @@ ImageView::~ImageView()
   Destroy();
 }
 
+void ImageView::Destroy()
+{
+  DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying ImageView: %p\n", static_cast<VkImageView>(mImageView));
+  auto device = mDevice.GetLogicalDevice();
+  device.destroyImageView(mImageView, mDevice.GetAllocator());
+}
+
 vk::ImageView ImageView::GetVkHandle() const
 {
   return mImageView;
@@ -135,12 +142,6 @@ vk::ImageAspectFlags ImageView::GetImageAspectMask() const
   return vk::ImageAspectFlags();
 }
 
-void ImageView::Destroy()
-{
-  auto device = mDevice.GetLogicalDevice();
-  device.destroyImageView(mImageView, mDevice.GetAllocator());
-}
-
 } // namespace Vulkan
 } // namespace Graphics
 } // namespace Dali
index b7454ad..2883029 100644 (file)
@@ -52,6 +52,8 @@ public:
 
   ~ImageView();
 
+  void Destroy();
+
   /**
    *
    * @return
@@ -79,8 +81,6 @@ public:
    */
   [[nodiscard]] vk::ImageAspectFlags GetImageAspectMask() const;
 
-  void Destroy();
-
 private:
   Device&                 mDevice;
   const Image&            mImage;
index 83bcf5d..ce333d4 100644 (file)
@@ -77,13 +77,6 @@ void MemoryImpl::Unmap()
   }
 }
 
-vk::DeviceMemory MemoryImpl::ReleaseVkObject()
-{
-  auto retval  = deviceMemory;
-  deviceMemory = nullptr;
-  return retval;
-}
-
 void MemoryImpl::Flush()
 {
   // Don't flush if we are using host coherent memory - it's un-necessary
index c9a2e47..40a2fb7 100644 (file)
@@ -38,7 +38,7 @@ public:
   }
 
   // No copy constructor or assignment operator
-  MemoryImpl(MemoryImpl&) = delete;
+  MemoryImpl(MemoryImpl&)            = delete;
   MemoryImpl& operator=(MemoryImpl&) = delete;
 
   void* Map();
@@ -49,13 +49,6 @@ public:
 
   void Flush();
 
-  /**
-   * Releases vk::DeviceMemory object so it can be deleted
-   * externally
-   * @return
-   */
-  vk::DeviceMemory ReleaseVkObject();
-
   [[nodiscard]] vk::DeviceMemory GetVkHandle() const;
 
 private:
index 6cf4fc4..95a4b03 100644 (file)
@@ -56,6 +56,11 @@ Pipeline::Pipeline(const Graphics::PipelineCreateInfo& createInfo, VulkanGraphic
   mPipeline = std::make_unique<PipelineImpl>(createInfo, controller, pipelineCache);
 }
 
+bool Pipeline::InitializeResource()
+{
+  return true;
+}
+
 void Pipeline::DiscardResource()
 {
   // Send pipeline to discard queue if refcount is 0
index 2e92309..8f3d16b 100644 (file)
@@ -35,7 +35,7 @@ class PipelineCache;
 /**
  * @brief Pipeline class wraps the PipelineImpl
  */
-class Pipeline : public Graphics::Pipeline
+class Pipeline : public Graphics::Pipeline, public Vulkan::ResourceBase
 {
 public:
   Pipeline() = delete;
@@ -82,22 +82,23 @@ public:
   bool operator==(const PipelineImpl* impl) const;
 
   /**
-   * @brief Run by UniquePtr to discard resource
+   * @brief Initialize the resource
    */
-  void DiscardResource();
+  bool InitializeResource() override;
+
+  /**
+   * @brief trigger discard
+   */
+  void DiscardResource() override;
 
   /**
    * @brief Destroy resource
-   *
-   * Despite this class doesn't inherit Resource it must provide
-   * (so it won't duplicate same data) same set of functions
-   * so it can work with resource management functions of Controller.
    */
-  void DestroyResource();
+  void DestroyResource() override;
 
 private:
   std::unique_ptr<PipelineImpl> mPipeline; // TODO: it may need to be changed when we have caching
 };
 
 } // namespace Dali::Graphics::Vulkan
-#endif
\ No newline at end of file
+#endif
index 0f50162..d5eda21 100644 (file)
@@ -64,9 +64,19 @@ const ProgramCreateInfo& Program::GetCreateInfo() const
   return GetImplementation()->GetCreateInfo();
 }
 
+bool Program::InitializeResource()
+{
+  return true;
+}
+
 void Program::DiscardResource()
 {
   GetController().DiscardResource(this);
 }
 
+void Program::DestroyResource()
+{
+  // nothing to do here
+}
+
 }; // namespace Dali::Graphics::Vulkan
index 041bbe0..bc19a42 100644 (file)
@@ -28,6 +28,7 @@ namespace Dali::Graphics::Vulkan
 {
 class Reflection;
 class ProgramImpl;
+
 /**
  * @brief Wrapper for the program implementation
  *
@@ -37,7 +38,7 @@ class ProgramImpl;
  * within Graphics API is a set of shader stages linked together
  * so the reflection can do its work on it.
  */
-class Program : public Graphics::Program
+class Program : public Graphics::Program, public Vulkan::ResourceBase
 {
 public:
   /**
@@ -59,7 +60,6 @@ public:
 
   /**
    * @brief Returns reference to the Reflection object
-
    * @return Reflection
    */
   [[nodiscard]] const Vulkan::Reflection& GetReflection() const;
@@ -104,9 +104,14 @@ public:
   }
 
   /**
+   * @brief Initialize the resource
+   */
+  bool InitializeResource() override;
+
+  /**
    * @brief Run by UniquePtr to discard resource
    */
-  void DiscardResource();
+  void DiscardResource() override;
 
   /**
    * @brief Destroying resources
@@ -114,10 +119,7 @@ public:
    * This function is kept for compatibility with Resource<> class
    * so can the object can be use with templated functions.
    */
-  void DestroyResource()
-  {
-    // nothing to do here
-  }
+  void DestroyResource() override;
 
   bool TryRecycle(const Graphics::ProgramCreateInfo& createInfo, VulkanGraphicsController& controller)
   {
@@ -129,4 +131,4 @@ private:
 };
 } // namespace Dali::Graphics::Vulkan
 
-#endif //DALI_GRAPHICS_VULKAN_PROGRAM_H
+#endif // DALI_GRAPHICS_VULKAN_PROGRAM_H
index eceb474..c9b2ebd 100644 (file)
@@ -49,26 +49,24 @@ RenderPassImpl::RenderPassImpl(Vulkan::Device&                            device
 
 RenderPassImpl::~RenderPassImpl() = default;
 
-vk::RenderPass RenderPassImpl::GetVkHandle()
-{
-  return mVkRenderPass;
-}
-
-bool RenderPassImpl::OnDestroy()
+void RenderPassImpl::Destroy()
 {
   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); });
+
+    DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying render pass: %p\n", static_cast<VkRenderPass>(renderPass));
+    device.destroyRenderPass(renderPass, allocator);
 
     mVkRenderPass = nullptr;
   }
-  return false;
+}
+
+vk::RenderPass RenderPassImpl::GetVkHandle()
+{
+  return mVkRenderPass;
 }
 
 std::vector<vk::ImageView>& RenderPassImpl::GetAttachments()
index 6122634..ade80a0 100644 (file)
@@ -41,7 +41,7 @@ class RenderTarget;
  * FramebufferImpl will create a separate compatible RenderPassImpl if a matching
  * render pass is NOT found.
  */
-class RenderPassImpl final : public Dali::Graphics::Vulkan::VkManaged
+class RenderPassImpl
 {
 public:
   struct CreateInfo
@@ -61,11 +61,11 @@ public:
 
   RenderPassImpl(Vulkan::Device& device, const std::vector<FramebufferAttachment*>& colorAttachments, FramebufferAttachment* depthAttachment);
 
-  ~RenderPassImpl() override;
+  ~RenderPassImpl();
 
-  vk::RenderPass GetVkHandle();
+  void Destroy();
 
-  bool OnDestroy() override;
+  vk::RenderPass GetVkHandle();
 
   std::vector<vk::ImageView>& GetAttachments();
 
index d3c4310..15dcb08 100644 (file)
@@ -61,6 +61,23 @@ public:
   void DiscardResource() override;
 
   /**
+   * @copydoc Graphics::Vulkan::Resource::GetAllocationCallbacks()
+   */
+  [[nodiscard]] const Graphics::AllocationCallbacks* GetAllocationCallbacks() const override
+  {
+    return mCreateInfo.allocationCallbacks;
+  }
+
+  /**
+   * @copydoc Graphics::Vulkan::Resource::InvokeDeleter()
+   * Only intended for use by discard queue.
+   */
+  void InvokeDeleter() override
+  {
+    this->~RenderTarget();
+  }
+
+  /**
    * @brief Returns framebuffer associated with the render target
    */
   [[nodiscard]] Vulkan::Framebuffer* GetFramebuffer() const;
@@ -91,4 +108,4 @@ private:
 
 } // namespace Dali::Graphics::Vulkan
 
-#endif //DALI_INTERNAL_GRAPHICS_VULKAN_RENDER_TARGET_H
+#endif // DALI_INTERNAL_GRAPHICS_VULKAN_RENDER_TARGET_H
index f35d100..b950c3d 100644 (file)
@@ -39,13 +39,25 @@ SamplerImpl::SamplerImpl(Device& device, const vk::SamplerCreateInfo& samplerCre
 {
 }
 
-SamplerImpl::~SamplerImpl() = default;
+SamplerImpl::~SamplerImpl()
+{
+  Destroy();
+}
 
 void SamplerImpl::Initialize()
 {
   VkAssert(mDevice.GetLogicalDevice().createSampler(&mCreateInfo, &mDevice.GetAllocator("SAMPLER"), &mSampler));
 }
 
+void SamplerImpl::Destroy()
+{
+  if(mSampler)
+  {
+    mDevice.GetLogicalDevice().destroySampler(mSampler);
+    mSampler = nullptr;
+  }
+}
+
 vk::Sampler SamplerImpl::GetVkHandle() const
 {
   return mSampler;
index e8f040e..7028627 100644 (file)
@@ -36,6 +36,8 @@ public:
 
   void Initialize();
 
+  void Destroy();
+
   /**
    * Returns VkSampler object
    * @return
index ffc2b5b..4ad402b 100644 (file)
@@ -24,7 +24,6 @@
 
 namespace Dali::Graphics::Vulkan
 {
-
 namespace
 {
 constexpr vk::Filter ConvertFilter(Dali::Graphics::SamplerFilter filter)
@@ -82,7 +81,11 @@ Sampler::~Sampler() = default;
 
 void Sampler::DestroyResource()
 {
-  // For now, no GPU resources are initialized so nothing to destroy
+  if(mSamplerImpl)
+  {
+    mSamplerImpl->Destroy();
+    mSamplerImpl = nullptr;
+  }
 }
 
 bool Sampler::InitializeResource()
index ac42ac0..715a66e 100644 (file)
@@ -48,7 +48,7 @@ public:
   /**
    * @brief Called when GPU resources are destroyed
    */
-  void DestroyResource();
+  void DestroyResource() override;
 
   /**
    * @brief Called when initializing the resource
@@ -67,6 +67,23 @@ public:
     return mSamplerImpl;
   }
 
+  /**
+   * @copydoc Graphics::Vulkan::Resource::GetAllocationCallbacks()
+   */
+  [[nodiscard]] const Graphics::AllocationCallbacks* GetAllocationCallbacks() const override
+  {
+    return mCreateInfo.allocationCallbacks;
+  }
+
+  /**
+   * @copydoc Graphics::Vulkan::Resource::InvokeDeleter()
+   * Only intended for use by discard queue.
+   */
+  void InvokeDeleter() override
+  {
+    this->~Sampler();
+  }
+
 private:
   SamplerImpl* mSamplerImpl;
 };
index 3ecc55a..fe89ecd 100644 (file)
@@ -163,6 +163,12 @@ uint32_t ShaderImpl::Release()
   return mImpl->refCount;
 }
 
+void ShaderImpl::Destroy()
+{
+  mImpl->Destroy();
+  mImpl.reset();
+}
+
 [[nodiscard]] uint32_t ShaderImpl::IncreaseFlushCount()
 {
   return ++mImpl->flushCount;
index 288dac4..06e90c3 100644 (file)
@@ -21,7 +21,9 @@
 // INTERNAL INCLUDES
 #include <dali/graphics-api/graphics-shader-create-info.h>
 #include <dali/graphics-api/graphics-shader.h>
-#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-resource.h>
+
+#include <dali/internal/graphics/vulkan-impl/vulkan-graphics-controller.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-types.h>
 
 // EXTERNAL INCLUDES
 #include <vulkan/vulkan.hpp>
@@ -36,7 +38,7 @@ public:
    * @param[in] createInfo Valid createInfo structure
    * @param[in] controller Reference to the controller
    */
-  ShaderImpl(const Graphics::ShaderCreateInfo& createInfo, Graphics::Vulkan::VulkanGraphicsController& controller);
+  ShaderImpl(const Graphics::ShaderCreateInfo& createInfo, VulkanGraphicsController& controller);
 
   /**
    * @brief destructor
@@ -62,6 +64,11 @@ public:
   [[nodiscard]] uint32_t GetRefCount() const;
 
   /**
+   * @brief Destroys Vulkan shader module
+   */
+  void Destroy();
+
+  /**
    * Whilst unreferenced, increase the flush count and return it
    *
    * @return The new flush count
@@ -83,11 +90,6 @@ public:
   [[nodiscard]] bool Compile() const;
 
   /**
-   * @brief Destroys Vulkan shader module
-   */
-  void Destroy();
-
-  /**
    * @brief Returns Vulkan resource
    * @return Valid Vulkan shader resource
    */
index ba41033..f98bf8a 100644 (file)
@@ -19,8 +19,8 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-surface-impl.h>
 
 // INTERNAL INCLUDES
-#include <dali/internal/graphics/vulkan/vulkan-device.h>
 #include <dali/integration-api/debug.h>
+#include <dali/internal/graphics/vulkan/vulkan-device.h>
 
 #if defined(DEBUG_ENABLED)
 extern Debug::Filter* gVulkanFilter;
@@ -29,13 +29,30 @@ extern Debug::Filter* gVulkanFilter;
 namespace Dali::Graphics::Vulkan
 {
 
-SurfaceImpl::SurfaceImpl( Device& device, vk::SurfaceKHR surfaceKhr)
-: mGraphicsDevice( device ),
+SurfaceImpl::SurfaceImpl(Device& device, vk::SurfaceKHR surfaceKhr)
+: mGraphicsDevice(device),
   mSurface(surfaceKhr)
 {
 }
 
-SurfaceImpl::~SurfaceImpl() = default;
+SurfaceImpl::~SurfaceImpl()
+{
+  Destroy();
+};
+
+void SurfaceImpl::Destroy()
+{
+  if(mSurface)
+  {
+    auto instance  = mGraphicsDevice.GetInstance();
+    auto surface   = mSurface;
+    auto allocator = &mGraphicsDevice.GetAllocator();
+
+    DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying surface: %p\n", static_cast<VkSurfaceKHR>(surface));
+    instance.destroySurfaceKHR(surface, allocator);
+    mSurface = nullptr;
+  }
+}
 
 vk::SurfaceKHR SurfaceImpl::GetVkHandle() const
 {
@@ -54,42 +71,43 @@ vk::SurfaceCapabilitiesKHR& SurfaceImpl::GetCapabilities()
 
 bool SurfaceImpl::GetSupportedFormats(
   vk::SurfaceFormatKHR requestedFormat,
-  vk::Format& swapchainImageFormat,
-  vk::ColorSpaceKHR& swapchainColorSpace)
+  vk::Format&          swapchainImageFormat,
+  vk::ColorSpaceKHR&   swapchainColorSpace)
 {
-  bool found=false;
-  auto supportedFormats = VkAssert( mGraphicsDevice.GetPhysicalDevice().getSurfaceFormatsKHR( mSurface ) );
+  bool found            = false;
+  auto supportedFormats = VkAssert(mGraphicsDevice.GetPhysicalDevice().getSurfaceFormatsKHR(mSurface));
 
   // If the surface format list only includes one entry with VK_FORMAT_UNDEFINED,
   // there is no preferred format, so we assume vk::Format::eB8G8R8A8Unorm
-  if( supportedFormats.size() == 1 && supportedFormats[0].format == vk::Format::eUndefined )
+  if(supportedFormats.size() == 1 && supportedFormats[0].format == vk::Format::eUndefined)
   {
-    swapchainColorSpace = supportedFormats[0].colorSpace;
+    swapchainColorSpace  = supportedFormats[0].colorSpace;
     swapchainImageFormat = vk::Format::eB8G8R8A8Unorm;
   }
   else // Try to find the requested format in the list
   {
     auto iter = std::find_if(supportedFormats.begin(),
                              supportedFormats.end(),
-                             [ & ]( vk::SurfaceFormatKHR supportedFormat ) {
+                             [&](vk::SurfaceFormatKHR supportedFormat)
+                             {
                                return requestedFormat == supportedFormat.format;
-                             } );
+                             });
     // If found assign it.
-    if( iter != supportedFormats.end() )
+    if(iter != supportedFormats.end())
     {
-      found = true;
-      auto surfaceFormat = *iter;
-      swapchainColorSpace = surfaceFormat.colorSpace;
+      found                = true;
+      auto surfaceFormat   = *iter;
+      swapchainColorSpace  = surfaceFormat.colorSpace;
       swapchainImageFormat = surfaceFormat.format;
     }
     else // Requested format not found...attempt to use the first one on the list
     {
-      auto surfaceFormat = supportedFormats[0];
-      swapchainColorSpace = surfaceFormat.colorSpace;
+      auto surfaceFormat   = supportedFormats[0];
+      swapchainColorSpace  = surfaceFormat.colorSpace;
       swapchainImageFormat = surfaceFormat.format;
     }
   }
-  assert( swapchainImageFormat != vk::Format::eUndefined && "Could not find a supported swap chain image format." );
+  assert(swapchainImageFormat != vk::Format::eUndefined && "Could not find a supported swap chain image format.");
   return found;
 }
 
@@ -99,29 +117,10 @@ std::vector<vk::PresentModeKHR> SurfaceImpl::GetSurfacePresentModes()
   return presentModes;
 }
 
-void SurfaceImpl::UpdateSize( unsigned int width, unsigned int height )
+void SurfaceImpl::UpdateSize(unsigned int width, unsigned int height)
 {
-  mCapabilities.currentExtent.width = width;
+  mCapabilities.currentExtent.width  = width;
   mCapabilities.currentExtent.height = height;
 }
 
-bool SurfaceImpl::OnDestroy()
-{
-  if( mSurface )
-  {
-    auto instance = mGraphicsDevice.GetInstance();
-    auto surface = mSurface;
-    auto allocator = &mGraphicsDevice.GetAllocator();
-
-    mGraphicsDevice.DiscardResource( [ instance, surface, allocator ]() {
-      DALI_LOG_INFO( gVulkanFilter, Debug::General, "Invoking deleter function: surface->%p\n",
-                     static_cast< VkSurfaceKHR >( surface ) )
-      instance.destroySurfaceKHR( surface, allocator );
-    } );
-
-    mSurface = nullptr;
-  }
-  return false;
-}
-
 } // namespace Dali::Graphics::Vulkan
index 0542131..7374465 100644 (file)
@@ -25,12 +25,14 @@ namespace Dali::Graphics::Vulkan
 {
 class Device;
 
-class SurfaceImpl final : public Dali::Graphics::Vulkan::VkManaged
+class SurfaceImpl
 {
 public:
   explicit SurfaceImpl(Device& device, vk::SurfaceKHR surfaceKhr);
 
-  ~SurfaceImpl() final;
+  ~SurfaceImpl();
+
+  void Destroy();
 
   /**
    * @return the handle to this surface
@@ -57,16 +59,14 @@ public:
    */
   bool GetSupportedFormats(
     vk::SurfaceFormatKHR requestedFormat,
-    vk::Format& swapchainImageFormat,
-    vk::ColorSpaceKHR& swapchainColorSpace);
+    vk::Format&          swapchainImageFormat,
+    vk::ColorSpaceKHR&   swapchainColorSpace);
 
   /**
    * Update size of surface
    */
   void UpdateSize(unsigned int width, unsigned int height);
 
-  bool OnDestroy() override;
-
 private:
   Device&                    mGraphicsDevice;
   vk::SurfaceKHR             mSurface;
index 1f4f0ae..87ea40c 100644 (file)
@@ -100,7 +100,9 @@ Swapchain::Swapchain(Device& graphicsDevice, Queue& presentationQueue)
 {
 }
 
-Swapchain::~Swapchain() = default;
+Swapchain::~Swapchain()
+{
+}
 
 void Swapchain::CreateVkSwapchain(
   vk::SwapchainKHR   oldSwapchain,
@@ -161,7 +163,8 @@ void Swapchain::CreateVkSwapchain(
   auto presentModes = surface->GetSurfacePresentModes();
   auto found        = std::find_if(presentModes.begin(),
                             presentModes.end(),
-                            [&](vk::PresentModeKHR mode) {
+                            [&](vk::PresentModeKHR mode)
+                            {
                               return presentMode == mode;
                             });
 
@@ -193,6 +196,22 @@ void Swapchain::CreateVkSwapchain(
   mSwapchainKHR = VkAssert(mGraphicsDevice.GetLogicalDevice().createSwapchainKHR(mSwapchainCreateInfoKHR, mGraphicsDevice.GetAllocator()));
 }
 
+void Swapchain::Destroy()
+{
+  if(mSwapchainKHR)
+  {
+    auto device    = mGraphicsDevice.GetLogicalDevice();
+    auto swapchain = mSwapchainKHR;
+    auto allocator = &mGraphicsDevice.GetAllocator();
+    mFramebuffers.clear();
+    mSwapchainBuffers.clear();
+
+    DALI_LOG_INFO(gVulkanFilter, Debug::General, "Destroying SwapChain: %p\n", static_cast<VkSwapchainKHR>(swapchain));
+    device.destroySwapchainKHR(swapchain, allocator);
+    mSwapchainKHR = nullptr;
+  }
+}
+
 void Swapchain::CreateFramebuffers()
 {
   assert(mSwapchainKHR && "Needs a swapchain before creating framebuffers");
@@ -227,19 +246,28 @@ void Swapchain::CreateFramebuffers()
                                                               mSwapchainCreateInfoKHR.imageFormat,
                                                               mSwapchainCreateInfoKHR.imageExtent);
 
-    auto colorImageView = ImageView::NewFromImage(mGraphicsDevice, *colorImage);
+    std::unique_ptr<ImageView> colorImageView;
+    colorImageView.reset(ImageView::NewFromImage(mGraphicsDevice, *colorImage));
 
     // A new color attachment for each framebuffer
-    auto colorAttachment = FramebufferAttachment::NewColorAttachment(colorImageView,
-                                                                     clearColor,
-                                                                     true); // presentable
-
-    mFramebuffers.push_back(FramebufferImpl::New(mGraphicsDevice,
-                                                 compatibleRenderPass,
-                                                 {colorAttachment},
-                                                 nullptr,
-                                                 mSwapchainCreateInfoKHR.imageExtent.width,
-                                                 mSwapchainCreateInfoKHR.imageExtent.height));
+    OwnedAttachments attachments;
+    attachments.emplace_back(FramebufferAttachment::NewColorAttachment(colorImageView,
+                                                                       clearColor,
+                                                                       true));
+    std::unique_ptr<FramebufferAttachment>                       depthAttachment;
+    std::unique_ptr<FramebufferImpl, void (*)(FramebufferImpl*)> framebuffer(
+      FramebufferImpl::New(mGraphicsDevice,
+                           compatibleRenderPass,
+                           attachments,
+                           depthAttachment,
+                           mSwapchainCreateInfoKHR.imageExtent.width,
+                           mSwapchainCreateInfoKHR.imageExtent.height),
+      [](FramebufferImpl* framebuffer1)
+      {
+        framebuffer1->Destroy();
+        delete framebuffer1;
+      });
+    mFramebuffers.push_back(std::move(framebuffer));
 
     if(compatibleRenderPass == nullptr)
     {
@@ -264,7 +292,7 @@ FramebufferImpl* Swapchain::GetCurrentFramebuffer() const
 
 FramebufferImpl* Swapchain::GetFramebuffer(uint32_t index) const
 {
-  return mFramebuffers[index];
+  return mFramebuffers[index].get();
 }
 
 FramebufferImpl* Swapchain::AcquireNextFramebuffer(bool shouldCollectGarbageNow)
@@ -319,8 +347,8 @@ FramebufferImpl* Swapchain::AcquireNextFramebuffer(bool shouldCollectGarbageNow)
   // cause a stall ( nvidia, ubuntu )
   if(mFrameCounter >= mSwapchainBuffers.size())
   {
-    vk::Result result = swapchainBuffer->endOfFrameFence->GetStatus();
-    if(result == vk::Result::eNotReady)
+    vk::Result status = swapchainBuffer->endOfFrameFence->GetStatus();
+    if(status == vk::Result::eNotReady)
     {
       swapchainBuffer->endOfFrameFence->Wait();
       swapchainBuffer->endOfFrameFence->Reset();
@@ -332,7 +360,7 @@ FramebufferImpl* Swapchain::AcquireNextFramebuffer(bool shouldCollectGarbageNow)
   }
   // mGraphicsDevice.CollectGarbage();
 
-  return mFramebuffers[mSwapchainImageIndex];
+  return mFramebuffers[mSwapchainImageIndex].get();
 }
 
 void Swapchain::Submit(CommandBufferImpl* commandBuffer)
@@ -391,23 +419,6 @@ void Swapchain::Present()
   mFrameCounter++;
 }
 
-bool Swapchain::OnDestroy()
-{
-  if(mSwapchainKHR)
-  {
-    auto device    = mGraphicsDevice.GetLogicalDevice();
-    auto swapchain = mSwapchainKHR;
-    auto allocator = &mGraphicsDevice.GetAllocator();
-
-    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); });
-
-    mSwapchainKHR = nullptr;
-  }
-  return false;
-}
-
 bool Swapchain::IsValid() const
 {
   return mIsValid;
index aacaa73..9238047 100644 (file)
@@ -33,7 +33,7 @@ class SwapchainBuffer;
 /**
  * Creates swapchain for given surface and queue
  */
-class Swapchain : public VkManaged
+class Swapchain
 {
 public:
   static Swapchain* NewSwapchain(
@@ -47,11 +47,13 @@ public:
 
   Swapchain(Device& graphicsDevice, Queue& presentationQueue);
 
-  ~Swapchain() override;
+  ~Swapchain();
 
   Swapchain(const Swapchain&)            = delete;
   Swapchain& operator=(const Swapchain&) = delete;
 
+  void Destroy();
+
   /**
    * Automatically create framebuffers (generating compatible render passes)
    */
@@ -94,8 +96,6 @@ public:
    */
   void Present();
 
-  bool OnDestroy() override;
-
   /**
    * Returns true when swapchain expired
    * @return
@@ -143,16 +143,14 @@ private:
   /**
    * FramebufferImpl object associated with the buffer
    */
-  std::vector<FramebufferImpl*> mFramebuffers;
+  using OwnedFramebuffer = std::unique_ptr<FramebufferImpl, void (*)(FramebufferImpl*)>;
+  std::vector<OwnedFramebuffer> mFramebuffers;
 
   /**
    * Array of swapchain buffers
    */
   std::vector<std::unique_ptr<SwapchainBuffer>> mSwapchainBuffers;
-
-  FenceImpl* mBetweenRenderPassFence{};
-
-  uint32_t mFrameCounter{0u}; ///< Current frame number
+  uint32_t                                      mFrameCounter{0u}; ///< Current frame number
 
   bool mIsValid; // indicates whether the swapchain is still valid or requires to be recreated
 };
index fa6a1f8..2121f0b 100644 (file)
@@ -928,7 +928,8 @@ bool Texture::TryConvertPixelData(const void* pData, uint32_t sizeInBytes, uint3
     return false;
   }
 
-  auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item) { return item.oldFormat == mConvertFromFormat; });
+  auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item)
+                         { return item.oldFormat == mConvertFromFormat; });
 
   // No suitable format, return empty array
   if(it == COLOR_CONVERSION_TABLE.end())
@@ -950,7 +951,8 @@ bool Texture::TryConvertPixelData(const void* pData, uint32_t sizeInBytes, uint3
     return false;
   }
 
-  auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item) { return item.oldFormat == mConvertFromFormat; });
+  auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item)
+                         { return item.oldFormat == mConvertFromFormat; });
 
   // No suitable format, return empty array
   if(it == COLOR_CONVERSION_TABLE.end())
@@ -1099,7 +1101,8 @@ vk::Format Texture::ValidateFormat(vk::Format sourceFormat)
   // if format isn't supported, see whether suitable conversion is implemented
   if(!formatFlags)
   {
-    auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item) { return item.oldFormat == sourceFormat; });
+    auto it = std::find_if(COLOR_CONVERSION_TABLE.begin(), COLOR_CONVERSION_TABLE.end(), [&](auto& item)
+                           { return item.oldFormat == sourceFormat; });
 
     // No suitable format, return empty array
     if(it != COLOR_CONVERSION_TABLE.end())
@@ -1160,10 +1163,26 @@ bool Texture::InitializeResource()
 
 void Texture::DestroyResource()
 {
+  if(mImageView)
+  {
+    mImageView->Destroy();
+    mImageView = nullptr;
+  }
+  if(mImage)
+  {
+    mImage->Destroy();
+    mImage = nullptr;
+  }
+  if(mSampler)
+  {
+    mSampler->Destroy();
+    mSampler = nullptr;
+  }
 }
 
 void Texture::DiscardResource()
 {
+  mController.DiscardResource(this);
 }
 
 void Texture::SetFormatAndUsage()
index b64f977..d3d16be 100644 (file)
@@ -42,11 +42,36 @@ public:
   Texture(const Graphics::TextureCreateInfo& createInfo, VulkanGraphicsController& controller);
   ~Texture();
 
+  /**
+   * @copydoc Graphics::Vulkan::Resource::InitializeResource();
+   */
   bool InitializeResource() override;
 
+  /**
+   * @copydoc Graphics::Vulkan::Resource::DiscardResource();
+   */
+  void DiscardResource() override;
+  /**
+   * @copydoc Graphics::Vulkan::Resource::DestroyResource();
+   */
   void DestroyResource() override;
 
-  void DiscardResource() override;
+  /**
+   * @copydoc Graphics::Vulkan::Resource::GetAllocationCallbacks()
+   */
+  [[nodiscard]] const Graphics::AllocationCallbacks* GetAllocationCallbacks() const override
+  {
+    return mCreateInfo.allocationCallbacks;
+  }
+
+  /**
+   * @copydoc Graphics::Vulkan::Resource::InvokeDeleter()
+   * Only intended for use by discard queue.
+   */
+  void InvokeDeleter() override
+  {
+    this->~Texture();
+  }
 
   bool IsSamplerImmutable() const;
 
index 5d9b1e0..1810932 100644 (file)
@@ -35,7 +35,6 @@
 
 namespace Dali::Graphics
 {
-
 namespace
 {
 // Default value use to clear the stencil buffer
@@ -50,7 +49,6 @@ std::unique_ptr<T> MakeUnique(Args&&... args)
 
 namespace Vulkan
 {
-
 /**
  * Forward class declarations
  */
@@ -194,12 +192,12 @@ struct VkStoreOpType
   vk::AttachmentStoreOp storeOp{vk::AttachmentStoreOp::eDontCare};
 };
 
-class VkManaged
+class VkSharedResource // E.g. render pass
 {
 public:
-  VkManaged() = default;
+  VkSharedResource() = default;
 
-  virtual ~VkManaged() = default;
+  virtual ~VkSharedResource() = default;
 
   void Release()
   {
index 2796b7f..5065b96 100644 (file)
@@ -95,6 +95,7 @@ Device::~Device()
   DALI_LOG_STREAM(gVulkanFilter, Debug::General, "DESTROYING GRAPHICS CONTEXT--------------------------------\n");
 
   SwapBuffers();
+  ReleaseCommandPools();
 
   // We are done with all resources (technically... . If not we will get a ton of validation layer errors)
   // Kill the Vulkan logical device
@@ -379,7 +380,8 @@ Swapchain* Device::CreateSwapchain(SurfaceImpl*       surface,
     // during replacing the swapchain
     auto khr = oldSwapchain->GetVkHandle();
     oldSwapchain->SetVkHandle(nullptr);
-    oldSwapchain->Release();
+    oldSwapchain->Destroy();
+    delete oldSwapchain;
 
     mLogicalDevice.destroySwapchainKHR(khr, *mAllocator);
   }
@@ -437,8 +439,8 @@ Queue& Device::GetPresentQueue() const
 
 void Device::DiscardResource(std::function<void()> deleter)
 {
-  // std::lock_guard< std::mutex > lock( mMutex );
-  // mDiscardQueue[mCurrentBufferIndex].push_back( std::move( deleter ) );
+  // For now, just call immediately.
+  deleter();
 }
 
 Image* Device::CreateImageFromExternal(vk::Image externalImage, vk::Format imageFormat, vk::Extent2D extent)
@@ -543,6 +545,15 @@ CommandPool* Device::GetCommandPool(std::thread::id threadId)
   return commandPool;
 }
 
+void Device::ReleaseCommandPools()
+{
+  for(auto& commandPool : mCommandPools)
+  {
+    commandPool.second->Reset(true);
+    delete commandPool.second;
+  }
+}
+
 void Device::SurfaceResized(unsigned int width, unsigned int height)
 {
   // Get main window's surface
index 3742807..e40de4b 100644 (file)
@@ -153,6 +153,8 @@ private: // Methods
 
   std::vector<const char*> PrepareDefaultInstanceExtensions();
 
+  void ReleaseCommandPools();
+
 private: // Members
   vk::PhysicalDevice mPhysicalDevice;
   vk::Device         mLogicalDevice;
@@ -166,10 +168,10 @@ private: // Members
   std::vector<vk::QueueFamilyProperties> mQueueFamilyProperties;
 
   // Sets of queues
-  std::vector<std::unique_ptr<Queue> > mAllQueues;
-  std::vector<Queue*>                  mGraphicsQueues;
-  std::vector<Queue*>                  mTransferQueues;
-  std::vector<Queue*>                  mComputeQueues;
+  std::vector<std::unique_ptr<Queue>> mAllQueues;
+  std::vector<Queue*>                 mGraphicsQueues;
+  std::vector<Queue*>                 mTransferQueues;
+  std::vector<Queue*>                 mComputeQueues;
 
   CommandPoolMap mCommandPools;
 
index 43ffa2b..e9680d7 100644 (file)
@@ -98,9 +98,9 @@ Graphics::SurfaceId VulkanGraphics::CreateSurface(
   return surfaceId;
 }
 
-void VulkanGraphics::DestroySurface(Graphics::SurfaceId)
+void VulkanGraphics::DestroySurface(Graphics::SurfaceId surfaceId)
 {
-  // @todo Destroy swapchain.
+  mGraphicsDevice.DestroySurface(surfaceId);
 }
 
 bool VulkanGraphics::ReplaceSurface(Graphics::SurfaceId surface, int width, int height)
@@ -132,6 +132,7 @@ void VulkanGraphics::Shutdown()
 
 void VulkanGraphics::Destroy()
 {
+  mGraphicsController.RunGarbageCollector(0);
 }
 
 void VulkanGraphics::Pause()