Re-factoring vk discard queues. 57/320157/3
authorDavid Steele <david.steele@samsung.com>
Fri, 21 Feb 2025 19:33:51 +0000 (19:33 +0000)
committerDavid Steele <david.steele@samsung.com>
Wed, 26 Feb 2025 11:34:09 +0000 (11:34 +0000)
Changed Resource, so now we have ResourceWithDeleter
and ResourceWithoutDeleter, but ResourceBase can be used
as common type with calls to GetAllocationCallbacks and
InvokeDeleter.

(Note, only Program/Pipeline objects currently inherit
from ResourceWithoutDeleter, as these are proxy objects
into a cache)

Means that the DiscardQueue is simplified so it only
deals with ResourceBase objects. (Don't have to do
specialization magic depending on resource type).

Change-Id: If8538fa9bbdae9fb6f5b3aeb183c25b9523c673b

dali/internal/graphics/vulkan-impl/vulkan-discard-queue.h [new file with mode: 0644]
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-pipeline.h
dali/internal/graphics/vulkan-impl/vulkan-program.h

diff --git a/dali/internal/graphics/vulkan-impl/vulkan-discard-queue.h b/dali/internal/graphics/vulkan-impl/vulkan-discard-queue.h
new file mode 100644 (file)
index 0000000..003e4ae
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef VULKAN_DISCARD_QUEUE_H
+#define VULKAN_DISCARD_QUEUE_H
+
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <dali/internal/graphics/vulkan/vulkan-device.h>
+#include <memory>
+#include <queue>
+
+namespace Dali::Graphics::Vulkan
+{
+class Device;
+
+/**
+ * @brief DiscardQueues holds a growable number of queues to hold
+ * resource data until it's no longer in use and can safely be
+ * discarded.
+ *
+ * The number of discard queues corresponds to the number of swapchain
+ * images that can be drawn to, and isn't known at creation time.
+ * Instead, the vector of queues grows to match the bufferIndex of the
+ * current frame.
+ * In practice, this is either 2 or 3.
+ *
+ * @tparam ResourceType The resource type for this discard queue
+ */
+template<class ResourceType>
+class DiscardQueues
+{
+public:
+  DiscardQueues()
+  : mDevice(nullptr),
+    mQueues()
+  {
+    // Nothing to do.
+  }
+
+  /**
+   * Initialize the object.
+   * @param[in] device The vulkan device
+   */
+  void Initialize(Device& device)
+  {
+    mDevice = &device;
+  }
+
+  using DiscardQueue               = std::queue<ResourceType*>;
+  using OwnedDiscardQueue          = std::unique_ptr<DiscardQueue>;
+  using OwnedDiscardQueueContainer = std::vector<OwnedDiscardQueue>;
+
+  /**
+   * Check if we need to increase the number of queues.
+   *
+   * If we do need more queues, resize the vector, but don't allocate until
+   * we need to discard resources into it.
+   *
+   * @param[in] bufferCount The current number of swapchain buffers
+   */
+  void Resize(uint32_t bufferCount)
+  {
+    if(mQueues.size() < bufferCount)
+    {
+      mQueues.resize(bufferCount);
+    }
+  }
+
+  /**
+   * Discard the resource - add to this frame's queue.
+   * If there is no queue for this buffer index, create a queue.
+   *
+   * @param[in] resource The resource to discard
+   */
+  void Discard(ResourceType* resource)
+  {
+    DALI_ASSERT_DEBUG(mDevice && "No graphics device available");
+    uint32_t bufferIndex = mDevice->GetCurrentBufferIndex();
+
+    // Ensure there is a discard queue for this buffer index
+    if(mQueues.size() < bufferIndex || !mQueues[bufferIndex])
+    {
+      for(auto i = 0u; i <= bufferIndex; ++i)
+      {
+        if(!mQueues[i])
+        {
+          mQueues[i] = std::make_unique<std::queue<ResourceType*>>();
+        }
+      }
+    }
+    mQueues[bufferIndex]->push(resource);
+  }
+
+  /**
+   * @brief Processes a discard queue for objects created with NewObject
+   *
+   * @param[in] bufferIndex The buffer index of the oldest queue
+   */
+  void Process(uint32_t bufferIndex)
+  {
+    if(bufferIndex < mQueues.size())
+    {
+      auto& queue = mQueues[bufferIndex];
+      while(queue && !queue->empty())
+      {
+        auto* object = const_cast<ResourceType*>(queue->front());
+
+        // Destroy the resource
+        object->DestroyResource();
+
+        // If there are allocation callbacks, then invoke the deleter and
+        // execute the callback.
+        auto* allocationCallbacks = object->GetAllocationCallbacks();
+        if(allocationCallbacks)
+        {
+          object->InvokeDeleter();
+          allocationCallbacks->freeCallback(object, allocationCallbacks->userData);
+        }
+        else
+        {
+          // Otherwise, just delete the object.
+          delete object;
+        }
+        queue->pop();
+      }
+    }
+  }
+
+  /**
+   * Check if the discard queue is empty.
+   *
+   * @param bufferIndex The buffer index of the current frame
+   * @return true if the discard queue is empty for this frame
+   */
+  bool IsEmpty(uint32_t bufferIndex)
+  {
+    if(bufferIndex < mQueues.size())
+    {
+      return mQueues[bufferIndex]->empty();
+    }
+    return true;
+  }
+
+private:
+  Device*                    mDevice;
+  OwnedDiscardQueueContainer mQueues;
+};
+
+} // namespace Dali::Graphics::Vulkan
+
+#endif // VULKAN_DISCARD_QUEUE_H
index 9c87f72f4f1018f8235e0304325e0db8d3d592fc..dc908ad3557347d0fcb617cafc91caa655b6851b 100644 (file)
@@ -26,8 +26,8 @@
 #include <dali/internal/graphics/vulkan-impl/vulkan-buffer.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-command-buffer-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-command-buffer.h>
+#include <dali/internal/graphics/vulkan-impl/vulkan-discard-queue.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-fence-impl.h>
-#include <dali/internal/graphics/vulkan-impl/vulkan-framebuffer-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-image-impl.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-memory.h>
 #include <dali/internal/graphics/vulkan-impl/vulkan-pipeline.h>
@@ -160,6 +160,7 @@ struct VulkanGraphicsController::Impl
   bool Initialize(Vulkan::Device& device)
   {
     mGraphicsDevice = &device;
+    mDiscardQueues.Initialize(device);
 
     // @todo Create pipeline cache & descriptor set allocator here
 
@@ -455,98 +456,28 @@ struct VulkanGraphicsController::Impl
     }
   }
 
-  template<class ResourceType>
-  void DiscardResource(std::vector<std::unique_ptr<std::queue<ResourceType*>>>& queue, ResourceType* resource)
-  {
-    uint32_t bufferIndex = mGraphicsDevice->GetCurrentBufferIndex();
-
-    // Ensure there is a discard queue for this buffer index
-    if(queue.size() < bufferIndex || !queue[bufferIndex])
-    {
-      for(auto i = 0u; i <= bufferIndex; ++i)
-      {
-        if(!queue[i])
-        {
-          queue[i] = std::make_unique<std::queue<ResourceType*>>();
-        }
-      }
-    }
-    queue[bufferIndex]->push(resource);
-  }
-
-  /**
-   * @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)
-  {
-    if(queue != nullptr)
-    {
-      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)
-  {
-    if(queue != nullptr)
-    {
-      while(!queue->empty())
-      {
-        auto* object = queue->front();
-
-        // Destroy
-        object->DestroyResource();
-        delete object;
-
-        queue->pop();
-      }
-    }
-  }
-
-  void GarbageCollect()
+  void GarbageCollect(bool allQueues)
   {
     // Only garbage collect from the oldest discard queue.
     auto bufferIndex = mGraphicsDevice->GetCurrentBufferIndex() + 1;
     bufferIndex %= mGraphicsDevice->GetBufferCount();
-    if(bufferIndex < mResourceDiscardQueues.size())
+    if(!allQueues)
     {
-      ProcessResourceDiscardQueue<ResourceWithDeleter>(mResourceDiscardQueues[bufferIndex].get());
+      mDiscardQueues.Process(bufferIndex);
     }
-    if(bufferIndex < mDiscardQueues.size())
+    else
     {
-      ProcessDiscardQueue<ResourceBase>(mDiscardQueues[bufferIndex].get());
+      for(uint32_t i = 0; i < mGraphicsDevice->GetBufferCount(); i++)
+      {
+        mDiscardQueues.Process(i);
+      }
     }
   }
 
   void Flush()
   {
     // Flush any outstanding queues.
-
-    GarbageCollect();
+    GarbageCollect(false);
   }
 
   VulkanGraphicsController& mGraphicsController;
@@ -558,10 +489,7 @@ struct VulkanGraphicsController::Impl
   std::vector<ResourceTransferRequest> mResourceTransferRequests;
   std::recursive_mutex                 mResourceTransferMutex{};
 
-  using DiscardQueues         = std::vector<std::unique_ptr<std::queue<ResourceBase*>>>;
-  using ResourceDiscardQueues = std::vector<std::unique_ptr<std::queue<ResourceWithDeleter*>>>;
-  DiscardQueues         mDiscardQueues;
-  ResourceDiscardQueues mResourceDiscardQueues;
+  DiscardQueues<ResourceBase> mDiscardQueues;
 
   std::unique_ptr<Vulkan::Buffer>       mTextureStagingBuffer{};
   Dali::SharedFuture                    mTextureStagingBufferFuture{};
@@ -586,7 +514,7 @@ VulkanGraphicsController::VulkanGraphicsController()
 
 VulkanGraphicsController::~VulkanGraphicsController()
 {
-  mImpl->GarbageCollect();
+  mImpl->GarbageCollect(true);
 }
 
 void VulkanGraphicsController::Initialize(Dali::Graphics::VulkanGraphics& graphicsImplementation,
@@ -607,12 +535,7 @@ void VulkanGraphicsController::FrameStart()
   mImpl->mCapacity = 0;
   // Check the size of the discard queues.
   auto bufferCount = mImpl->mGraphicsDevice->GetBufferCount();
-  if(bufferCount > mImpl->mDiscardQueues.size())
-  {
-    mImpl->mDiscardQueues.resize(bufferCount);
-    mImpl->mResourceDiscardQueues.resize(bufferCount);
-    // Leave as unset uniq ptrs - discarding resource will allocate q as needed
-  }
+  mImpl->mDiscardQueues.Resize(bufferCount);
 }
 
 void VulkanGraphicsController::SetResourceBindingHints(const std::vector<SceneResourceBinding>& resourceBindings)
@@ -706,6 +629,7 @@ void VulkanGraphicsController::Shutdown()
 
 void VulkanGraphicsController::Destroy()
 {
+  mImpl->Flush();
 }
 
 void VulkanGraphicsController::UpdateTextures(
@@ -989,7 +913,7 @@ bool VulkanGraphicsController::EnableDepthStencilBuffer(
 
 void VulkanGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
 {
-  mImpl->GarbageCollect();
+  mImpl->GarbageCollect(false);
 }
 
 void VulkanGraphicsController::DiscardUnusedResources()
@@ -999,7 +923,7 @@ void VulkanGraphicsController::DiscardUnusedResources()
 bool VulkanGraphicsController::IsDiscardQueueEmpty()
 {
   auto bufferIndex = mImpl->mGraphicsDevice->GetCurrentBufferIndex();
-  return mImpl->mResourceDiscardQueues[bufferIndex]->empty() && mImpl->mDiscardQueues[bufferIndex]->empty();
+  return mImpl->mDiscardQueues.IsEmpty(bufferIndex);
 }
 
 bool VulkanGraphicsController::IsDrawOnResumeRequired()
@@ -1071,12 +995,7 @@ UniquePtr<Graphics::SyncObject> VulkanGraphicsController::CreateSyncObject(const
 
 void VulkanGraphicsController::DiscardResource(ResourceBase* resource)
 {
-  mImpl->DiscardResource(mImpl->mDiscardQueues, resource);
-}
-
-void VulkanGraphicsController::DiscardResource(ResourceWithDeleter* resource)
-{
-  mImpl->DiscardResource(mImpl->mResourceDiscardQueues, resource);
+  mImpl->mDiscardQueues.Discard(resource);
 }
 
 UniquePtr<Graphics::Memory> VulkanGraphicsController::MapBufferRange(const MapBufferInfo& mapInfo)
index ca185a7f402b159dff2e49f4d5951c32040d0cfd..eeb0e868ac021e74c674ad81b3fdc52f172666c9 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GRAPHICS_VULKAN_CONTROLLER_IMPL_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -282,8 +282,6 @@ public:
    */
   void DiscardResource(Vulkan::ResourceBase* resource);
 
-  void DiscardResource(Vulkan::ResourceWithDeleter* program);
-
   /**
    * @brief Maps memory associated with Buffer object
    *
index 4d145c9b0a2073e8e750803ca26dc470d0f339e2..79a32c967fb0b9845c74486a8c90efb35beecbc8 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_INTERNAL_GRAPHICS_VULKAN_RESOURCE_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,22 +53,32 @@ public:
    */
   virtual void DiscardResource() = 0;
 
+  virtual void InvokeDeleter() = 0;
+
+  [[nodiscard]] virtual const Graphics::AllocationCallbacks* GetAllocationCallbacks() const = 0;
+
   virtual ~ResourceBase() = default;
 };
 
-class ResourceWithDeleter : public ResourceBase
+class ResourceWithoutDeleter : public ResourceBase
 {
-public:
-  /**
-   * @brief Get the allocation callbacks for this object
-   */
-  [[nodiscard]] virtual const Graphics::AllocationCallbacks* GetAllocationCallbacks() const = 0;
+  [[nodiscard]] const Graphics::AllocationCallbacks* GetAllocationCallbacks() const override
+  {
+    return nullptr;
+  }
 
-  /**
-   * @brief Invoke the deleter of the derived type.
-   */
-  virtual void InvokeDeleter() = 0;
+  void InvokeDeleter() override
+  {
+    delete this;
+  }
+};
 
+/**
+ * Resource must implement GetAllocationCallbacks and InvokeDeleter.
+ */
+class ResourceWithDeleter : public ResourceBase
+{
+public:
   ~ResourceWithDeleter() override = default;
 };
 
index 8f3d16b6c397177b1e079f40fe9bce1e79734a74..6ba9dcfc819b855c97c329f2f470377a1c44c96a 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_VULKAN_PIPELINE_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@ class PipelineCache;
 /**
  * @brief Pipeline class wraps the PipelineImpl
  */
-class Pipeline : public Graphics::Pipeline, public Vulkan::ResourceBase
+class Pipeline : public Graphics::Pipeline, public Vulkan::ResourceWithoutDeleter
 {
 public:
   Pipeline() = delete;
index bc19a4264a2eaefd8a6bbbfa9eb22f4eb21bf219..32c5c6a3098994e3c7e9898372d52f52402095cb 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_GRAPHICS_VULKAN_PROGRAM_H
 
 /*
- * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,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, public Vulkan::ResourceBase
+class Program : public Graphics::Program, public Vulkan::ResourceWithoutDeleter
 {
 public:
   /**