{
}
+BufferImpl::~BufferImpl()
+{
+ Destroy();
+}
+
void BufferImpl::Initialize(vk::MemoryPropertyFlags memoryProperties)
{
// Allocate
}
}
-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()
#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
* @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;
#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)
{
}
mBufferPtr = nullptr;
}
- // Deestroy GPU allocation
- else
+ else // Destroy GPU allocation
{
delete(mBufferImpl);
mBufferImpl = nullptr;
* @copydoc Graphics::Vulkan::Resource::InitializeResource();
*/
bool InitializeResource() override;
- void InitializeCPUBuffer();
- void InitializeGPUBuffer();
/**
* @return false - Vulkan should always allocate GPU buffers
*/
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()
return nullptr;
}
+private:
+ void InitializeCPUBuffer();
+ void InitializeGPUBuffer();
+
private:
union
{
{
}
-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,
auto info = vk::CommandBufferBeginInfo{};
vk::CommandBufferInheritanceInfo defaultInheritanceInfo{};
- defaultInheritanceInfo.sType = vk::StructureType::eCommandBufferInheritanceInfo;
defaultInheritanceInfo.pNext = nullptr;
defaultInheritanceInfo.subpass = 0;
defaultInheritanceInfo.occlusionQueryEnable = false;
return mPoolAllocationIndex;
}
-bool CommandBufferImpl::OnDestroy()
-{
- mOwnerCommandPool->ReleaseCommandBuffer(*this);
- return true;
-}
-
void CommandBufferImpl::Draw(uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
class CommandPool;
class PipelineImpl;
-class CommandBufferImpl : public VkManaged
+class CommandBufferImpl
{
friend class CommandPool;
public:
CommandBufferImpl() = delete;
- ~CommandBufferImpl() override;
+ ~CommandBufferImpl();
+
+ void Destroy();
/** Begin recording */
void Begin(vk::CommandBufferUsageFlags usageFlags, vk::CommandBufferInheritanceInfo* inheritanceInfo);
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);
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()
void CommandBuffer::DiscardResource()
{
+ mController.DiscardResource(this);
}
void CommandBuffer::Begin(const Graphics::CommandBufferBeginInfo& info)
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;
*/
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.
*
#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>
*
* 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;
}
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();
}
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();
}
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)
{
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
{
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;
}
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
class Device;
class CommandBufferImpl;
-class CommandPool : public VkManaged
+class CommandPool
{
public: // Construction, destruction
/**
CommandPool(Device& graphicsDevice, const vk::CommandPoolCreateInfo& createInfo);
- ~CommandPool() override;
+ ~CommandPool();
vk::CommandPool GetVkHandle() const;
bool Initialize();
- bool OnDestroy() override; // TODO: Queue deleter for destruction
+ void Destroy();
/**
* Resets command pool
namespace Dali::Graphics::Vulkan
{
-
FenceImpl* FenceImpl::New(Device& graphicsDevice, const vk::FenceCreateInfo& fenceCreateInfo)
{
auto fence = new FenceImpl(graphicsDevice);
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);
}
FramebufferAttachment* FramebufferAttachment::NewDepthAttachment(
- ImageView* imageView,
- vk::ClearDepthStencilValue clearDepthStencilValue)
+ std::unique_ptr<ImageView>& imageView,
+ vk::ClearDepthStencilValue clearDepthStencilValue)
{
assert(imageView->GetImage()->GetUsageFlags() & vk::ImageUsageFlagBits::eDepthStencilAttachment);
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();
ImageView* FramebufferAttachment::GetImageView() const
{
- return mImageView;
+ return mImageView.get();
}
const vk::AttachmentDescription& FramebufferAttachment::GetDescription() 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()));
}
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;
}
// 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;
{
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:
{
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:
if(mHasDepthAttachment)
{
retval.reserve(1);
- retval.push_back(mAttachments.back());
+ retval.emplace_back(mAttachments.back().get());
}
break;
}
{
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
#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;
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;
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;
[[nodiscard]] std::vector<vk::ClearValue> GetClearValues() const;
- bool OnDestroy() override;
-
private:
Device* mGraphicsDevice;
};
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
#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),
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;
}
{
}
-} // namespace Vulkan
-} // namespace Graphics
-} // namespace Dali
+} // namespace Dali::Graphics::Vulkan
#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
{
class FramebufferImpl;
using FramebufferResource = Resource<Graphics::Framebuffer, Graphics::FramebufferCreateInfo>;
+
class Framebuffer : public FramebufferResource
{
public:
~Framebuffer() override;
/**
- * @brief Called when GL resources are destroyed
+ * @brief Called when resources are destroyed
*/
void DestroyResource() override;
*/
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;
};
*
* 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)
{
* @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;
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
{
// 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
{
}
}
- // 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;
}
// Do not destroy
if(buffer != mTextureStagingBuffer->GetImpl())
{
- buffer->DestroyNow();
+ buffer->Destroy();
}
}
else if(request.requestType == TransferRequestType::IMAGE_TO_IMAGE)
auto& image = request.imageToImageInfo.srcImage;
if(image->GetVkHandle())
{
- image->DestroyNow();
+ image->Destroy();
}
}
}
}
}
+ /**
+ * @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{};
{
}
-VulkanGraphicsController::~VulkanGraphicsController() = default;
+VulkanGraphicsController::~VulkanGraphicsController()
+{
+ mImpl->GarbageCollect();
+}
void VulkanGraphicsController::Initialize(Dali::Graphics::VulkanGraphics& graphicsImplementation,
Vulkan::Device& graphicsDevice)
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)
void VulkanGraphicsController::RunGarbageCollector(size_t numberOfDiscardedRenderers)
{
+ mImpl->GarbageCollect();
}
void VulkanGraphicsController::DiscardUnusedResources()
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)
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)
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,
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
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();
}
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;
return gfxTexture;
}
+void VulkanGraphicsController::Flush()
+{
+ mImpl->Flush();
+}
+
std::size_t VulkanGraphicsController::GetCapacity() const
{
return mImpl->mCapacity;
UniquePtr<Graphics::SyncObject> CreateSyncObject(const Graphics::SyncObjectCreateInfo& syncObjectCreateInfo,
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
*
*/
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;
std::size_t GetCapacity() const;
private:
+ /**
+ * Flush all outstanding queues.
+ */
+ void Flush();
+
bool IsAdvancedBlendEquationSupported();
struct Impl;
*
*/
+#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:
/**
return mController;
}
- /**
- * @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;
}
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);
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
*/
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. ?!?!
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;
};
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;
return vk::ImageAspectFlags();
}
-void ImageView::Destroy()
-{
- auto device = mDevice.GetLogicalDevice();
- device.destroyImageView(mImageView, mDevice.GetAllocator());
-}
-
} // namespace Vulkan
} // namespace Graphics
} // namespace Dali
~ImageView();
+ void Destroy();
+
/**
*
* @return
*/
[[nodiscard]] vk::ImageAspectFlags GetImageAspectMask() const;
- void Destroy();
-
private:
Device& mDevice;
const Image& mImage;
}
}
-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
}
// No copy constructor or assignment operator
- MemoryImpl(MemoryImpl&) = delete;
+ MemoryImpl(MemoryImpl&) = delete;
MemoryImpl& operator=(MemoryImpl&) = delete;
void* Map();
void Flush();
- /**
- * Releases vk::DeviceMemory object so it can be deleted
- * externally
- * @return
- */
- vk::DeviceMemory ReleaseVkObject();
-
[[nodiscard]] vk::DeviceMemory GetVkHandle() const;
private:
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
/**
* @brief Pipeline class wraps the PipelineImpl
*/
-class Pipeline : public Graphics::Pipeline
+class Pipeline : public Graphics::Pipeline, public Vulkan::ResourceBase
{
public:
Pipeline() = delete;
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
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
{
class Reflection;
class ProgramImpl;
+
/**
* @brief Wrapper for the program implementation
*
* 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:
/**
/**
* @brief Returns reference to the Reflection object
-
* @return Reflection
*/
[[nodiscard]] const Vulkan::Reflection& GetReflection() const;
return (program.mProgram != mProgram);
}
+ /**
+ * @brief Initialize the resource
+ */
+ bool InitializeResource() override;
+
/**
* @brief Run by UniquePtr to discard resource
*/
- void DiscardResource();
+ void DiscardResource() override;
/**
* @brief Destroying resources
* 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)
{
};
} // namespace Dali::Graphics::Vulkan
-#endif //DALI_GRAPHICS_VULKAN_PROGRAM_H
+#endif // DALI_GRAPHICS_VULKAN_PROGRAM_H
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()
* 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
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();
*/
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
*/
} // namespace Dali::Graphics::Vulkan
-#endif //DALI_INTERNAL_GRAPHICS_VULKAN_RENDER_TARGET_H
+#endif // DALI_INTERNAL_GRAPHICS_VULKAN_RENDER_TARGET_H
{
}
-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;
void Initialize();
+ void Destroy();
+
/**
* Returns VkSampler object
* @return
namespace Dali::Graphics::Vulkan
{
-
namespace
{
constexpr vk::Filter ConvertFilter(Dali::Graphics::SamplerFilter filter)
void Sampler::DestroyResource()
{
- // For now, no GPU resources are initialized so nothing to destroy
+ if(mSamplerImpl)
+ {
+ mSamplerImpl->Destroy();
+ mSamplerImpl = nullptr;
+ }
}
bool Sampler::InitializeResource()
/**
* @brief Called when GPU resources are destroyed
*/
- void DestroyResource();
+ void DestroyResource() override;
/**
* @brief Called when initializing the resource
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;
};
return mImpl->refCount;
}
+void ShaderImpl::Destroy()
+{
+ mImpl->Destroy();
+ mImpl.reset();
+}
+
[[nodiscard]] uint32_t ShaderImpl::IncreaseFlushCount()
{
return ++mImpl->flushCount;
// 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>
* @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
*/
[[nodiscard]] uint32_t GetRefCount() const;
+ /**
+ * @brief Destroys Vulkan shader module
+ */
+ void Destroy();
+
/**
* Whilst unreferenced, increase the flush count and return it
*
*/
[[nodiscard]] bool Compile() const;
- /**
- * @brief Destroys Vulkan shader module
- */
- void Destroy();
-
/**
* @brief Returns Vulkan resource
* @return Valid Vulkan shader resource
#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;
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
{
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;
}
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
{
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
*/
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;
{
}
-Swapchain::~Swapchain() = default;
+Swapchain::~Swapchain()
+{
+}
void Swapchain::CreateVkSwapchain(
vk::SwapchainKHR oldSwapchain,
auto presentModes = surface->GetSurfacePresentModes();
auto found = std::find_if(presentModes.begin(),
presentModes.end(),
- [&](vk::PresentModeKHR mode) {
+ [&](vk::PresentModeKHR mode)
+ {
return presentMode == mode;
});
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");
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)
{
FramebufferImpl* Swapchain::GetFramebuffer(uint32_t index) const
{
- return mFramebuffers[index];
+ return mFramebuffers[index].get();
}
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();
}
// mGraphicsDevice.CollectGarbage();
- return mFramebuffers[mSwapchainImageIndex];
+ return mFramebuffers[mSwapchainImageIndex].get();
}
void Swapchain::Submit(CommandBufferImpl* commandBuffer)
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;
/**
* Creates swapchain for given surface and queue
*/
-class Swapchain : public VkManaged
+class Swapchain
{
public:
static Swapchain* NewSwapchain(
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)
*/
*/
void Present();
- bool OnDestroy() override;
-
/**
* Returns true when swapchain expired
* @return
/**
* 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
};
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())
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())
// 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())
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()
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;
namespace Dali::Graphics
{
-
namespace
{
// Default value use to clear the stencil buffer
namespace Vulkan
{
-
/**
* Forward class declarations
*/
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()
{
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
// during replacing the swapchain
auto khr = oldSwapchain->GetVkHandle();
oldSwapchain->SetVkHandle(nullptr);
- oldSwapchain->Release();
+ oldSwapchain->Destroy();
+ delete oldSwapchain;
mLogicalDevice.destroySwapchainKHR(khr, *mAllocator);
}
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)
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
std::vector<const char*> PrepareDefaultInstanceExtensions();
+ void ReleaseCommandPools();
+
private: // Members
vk::PhysicalDevice mPhysicalDevice;
vk::Device mLogicalDevice;
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;
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)
void VulkanGraphics::Destroy()
{
+ mGraphicsController.RunGarbageCollector(0);
}
void VulkanGraphics::Pause()