Browse Source

Add the FrameGarbageCollector

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
b17b527088

+ 2 - 1
AnKi/Gr/CMakeLists.txt

@@ -49,7 +49,8 @@ if(VULKAN)
 		"Vulkan/TextureViewImpl.cpp"
 		"Vulkan/TextureViewImpl.cpp"
 		"Vulkan/TimestampQuery.cpp"
 		"Vulkan/TimestampQuery.cpp"
 		"Vulkan/TimestampQueryImpl.cpp"
 		"Vulkan/TimestampQueryImpl.cpp"
-		"Vulkan/VulkanObject.cpp")
+		"Vulkan/VulkanObject.cpp"
+		"Vulkan/FrameGarbageCollector.cpp")
 
 
 	if(ANKI_HEADLESS)
 	if(ANKI_HEADLESS)
 		set(VKCPP ${VKCPP} "Vulkan/GrManagerImplHeadless.cpp")
 		set(VKCPP ${VKCPP} "Vulkan/GrManagerImplHeadless.cpp")

+ 0 - 3
AnKi/Gr/CommandBuffer.h

@@ -446,9 +446,6 @@ public:
 	void pushSecondLevelCommandBuffer(CommandBufferPtr cmdb);
 	void pushSecondLevelCommandBuffer(CommandBufferPtr cmdb);
 
 
 	Bool isEmpty() const;
 	Bool isEmpty() const;
-
-	/// The command buffer will co-own a pointer. Useful to track the lifetime of bindless resources.
-	void addReference(GrObjectPtr ptr);
 	/// @}
 	/// @}
 
 
 protected:
 protected:

+ 4 - 9
AnKi/Gr/Vulkan/BufferImpl.cpp

@@ -12,15 +12,10 @@ BufferImpl::~BufferImpl()
 {
 {
 	ANKI_ASSERT(!m_mapped);
 	ANKI_ASSERT(!m_mapped);
 
 
-	if(m_handle)
-	{
-		vkDestroyBuffer(getDevice(), m_handle, nullptr);
-	}
-
-	if(m_memHandle)
-	{
-		getGrManagerImpl().getGpuMemoryManager().freeMemory(m_memHandle);
-	}
+	BufferGarbage* garbage = getAllocator().newInstance<BufferGarbage>();
+	garbage->m_bufferHandle = m_handle;
+	garbage->m_memoryHandle = m_memHandle;
+	getGrManagerImpl().getFrameGarbageCollector().newBufferGarbage(garbage);
 
 
 #if ANKI_EXTRA_CHECKS
 #if ANKI_EXTRA_CHECKS
 	if(m_needsFlush && m_flushCount.load() == 0)
 	if(m_needsFlush && m_flushCount.load() == 0)

+ 0 - 6
AnKi/Gr/Vulkan/CommandBuffer.cpp

@@ -451,10 +451,4 @@ void CommandBuffer::setLineWidth(F32 width)
 	self.setLineWidth(width);
 	self.setLineWidth(width);
 }
 }
 
 
-void CommandBuffer::addReference(GrObjectPtr ptr)
-{
-	ANKI_VK_SELF(CommandBufferImpl);
-	self.addReference(ptr);
-}
-
 } // end namespace anki
 } // end namespace anki

+ 0 - 5
AnKi/Gr/Vulkan/CommandBufferImpl.h

@@ -379,11 +379,6 @@ public:
 
 
 	void setLineWidth(F32 width);
 	void setLineWidth(F32 width);
 
 
-	void addReference(GrObjectPtr& ptr)
-	{
-		m_microCmdb->pushObjectRef(ptr);
-	}
-
 private:
 private:
 	StackAllocator<U8> m_alloc;
 	StackAllocator<U8> m_alloc;
 
 

+ 156 - 0
AnKi/Gr/Vulkan/FrameGarbageCollector.cpp

@@ -0,0 +1,156 @@
+// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Gr/Vulkan/FrameGarbageCollector.h>
+#include <AnKi/Gr/Vulkan/GrManagerImpl.h>
+#include <AnKi/Gr/Fence.h>
+
+namespace anki {
+
+FrameGarbageCollector::~FrameGarbageCollector()
+{
+	destroy();
+}
+
+void FrameGarbageCollector::collectGarbage()
+{
+	if(ANKI_LIKELY(m_frames.isEmpty()))
+	{
+		return;
+	}
+
+	const VkDevice dev = m_gr->getDevice();
+	GrAllocator<U8> alloc = m_gr->getAllocator();
+
+	IntrusiveList<FrameGarbage> newFrames;
+	while(!m_frames.isEmpty())
+	{
+		FrameGarbage& frame = *m_frames.popFront();
+
+		if(frame.m_fence.isCreated() && !frame.m_fence->done())
+		{
+			ANKI_ASSERT(!frame.m_textureGarbage.isEmpty() || !frame.m_bufferGarbage.isEmpty());
+			newFrames.pushBack(&frame);
+			continue;
+		}
+
+		// Frame is done, dispose garbage and destroy it
+
+		// Dispose texture garbage
+		while(!frame.m_textureGarbage.isEmpty())
+		{
+			TextureGarbage* textureGarbage = frame.m_textureGarbage.popBack();
+
+			for(VkImageView viewHandle : textureGarbage->m_viewHandles)
+			{
+				vkDestroyImageView(dev, viewHandle, nullptr);
+			}
+			textureGarbage->m_viewHandles.destroy(alloc);
+
+			for(U32 bindlessIndex : textureGarbage->m_bindlessIndices)
+			{
+				m_gr->getDescriptorSetFactory().unbindBindlessImage(bindlessIndex);
+			}
+			textureGarbage->m_bindlessIndices.destroy(alloc);
+
+			if(textureGarbage->m_imageHandle)
+			{
+				vkDestroyImage(dev, textureGarbage->m_imageHandle, nullptr);
+			}
+
+			if(textureGarbage->m_memoryHandle)
+			{
+				m_gr->getGpuMemoryManager().freeMemory(textureGarbage->m_memoryHandle);
+			}
+
+			alloc.deleteInstance(textureGarbage);
+		}
+
+		// Dispose buffer garbage
+		while(!frame.m_bufferGarbage.isEmpty())
+		{
+			BufferGarbage* bufferGarbage = frame.m_bufferGarbage.popBack();
+
+			if(bufferGarbage->m_bufferHandle)
+			{
+				vkDestroyBuffer(dev, bufferGarbage->m_bufferHandle, nullptr);
+			}
+
+			if(bufferGarbage->m_memoryHandle)
+			{
+				m_gr->getGpuMemoryManager().freeMemory(bufferGarbage->m_memoryHandle);
+			}
+
+			alloc.deleteInstance(bufferGarbage);
+		}
+
+		alloc.deleteInstance(&frame);
+	}
+
+	m_frames = std::move(newFrames);
+}
+
+FrameGarbageCollector::FrameGarbage& FrameGarbageCollector::getFrame()
+{
+	if(!m_frames.isEmpty() && !m_frames.getBack().m_fence.isCreated())
+	{
+		// Do nothing
+	}
+	else
+	{
+		FrameGarbage* newGarbage = m_gr->getAllocator().newInstance<FrameGarbage>();
+		m_frames.pushBack(newGarbage);
+	}
+
+	return m_frames.getBack();
+}
+
+void FrameGarbageCollector::setNewFrame(MicroFencePtr frameFence)
+{
+	ANKI_ASSERT(frameFence.isCreated());
+
+	LockGuard<Mutex> lock(m_mtx);
+	ANKI_ASSERT(m_initialized);
+
+	if(!m_frames.isEmpty() && !m_frames.getBack().m_fence.isCreated())
+	{
+		// Last frame is without a fence, asign the fence to not not have it garbage collected
+		m_frames.getBack().m_fence = frameFence;
+	}
+
+	collectGarbage();
+}
+
+void FrameGarbageCollector::newTextureGarbage(TextureGarbage* textureGarbage)
+{
+	ANKI_ASSERT(textureGarbage);
+	LockGuard<Mutex> lock(m_mtx);
+	ANKI_ASSERT(m_initialized);
+	FrameGarbage& frame = getFrame();
+	frame.m_textureGarbage.pushBack(textureGarbage);
+}
+
+void FrameGarbageCollector::newBufferGarbage(BufferGarbage* bufferGarbage)
+{
+	ANKI_ASSERT(bufferGarbage);
+	LockGuard<Mutex> lock(m_mtx);
+	ANKI_ASSERT(m_initialized);
+	FrameGarbage& frame = getFrame();
+	frame.m_bufferGarbage.pushBack(bufferGarbage);
+}
+
+void FrameGarbageCollector::destroy()
+{
+	LockGuard<Mutex> lock(m_mtx);
+
+	collectGarbage();
+	ANKI_ASSERT(m_frames.isEmpty());
+
+#if ANKI_EXTRA_CHECKS
+	m_initialized = false;
+#endif
+}
+
+} // end namespace anki

+ 90 - 0
AnKi/Gr/Vulkan/FrameGarbageCollector.h

@@ -0,0 +1,90 @@
+// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Gr/Vulkan/Common.h>
+#include <AnKi/Gr/Vulkan/GpuMemoryManager.h>
+#include <AnKi/Gr/Vulkan/FenceFactory.h>
+#include <AnKi/Util/DynamicArray.h>
+#include <AnKi/Util/List.h>
+
+namespace anki {
+
+/// @addtogroup vulkan
+/// @{
+
+/// @memberof FrameGarbageCollector
+class TextureGarbage : public IntrusiveListEnabled<TextureGarbage>
+{
+public:
+	DynamicArray<VkImageView> m_viewHandles;
+	DynamicArray<U32> m_bindlessIndices;
+	VkImage m_imageHandle = VK_NULL_HANDLE;
+	GpuMemoryHandle m_memoryHandle;
+};
+
+/// @memberof FrameGarbageCollector
+class BufferGarbage : public IntrusiveListEnabled<BufferGarbage>
+{
+public:
+	VkBuffer m_bufferHandle = VK_NULL_HANDLE;
+	GpuMemoryHandle m_memoryHandle;
+};
+
+/// This class gathers various garbages and disposes them when in some later frame where it is safe to do so. This is
+/// used on bindless textures and buffers where we have to wait until the frame where they were deleted is done.
+class FrameGarbageCollector
+{
+public:
+	FrameGarbageCollector() = default;
+
+	~FrameGarbageCollector();
+
+	void init(GrManagerImpl* gr)
+	{
+		m_gr = gr;
+#if ANKI_EXTRA_CHECKS
+		m_initialized = true;
+#endif
+	}
+
+	void destroy();
+
+	/// Sets a new frame and collects garbage as well.
+	/// @note It's thread-safe.
+	void setNewFrame(MicroFencePtr frameFence);
+
+	/// @note It's thread-safe.
+	void newTextureGarbage(TextureGarbage* textureGarbage);
+
+	/// @note It's thread-safe.
+	void newBufferGarbage(BufferGarbage* bufferGarbage);
+
+private:
+	class FrameGarbage : public IntrusiveListEnabled<FrameGarbage>
+	{
+	public:
+		IntrusiveList<TextureGarbage> m_textureGarbage;
+		IntrusiveList<BufferGarbage> m_bufferGarbage;
+		MicroFencePtr m_fence;
+	};
+
+	GrManagerImpl* m_gr = nullptr;
+
+	Mutex m_mtx;
+	IntrusiveList<FrameGarbage> m_frames;
+
+#if ANKI_EXTRA_CHECKS
+	Bool m_initialized = false;
+#endif
+
+	void collectGarbage();
+
+	FrameGarbage& getFrame();
+};
+/// @}
+
+} // end namespace anki

+ 41 - 30
AnKi/Gr/Vulkan/GrManagerImpl.cpp

@@ -40,9 +40,9 @@ GrManagerImpl::~GrManagerImpl()
 		}
 		}
 	}
 	}
 
 
+	// 3rd THING: The destroy everything that has a reference to GrObjects.
 	m_cmdbFactory.destroy();
 	m_cmdbFactory.destroy();
 
 
-	// 3rd THING: The destroy everything that has a reference to GrObjects.
 	for(PerFrame& frame : m_perFrame)
 	for(PerFrame& frame : m_perFrame)
 	{
 	{
 		frame.m_presentFence.reset(nullptr);
 		frame.m_presentFence.reset(nullptr);
@@ -53,11 +53,13 @@ GrManagerImpl::~GrManagerImpl()
 	m_crntSwapchain.reset(nullptr);
 	m_crntSwapchain.reset(nullptr);
 
 
 	// 4th THING: Continue with the rest
 	// 4th THING: Continue with the rest
-	m_gpuMemManager.destroy();
 
 
 	m_barrierFactory.destroy(); // Destroy before fences
 	m_barrierFactory.destroy(); // Destroy before fences
 	m_semaphoreFactory.destroy(); // Destroy before fences
 	m_semaphoreFactory.destroy(); // Destroy before fences
 	m_swapchainFactory.destroy(); // Destroy before fences
 	m_swapchainFactory.destroy(); // Destroy before fences
+	m_frameGarbageCollector.destroy();
+
+	m_gpuMemManager.destroy();
 
 
 	m_pplineLayoutFactory.destroy();
 	m_pplineLayoutFactory.destroy();
 	m_descrFactory.destroy();
 	m_descrFactory.destroy();
@@ -193,6 +195,8 @@ Error GrManagerImpl::initInternal(const GrManagerInitInfo& init)
 	ANKI_CHECK(m_descrFactory.init(getAllocator(), m_device, MAX_BINDLESS_TEXTURES, MAX_BINDLESS_IMAGES));
 	ANKI_CHECK(m_descrFactory.init(getAllocator(), m_device, MAX_BINDLESS_TEXTURES, MAX_BINDLESS_IMAGES));
 	m_pplineLayoutFactory.init(getAllocator(), m_device);
 	m_pplineLayoutFactory.init(getAllocator(), m_device);
 
 
+	m_frameGarbageCollector.init(this);
+
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
@@ -1327,48 +1331,55 @@ void GrManagerImpl::flushCommandBuffer(MicroCommandBufferPtr cmdb, Bool cmdbRend
 		++submit.signalSemaphoreCount;
 		++submit.signalSemaphoreCount;
 	}
 	}
 
 
-	// Protect the class, the queue and other stuff
-	LockGuard<Mutex> lock(m_globalMtx);
-
-	// Do some special stuff for the last command buffer
-	PerFrame& frame = m_perFrame[m_frame % MAX_FRAMES_IN_FLIGHT];
-	if(cmdbRenderedToSwapchain)
+	// Submit
 	{
 	{
-		// Wait semaphore
-		waitSemaphores[submit.waitSemaphoreCount] = frame.m_acquireSemaphore->getHandle();
+		// Protect the class, the queue and other stuff
+		LockGuard<Mutex> lock(m_globalMtx);
 
 
-		// That depends on how we use the swapchain img. Be a bit conservative
-		waitStages[submit.waitSemaphoreCount] =
-			VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
-		++submit.waitSemaphoreCount;
+		// Do some special stuff for the last command buffer
+		PerFrame& frame = m_perFrame[m_frame % MAX_FRAMES_IN_FLIGHT];
+		if(cmdbRenderedToSwapchain)
+		{
+			// Wait semaphore
+			waitSemaphores[submit.waitSemaphoreCount] = frame.m_acquireSemaphore->getHandle();
 
 
-		// Refresh the fence because the semaphore can't be recycled until the current submission is done
-		frame.m_acquireSemaphore->setFence(fence);
+			// That depends on how we use the swapchain img. Be a bit conservative
+			waitStages[submit.waitSemaphoreCount] =
+				VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+			++submit.waitSemaphoreCount;
 
 
-		// Create the semaphore to signal
-		ANKI_ASSERT(!frame.m_renderSemaphore && "Only one begin/end render pass is allowed with the default fb");
-		frame.m_renderSemaphore = m_semaphoreFactory.newInstance(fence, false);
+			// Refresh the fence because the semaphore can't be recycled until the current submission is done
+			frame.m_acquireSemaphore->setFence(fence);
 
 
-		signalSemaphores[submit.signalSemaphoreCount++] = frame.m_renderSemaphore->getHandle();
+			// Create the semaphore to signal
+			ANKI_ASSERT(!frame.m_renderSemaphore && "Only one begin/end render pass is allowed with the default fb");
+			frame.m_renderSemaphore = m_semaphoreFactory.newInstance(fence, false);
 
 
-		// Update the frame fence
-		frame.m_presentFence = fence;
+			signalSemaphores[submit.signalSemaphoreCount++] = frame.m_renderSemaphore->getHandle();
 
 
-		// Update the swapchain's fence
-		m_crntSwapchain->setFence(fence);
+			// Update the frame fence
+			frame.m_presentFence = fence;
 
 
-		frame.m_queueWroteToSwapchainImage = cmdb->getVulkanQueueType();
-	}
+			// Update the swapchain's fence
+			m_crntSwapchain->setFence(fence);
 
 
-	// Submit
-	{
+			frame.m_queueWroteToSwapchainImage = cmdb->getVulkanQueueType();
+		}
+
+		// Submit
 		ANKI_TRACE_SCOPED_EVENT(VK_QUEUE_SUBMIT);
 		ANKI_TRACE_SCOPED_EVENT(VK_QUEUE_SUBMIT);
 		ANKI_VK_CHECKF(vkQueueSubmit(m_queues[cmdb->getVulkanQueueType()], 1, &submit, fence->getHandle()));
 		ANKI_VK_CHECKF(vkQueueSubmit(m_queues[cmdb->getVulkanQueueType()], 1, &submit, fence->getHandle()));
+
+		if(wait)
+		{
+			vkQueueWaitIdle(m_queues[cmdb->getVulkanQueueType()]);
+		}
 	}
 	}
 
 
-	if(wait)
+	// Garbage work
+	if(cmdbRenderedToSwapchain)
 	{
 	{
-		vkQueueWaitIdle(m_queues[cmdb->getVulkanQueueType()]);
+		m_frameGarbageCollector.setNewFrame(fence);
 	}
 	}
 }
 }
 
 

+ 8 - 0
AnKi/Gr/Vulkan/GrManagerImpl.h

@@ -19,6 +19,7 @@
 #include <AnKi/Gr/Vulkan/PipelineLayout.h>
 #include <AnKi/Gr/Vulkan/PipelineLayout.h>
 #include <AnKi/Gr/Vulkan/PipelineCache.h>
 #include <AnKi/Gr/Vulkan/PipelineCache.h>
 #include <AnKi/Gr/Vulkan/DescriptorSet.h>
 #include <AnKi/Gr/Vulkan/DescriptorSet.h>
+#include <AnKi/Gr/Vulkan/FrameGarbageCollector.h>
 #include <AnKi/Util/HashMap.h>
 #include <AnKi/Util/HashMap.h>
 #include <AnKi/Util/File.h>
 #include <AnKi/Util/File.h>
 
 
@@ -213,6 +214,11 @@ public:
 
 
 	void printPipelineShaderInfo(VkPipeline ppline, CString name, ShaderTypeBit stages, U64 hash = 0) const;
 	void printPipelineShaderInfo(VkPipeline ppline, CString name, ShaderTypeBit stages, U64 hash = 0) const;
 
 
+	FrameGarbageCollector& getFrameGarbageCollector()
+	{
+		return m_frameGarbageCollector;
+	}
+
 private:
 private:
 	U64 m_frame = 0;
 	U64 m_frame = 0;
 
 
@@ -315,6 +321,8 @@ private:
 	mutable HashMap<U64, StringAuto> m_vkHandleToName;
 	mutable HashMap<U64, StringAuto> m_vkHandleToName;
 	mutable SpinLock m_vkHandleToNameLock;
 	mutable SpinLock m_vkHandleToNameLock;
 
 
+	FrameGarbageCollector m_frameGarbageCollector;
+
 	ANKI_USE_RESULT Error initInternal(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initInternal(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initInstance(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initInstance(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initSurface(const GrManagerInitInfo& init);
 	ANKI_USE_RESULT Error initSurface(const GrManagerInitInfo& init);

+ 34 - 28
AnKi/Gr/Vulkan/TextureImpl.cpp

@@ -83,27 +83,54 @@ TextureImpl::~TextureImpl()
 	}
 	}
 #endif
 #endif
 
 
+	TextureGarbage* garbage = getAllocator().newInstance<TextureGarbage>();
+
 	for(MicroImageView& it : m_viewsMap)
 	for(MicroImageView& it : m_viewsMap)
 	{
 	{
-		destroyMicroImageView(it);
+		garbage->m_viewHandles.emplaceBack(getAllocator(), it.m_handle);
+		it.m_handle = VK_NULL_HANDLE;
+
+		if(it.m_bindlessIndices[0] != MAX_U32)
+		{
+			garbage->m_bindlessIndices.emplaceBack(getAllocator(), it.m_bindlessIndices[0]);
+			it.m_bindlessIndices[0] = MAX_U32;
+		}
+
+		if(it.m_bindlessIndices[1] != MAX_U32)
+		{
+			garbage->m_bindlessIndices.emplaceBack(getAllocator(), it.m_bindlessIndices[1]);
+			it.m_bindlessIndices[1] = MAX_U32;
+		}
 	}
 	}
 
 
 	m_viewsMap.destroy(getAllocator());
 	m_viewsMap.destroy(getAllocator());
 
 
 	if(m_singleSurfaceImageView.m_handle != VK_NULL_HANDLE)
 	if(m_singleSurfaceImageView.m_handle != VK_NULL_HANDLE)
 	{
 	{
-		destroyMicroImageView(m_singleSurfaceImageView);
+		garbage->m_viewHandles.emplaceBack(getAllocator(), m_singleSurfaceImageView.m_handle);
+		m_singleSurfaceImageView.m_handle = VK_NULL_HANDLE;
+
+		if(m_singleSurfaceImageView.m_bindlessIndices[0] != MAX_U32)
+		{
+			garbage->m_bindlessIndices.emplaceBack(getAllocator(), m_singleSurfaceImageView.m_bindlessIndices[0]);
+			m_singleSurfaceImageView.m_bindlessIndices[0] = MAX_U32;
+		}
+
+		if(m_singleSurfaceImageView.m_bindlessIndices[1] != MAX_U32)
+		{
+			garbage->m_bindlessIndices.emplaceBack(getAllocator(), m_singleSurfaceImageView.m_bindlessIndices[1]);
+			m_singleSurfaceImageView.m_bindlessIndices[1] = MAX_U32;
+		}
 	}
 	}
 
 
 	if(m_imageHandle && !(m_usage & TextureUsageBit::PRESENT))
 	if(m_imageHandle && !(m_usage & TextureUsageBit::PRESENT))
 	{
 	{
-		vkDestroyImage(getDevice(), m_imageHandle, nullptr);
+		garbage->m_imageHandle = m_imageHandle;
 	}
 	}
 
 
-	if(m_memHandle)
-	{
-		getGrManagerImpl().getGpuMemoryManager().freeMemory(m_memHandle);
-	}
+	garbage->m_memoryHandle = m_memHandle;
+
+	getGrManagerImpl().getFrameGarbageCollector().newTextureGarbage(garbage);
 }
 }
 
 
 Error TextureImpl::initInternal(VkImage externalImage, const TextureInitInfo& init_)
 Error TextureImpl::initInternal(VkImage externalImage, const TextureInitInfo& init_)
@@ -622,25 +649,4 @@ TextureType TextureImpl::computeNewTexTypeOfSubresource(const TextureSubresource
 	return m_texType;
 	return m_texType;
 }
 }
 
 
-void TextureImpl::destroyMicroImageView(MicroImageView& view)
-{
-	if(view.m_handle != VK_NULL_HANDLE)
-	{
-		vkDestroyImageView(getDevice(), view.m_handle, nullptr);
-		view.m_handle = VK_NULL_HANDLE;
-	}
-
-	if(view.m_bindlessIndices[0] != MAX_U32)
-	{
-		getGrManagerImpl().getDescriptorSetFactory().unbindBindlessTexture(view.m_bindlessIndices[0]);
-		view.m_bindlessIndices[0] = MAX_U32;
-	}
-
-	if(view.m_bindlessIndices[1] != MAX_U32)
-	{
-		getGrManagerImpl().getDescriptorSetFactory().unbindBindlessImage(view.m_bindlessIndices[1]);
-		view.m_bindlessIndices[1] = MAX_U32;
-	}
-}
-
 } // end namespace anki
 } // end namespace anki

+ 0 - 2
AnKi/Gr/Vulkan/TextureImpl.h

@@ -220,8 +220,6 @@ private:
 
 
 	void computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level, VkPipelineStageFlags& stages,
 	void computeBarrierInfo(TextureUsageBit usage, Bool src, U32 level, VkPipelineStageFlags& stages,
 							VkAccessFlags& accesses) const;
 							VkAccessFlags& accesses) const;
-
-	void destroyMicroImageView(MicroImageView& view);
 };
 };
 /// @}
 /// @}
 
 

+ 0 - 3
Tests/Gr/Gr.cpp

@@ -2263,9 +2263,6 @@ void main()
 	cmdb->bindSampler(1, 1, sampler);
 	cmdb->bindSampler(1, 1, sampler);
 	cmdb->bindShaderProgram(prog);
 	cmdb->bindShaderProgram(prog);
 
 
-	cmdb->addReference(viewA);
-	cmdb->addReference(viewB);
-	cmdb->addReference(viewC);
 	const U32 idx0 = viewA->getOrCreateBindlessImageIndex();
 	const U32 idx0 = viewA->getOrCreateBindlessImageIndex();
 	const U32 idx1 = viewB->getOrCreateBindlessTextureIndex();
 	const U32 idx1 = viewB->getOrCreateBindlessTextureIndex();
 	const U32 idx2 = viewC->getOrCreateBindlessTextureIndex();
 	const U32 idx2 = viewC->getOrCreateBindlessTextureIndex();