瀏覽代碼

Vulkan: Some work on descriptors

Panagiotis Christopoulos Charitos 9 年之前
父節點
當前提交
a037644439

+ 7 - 0
src/anki/gr/vulkan/Common.h

@@ -32,6 +32,13 @@ class GrManagerImpl;
 /// @addtogroup vulkan
 /// @addtogroup vulkan
 /// @{
 /// @{
 
 
+/// @name Constants
+/// @{
+const U DESCRIPTOR_POOL_INITIAL_SIZE = 64;
+const F32 DESCRIPTOR_POOL_SIZE_SCALE = 2.0;
+const U DESCRIPTOR_FRAME_BUFFERING = 60 * 5; ///< How many frames worth of descriptors to buffer.
+/// @}
+
 /// Check if a vulkan function failed. It will abort on failure.
 /// Check if a vulkan function failed. It will abort on failure.
 #define ANKI_VK_CHECKF(x)                                                                                              \
 #define ANKI_VK_CHECKF(x)                                                                                              \
 	do                                                                                                                 \
 	do                                                                                                                 \

+ 265 - 63
src/anki/gr/vulkan/DescriptorSet.cpp

@@ -4,91 +4,220 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 #include <anki/gr/vulkan/DescriptorSet.h>
 #include <anki/gr/vulkan/DescriptorSet.h>
+#include <anki/util/List.h>
+#include <anki/util/HashMap.h>
 #include <algorithm>
 #include <algorithm>
 
 
 namespace anki
 namespace anki
 {
 {
 
 
+/// Descriptor set internal class.
+class DS : public IntrusiveListEnabled<DS>, public IntrusiveHashMapEnabled<DS>
+{
+public:
+	VkDescriptorSet m_handle = {};
+	U64 m_lastFrameUsed = MAX_U64;
+};
+
+class DSThreadAllocator
+{
+public:
+	const DSLayoutCacheEntry* m_layoutEntry; ///< Know your father.
+
+	ThreadId m_tid;
+	DynamicArray<VkDescriptorPool> m_pools;
+	U32 m_lastPoolDSCount = 0;
+	U32 m_lastPoolFreeDSCount = 0;
+
+	IntrusiveList<DS> m_list; ///< At the left of the list are the least used sets.
+	IntrusiveHashMap<U64, DS> m_hashmap;
+
+	DSThreadAllocator(const DSLayoutCacheEntry* layout, ThreadId tid)
+		: m_layoutEntry(layout)
+		, m_tid(tid)
+	{
+		ANKI_ASSERT(m_layoutEntry);
+	}
+
+	~DSThreadAllocator();
+
+	ANKI_USE_RESULT Error init();
+	ANKI_USE_RESULT Error createNewPool();
+
+	ANKI_USE_RESULT Error getOrCreateSet(U64 hash, const DSWriteInfo& inf, DS*& out)
+	{
+		out = tryFindSet(hash);
+		if(out == nullptr)
+		{
+			ANKI_CHECK(newSet(hash, inf, out));
+		}
+
+		return ErrorCode::NONE;
+	}
+
+private:
+	ANKI_USE_RESULT DS* tryFindSet(U64 hash);
+	ANKI_USE_RESULT Error newSet(U64 hash, const DSWriteInfo& inf, DS*& out);
+	void writeSet(const DSWriteInfo& inf, DS& set);
+};
+
 /// Cache entry. It's built around a specific descriptor set layout.
 /// Cache entry. It's built around a specific descriptor set layout.
-class DescriptorSetFactory::Cache
+class DSLayoutCacheEntry
 {
 {
 public:
 public:
-	U64 m_hash;
-	VkDescriptorSetLayout m_layoutHandle;
-	VkDescriptorPool m_poolHandle;
-	Mutex m_mtx;
+	DescriptorSetFactory* m_factory;
+
+	U64 m_hash = 0; ///< Layout hash.
+	VkDescriptorSetLayout m_layoutHandle = {};
+
+	// Cache the create info
+	Array<VkDescriptorPoolSize, DESCRIPTOR_TYPE_COUNT> m_poolSizesCreateInf = {};
+	VkDescriptorPoolCreateInfo m_poolCreateInf = {};
+
+	DynamicArray<DSThreadAllocator*> m_threadCaches;
+	Mutex m_threadCachesMtx;
+
+	DSLayoutCacheEntry(DescriptorSetFactory* factory)
+		: m_factory(factory)
+	{
+	}
+
+	~DSLayoutCacheEntry();
+
+	ANKI_USE_RESULT Error init(const DescriptorBinding* bindings, U bindingCount, U64 hash);
 };
 };
 
 
-DescriptorSetFactory::~DescriptorSetFactory()
+Error DSThreadAllocator::init()
 {
 {
+	ANKI_CHECK(createNewPool());
+	return ErrorCode::NONE;
 }
 }
 
 
-void DescriptorSetFactory::init(const GrAllocator<U8>& alloc, VkDevice dev)
+Error DSThreadAllocator::createNewPool()
 {
 {
-	m_alloc = alloc;
-	m_dev = dev;
+	m_lastPoolDSCount =
+		(m_lastPoolDSCount != 0) ? (m_lastPoolDSCount * DESCRIPTOR_POOL_SIZE_SCALE) : DESCRIPTOR_POOL_INITIAL_SIZE;
+	m_lastPoolFreeDSCount = m_lastPoolDSCount;
+
+	// Set the create info
+	Array<VkDescriptorPoolSize, DESCRIPTOR_TYPE_COUNT> poolSizes;
+	memcpy(&poolSizes[0],
+		&m_layoutEntry->m_poolSizesCreateInf[0],
+		sizeof(poolSizes[0]) * m_layoutEntry->m_poolCreateInf.poolSizeCount);
+
+	for(U i = 0; i < m_layoutEntry->m_poolCreateInf.poolSizeCount; ++i)
+	{
+		poolSizes[i].descriptorCount *= m_lastPoolDSCount;
+		ANKI_ASSERT(poolSizes[i].descriptorCount > 0);
+	}
+
+	VkDescriptorPoolCreateInfo ci = m_layoutEntry->m_poolCreateInf;
+	ci.pPoolSizes = &poolSizes[0];
+	ci.maxSets = m_lastPoolDSCount;
+
+	// Create
+	VkDescriptorPool pool;
+	ANKI_VK_CHECK(vkCreateDescriptorPool(m_layoutEntry->m_factory->m_dev, &ci, nullptr, &pool));
+
+	// Push back
+	m_pools.resize(m_layoutEntry->m_factory->m_alloc, m_pools.getSize() + 1);
+	m_pools[m_pools.getSize() - 1] = pool;
+
+	return ErrorCode::NONE;
 }
 }
 
 
-void DescriptorSetFactory::newDescriptorSetLayout(const DescriptorSetLayoutInitInfo& init, DescriptorSetLayout& layout)
+DS* DSThreadAllocator::tryFindSet(U64 hash)
 {
 {
-	// Compute the hash for the layout
-	Array<DescriptorBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> bindings;
-	U bindingCount = init.m_bindings.getSize();
-	U64 hash;
+	ANKI_ASSERT(hash > 0);
 
 
-	if(init.m_bindings.getSize() > 0)
+	auto it = m_hashmap.find(hash);
+	if(it != m_hashmap.getEnd())
 	{
 	{
-		memcpy(&bindings[0], &init.m_bindings[0], init.m_bindings.getSizeInBytes());
-		std::sort(&bindings[0],
-			&bindings[0] + bindingCount,
-			[](const DescriptorBinding& a, const DescriptorBinding& b) { return a.m_binding < b.m_binding; });
-
-		hash = computeHash(&bindings[0], init.m_bindings.getSizeInBytes());
-		ANKI_ASSERT(hash != 1);
+		return nullptr;
 	}
 	}
 	else
 	else
 	{
 	{
-		hash = 1;
+		DS* ds = &(*it);
+
+		// Remove from the list and place at the end of the list
+		m_list.erase(ds);
+		m_list.pushBack(ds);
+		ds->m_lastFrameUsed = m_layoutEntry->m_factory->m_frameCount;
+
+		return ds;
 	}
 	}
+}
 
 
-	// Find or create the cache entry
-	LockGuard<Mutex> lock(m_mtx);
+Error DSThreadAllocator::newSet(U64 hash, const DSWriteInfo& inf, DS*& out)
+{
+	out = nullptr;
 
 
-	Cache* cache = nullptr;
-	U cacheIdx = MAX_U;
-	U count = 0;
-	for(Cache* it : m_caches)
+	// First try to see if there are unused to recycle
+	const U64 crntFrame = m_layoutEntry->m_factory->m_frameCount;
+	auto it = m_list.getBegin();
+	const auto end = m_list.getEnd();
+	while(it != end)
 	{
 	{
-		if(it->m_hash == hash)
+		DS* set = &(*it);
+		U64 frameDiff = crntFrame - set->m_lastFrameUsed;
+		if(frameDiff > DESCRIPTOR_FRAME_BUFFERING)
 		{
 		{
-			cache = it;
-			cacheIdx = count;
+			// Found something, recycle
+			m_hashmap.erase(set);
+			m_list.erase(set);
+			m_list.pushBack(set);
+			m_hashmap.pushBack(hash, set);
+
+			out = set;
 			break;
 			break;
 		}
 		}
-		++count;
 	}
 	}
 
 
-	if(cache == nullptr)
+	if(out == nullptr)
 	{
 	{
-		cache = newCacheEntry(&bindings[0], bindingCount, hash);
-		m_caches.resize(m_alloc, m_caches.getSize() + 1);
-		m_caches[m_caches.getSize() - 1] = cache;
-		cacheIdx = m_caches.getSize() - 1;
+		// Need to allocate one
+
+		if(m_lastPoolFreeDSCount == 0)
+		{
+			// Can't allocate one from the current pool, create new
+			ANKI_CHECK(createNewPool());
+		}
+
+		VkDescriptorSetAllocateInfo ci = {};
+		ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+		ci.descriptorPool = m_pools.getBack();
+		ci.pSetLayouts = &m_layoutEntry->m_layoutHandle;
+		ci.descriptorSetCount = 1;
+
+		VkDescriptorSet handle;
+		VkResult rez = vkAllocateDescriptorSets(m_layoutEntry->m_factory->m_dev, &ci, &handle);
+		(void)rez;
+		ANKI_ASSERT(rez == VK_SUCCESS && "That allocation can't fail");
+
+		out = m_layoutEntry->m_factory->m_alloc.newInstance<DS>();
+		out->m_handle = handle;
 	}
 	}
 
 
-	// Set the layout
-	layout.m_handle = cache->m_layoutHandle;
-	layout.m_cacheEntryIdx = cacheIdx;
+	ANKI_ASSERT(out);
+	out->m_lastFrameUsed = m_layoutEntry->m_factory->m_frameCount;
+
+	// Finally, write it
+	writeSet(inf, *out);
+
+	return ErrorCode::NONE;
 }
 }
 
 
-DescriptorSetFactory::Cache* DescriptorSetFactory::newCacheEntry(
-	const DescriptorBinding* bindings, U bindingCount, U64 hash)
+void DSThreadAllocator::writeSet(const DSWriteInfo& inf, DS& set)
+{
+	ANKI_ASSERT(!"TODO");
+}
+
+Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount, U64 hash)
 {
 {
 	ANKI_ASSERT(bindings);
 	ANKI_ASSERT(bindings);
+	ANKI_ASSERT(hash > 0);
 
 
-	// Create
-	Cache* cache = m_alloc.newInstance<Cache>();
-	cache->m_hash = hash;
+	m_hash = hash;
 
 
 	// Create the VK layout
 	// Create the VK layout
 	Array<VkDescriptorSetLayoutBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> vkBindings;
 	Array<VkDescriptorSetLayoutBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> vkBindings;
@@ -110,48 +239,121 @@ DescriptorSetFactory::Cache* DescriptorSetFactory::newCacheEntry(
 	ci.bindingCount = bindingCount;
 	ci.bindingCount = bindingCount;
 	ci.pBindings = &vkBindings[0];
 	ci.pBindings = &vkBindings[0];
 
 
-	ANKI_VK_CHECKF(vkCreateDescriptorSetLayout(m_dev, &ci, nullptr, &cache->m_layoutHandle));
+	ANKI_VK_CHECK(vkCreateDescriptorSetLayout(m_factory->m_dev, &ci, nullptr, &m_layoutHandle));
 
 
-	// Create the pool
-	Array<VkDescriptorPoolSize, DESCRIPTOR_TYPE_COUNT> poolSizes;
+	// Create the pool info
 	U poolSizeCount = 0;
 	U poolSizeCount = 0;
 	for(U i = 0; i < bindingCount; ++i)
 	for(U i = 0; i < bindingCount; ++i)
 	{
 	{
 		U j;
 		U j;
 		for(j = 0; j < poolSizeCount; ++j)
 		for(j = 0; j < poolSizeCount; ++j)
 		{
 		{
-			if(poolSizes[j].type == bindings[i].m_type)
+			if(m_poolSizesCreateInf[j].type == bindings[i].m_type)
 			{
 			{
-				++poolSizes[j].descriptorCount;
+				++m_poolSizesCreateInf[j].descriptorCount;
 				break;
 				break;
 			}
 			}
 		}
 		}
 
 
 		if(j == poolSizeCount)
 		if(j == poolSizeCount)
 		{
 		{
-			poolSizes[poolSizeCount].type = static_cast<VkDescriptorType>(bindings[i].m_type);
-			poolSizes[poolSizeCount].descriptorCount = 1;
+			m_poolSizesCreateInf[poolSizeCount].type = static_cast<VkDescriptorType>(bindings[i].m_type);
+
+			switch(m_poolSizesCreateInf[poolSizeCount].type)
+			{
+			case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+				m_poolSizesCreateInf[poolSizeCount].descriptorCount = MAX_TEXTURE_BINDINGS;
+				break;
+			case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+				m_poolSizesCreateInf[poolSizeCount].descriptorCount = MAX_UNIFORM_BUFFER_BINDINGS;
+				break;
+			case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+				m_poolSizesCreateInf[poolSizeCount].descriptorCount = MAX_STORAGE_BUFFER_BINDINGS;
+				break;
+			case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+				m_poolSizesCreateInf[poolSizeCount].descriptorCount = MAX_IMAGE_BINDINGS;
+				break;
+			default:
+				ANKI_ASSERT(0);
+			}
+
+			m_poolSizesCreateInf[poolSizeCount].descriptorCount = 1;
 			++poolSizeCount;
 			++poolSizeCount;
 		}
 		}
 	}
 	}
 
 
 	ANKI_ASSERT(poolSizeCount > 0);
 	ANKI_ASSERT(poolSizeCount > 0);
 
 
-	for(U i = 0; i < poolSizeCount; ++i)
+	m_poolCreateInf.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+	m_poolCreateInf.poolSizeCount = poolSizeCount;
+
+	return ErrorCode::NONE;
+}
+
+DescriptorSetFactory::~DescriptorSetFactory()
+{
+}
+
+void DescriptorSetFactory::init(const GrAllocator<U8>& alloc, VkDevice dev)
+{
+	m_alloc = alloc;
+	m_dev = dev;
+}
+
+Error DescriptorSetFactory::newDescriptorSetLayout(const DescriptorSetLayoutInitInfo& init, DescriptorSetLayout& layout)
+{
+	// Compute the hash for the layout
+	Array<DescriptorBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> bindings;
+	U bindingCount = init.m_bindings.getSize();
+	U64 hash;
+
+	if(init.m_bindings.getSize() > 0)
+	{
+		memcpy(&bindings[0], &init.m_bindings[0], init.m_bindings.getSizeInBytes());
+		std::sort(&bindings[0],
+			&bindings[0] + bindingCount,
+			[](const DescriptorBinding& a, const DescriptorBinding& b) { return a.m_binding < b.m_binding; });
+
+		hash = computeHash(&bindings[0], init.m_bindings.getSizeInBytes());
+		ANKI_ASSERT(hash != 1);
+	}
+	else
+	{
+		hash = 1;
+	}
+
+	// Find or create the cache entry
+	LockGuard<Mutex> lock(m_cachesMtx);
+
+	DSLayoutCacheEntry* cache = nullptr;
+	U cacheIdx = MAX_U;
+	U count = 0;
+	for(DSLayoutCacheEntry* it : m_caches)
 	{
 	{
-		poolSizes[i].descriptorCount *= MAX_DESCRIPTOR_SETS_PER_POOL;
+		if(it->m_hash == hash)
+		{
+			cache = it;
+			cacheIdx = count;
+			break;
+		}
+		++count;
 	}
 	}
 
 
-	VkDescriptorPoolCreateInfo poolci = {};
-	poolci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
-	poolci.maxSets = MAX_DESCRIPTOR_SETS_PER_POOL;
-	poolci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
-	poolci.poolSizeCount = poolSizeCount;
-	poolci.pPoolSizes = &poolSizes[0];
+	if(cache == nullptr)
+	{
+		cache = m_alloc.newInstance<DSLayoutCacheEntry>(this);
+		ANKI_CHECK(cache->init(&bindings[0], bindingCount, hash));
 
 
-	ANKI_VK_CHECKF(vkCreateDescriptorPool(m_dev, &poolci, nullptr, &cache->m_poolHandle));
+		m_caches.resize(m_alloc, m_caches.getSize() + 1);
+		m_caches[m_caches.getSize() - 1] = cache;
+		cacheIdx = m_caches.getSize() - 1;
+	}
+
+	// Set the layout
+	layout.m_handle = cache->m_layoutHandle;
+	layout.m_cacheEntryIdx = cacheIdx;
 
 
-	return cache;
+	return ErrorCode::NONE;
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 49 - 35
src/anki/gr/vulkan/DescriptorSet.h

@@ -12,6 +12,10 @@
 namespace anki
 namespace anki
 {
 {
 
 
+// Forward
+class DSThreadAllocator;
+class DSLayoutCacheEntry;
+
 /// @addtogroup vulkan
 /// @addtogroup vulkan
 /// @{
 /// @{
 
 
@@ -53,8 +57,39 @@ private:
 	U32 m_cacheEntryIdx = MAX_U32;
 	U32 m_cacheEntryIdx = MAX_U32;
 };
 };
 
 
+class TextureBinding
+{
+public:
+	TexturePtr m_tex;
+	SamplerPtr m_sampler;
+};
+
+class BufferBinding
+{
+public:
+	BufferPtr m_buff;
+	PtrSize m_offset = MAX_PTR_SIZE;
+	PtrSize m_range = 0;
+};
+
+class ImageBinding
+{
+public:
+	TexturePtr m_tex;
+	U16 m_level = 0;
+};
+
+class DSWriteInfo
+{
+public:
+	Array<BufferBinding, MAX_UNIFORM_BUFFER_BINDINGS> m_uniformBuffers;
+	Array<BufferBinding, MAX_STORAGE_BUFFER_BINDINGS> m_storageBuffers;
+	Array<TextureBinding, MAX_TEXTURE_BINDINGS> m_textures;
+	Array<ImageBinding, MAX_IMAGE_BINDINGS> m_images;
+};
+
 /// A state tracker of descriptors.
 /// A state tracker of descriptors.
-class DescriptorSetState
+class DescriptorSetState : private DSWriteInfo
 {
 {
 public:
 public:
 	void bindUniformBuffer(U binding, const BufferPtr& buff, PtrSize offset, PtrSize range)
 	void bindUniformBuffer(U binding, const BufferPtr& buff, PtrSize offset, PtrSize range)
@@ -76,34 +111,7 @@ public:
 	}
 	}
 
 
 private:
 private:
-	class TextureBinding
-	{
-	public:
-		TexturePtr m_tex;
-		SamplerPtr m_sampler;
-	};
-
-	class BufferBinding
-	{
-	public:
-		BufferPtr m_buff;
-		PtrSize m_offset = MAX_PTR_SIZE;
-		PtrSize m_range = 0;
-	};
-
-	class ImageBinding
-	{
-	public:
-		TexturePtr m_tex;
-		U16 m_level = 0;
-	};
-
 	DescriptorSetLayout m_layout;
 	DescriptorSetLayout m_layout;
-	Array<BufferBinding, MAX_UNIFORM_BUFFER_BINDINGS> m_uniformBuffers;
-	Array<BufferBinding, MAX_STORAGE_BUFFER_BINDINGS> m_storageBuffers;
-	Array<TextureBinding, MAX_TEXTURE_BINDINGS> m_textures;
-	Array<ImageBinding, MAX_IMAGE_BINDINGS> m_images;
-
 	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U8> m_setBindings = {false};
 	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U8> m_setBindings = {false};
 };
 };
 
 
@@ -123,6 +131,9 @@ private:
 /// Creates new descriptor set layouts and descriptor sets.
 /// Creates new descriptor set layouts and descriptor sets.
 class DescriptorSetFactory
 class DescriptorSetFactory
 {
 {
+	friend class DSLayoutCacheEntry;
+	friend class DSThreadAllocator;
+
 public:
 public:
 	DescriptorSetFactory() = default;
 	DescriptorSetFactory() = default;
 	~DescriptorSetFactory();
 	~DescriptorSetFactory();
@@ -135,21 +146,24 @@ public:
 	}
 	}
 
 
 	/// @note It's thread-safe.
 	/// @note It's thread-safe.
-	void newDescriptorSetLayout(const DescriptorSetLayoutInitInfo& init, DescriptorSetLayout& layout);
+	ANKI_USE_RESULT Error newDescriptorSetLayout(const DescriptorSetLayoutInitInfo& init, DescriptorSetLayout& layout);
 
 
 	void newDescriptorSet(const DescriptorSetState& init, DescriptorSet& set);
 	void newDescriptorSet(const DescriptorSetState& init, DescriptorSet& set);
 
 
-	void collectGarbage();
+	void endFrame()
+	{
+		++m_frameCount;
+	}
 
 
 private:
 private:
-	class Cache;
-
 	GrAllocator<U8> m_alloc;
 	GrAllocator<U8> m_alloc;
 	VkDevice m_dev = VK_NULL_HANDLE;
 	VkDevice m_dev = VK_NULL_HANDLE;
-	DynamicArray<Cache*> m_caches;
-	Mutex m_mtx;
+	U64 m_frameCount = 0;
+
+	DynamicArray<DSLayoutCacheEntry*> m_caches;
+	Mutex m_cachesMtx;
 
 
-	Cache* newCacheEntry(const DescriptorBinding* bindings, U bindingCount, U64 hash);
+	void initThreadAllocator(DSThreadAllocator& alloc);
 };
 };
 /// @}
 /// @}
 
 

+ 3 - 3
src/anki/renderer/Drawer.cpp

@@ -140,10 +140,10 @@ public:
 class SetupRenderableVariableVisitor
 class SetupRenderableVariableVisitor
 {
 {
 public:
 public:
-	DrawContext* m_ctx ANKI_DBG_NULLIFY_PTR;
-	const RenderableDrawer* m_drawer ANKI_DBG_NULLIFY_PTR;
+	DrawContext* m_ctx ANKI_DBG_NULLIFY;
+	const RenderableDrawer* m_drawer ANKI_DBG_NULLIFY;
 	WeakArray<U8> m_uniformBuffer;
 	WeakArray<U8> m_uniformBuffer;
-	const MaterialVariant* m_variant ANKI_DBG_NULLIFY_PTR;
+	const MaterialVariant* m_variant ANKI_DBG_NULLIFY;
 	F32 m_flod;
 	F32 m_flod;
 
 
 	/// Set a uniform in a client block
 	/// Set a uniform in a client block

+ 2 - 2
src/anki/renderer/Renderer.cpp

@@ -434,8 +434,8 @@ Error Renderer::buildCommandBuffers(RenderingContext& ctx)
 	class Task : public ThreadPoolTask
 	class Task : public ThreadPoolTask
 	{
 	{
 	public:
 	public:
-		Renderer* m_r ANKI_DBG_NULLIFY_PTR;
-		RenderingContext* m_ctx ANKI_DBG_NULLIFY_PTR;
+		Renderer* m_r ANKI_DBG_NULLIFY;
+		RenderingContext* m_ctx ANKI_DBG_NULLIFY;
 
 
 		Error operator()(U32 threadId, PtrSize threadCount)
 		Error operator()(U32 threadId, PtrSize threadCount)
 		{
 		{

+ 1 - 1
src/anki/renderer/Renderer.h

@@ -33,7 +33,7 @@ class RenderingContext
 {
 {
 public:
 public:
 	/// Active frustum.
 	/// Active frustum.
-	FrustumComponent* m_frustumComponent ANKI_DBG_NULLIFY_PTR;
+	FrustumComponent* m_frustumComponent ANKI_DBG_NULLIFY;
 	Mat4 m_prevViewProjMat;
 	Mat4 m_prevViewProjMat;
 
 
 	CommandBufferPtr m_commandBuffer; ///< Primary command buffer.
 	CommandBufferPtr m_commandBuffer; ///< Primary command buffer.

+ 1 - 1
src/anki/resource/Mesh.cpp

@@ -18,7 +18,7 @@ namespace anki
 class MeshLoadTask : public AsyncLoaderTask
 class MeshLoadTask : public AsyncLoaderTask
 {
 {
 public:
 public:
-	ResourceManager* m_manager ANKI_DBG_NULLIFY_PTR;
+	ResourceManager* m_manager ANKI_DBG_NULLIFY;
 	BufferPtr m_vertBuff;
 	BufferPtr m_vertBuff;
 	BufferPtr m_indicesBuff;
 	BufferPtr m_indicesBuff;
 	MeshLoader m_loader;
 	MeshLoader m_loader;

+ 1 - 1
src/anki/resource/Model.h

@@ -122,7 +122,7 @@ public:
 	void getRenderingDataSub(const RenderingKey& key, WeakArray<U8> subMeshIndicesArray, ModelRenderingInfo& inf) const;
 	void getRenderingDataSub(const RenderingKey& key, WeakArray<U8> subMeshIndicesArray, ModelRenderingInfo& inf) const;
 
 
 private:
 private:
-	Model* m_model ANKI_DBG_NULLIFY_PTR;
+	Model* m_model ANKI_DBG_NULLIFY;
 
 
 	Array<MeshResourcePtr, MAX_LODS> m_meshes; ///< One for each LOD
 	Array<MeshResourcePtr, MAX_LODS> m_meshes; ///< One for each LOD
 	U8 m_meshCount = 0;
 	U8 m_meshCount = 0;

+ 2 - 2
src/anki/resource/TextureResource.cpp

@@ -18,8 +18,8 @@ class TexUploadTask : public AsyncLoaderTask
 public:
 public:
 	ImageLoader m_loader;
 	ImageLoader m_loader;
 	TexturePtr m_tex;
 	TexturePtr m_tex;
-	GrManager* m_gr ANKI_DBG_NULLIFY_PTR;
-	StagingGpuMemoryManager* m_stagingMem ANKI_DBG_NULLIFY_PTR;
+	GrManager* m_gr ANKI_DBG_NULLIFY;
+	StagingGpuMemoryManager* m_stagingMem ANKI_DBG_NULLIFY;
 	U m_layers = 0;
 	U m_layers = 0;
 	U m_faces = 0;
 	U m_faces = 0;
 	TextureType m_texType;
 	TextureType m_texType;

+ 1 - 1
src/anki/scene/VisibilityInternal.h

@@ -150,7 +150,7 @@ public:
 	U32 m_taskCount;
 	U32 m_taskCount;
 	WeakPtr<VisibilityTestResults> m_result;
 	WeakPtr<VisibilityTestResults> m_result;
 	Timestamp m_timestamp = 0;
 	Timestamp m_timestamp = 0;
-	SoftwareRasterizer* m_r ANKI_DBG_NULLIFY_PTR;
+	SoftwareRasterizer* m_r ANKI_DBG_NULLIFY;
 
 
 	/// Thread hive task.
 	/// Thread hive task.
 	static void callback(void* ud, U32 threadId, ThreadHive& hive)
 	static void callback(void* ud, U32 threadId, ThreadHive& hive)

+ 36 - 8
src/anki/util/HashMap.h

@@ -43,12 +43,12 @@ public:
 	{
 	{
 	}
 	}
 
 
-	TValue& getValue()
+	TValue& getHashMapNodeValue()
 	{
 	{
 		return m_value;
 		return m_value;
 	}
 	}
 
 
-	const TValue& getValue() const
+	const TValue& getHashMapNodeValue() const
 	{
 	{
 		return m_value;
 		return m_value;
 	}
 	}
@@ -93,13 +93,13 @@ public:
 	TValueReference operator*() const
 	TValueReference operator*() const
 	{
 	{
 		ANKI_ASSERT(m_node);
 		ANKI_ASSERT(m_node);
-		return m_node->getValue();
+		return m_node->getHashMapNodeValue();
 	}
 	}
 
 
 	TValuePointer operator->() const
 	TValuePointer operator->() const
 	{
 	{
 		ANKI_ASSERT(m_node);
 		ANKI_ASSERT(m_node);
-		return &m_node->getValue();
+		return &m_node->getHashMapNodeValue();
 	}
 	}
 
 
 	HashMapIterator& operator++()
 	HashMapIterator& operator++()
@@ -291,8 +291,33 @@ public:
 	}
 	}
 };
 };
 
 
+/// Default hasher.
+template<typename TKey>
+class DefaultHasher
+{
+public:
+	U64 operator()(const TKey& a) const
+	{
+		return a.genHash();
+	}
+};
+
+/// Specialization for U64 keys.
+template<>
+class DefaultHasher<U64>
+{
+public:
+	U64 operator()(const U64 a) const
+	{
+		return a;
+	}
+};
+
 /// Hash map template.
 /// Hash map template.
-template<typename TKey, typename TValue, typename THasher, typename TCompare = DefaultHashKeyCompare<TKey>>
+template<typename TKey,
+	typename TValue,
+	typename THasher = DefaultHasher<TKey>,
+	typename TCompare = DefaultHashKeyCompare<TKey>>
 class HashMap : public detail::HashMapBase<TKey, TValue, THasher, TCompare, detail::HashMapNode<TValue>>
 class HashMap : public detail::HashMapBase<TKey, TValue, THasher, TCompare, detail::HashMapNode<TValue>>
 {
 {
 private:
 private:
@@ -412,12 +437,12 @@ private:
 	TClass* m_right = nullptr;
 	TClass* m_right = nullptr;
 	TClass* m_parent = nullptr; ///< Used for iterating.
 	TClass* m_parent = nullptr; ///< Used for iterating.
 
 
-	TClass& getValue()
+	TClass& getHashMapNodeValue()
 	{
 	{
 		return *static_cast<TClass*>(this);
 		return *static_cast<TClass*>(this);
 	}
 	}
 
 
-	const TClass& getValue() const
+	const TClass& getHashMapNodeValue() const
 	{
 	{
 		return *static_cast<const TClass*>(this);
 		return *static_cast<const TClass*>(this);
 	}
 	}
@@ -425,7 +450,10 @@ private:
 
 
 /// Hash map that doesn't perform any allocations. To work the TValue nodes will have to inherit from
 /// Hash map that doesn't perform any allocations. To work the TValue nodes will have to inherit from
 /// IntrusiveHashMapEnabled.
 /// IntrusiveHashMapEnabled.
-template<typename TKey, typename TValue, typename THasher, typename TCompare>
+template<typename TKey,
+	typename TValue,
+	typename THasher = DefaultHasher<TKey>,
+	typename TCompare = DefaultHashKeyCompare<TKey>>
 class IntrusiveHashMap : public detail::HashMapBase<TKey, TValue, THasher, TCompare, TValue>
 class IntrusiveHashMap : public detail::HashMapBase<TKey, TValue, THasher, TCompare, TValue>
 {
 {
 private:
 private:

+ 10 - 10
src/anki/util/List.h

@@ -38,12 +38,12 @@ public:
 	{
 	{
 	}
 	}
 
 
-	T& getValue()
+	T& getListNodeValue()
 	{
 	{
 		return m_value;
 		return m_value;
 	}
 	}
 
 
-	const T& getValue() const
+	const T& getListNodeValue() const
 	{
 	{
 		return m_value;
 		return m_value;
 	}
 	}
@@ -90,13 +90,13 @@ public:
 	TValueReference operator*() const
 	TValueReference operator*() const
 	{
 	{
 		ANKI_ASSERT(m_node);
 		ANKI_ASSERT(m_node);
-		return m_node->getValue();
+		return m_node->getListNodeValue();
 	}
 	}
 
 
 	TValuePointer operator->() const
 	TValuePointer operator->() const
 	{
 	{
 		ANKI_ASSERT(m_node);
 		ANKI_ASSERT(m_node);
-		return &m_node->getValue();
+		return &m_node->getListNodeValue();
 	}
 	}
 
 
 	ListIterator& operator++()
 	ListIterator& operator++()
@@ -206,28 +206,28 @@ public:
 	ConstReference getFront() const
 	ConstReference getFront() const
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_head->getValue();
+		return m_head->getListNodeValue();
 	}
 	}
 
 
 	/// Get first element.
 	/// Get first element.
 	Reference getFront()
 	Reference getFront()
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_head->getValue();
+		return m_head->getListNodeValue();
 	}
 	}
 
 
 	/// Get last element.
 	/// Get last element.
 	ConstReference getBack() const
 	ConstReference getBack() const
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_tail->getValue();
+		return m_tail->getListNodeValue();
 	}
 	}
 
 
 	/// Get last element.
 	/// Get last element.
 	Reference getBack()
 	Reference getBack()
 	{
 	{
 		ANKI_ASSERT(!isEmpty());
 		ANKI_ASSERT(!isEmpty());
-		return m_tail->getValue();
+		return m_tail->getListNodeValue();
 	}
 	}
 
 
 	/// Get begin.
 	/// Get begin.
@@ -573,12 +573,12 @@ private:
 	{
 	{
 	}
 	}
 
 
-	TClass& getValue()
+	TClass& getListNodeValue()
 	{
 	{
 		return *static_cast<TClass*>(this);
 		return *static_cast<TClass*>(this);
 	}
 	}
 
 
-	const TClass& getValue() const
+	const TClass& getListNodeValue() const
 	{
 	{
 		return *static_cast<const TClass*>(this);
 		return *static_cast<const TClass*>(this);
 	}
 	}

+ 3 - 3
src/anki/util/List.inl.h

@@ -130,7 +130,7 @@ Error ListBase<T, TNode>::iterateForward(TFunc func)
 	TNode* node = m_head;
 	TNode* node = m_head;
 	while(node && !err)
 	while(node && !err)
 	{
 	{
-		err = func(node->getValue());
+		err = func(node->getListNodeValue());
 		node = node->m_next;
 		node = node->m_next;
 	}
 	}
 
 
@@ -145,7 +145,7 @@ Error ListBase<T, TNode>::iterateBackward(TFunc func)
 	TNode* node = m_tail;
 	TNode* node = m_tail;
 	while(node && !err)
 	while(node && !err)
 	{
 	{
-		err = func(node->getValue());
+		err = func(node->getListNodeValue());
 		node = node->m_prev;
 		node = node->m_prev;
 	}
 	}
 
 
@@ -171,7 +171,7 @@ void ListBase<T, TNode>::sort(TCompFunc compFunc)
 			TNode* sortPtrNext = sortPtr->m_next;
 			TNode* sortPtrNext = sortPtr->m_next;
 			ANKI_ASSERT(sortPtrNext != nullptr);
 			ANKI_ASSERT(sortPtrNext != nullptr);
 
 
-			if(compFunc(sortPtrNext->getValue(), sortPtr->getValue()))
+			if(compFunc(sortPtrNext->getListNodeValue(), sortPtr->getListNodeValue()))
 			{
 			{
 				sortPtr = swap(sortPtr, sortPtrNext);
 				sortPtr = swap(sortPtr, sortPtrNext);
 				swapped = true;
 				swapped = true;

+ 2 - 2
src/anki/util/StdTypes.h

@@ -180,9 +180,9 @@ private:
 
 
 /// Macro to nuliffy a pointer on debug builds.
 /// Macro to nuliffy a pointer on debug builds.
 #if ANKI_DEBUG == 1
 #if ANKI_DEBUG == 1
-#define ANKI_DBG_NULLIFY_PTR = nullptr
+#define ANKI_DBG_NULLIFY = {}
 #else
 #else
-#define ANKI_DBG_NULLIFY_PTR
+#define ANKI_DBG_NULLIFY
 #endif
 #endif
 /// @}
 /// @}
 
 

+ 2 - 2
src/anki/util/ThreadHive.h

@@ -30,10 +30,10 @@ class ThreadHiveTask
 {
 {
 public:
 public:
 	/// What this task will do.
 	/// What this task will do.
-	ThreadHiveTaskCallback m_callback ANKI_DBG_NULLIFY_PTR;
+	ThreadHiveTaskCallback m_callback ANKI_DBG_NULLIFY;
 
 
 	/// Arguments to pass to the m_callback.
 	/// Arguments to pass to the m_callback.
-	void* m_argument ANKI_DBG_NULLIFY_PTR;
+	void* m_argument ANKI_DBG_NULLIFY;
 
 
 	/// The tasks that this task will depend on.
 	/// The tasks that this task will depend on.
 	WeakArray<ThreadHiveDependencyHandle> m_inDependencies;
 	WeakArray<ThreadHiveDependencyHandle> m_inDependencies;