Преглед изворни кода

[REFACTOR] Move some common functionality to a new class

Panagiotis Christopoulos Charitos пре 8 година
родитељ
комит
c8cb4b1b86

+ 0 - 94
src/anki/gr/vulkan/DeferredBarrierFactory.cpp

@@ -1,94 +0,0 @@
-// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <anki/gr/vulkan/DeferredBarrierFactory.h>
-
-namespace anki
-{
-
-void DeferredBarrierFactory::destroy()
-{
-	U count = m_barrierCount;
-	while(count--)
-	{
-		m_alloc.deleteInstance(m_barriers[count]);
-	}
-
-	m_barriers.destroy(m_alloc);
-}
-
-void DeferredBarrierFactory::releaseFences()
-{
-	U count = m_barrierCount;
-	while(count--)
-	{
-		MicroDeferredBarrier& b = *m_barriers[count];
-		if(b.m_fence && b.m_fence->done())
-		{
-			b.m_fence.reset(nullptr);
-		}
-	}
-}
-
-MicroDeferredBarrierPtr DeferredBarrierFactory::newInstance()
-{
-	LockGuard<Mutex> lock(m_mtx);
-
-	MicroDeferredBarrier* out = nullptr;
-
-	if(m_barrierCount > 0)
-	{
-		releaseFences();
-
-		U count = m_barrierCount;
-		while(count--)
-		{
-			if(!m_barriers[count]->m_fence)
-			{
-				out = m_barriers[count];
-
-				// Pop it
-				for(U i = count; i < m_barrierCount - 1; ++i)
-				{
-					m_barriers[i] = m_barriers[i + 1];
-				}
-
-				--m_barrierCount;
-
-				break;
-			}
-		}
-	}
-
-	if(out == nullptr)
-	{
-		// Create a new one
-		out = m_alloc.newInstance<MicroDeferredBarrier>(this);
-	}
-
-	ANKI_ASSERT(out->m_refcount.get() == 0);
-	return MicroDeferredBarrierPtr(out);
-}
-
-void DeferredBarrierFactory::destroyBarrier(MicroDeferredBarrier* s)
-{
-	ANKI_ASSERT(s);
-	ANKI_ASSERT(s->m_refcount.get() == 0);
-
-	LockGuard<Mutex> lock(m_mtx);
-
-	if(m_barriers.getSize() <= m_barrierCount)
-	{
-		// Grow storage
-		m_barriers.resize(m_alloc, max<U>(1, m_barriers.getSize() * 2));
-	}
-
-	m_barriers[m_barrierCount] = s;
-	++m_barrierCount;
-
-	releaseFences();
-}
-
-} // end namespace anki

+ 11 - 6
src/anki/gr/vulkan/DeferredBarrierFactory.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/gr/vulkan/FenceFactory.h>
+#include <anki/gr/vulkan/MicroObjectRecycler.h>
 
 namespace anki
 {
@@ -45,6 +46,11 @@ public:
 		m_fence = f;
 	}
 
+	MicroFencePtr& getFence()
+	{
+		return m_fence;
+	}
+
 private:
 	VkEvent m_handle = VK_NULL_HANDLE;
 	Atomic<U32> m_refcount = {0};
@@ -78,20 +84,19 @@ public:
 		m_dev = dev;
 	}
 
-	void destroy();
+	void destroy()
+	{
+		m_recycler.destroy();
+	}
 
 	MicroDeferredBarrierPtr newInstance();
 
 private:
 	GrAllocator<U8> m_alloc;
 	VkDevice m_dev = VK_NULL_HANDLE;
-	DynamicArray<MicroDeferredBarrier*> m_barriers;
-	U32 m_barrierCount = 0;
-	Mutex m_mtx;
+	MicroObjectRecycler<MicroDeferredBarrier> m_recycler;
 
 	void destroyBarrier(MicroDeferredBarrier* barrier);
-
-	void releaseFences();
 };
 /// @}
 

+ 20 - 2
src/anki/gr/vulkan/DeferredBarrierFactory.inl.h

@@ -26,10 +26,28 @@ inline MicroDeferredBarrier::~MicroDeferredBarrier()
 	}
 }
 
+inline GrAllocator<U8> MicroDeferredBarrier::getAllocator() const
+{
+	return m_factory->m_alloc;
+}
+
 inline void MicroDeferredBarrierPtrDeleter::operator()(MicroDeferredBarrier* s)
 {
 	ANKI_ASSERT(s);
-	s->m_factory->destroyBarrier(s);
+	s->m_factory->m_recycler.recycle(s);
+}
+
+inline MicroDeferredBarrierPtr DeferredBarrierFactory::newInstance()
+{
+	MicroDeferredBarrier* out = m_recycler.findToReuse();
+
+	if(out == nullptr)
+	{
+		// Create a new one
+		out = m_alloc.newInstance<MicroDeferredBarrier>(this);
+	}
+
+	return MicroDeferredBarrierPtr(out);
 }
 
-} // end namespace anki
+} // end namespace anki

+ 65 - 0
src/anki/gr/vulkan/MicroObjectRecycler.h

@@ -0,0 +1,65 @@
+// Copyright (C) 2009-2017, 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/util/DynamicArray.h>
+
+namespace anki
+{
+
+/// @addtogroup vulkan
+/// @{
+
+/// Helper class for MicroXXX objects.
+template<typename T>
+class MicroObjectRecycler
+{
+public:
+	MicroObjectRecycler()
+	{
+	}
+
+	MicroObjectRecycler(GrAllocator<U8> alloc)
+	{
+		init(alloc);
+	}
+
+	~MicroObjectRecycler()
+	{
+		destroy();
+	}
+
+	void init(GrAllocator<U8> alloc)
+	{
+		m_alloc = alloc;
+	}
+
+	/// It's thread-safe.
+	void destroy();
+
+	/// Find a new one to reuse. It's thread-safe.
+	T* findToReuse();
+
+	/// Release an object back to the recycler. It's thread-safe.
+	void recycle(T* s);
+
+private:
+	GrAllocator<U8> m_alloc;
+	DynamicArray<T*> m_objects;
+	U32 m_objectCount = 0;
+	Mutex m_mtx;
+#if ANKI_EXTRA_CHECKS
+	U32 m_createdAndNotRecycled = 0;
+#endif
+
+	void releaseFences();
+};
+/// @}
+
+} // end namespace anki
+
+#include <anki/gr/vulkan/MicroObjectRecycler.inl.h>

+ 111 - 0
src/anki/gr/vulkan/MicroObjectRecycler.inl.h

@@ -0,0 +1,111 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/gr/vulkan/MicroObjectRecycler.h>
+
+namespace anki
+{
+
+template<typename T>
+inline void MicroObjectRecycler<T>::destroy()
+{
+	LockGuard<Mutex> lock(m_mtx);
+
+	U count = m_objectCount;
+	while(count--)
+	{
+		T* obj = m_objects[count];
+		ANKI_ASSERT(obj);
+		ANKI_ASSERT(!obj->getFence() || obj->getFence()->done());
+
+		auto alloc = obj->getAllocator();
+		alloc.deleteInstance(obj);
+#if ANKI_EXTRA_CHECKS
+		--m_createdAndNotRecycled;
+#endif
+	}
+
+	m_objectCount = 0;
+	m_objects.destroy(m_alloc);
+	ANKI_ASSERT(m_createdAndNotRecycled == 0 && "Destroying the recycler while objects have not recycled yet");
+}
+
+template<typename T>
+inline void MicroObjectRecycler<T>::releaseFences()
+{
+	U count = m_objectCount;
+	while(count--)
+	{
+		T& obj = *m_objects[count];
+		if(obj.getFence() && obj.getFence()->done())
+		{
+			obj.getFence().reset(nullptr);
+		}
+	}
+}
+
+template<typename T>
+inline T* MicroObjectRecycler<T>::findToReuse()
+{
+	T* out = nullptr;
+	LockGuard<Mutex> lock(m_mtx);
+
+	if(m_objectCount > 0)
+	{
+		releaseFences();
+
+		U count = m_objectCount;
+		while(count--)
+		{
+			if(!m_objects[count]->getFence())
+			{
+				out = m_objects[count];
+
+				// Pop it
+				for(U i = count; i < m_objectCount - 1; ++i)
+				{
+					m_objects[i] = m_objects[i + 1];
+				}
+
+				--m_objectCount;
+
+				break;
+			}
+		}
+
+		ANKI_ASSERT(out->getRefcount().get() == 0);
+	}
+
+#if ANKI_EXTRA_CHECKS
+	if(out == nullptr)
+	{
+		++m_createdAndNotRecycled;
+	}
+#endif
+
+	return out;
+}
+
+template<typename T>
+inline void MicroObjectRecycler<T>::recycle(T* s)
+{
+	ANKI_ASSERT(s);
+	ANKI_ASSERT(s->getRefcount().get() == 0);
+
+	LockGuard<Mutex> lock(m_mtx);
+
+	releaseFences();
+
+	if(m_objects.getSize() <= m_objectCount)
+	{
+		// Grow storage
+		m_objects.resize(m_alloc, max<U>(1, m_objects.getSize() * 2));
+	}
+
+	m_objects[m_objectCount] = s;
+	++m_objectCount;
+}
+
+} // end namespace anki

+ 0 - 99
src/anki/gr/vulkan/SemaphoreFactory.cpp

@@ -1,99 +0,0 @@
-// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#include <anki/gr/vulkan/SemaphoreFactory.h>
-
-namespace anki
-{
-
-void SemaphoreFactory::destroy()
-{
-	for(U i = 0; i < m_semCount; ++i)
-	{
-		m_alloc.deleteInstance(m_sems[i]);
-	}
-
-	m_sems.destroy(m_alloc);
-}
-
-void SemaphoreFactory::releaseFences()
-{
-	U count = m_semCount;
-	while(count--)
-	{
-		MicroSemaphore& sem = *m_sems[count];
-		if(sem.m_fence && sem.m_fence->done())
-		{
-			sem.m_fence.reset(nullptr);
-		}
-	}
-}
-
-MicroSemaphorePtr SemaphoreFactory::newInstance(MicroFencePtr fence)
-{
-	ANKI_ASSERT(fence);
-
-	LockGuard<Mutex> lock(m_mtx);
-
-	MicroSemaphore* out = nullptr;
-
-	if(m_semCount > 0)
-	{
-		releaseFences();
-
-		U count = m_semCount;
-		while(count--)
-		{
-			if(!m_sems[count]->m_fence)
-			{
-				out = m_sems[count];
-
-				// Pop it
-				for(U i = count; i < m_semCount - 1; ++i)
-				{
-					m_sems[i] = m_sems[i + 1];
-				}
-
-				--m_semCount;
-
-				break;
-			}
-		}
-	}
-
-	if(out == nullptr)
-	{
-		// Create a new one
-		out = m_alloc.newInstance<MicroSemaphore>(this, fence);
-	}
-	else
-	{
-		out->m_fence = fence;
-	}
-
-	ANKI_ASSERT(out->m_refcount.get() == 0);
-	return MicroSemaphorePtr(out);
-}
-
-void SemaphoreFactory::destroySemaphore(MicroSemaphore* s)
-{
-	ANKI_ASSERT(s);
-	ANKI_ASSERT(s->m_refcount.get() == 0);
-
-	LockGuard<Mutex> lock(m_mtx);
-
-	if(m_sems.getSize() <= m_semCount)
-	{
-		// Grow storage
-		m_sems.resize(m_alloc, max<U>(1, m_sems.getSize() * 2));
-	}
-
-	m_sems[m_semCount] = s;
-	++m_semCount;
-
-	releaseFences();
-}
-
-} // end namespace anki

+ 12 - 9
src/anki/gr/vulkan/SemaphoreFactory.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/gr/vulkan/FenceFactory.h>
+#include <anki/gr/vulkan/MicroObjectRecycler.h>
 
 namespace anki
 {
@@ -38,6 +39,11 @@ public:
 		return m_refcount;
 	}
 
+	MicroFencePtr& getFence()
+	{
+		return m_fence;
+	}
+
 private:
 	VkSemaphore m_handle = VK_NULL_HANDLE;
 	Atomic<U32> m_refcount = {0};
@@ -73,23 +79,20 @@ public:
 		ANKI_ASSERT(dev);
 		m_alloc = alloc;
 		m_dev = dev;
+		m_recycler.init(alloc);
 	}
 
-	void destroy();
+	void destroy()
+	{
+		m_recycler.destroy();
+	}
 
 	MicroSemaphorePtr newInstance(MicroFencePtr fence);
 
 private:
 	GrAllocator<U8> m_alloc;
-	DynamicArray<MicroSemaphore*> m_sems;
-	U32 m_semCount = 0;
 	VkDevice m_dev = VK_NULL_HANDLE;
-	Mutex m_mtx;
-
-	void destroySemaphore(MicroSemaphore* s);
-
-	/// Iterate the semaphores and release the fences.
-	void releaseFences();
+	MicroObjectRecycler<MicroSemaphore> m_recycler;
 };
 /// @}
 

+ 26 - 1
src/anki/gr/vulkan/SemaphoreFactory.inl.h

@@ -30,10 +30,35 @@ inline MicroSemaphore::~MicroSemaphore()
 	}
 }
 
+inline GrAllocator<U8> MicroSemaphore::getAllocator() const
+{
+	return m_factory->m_alloc;
+}
+
 inline void MicroSemaphorePtrDeleter::operator()(MicroSemaphore* s)
 {
 	ANKI_ASSERT(s);
-	s->m_factory->destroySemaphore(s);
+	s->m_factory->m_recycler.recycle(s);
+}
+
+inline MicroSemaphorePtr SemaphoreFactory::newInstance(MicroFencePtr fence)
+{
+	ANKI_ASSERT(fence);
+
+	MicroSemaphore* out = m_recycler.findToReuse();
+
+	if(out == nullptr)
+	{
+		// Create a new one
+		out = m_alloc.newInstance<MicroSemaphore>(this, fence);
+	}
+	else
+	{
+		out->m_fence = fence;
+	}
+
+	ANKI_ASSERT(out->m_refcount.get() == 0);
+	return MicroSemaphorePtr(out);
 }
 
 } // end namespace anki

+ 6 - 83
src/anki/gr/vulkan/SwapchainFactory.cpp

@@ -280,102 +280,25 @@ GrAllocator<U8> MicroSwapchain::getAllocator() const
 	return m_factory->m_gr->getAllocator();
 }
 
-void SwapchainFactory::destroy()
-{
-	LockGuard<Mutex> lock(m_mtx);
-
-	U count = m_swapchainCount;
-	while(count--)
-	{
-		if(m_swapchains[count]->m_fence)
-		{
-			ANKI_ASSERT(m_swapchains[count]->m_fence->done());
-		}
-
-		m_gr->getAllocator().deleteInstance(m_swapchains[count]);
-#if ANKI_EXTRA_CHECKS
-		--m_swapchainsInFlight;
-#endif
-	}
-
-	m_swapchains.destroy(m_gr->getAllocator());
-
-	ANKI_ASSERT(m_swapchainsInFlight == 0 && "Wrong destroy order");
-}
-
 MicroSwapchainPtr SwapchainFactory::newInstance()
 {
-	LockGuard<Mutex> lock(m_mtx);
-
-	MicroSwapchain* out = nullptr;
-
-	if(m_swapchainCount > 0)
-	{
-		releaseFences();
-
-		U count = m_swapchainCount;
-		while(count--)
-		{
-			if(!m_swapchains[count]->m_fence)
-			{
-				out = m_swapchains[count];
-
-				// Pop it
-				for(U i = count; i < m_swapchainCount - 1; ++i)
-				{
-					m_swapchains[i] = m_swapchains[i + 1];
-				}
-
-				--m_swapchainCount;
-
-				break;
-			}
-		}
-	}
+	MicroSwapchain* out = m_recycler.findToReuse();
 
 	if(out == nullptr)
 	{
 		// Create a new one
 		out = m_gr->getAllocator().newInstance<MicroSwapchain>(this);
-#if ANKI_EXTRA_CHECKS
-		++m_swapchainsInFlight;
-#endif
 	}
 
-	ANKI_ASSERT(out->m_refcount.get() == 0);
 	return MicroSwapchainPtr(out);
 }
 
-void SwapchainFactory::releaseFences()
+void SwapchainFactory::init(GrManagerImpl* manager, Bool vsync)
 {
-	U count = m_swapchainCount;
-	while(count--)
-	{
-		MicroSwapchain& schain = *m_swapchains[count];
-		if(schain.m_fence && schain.m_fence->done())
-		{
-			schain.m_fence.reset(nullptr);
-		}
-	}
-}
-
-void SwapchainFactory::destroySwapchain(MicroSwapchain* schain)
-{
-	ANKI_ASSERT(schain);
-	ANKI_ASSERT(schain->m_refcount.get() == 0);
-
-	LockGuard<Mutex> lock(m_mtx);
-
-	releaseFences();
-
-	if(m_swapchains.getSize() <= m_swapchainCount)
-	{
-		// Grow storage
-		m_swapchains.resize(m_gr->getAllocator(), max<U>(1, m_swapchains.getSize() * 2));
-	}
-
-	m_swapchains[m_swapchainCount] = schain;
-	++m_swapchainCount;
+	ANKI_ASSERT(manager);
+	m_gr = manager;
+	m_vsync = vsync;
+	m_recycler.init(m_gr->getAllocator());
 }
 
 } // end namespace anki

+ 12 - 19
src/anki/gr/vulkan/SwapchainFactory.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/gr/vulkan/FenceFactory.h>
+#include <anki/gr/vulkan/MicroObjectRecycler.h>
 #include <anki/util/Ptr.h>
 
 namespace anki
@@ -54,6 +55,11 @@ public:
 		m_fence = fence;
 	}
 
+	MicroFencePtr& getFence()
+	{
+		return m_fence;
+	}
+
 	VkRenderPass getRenderPass(VkAttachmentLoadOp loadOp) const
 	{
 		const U idx = (loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE) ? RPASS_LOAD_DONT_CARE : RPASS_LOAD_CLEAR;
@@ -95,39 +101,26 @@ class SwapchainFactory
 	friend class MicroSwapchain;
 
 public:
-	void init(GrManagerImpl* manager, Bool vsync)
+	void init(GrManagerImpl* manager, Bool vsync);
+
+	void destroy()
 	{
-		ANKI_ASSERT(manager);
-		m_gr = manager;
-		m_vsync = vsync;
+		m_recycler.destroy();
 	}
 
-	void destroy();
-
 	MicroSwapchainPtr newInstance();
 
 private:
 	GrManagerImpl* m_gr = nullptr;
 	Bool8 m_vsync = false;
-
-	Mutex m_mtx;
-
-	DynamicArray<MicroSwapchain*> m_swapchains;
-	U32 m_swapchainCount = 0;
-#if ANKI_EXTRA_CHECKS
-	U32 m_swapchainsInFlight = 0;
-#endif
-
-	void destroySwapchain(MicroSwapchain* schain);
-
-	void releaseFences();
+	MicroObjectRecycler<MicroSwapchain> m_recycler;
 };
 /// @}
 
 inline void MicroSwapchainPtrDeleter::operator()(MicroSwapchain* s)
 {
 	ANKI_ASSERT(s);
-	s->m_factory->destroySwapchain(s);
+	s->m_factory->m_recycler.recycle(s);
 }
 
 } // end namespace anki