- Fixed the program shutdown crashes by destroying the graphics resources in the correct order.
> Current status: Not all object references are released during shutdown. This leads to many validation errors when destroying the logical device.
> This is caused due to higher level code in DALi still holding references to internal graphics resources.
- Removed an unused CommandPool handle from the Vulkan API controller.
- Added a missing nullptr check to the GC method of the GpuMemoryDefaultAllocator that was leading to crashes due to double frees.
- The OnDestroy method of all Vulkan reference counted objects no longer calls the ResourceCache's Remove* methods if invoked during program teardown.
- Added debug prints for the deleter functions of all Vulkan reference counted objects. Only works in debug builds.
- Fixed a bug where the CommandPool class would destroy the Vulkan handle in its destructor. It now correctly enqueues a deleter function in the discard queue.
- Removed the PIMPL pattern from the DescriptorPool class.
- Removed the PIMPL pattern from the DescriptoSet class.
- Added a boolean flag to the Graphics class that indicates when the program is executing teardown.
- Removed #pragmas from the Pipeline class.
- Implemented a debug method in the ResourceCache class that dumps a report about the objects stored in the cache (object lists, object counts, reference counts).
- The Shader class now correctly enqueues a deleter function to the discard queue when the OnDestroy method is invoked.
Change-Id: Iaba952b3d277f12c000ab8c00efa3b851c6b612c
std::unique_ptr<VulkanAPI::ShaderFactory> mShaderFactory;
std::unique_ptr<VulkanAPI::BufferFactory> mBufferFactory;
- // todo: should be per thread
- Vulkan::RefCountedCommandPool mCommandPool;
-
std::vector<std::unique_ptr<VulkanAPI::BufferMemoryTransfer>> mBufferTransferRequests;
std::unique_ptr<Vulkan::PipelineCache> mPipelineCache;
{
for( auto&& block : mUniqueBlocks )
{
- if( block->GetRefCount() == 1 )
+ if( block != nullptr && block->GetRefCount() == 1 )
{
// collect and make invalid ( maybe freelist or sumtink )
mGraphics.GetDevice().freeMemory( (**block.get()), mGraphics.GetAllocator() );
bool Buffer::OnDestroy()
{
- mGraphics->RemoveBuffer( *this );
+ if( !mGraphics->IsShuttingDown() )
+ {
+ mGraphics->RemoveBuffer( *this );
+ }
auto device = mGraphics->GetDevice();
auto buffer = mBuffer;
auto allocator = &mGraphics->GetAllocator();
mGraphics->DiscardResource( [device, buffer, allocator]() {
+#ifndef NDEBUG
+ printf("Invoking BUFFER deleter function\n");
+#endif
device.destroyBuffer(buffer, allocator);
} );
}
}
-std::vector< vk::CommandBuffer > CommandPool::InternalPool::AllocateVkCommandBuffers( vk::CommandBufferAllocateInfo allocateInfo )
+std::vector< vk::CommandBuffer >
+ CommandPool::InternalPool::AllocateVkCommandBuffers( vk::CommandBufferAllocateInfo allocateInfo )
{
return VkAssert( mGraphics->GetDevice().allocateCommandBuffers( allocateInfo ) );
}
{
}
-CommandPool::~CommandPool()
-{
- if(mCommandPool)
- {
- mGraphics->GetDevice().destroyCommandPool( mCommandPool, mGraphics->GetAllocator());
- }
-}
+CommandPool::~CommandPool() = default;
vk::CommandPool CommandPool::GetVkHandle() const
{
bool CommandPool::OnDestroy()
{
- mGraphics->RemoveCommandPool( *this );
+ if( !mGraphics->IsShuttingDown() )
+ {
+ mGraphics->RemoveCommandPool( *this );
+ }
auto device = mGraphics->GetDevice();
auto commandPool = mCommandPool;
auto allocator = &mGraphics->GetAllocator();
mGraphics->DiscardResource( [device, commandPool, allocator]() {
+#ifndef NDEBUG
+ printf("Invoking COMMAND POOL deleter function\n");
+#endif
device.destroyCommandPool( commandPool, allocator );
} );
{
namespace Vulkan
{
-struct DescriptorPool::Impl
-{
- Impl( DescriptorPool& owner, Graphics& graphics, vk::DescriptorPoolCreateInfo createInfo )
- : mGraphics( graphics ),
- mOwner( owner ),
- mCreateInfo( createInfo )
- {
-
- }
-
- ~Impl()
- {
-
- }
-
- /**
- * Allocates an array of descriptor sets
- * @param allocateInfo
- * @return
- */
- std::vector<Handle<DescriptorSet>> AllocateDescriptorSets( vk::DescriptorSetAllocateInfo allocateInfo )
- {
- // all other fields must be set correct
- allocateInfo.setDescriptorPool( mVkDescriptorPool );
- auto result = VkAssert( mGraphics.GetDevice().allocateDescriptorSets( allocateInfo ) );
-
- std::vector<Handle<DescriptorSet>> retval;
- retval.reserve( result.size() );
- for( auto&& item : result )
- {
- Handle<DescriptorSet> handle( new DescriptorSet(mGraphics, mOwner, item, allocateInfo) );
- retval.emplace_back( handle );
- mDescriptorSetCache.emplace_back( handle );
- }
-
- return retval;
- }
-
- void Reset()
- {
- mGraphics.GetDevice().resetDescriptorPool( mVkDescriptorPool );
- mDescriptorSetCache.clear();
- }
-
- bool Initialise()
- {
- mVkDescriptorPool = VkAssert( mGraphics.GetDevice().createDescriptorPool( mCreateInfo, mGraphics.GetAllocator() ) );
- return true;
- }
-
- Graphics& mGraphics;
- DescriptorPool& mOwner;
- vk::DescriptorPoolCreateInfo mCreateInfo;
-
- vk::DescriptorPool mVkDescriptorPool;
- // cache
- std::vector<Handle<DescriptorSet>> mDescriptorSetCache;
-};
+/**
+ * Class DescriptorPool
+ */
Handle<DescriptorPool> DescriptorPool::New( Graphics& graphics, const vk::DescriptorPoolCreateInfo& createInfo )
{
auto pool = Handle<DescriptorPool>( new DescriptorPool( graphics, createInfo ) );
- if(pool->mImpl->Initialise())
+ if(pool->Initialise())
{
graphics.AddDescriptorPool(pool);
}
return pool;
}
-DescriptorPool::DescriptorPool( Graphics& graphics, const vk::DescriptorPoolCreateInfo& createInfo )
-{
- mImpl = MakeUnique<Impl>( *this, graphics, createInfo );
-}
-
DescriptorPool::~DescriptorPool() = default;
-vk::DescriptorPool DescriptorPool::GetVkHandle() const
+bool DescriptorPool::Initialise()
{
- return mImpl->mVkDescriptorPool;
+ mDescriptorPool = VkAssert( mGraphics->GetDevice().createDescriptorPool( mCreateInfo, mGraphics->GetAllocator() ) );
+ return true;
}
-std::vector<DescriptorSetHandle> DescriptorPool::AllocateDescriptorSets( vk::DescriptorSetAllocateInfo allocateInfo )
+DescriptorPool::DescriptorPool( Graphics& graphics, const vk::DescriptorPoolCreateInfo& createInfo )
+ : mGraphics(&graphics),
+ mCreateInfo(createInfo)
{
- return mImpl->AllocateDescriptorSets( allocateInfo );
}
-void DescriptorPool::Reset()
+vk::DescriptorPool DescriptorPool::GetVkHandle() const
{
- mImpl->Reset();
+ return mDescriptorPool;
}
-/****************************************************************************************
- * Class DescriptorSet::Impl
- */
-
-struct DescriptorSet::Impl
+std::vector< RefCountedDescriptorSet > DescriptorPool::AllocateDescriptorSets( vk::DescriptorSetAllocateInfo allocateInfo )
{
- Impl( Graphics& graphics, DescriptorPool& pool, vk::DescriptorSet set, vk::DescriptorSetAllocateInfo allocateInfo )
- : mGraphics( graphics ),
- mPool( pool ),
- mAllocateInfo( allocateInfo ),
- mVkDescriptorSet( set )
- {
-
- }
+ // all other fields must be set correct
+ allocateInfo.setDescriptorPool( mDescriptorPool );
+ auto result = VkAssert( mGraphics->GetDevice().allocateDescriptorSets( allocateInfo ) );
- ~Impl()
+ std::vector< RefCountedDescriptorSet > retval;
+ retval.reserve( result.size() );
+ for( auto&& item : result )
{
- if(mVkDescriptorSet)
- {
- // TODO: @todo non freeable!!!
- //mGraphics.GetDevice().freeDescriptorSets( mPool.GetVkHandle(), 1, &mVkDescriptorSet );
- }
+ Handle<DescriptorSet> handle( new DescriptorSet(*mGraphics, *this, item, allocateInfo) );
+ retval.emplace_back( handle );
+ mDescriptorSetCache.emplace_back( handle );
}
- void WriteUniformBuffer( uint32_t binding, Handle<Buffer> buffer, uint32_t offset, uint32_t size )
- {
- // add resource to the list
- mResources.emplace_back( buffer.StaticCast<VkManaged>() );
-
- auto bufferInfo = vk::DescriptorBufferInfo{}
- .setOffset( U32(offset) )
- .setRange( U32(size) )
- .setBuffer(buffer->GetVkHandle() );
-
- auto write = vk::WriteDescriptorSet{}.setPBufferInfo( &bufferInfo )
- .setDescriptorType( vk::DescriptorType::eUniformBuffer )
- .setDescriptorCount( 1 )
- .setDstSet( mVkDescriptorSet )
- .setDstBinding( binding )
- .setDstArrayElement( 0 );
-
- // write descriptor set
- mGraphics.GetDevice().updateDescriptorSets( 1, &write, 0, nullptr );
- }
+ return retval;
+}
- void WriteCombinedImageSampler( uint32_t binding, RefCountedSampler sampler, RefCountedImageView imageView )
- {
- // add resource to the list
- mResources.emplace_back( sampler.StaticCast<VkManaged>() );
- mResources.emplace_back( imageView.StaticCast<VkManaged>() );
-
- auto imageViewInfo = vk::DescriptorImageInfo{}
- .setImageLayout( vk::ImageLayout::eShaderReadOnlyOptimal )
- .setImageView( imageView->GetVkHandle() )
- .setSampler(sampler->GetVkHandle() );
-
- auto write = vk::WriteDescriptorSet{}.setPImageInfo( &imageViewInfo )
- .setDescriptorType( vk::DescriptorType::eCombinedImageSampler )
- .setDescriptorCount( 1 )
- .setDstSet( mVkDescriptorSet )
- .setDstBinding( binding )
- .setDstArrayElement( 0 );
-
- // write descriptor set
- mGraphics.GetDevice().updateDescriptorSets( 1, &write, 0, nullptr );
- }
+void DescriptorPool::Reset()
+{
+ mGraphics->GetDevice().resetDescriptorPool( mDescriptorPool );
+ mDescriptorSetCache.clear();
+}
- void WriteStorageBuffer( Handle<Buffer> buffer, uint32_t offset, uint32_t size )
+bool DescriptorPool::OnDestroy()
+{
+ if( !mGraphics->IsShuttingDown() )
{
- mResources.emplace_back( buffer.StaticCast<VkManaged>() );
+ mGraphics->RemoveDescriptorPool( *this );
}
- Graphics& mGraphics;
- DescriptorPool& mPool;
- vk::DescriptorSetAllocateInfo mAllocateInfo;
- vk::DescriptorSet mVkDescriptorSet;
+ auto device = mGraphics->GetDevice();
+ auto descriptorPool = mDescriptorPool;
+ auto allocator = &mGraphics->GetAllocator();
- // attached resources
- std::vector<Handle<VkManaged>> mResources;
-};
+ mGraphics->DiscardResource( [device, descriptorPool, allocator] () {
+#ifndef NDEBUG
+ printf("Invoking DESCRIPTOR POOL deleter function\n");
+#endif
+ device.destroyDescriptorPool( descriptorPool, allocator );
+ } );
+
+ return false;
+}
/**
- * Called by DescriptorPool only!
+ * Class DescriptorSet
*/
-DescriptorSet::DescriptorSet( Graphics& graphics, DescriptorPool& pool, vk::DescriptorSet descriptorSet, vk::DescriptorSetAllocateInfo allocateInfo )
+
+//Called by DescriptorPool only!
+DescriptorSet::DescriptorSet( Graphics& graphics,
+ DescriptorPool& pool,
+ vk::DescriptorSet descriptorSet,
+ vk::DescriptorSetAllocateInfo allocateInfo )
+ : mGraphics( &graphics ),
+ mPool( &pool ),
+ mAllocateInfo( allocateInfo ),
+ mDescriptorSet( descriptorSet )
{
- mImpl = MakeUnique<Impl>( graphics, pool, descriptorSet, allocateInfo );
}
DescriptorSet::~DescriptorSet() = default;
void DescriptorSet::WriteUniformBuffer( uint32_t binding, Handle<Buffer> buffer, uint32_t offset, uint32_t size )
{
- mImpl->WriteUniformBuffer( binding, buffer, offset, size );
+ // add resource to the list
+ mResources.emplace_back( buffer.StaticCast<VkManaged>() );
+
+ auto bufferInfo = vk::DescriptorBufferInfo{}
+ .setOffset( U32(offset) )
+ .setRange( U32(size) )
+ .setBuffer(buffer->GetVkHandle() );
+
+ auto write = vk::WriteDescriptorSet{}.setPBufferInfo( &bufferInfo )
+ .setDescriptorType( vk::DescriptorType::eUniformBuffer )
+ .setDescriptorCount( 1 )
+ .setDstSet( mDescriptorSet )
+ .setDstBinding( binding )
+ .setDstArrayElement( 0 );
+
+ // write descriptor set
+ mGraphics->GetDevice().updateDescriptorSets( 1, &write, 0, nullptr );
}
vk::DescriptorSet DescriptorSet::GetVkDescriptorSet() const
{
- return mImpl->mVkDescriptorSet;
+ return mDescriptorSet;
}
void DescriptorSet::WriteCombinedImageSampler( uint32_t binding, RefCountedSampler sampler, RefCountedImageView imageView )
{
- mImpl->WriteCombinedImageSampler( binding, sampler, imageView );
+ // add resource to the list
+ mResources.emplace_back( sampler.StaticCast<VkManaged>() );
+ mResources.emplace_back( imageView.StaticCast<VkManaged>() );
+
+ auto imageViewInfo = vk::DescriptorImageInfo{}
+ .setImageLayout( vk::ImageLayout::eShaderReadOnlyOptimal )
+ .setImageView( imageView->GetVkHandle() )
+ .setSampler(sampler->GetVkHandle() );
+
+ auto write = vk::WriteDescriptorSet{}.setPImageInfo( &imageViewInfo )
+ .setDescriptorType( vk::DescriptorType::eCombinedImageSampler )
+ .setDescriptorCount( 1 )
+ .setDstSet( mDescriptorSet )
+ .setDstBinding( binding )
+ .setDstArrayElement( 0 );
+
+ // write descriptor set
+ mGraphics->GetDevice().updateDescriptorSets( 1, &write, 0, nullptr );
+}
+
+void DescriptorSet::WriteStorageBuffer( RefCountedBuffer buffer, uint32_t offset, uint32_t size )
+{
+ NotImplemented()
+}
+
+void DescriptorSet::WriteImage( Handle< Image > )
+{
+ NotImplemented()
+}
+
+void DescriptorSet::Write( vk::WriteDescriptorSet writeDescriptorSet )
+{
+ NotImplemented()
}
#if 0
* @param offset
* @param size
*/
- void WriteStorageBuffer( Handle<Buffer> buffer, uint32_t offset, uint32_t size );
+ void WriteStorageBuffer( RefCountedBuffer buffer, uint32_t offset, uint32_t size );
/**
*
DescriptorSet( Graphics& graphics, DescriptorPool& pool, vk::DescriptorSet descriptorSet, vk::DescriptorSetAllocateInfo allocateInfo );
- struct Impl;
- std::unique_ptr<Impl> mImpl;
-};
+ Graphics* mGraphics;
+ DescriptorPool* mPool;
+ vk::DescriptorSetAllocateInfo mAllocateInfo;
+ vk::DescriptorSet mDescriptorSet;
-using DescriptorSetHandle = Handle<DescriptorSet>;
+ // attached resources
+ std::vector<Handle<VkManaged>> mResources;
+};
class DescriptorPool : public VkManaged
{
~DescriptorPool() override;
+ bool Initialise();
+
vk::DescriptorPool GetVkHandle() const;
- std::vector<DescriptorSetHandle> AllocateDescriptorSets( vk::DescriptorSetAllocateInfo allocateInfo );
+ std::vector< RefCountedDescriptorSet > AllocateDescriptorSets( vk::DescriptorSetAllocateInfo allocateInfo );
/**
* Resets descriptor pool
*/
void Reset();
+ bool OnDestroy() override;
+
private:
DescriptorPool( Graphics& graphics, const vk::DescriptorPoolCreateInfo& createInfo );
- struct Impl;
- std::unique_ptr<Impl> mImpl;
+ Graphics* mGraphics;
+ vk::DescriptorPoolCreateInfo mCreateInfo;
+
+ vk::DescriptorPool mDescriptorPool;
+
+ // cache
+ std::vector<Handle<DescriptorSet>> mDescriptorSetCache;
};
#if 0
// capture copies of the pointers and handles
mGraphics->DiscardResource( [device, fence, allocator]() {
+#ifndef NDEBUG
+ printf("Invoking FENCE deleter function\n");
+#endif
device.destroyFence( fence, allocator );
} );
Graphics::Graphics() = default;
-Graphics::~Graphics() = default;
+Graphics::~Graphics()
+{
+ // Wait for everything to finish on the GPU
+ DeviceWaitIdle();
+
+ // We are shutting down. This flag is used to avoid cache manipulation by Handles' OnDestroy function calls.
+ // The cache will do its own house keeping on teardown
+ mShuttingDown = true;
+
+ // Manually resetting unique pointer here because we need to control the order of destruction.
+ // This defeats the purpose of unique pointers and we might as well use raw pointers. But a unique ptr
+ // communicates ownership more clearly (e.g by not allowing copies).
+ mGfxController.reset(nullptr);
+ mSurfaceFBIDMap.clear();
+ mPipelineDatabase.reset(nullptr);
+
+#ifndef NDEBUG
+ printf("DESTROYING GRAPHICS CONTEXT--------------------------------\n");
+ size_t totalObjCount = 0;
+ mResourceCache->PrintReferenceCountReport( &totalObjCount );
+#endif
+
+ // Clear the last references of resources in the cache.
+ // This should ensure that all resources have been queued for garbage collection
+ // This call assumes that the cash only holds the last reference of every resource in the program. (As it should)
+ mResourceCache->Clear();
+
+ mDeviceMemoryManager.reset(nullptr);
+
+ // Collect the garbage! And shut down gracefully...
+ CollectGarbage();
+
+ // We are done with all resources (technically... . If not we will get a ton of validation layer errors)
+ // Kill the Vulkan logical device
+ mDevice.destroy(mAllocator.get());
+
+ // Kill the Vulkan instance
+ mInstance.destroy(mAllocator.get());
+
+}
// Create methods -----------------------------------------------------------------------------------------------
void Graphics::Create()
{
return *mPipelineDatabase;
}
+
+bool Graphics::IsShuttingDown()
+{
+ return mShuttingDown;
+}
// --------------------------------------------------------------------------------------------------------------
// Cache manipulation methods -----------------------------------------------------------------------------------
PipelineCache& GetPipelineCache();
+ bool IsShuttingDown();
+
public: //Cache management methods
void AddBuffer( RefCountedBuffer buffer );
void DiscardResource( std::function< void() > deleter );
+
private: // Methods
void CreateInstance( const std::vector< const char* >& extensions,
private: // Members
- std::unique_ptr< GpuMemoryManager > mDeviceMemoryManager;
-
- vk::Instance mInstance;
- std::unique_ptr< vk::AllocationCallbacks > mAllocator{ nullptr };
-
// physical device
vk::PhysicalDevice mPhysicalDevice;
// logical device
vk::Device mDevice;
+ vk::Instance mInstance;
+
// physical device properties
std::unique_ptr< vk::PhysicalDeviceProperties > mPhysicalDeviceProperties;
std::unique_ptr< vk::PhysicalDeviceMemoryProperties > mPhysicalDeviceMemoryProperties;
std::unique_ptr< vk::PhysicalDeviceFeatures > mPhysicalDeviceFeatures;
+ std::unique_ptr< vk::AllocationCallbacks > mAllocator{ nullptr };
+
// queue family properties
std::vector< vk::QueueFamilyProperties > mQueueFamilyProperties;
- std::unordered_map< FBID, SwapchainSurfacePair > mSurfaceFBIDMap;
- FBID mBaseFBID{ 0u };
-
// Sets of queues
std::vector< std::unique_ptr< Queue > > mGraphicsQueues;
std::vector< std::unique_ptr< Queue > > mTransferQueues;
std::vector< std::unique_ptr< Queue > > mComputeQueues;
//std::unique_ptr< Queue > mPresentQueue;
- Platform mPlatform{ Platform::UNDEFINED };
+ std::unique_ptr< ResourceCache > mResourceCache;
- std::unique_ptr< Dali::Graphics::VulkanAPI::Controller > mGfxController;
+ std::unordered_map< FBID, SwapchainSurfacePair > mSurfaceFBIDMap;
+ FBID mBaseFBID{ 0u };
+
+ std::unique_ptr< GpuMemoryManager > mDeviceMemoryManager;
+
+ Platform mPlatform{ Platform::UNDEFINED };
// TODO: rename
std::unique_ptr< PipelineCache > mPipelineDatabase;
std::mutex mMutex;
- std::unique_ptr< ResourceCache > mResourceCache;
+
+ std::unique_ptr< Dali::Graphics::VulkanAPI::Controller > mGfxController;
+
+ bool mShuttingDown = false;
};
bool ImageView::OnDestroy()
{
- mGraphics->RemoveImageView( *this );
+ if( !mGraphics->IsShuttingDown() )
+ {
+ mGraphics->RemoveImageView( *this );
+ }
auto device = mGraphics->GetDevice();
auto imageView = mImageView;
auto allocator = &mGraphics->GetAllocator();
mGraphics->DiscardResource( [device, imageView, allocator]() {
+#ifndef NDEBUG
+ printf("Invoking IMAGE VIEW deleter function\n");
+#endif
device.destroyImageView(imageView, allocator);
} );
{
if( !mIsExternal )
{
- mGraphics->RemoveImage(*this);
+ if( !mGraphics->IsShuttingDown() )
+ {
+ mGraphics->RemoveImage(*this);
+ }
auto device = mGraphics->GetDevice();
auto image = mImage;
auto allocator = &mGraphics->GetAllocator();
mGraphics->DiscardResource([device, image, allocator]() {
+#ifndef NDEBUG
+ printf("Invoking IMAGE deleter function\n");
+#endif
device.destroyImage(image, allocator);
});
}
return mPipeline;
}
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
vk::Result Initialise()
{
if( !ValidateShaderModules() )
mColorBlendState.setPAttachments( &mAttachementNoBlendState );
mInfo.setPColorBlendState(&mColorBlendState);
}
-#pragma GCC diagnostic pop
/**
* Sets the shader. Must be set before compiling the pipeline, compiled pipeline
* @todo: Store SPIRV data of shader modules in the cache rather than
* parsing every time
*/
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
void CreatePipelineLayout()
{
mDSLayoutArray = dsLayouts;
mInfo.setLayout( mPipelineLayout );
}
-#pragma GCC diagnostic pop
vk::ShaderStageFlagBits GetShaderStage( RefCountedShader shader )
{
{
auto found = std::find_if(mBuffers.begin(),
mBuffers.end(),
- [&](const RefCountedBuffer entry) { return &(*entry) == &buffer; });
+ [&](const RefCountedBuffer& entry)
+ {
+ return entry->GetVkHandle() == buffer.GetVkHandle();
+ });
std::iter_swap(found, std::prev(mBuffers.end()));
mBuffers.back().Reset();
{
auto found = std::find_if(mImages.begin(),
mImages.end(),
- [&](const RefCountedImage entry) { return &(*entry) == ℑ });
+ [&](const RefCountedImage& entry)
+ {
+ return entry->GetVkHandle() == image.GetVkHandle();
+ });
std::iter_swap(found, std::prev(mImages.end()));
mImages.back().Reset();
{
auto found = std::find_if(mImageViews.begin(),
mImageViews.end(),
- [&](const RefCountedImageView entry) { return &(*entry) == &imageView; });
+ [&](const RefCountedImageView& entry)
+ {
+ return entry->GetVkHandle() == imageView.GetVkHandle();
+ });
std::iter_swap(found, std::prev(mImageViews.end()));
mImageViews.back().Reset();
{
auto iterator = std::find_if(mShaders.begin(),
mShaders.end(),
- [&](const RefCountedShader entry) { return &*entry == &shader; });
+ [&](const RefCountedShader& entry)
+ {
+ return &*entry == &shader;
+ });
std::iter_swap(iterator, std::prev(mShaders.end()));
mShaders.back().Reset();
{
if( !mCommandPools.empty() )
{
- using EntryPair = std::pair< std::thread::id, RefCountedCommandPool >;
- auto iterator = std::find_if(mCommandPools.begin(),
- mCommandPools.end(),
- [&](const EntryPair& entry) { return &*(entry.second) == &commandPool; });
- mCommandPools.erase( iterator );
+ auto found = mCommandPools.end();
+
+ auto it = mCommandPools.begin();
+ while ( it != mCommandPools.end() )
+ {
+ auto& refcounted = (*it).second;
+ if ( refcounted->GetVkHandle() == commandPool.GetVkHandle() )
+ {
+ found = it;
+ break;
+ }
+
+ ++it;
+ }
+
+ mCommandPools.erase( found );
}
return *this;
}
{
auto iterator = std::find_if(mDescriptorPools.begin(),
mDescriptorPools.end(),
- [&](const RefCountedDescriptorPool entry) { return &*entry == &descriptorPool; });
+ [&](const RefCountedDescriptorPool& entry)
+ {
+ return entry->GetVkHandle() == descriptorPool.GetVkHandle();
+ });
std::iter_swap(iterator, std::prev(mDescriptorPools.end()));
mDescriptorPools.back().Reset();
{
auto iterator = std::find_if(mFramebuffers.begin(),
mFramebuffers.end(),
- [&](const RefCountedFramebuffer entry) { return &*entry == &framebuffer; });
+ [&](const RefCountedFramebuffer& entry)
+ {
+ return entry->GetVkHandle() == framebuffer.GetVkHandle();
+ });
std::iter_swap(iterator, std::prev(mFramebuffers.end()));
mFramebuffers.back().Reset();
{
auto iterator = std::find_if(mSamplers.begin(),
mSamplers.end(),
- [&](const RefCountedSampler entry) { return &*entry == &sampler; });
+ [&](const RefCountedSampler& entry)
+ {
+ return entry->GetVkHandle() == sampler.GetVkHandle();
+ });
std::iter_swap(iterator, std::prev(mSamplers.end()));
mSamplers.back().Reset();
void ResourceCache::EnqueueDiscardOperation( std::function<void()> deleter )
{
mDiscardQueue.push_back(std::move(deleter));
+#ifndef NDEBUG
+ printf("DISCARD QUEUE SIZE: %ld\n", mDiscardQueue.size());
+#endif
+}
+
+// Called only by the Graphics class destructor
+void ResourceCache::Clear()
+{
+ //This call assumes that all possible render threads have been joined by this point.
+ //This function is called by the Graphics class destructor. At this point the caches
+ //should contain the last reference of all created objects.
+ //Clearing the cache here will enqueue all resources to the discard queue ready to be garbage collected.
+ mBuffers.clear();
+ mImages.clear();
+ mImageViews.clear();
+ mDescriptorPools.clear();
+ mShaders.clear();
+ mSamplers.clear();
+ mFramebuffers.clear();
+ mCommandPools.clear();
+}
+
+void ResourceCache::PrintReferenceCountReport( size_t* outObjectCount )
+{
+ auto totalObjectCount = mBuffers.size() +
+ mImages.size() +
+ mImageViews.size() +
+ mShaders.size() +
+ mDescriptorPools.size() +
+ mFramebuffers.size() +
+ mSamplers.size();
+
+ if( outObjectCount )
+ {
+ *outObjectCount = totalObjectCount;
+ }
+
+ uint32_t totalRefCount = 0;
+ printf("TOTAL OBJECT COUNT: %ld\n", totalObjectCount);
+ printf("BUFFER REFERENCES:\n");
+ for (auto& buffer : mBuffers)
+ {
+ auto refCount = buffer->GetRefCount();
+ printf("\tbuffer->%p : %d\n", static_cast< void* >(buffer->GetVkHandle()), refCount);
+ totalRefCount += refCount;
+ }
+ printf("\tTotal reference count: %d\n", totalRefCount);
+ printf("\tTotal object count: %ld\n\n", mBuffers.size());
+ totalRefCount = 0;
+
+ printf("IMAGE REFERENCES:\n");
+ for( auto& image : mImages )
+ {
+ auto refCount = image->GetRefCount();
+ printf("\timage->%p : %d\n", static_cast< void* >(image->GetVkHandle()), refCount);
+ totalRefCount += refCount;
+ }
+ printf("\tTotal reference count: %d\n", totalRefCount);
+ printf("\tTotal object count: %ld\n\n", mImages.size());
+ totalRefCount = 0;
+
+ printf("IMAGE VIEW REFERENCES:\n");
+ for( auto& imageView : mImageViews )
+ {
+ auto refCount = imageView->GetRefCount();
+ printf("\timage view->%p : %d\n", static_cast< void* >(imageView->GetVkHandle()), refCount);
+ totalRefCount += refCount;
+ }
+ printf("\tTotal reference count: %d\n", totalRefCount);
+ printf("\tTotal object count: %ld\n\n", mImageViews.size());
+ totalRefCount = 0;
+
+ printf("SHADER MODULE REFERENCES:\n");
+ for( auto& shader : mShaders )
+ {
+ auto refCount = shader->GetRefCount();
+ printf("\tshader module->%p : %d\n", static_cast< void* >(shader->GetVkHandle()), refCount);
+ totalRefCount += refCount;
+ }
+ printf("\tTotal reference count: %d\n", totalRefCount);
+ printf("\tTotal object count: %ld\n\n", mShaders.size());
+ totalRefCount = 0;
+
+ printf("DESCRIPTOR POOL REFERENCES:\n");
+ for( auto& descPool : mDescriptorPools )
+ {
+ auto refCount = descPool->GetRefCount();
+ printf("\tdescriptor pool->%p : %d\n", static_cast< void* >(descPool->GetVkHandle()), refCount);
+ totalRefCount += refCount;
+ }
+ printf("\tTotal reference count: %d\n", totalRefCount);
+ printf("\tTotal object count: %ld\n\n", mDescriptorPools.size());
+ totalRefCount = 0;
+
+ printf("FRAMEBUFFER REFERENCES:\n");
+ for( auto& framebuffer : mFramebuffers )
+ {
+ auto refCount = framebuffer->GetRefCount();
+ printf("\tframebuffer->%p : %d\n", static_cast< void* >(framebuffer->GetVkHandle()), refCount);
+ totalRefCount += refCount;
+ }
+ printf("\tTotal reference count: %d\n", totalRefCount);
+ printf("\tTotal object count: %ld\n\n", mFramebuffers.size());
+ totalRefCount = 0;
+
+ printf("SAMPLER REFERENCES:\n");
+ for( auto& sampler : mSamplers )
+ {
+ auto refCount = sampler->GetRefCount();
+ printf("\tsampler->%p : %d\n", static_cast< void* >(sampler->GetVkHandle()), refCount);
+ totalRefCount += refCount;
+ }
+ printf("\tTotal reference count: %d\n", totalRefCount);
+ printf("\tTotal object count: %ld\n\n", mSamplers.size());
}
} //namespace Vulkan
void EnqueueDiscardOperation( std::function<void()> deleter );
+ void Clear();
+
+#ifndef NDEBUG
+ void PrintReferenceCountReport( size_t* outObjectCount = nullptr );
+#endif
+
ResourceCache() = default;
// The cache should not be copyable
bool Sampler::OnDestroy()
{
- mGraphics->RemoveSampler( *this );
-
- mGraphics->DiscardResource( [this]() {
- mGraphics->GetDevice().destroySampler( mSampler, mGraphics->GetAllocator() );
+ if( mGraphics->IsShuttingDown() )
+ {
+ mGraphics->RemoveSampler( *this );
+ }
+
+ auto device = mGraphics->GetDevice();
+ auto sampler = mSampler;
+ auto allocator = &mGraphics->GetAllocator();
+
+ mGraphics->DiscardResource( [device, sampler, allocator]() {
+ printf("Invoking SAMPLER deleter function\n");
+ device.destroySampler( sampler, allocator );
} );
return false;
bool Shader::OnDestroy()
{
- mImpl->mGraphics.RemoveShader( *this );
+ if( !mImpl->mGraphics.IsShuttingDown() )
+ {
+ mImpl->mGraphics.RemoveShader( *this );
+ }
+
+ auto device = mImpl->mGraphics.GetDevice();
+ auto shaderModule = mImpl->mShaderModule;
+ auto allocator = &mImpl->mGraphics.GetAllocator();
+
+ mImpl->mGraphics.DiscardResource( [device, shaderModule, allocator]() {
+#ifndef NDEBUG
+ printf("Invoking SHADER MODULE deleter function\n");
+#endif
+ device.destroyShaderModule( shaderModule, allocator );
+ } );
+
return true;
}