Fixed application crashes/stalls during teardown
authorAngelos Gkountis <a.gkountis@samsung.com>
Tue, 12 Jun 2018 14:08:45 +0000 (15:08 +0100)
committerAngelos Gkountis <a.gkountis@samsung.com>
Tue, 12 Jun 2018 14:27:19 +0000 (14:27 +0000)
- 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

16 files changed:
dali/graphics/vulkan/api/vulkan-api-controller.cpp
dali/graphics/vulkan/gpu-memory/vulkan-gpu-memory-manager.cpp
dali/graphics/vulkan/vulkan-buffer.cpp
dali/graphics/vulkan/vulkan-command-pool.cpp
dali/graphics/vulkan/vulkan-descriptor-set.cpp
dali/graphics/vulkan/vulkan-descriptor-set.h
dali/graphics/vulkan/vulkan-fence.cpp
dali/graphics/vulkan/vulkan-graphics.cpp
dali/graphics/vulkan/vulkan-graphics.h
dali/graphics/vulkan/vulkan-image-view.cpp
dali/graphics/vulkan/vulkan-image.cpp
dali/graphics/vulkan/vulkan-pipeline.cpp
dali/graphics/vulkan/vulkan-resource-cache.cpp
dali/graphics/vulkan/vulkan-resource-cache.h
dali/graphics/vulkan/vulkan-sampler.cpp
dali/graphics/vulkan/vulkan-shader.cpp

index c01db12..69deed0 100644 (file)
@@ -234,9 +234,6 @@ struct Controller::Impl
   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;
index 0edddb9..9b34d72 100644 (file)
@@ -159,7 +159,7 @@ struct GpuMemoryDefaultAllocator : public GpuMemoryAllocator
   {
     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() );
index ddfa3ec..acb1d9b 100644 (file)
@@ -82,13 +82,19 @@ void Buffer::BindMemory( const RefCountedGpuMemoryBlock& handle )
 
 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);
   } );
 
index 617c696..cd943ef 100644 (file)
@@ -63,7 +63,8 @@ CommandPool::InternalPool::~InternalPool()
   }
 }
 
-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 ) );
 }
@@ -183,13 +184,7 @@ CommandPool::CommandPool(Graphics& graphics, const vk::CommandPoolCreateInfo& cr
 {
 }
 
-CommandPool::~CommandPool()
-{
-  if(mCommandPool)
-  {
-    mGraphics->GetDevice().destroyCommandPool( mCommandPool, mGraphics->GetAllocator());
-  }
-}
+CommandPool::~CommandPool() = default;
 
 vk::CommandPool CommandPool::GetVkHandle() const
 {
@@ -254,13 +249,19 @@ uint32_t CommandPool::GetAllocationCount( vk::CommandBufferLevel level ) 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 );
   } );
 
index 25a44fb..55c645d 100644 (file)
@@ -28,202 +28,164 @@ namespace Graphics
 {
 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
index cdb859d..70e97ae 100644 (file)
@@ -60,7 +60,7 @@ public:
    * @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 );
 
   /**
    *
@@ -83,11 +83,14 @@ private:
 
   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
 {
@@ -97,21 +100,30 @@ public:
 
   ~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
index fa71df3..c5fbb0f 100644 (file)
@@ -73,6 +73,9 @@ bool Fence::OnDestroy()
 
   // 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 );
   } );
 
index ed1987f..5419d3d 100644 (file)
@@ -83,7 +83,46 @@ const auto VALIDATION_LAYERS = std::vector< const char* >{
 
 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()
@@ -613,6 +652,11 @@ PipelineCache& Graphics::GetPipelineCache()
 {
   return *mPipelineDatabase;
 }
+
+bool Graphics::IsShuttingDown()
+{
+  return mShuttingDown;
+}
 // --------------------------------------------------------------------------------------------------------------
 
 // Cache manipulation methods -----------------------------------------------------------------------------------
index e952f23..506c4be 100644 (file)
@@ -188,6 +188,8 @@ public: // Getters
 
   PipelineCache& GetPipelineCache();
 
+  bool IsShuttingDown();
+
 public: //Cache management methods
 
   void AddBuffer( RefCountedBuffer buffer );
@@ -230,6 +232,7 @@ public: //Cache management methods
 
   void DiscardResource( std::function< void() > deleter );
 
+
 private: // Methods
 
   void CreateInstance( const std::vector< const char* >& extensions,
@@ -251,43 +254,47 @@ private: // Methods
 
 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;
 
 };
 
index d8cdc9a..e6d96b5 100644 (file)
@@ -86,13 +86,19 @@ ImageView::operator vk::ImageView*()
 
 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);
   } );
 
index 3418797..0c91036 100644 (file)
@@ -121,13 +121,19 @@ bool Image::OnDestroy()
 {
   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);
     });
   }
index 1b31be5..bcc8099 100644 (file)
@@ -70,8 +70,6 @@ struct Pipeline::Impl
     return mPipeline;
   }
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wframe-larger-than="
   vk::Result Initialise()
   {
     if( !ValidateShaderModules() )
@@ -243,7 +241,6 @@ struct Pipeline::Impl
     mColorBlendState.setPAttachments( &mAttachementNoBlendState );
     mInfo.setPColorBlendState(&mColorBlendState);
   }
-#pragma GCC diagnostic pop
 
   /**
    * Sets the shader. Must be set before compiling the pipeline, compiled pipeline
@@ -283,8 +280,6 @@ struct Pipeline::Impl
    * @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()
   {
 
@@ -342,7 +337,6 @@ struct Pipeline::Impl
     mDSLayoutArray = dsLayouts;
     mInfo.setLayout( mPipelineLayout );
   }
-#pragma GCC diagnostic pop
 
   vk::ShaderStageFlagBits GetShaderStage( RefCountedShader shader )
   {
index 953caa0..3265905 100644 (file)
@@ -159,7 +159,10 @@ ResourceCache& ResourceCache::RemoveBuffer( Buffer& buffer )
   {
     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();
@@ -174,7 +177,10 @@ ResourceCache& ResourceCache::RemoveImage( Image& image )
   {
     auto found = std::find_if(mImages.begin(),
                               mImages.end(),
-                              [&](const RefCountedImage entry) { return &(*entry) == &image; });
+                              [&](const RefCountedImage& entry)
+                              {
+                                return entry->GetVkHandle() == image.GetVkHandle();
+                              });
 
     std::iter_swap(found, std::prev(mImages.end()));
     mImages.back().Reset();
@@ -189,7 +195,10 @@ ResourceCache& ResourceCache::RemoveImageView( ImageView& imageView )
   {
     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();
@@ -204,7 +213,10 @@ ResourceCache& ResourceCache::RemoveShader( Shader& shader )
   {
     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();
@@ -217,12 +229,23 @@ ResourceCache& ResourceCache::RemoveCommandPool( CommandPool& commandPool )
 {
   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;
 }
@@ -233,7 +256,10 @@ ResourceCache& ResourceCache::RemoveDescriptorPool( DescriptorPool& descriptorPo
   {
     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();
@@ -248,7 +274,10 @@ ResourceCache& ResourceCache::RemoveFramebuffer( Framebuffer &framebuffer )
   {
     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();
@@ -263,7 +292,10 @@ ResourceCache& ResourceCache::RemoveSampler( Sampler &sampler )
   {
     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();
@@ -285,6 +317,120 @@ void ResourceCache::CollectGarbage()
 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
index 67df85d..f5a2193 100644 (file)
@@ -215,6 +215,12 @@ public:
 
   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
index 0b99df9..366b703 100644 (file)
@@ -150,10 +150,18 @@ Sampler::operator vk::Sampler*()
 
 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;
index b20717d..2f6f199 100644 (file)
@@ -107,7 +107,22 @@ vk::ShaderModule Shader::GetVkHandle() const
 
 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;
 }