--- /dev/null
+#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
#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>
bool Initialize(Vulkan::Device& device)
{
mGraphicsDevice = &device;
+ mDiscardQueues.Initialize(device);
// @todo Create pipeline cache & descriptor set allocator here
}
}
- 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;
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{};
VulkanGraphicsController::~VulkanGraphicsController()
{
- mImpl->GarbageCollect();
+ mImpl->GarbageCollect(true);
}
void VulkanGraphicsController::Initialize(Dali::Graphics::VulkanGraphics& graphicsImplementation,
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)
void VulkanGraphicsController::Destroy()
{
+ mImpl->Flush();
}
void VulkanGraphicsController::UpdateTextures(
void VulkanGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
{
- mImpl->GarbageCollect();
+ mImpl->GarbageCollect(false);
}
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()
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)
#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.
*/
void DiscardResource(Vulkan::ResourceBase* resource);
- void DiscardResource(Vulkan::ResourceWithDeleter* program);
-
/**
* @brief Maps memory associated with Buffer object
*
#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.
*/
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;
};
#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.
/**
* @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;
#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.
* 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:
/**