Browse Source

Vulkan: More work on the descriptor sets

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
34cd6384fe

+ 0 - 1
shaders/ClusterLightCommon.glsl

@@ -14,7 +14,6 @@ struct LightingUniforms
 	vec4 projectionParams;
 	vec4 rendererSizeTimePad1;
 	vec4 nearFarClustererMagicPad1;
-	mat4 viewMat;
 	mat3 invViewRotation;
 	uvec4 tileCount;
 	mat4 invViewProjMat;

+ 5 - 2
shaders/FsCommonFrag.glsl

@@ -161,8 +161,11 @@ vec3 computeLightColor(vec3 diffCol)
 		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
 		if(light.diffuseColorShadowmapId.w >= 0.0)
 		{
-			shadow = computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, -1.0 / light.posRadius.w, u_lightingUniforms.viewMat, u_omniMapArr);
+			shadow = computeShadowFactorOmni(frag2Light,
+				shadowmapLayerIdx,
+				light.specularColorRadius.w,
+				u_lightingUniforms.invViewRotation,
+				u_omniMapArr);
 		}
 #endif
 

+ 5 - 2
shaders/Is.frag.glsl

@@ -197,8 +197,11 @@ void main()
 		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
 		if(light.diffuseColorShadowmapId.w >= 0.0)
 		{
-			float shadow = computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, light.specularColorRadius.w, u_lightingUniforms.viewMat, u_omniMapArr);
+			float shadow = computeShadowFactorOmni(frag2Light,
+				shadowmapLayerIdx,
+				light.specularColorRadius.w,
+				u_lightingUniforms.invViewRotation,
+				u_omniMapArr);
 			lambert *= shadow;
 		}
 

+ 2 - 2
shaders/LightFunctions.glsl

@@ -137,9 +137,9 @@ float computeShadowFactorSpot(
 }
 
 float computeShadowFactorOmni(
-	in vec3 frag2Light, in float layer, in float radius, in mat4 viewMat, in samplerCubeArrayShadow omniMapArr)
+	in vec3 frag2Light, in float layer, in float radius, in mat3 invViewMat, in samplerCubeArrayShadow omniMapArr)
 {
-	vec3 dir = (viewMat * vec4(-frag2Light, 1.0)).xyz;
+	vec3 dir = invViewMat * -frag2Light;
 	vec3 dirabs = abs(dir);
 	float dist = -max(dirabs.x, max(dirabs.y, dirabs.z));
 	dir = normalize(dir);

+ 5 - 2
shaders/Volumetric.frag.glsl

@@ -60,8 +60,11 @@ vec3 computeLightColor(vec3 fragPos[MAX_SAMPLES_PER_CLUSTER], uint iterCount, ui
 			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
 			if(light.diffuseColorShadowmapId.w >= 0.0)
 			{
-				shadow = computeShadowFactorOmni(
-					frag2Light, shadowmapLayerIdx, -1.0 / light.posRadius.w, u_lightingUniforms.viewMat, u_omniMapArr);
+				shadow = computeShadowFactorOmni(frag2Light,
+					shadowmapLayerIdx,
+					-1.0 / light.posRadius.w,
+					u_lightingUniforms.invViewRotation,
+					u_omniMapArr);
 			}
 #endif
 

+ 10 - 1
src/anki/gr/Common.h

@@ -158,7 +158,16 @@ const U MAX_UNIFORM_BUFFER_BINDINGS = 5;
 const U MAX_STORAGE_BUFFER_BINDINGS = 4;
 const U MAX_IMAGE_BINDINGS = 4;
 
-const U DESCRIPTOR_TYPE_COUNT = 4;
+enum class DescriptorType : U8
+{
+	TEXTURE,
+	UNIFORM_BUFFER,
+	STORAGE_BUFFER,
+	IMAGE,
+
+	COUNT
+};
+
 const U MAX_BINDINGS_PER_DESCRIPTOR_SET =
 	MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS + MAX_IMAGE_BINDINGS;
 

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

@@ -138,6 +138,31 @@ ANKI_USE_RESULT inline VkVertexInputRate convertVertexStepRate(VertexStepRate ak
 	}
 	return out;
 }
+
+ANKI_USE_RESULT inline VkDescriptorType convertDescriptorType(DescriptorType ak)
+{
+	VkDescriptorType out;
+	switch(ak)
+	{
+	case DescriptorType::TEXTURE:
+		out = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+		break;
+	case DescriptorType::UNIFORM_BUFFER:
+		out = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+		break;
+	case DescriptorType::STORAGE_BUFFER:
+		out = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
+		break;
+	case DescriptorType::IMAGE:
+		out = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+		break;
+	default:
+		out = VK_DESCRIPTOR_TYPE_MAX_ENUM;
+		ANKI_ASSERT(0);
+	}
+
+	return out;
+}
 /// @}
 
 } // end namespace anki

+ 183 - 20
src/anki/gr/vulkan/DescriptorSet.cpp

@@ -4,6 +4,8 @@
 // http://www.anki3d.org/LICENSE
 
 #include <anki/gr/vulkan/DescriptorSet.h>
+#include <anki/gr/Buffer.h>
+#include <anki/gr/vulkan/BufferImpl.h>
 #include <anki/util/List.h>
 #include <anki/util/HashMap.h>
 #include <algorithm>
@@ -19,7 +21,8 @@ public:
 	U64 m_lastFrameUsed = MAX_U64;
 };
 
-class DSThreadAllocator
+/// Per thread allocator.
+class DSThreadAllocator : public NonCopyable
 {
 public:
 	const DSLayoutCacheEntry* m_layoutEntry; ///< Know your father.
@@ -44,21 +47,23 @@ public:
 	ANKI_USE_RESULT Error init();
 	ANKI_USE_RESULT Error createNewPool();
 
-	ANKI_USE_RESULT Error getOrCreateSet(U64 hash, const DSWriteInfo& inf, DS*& out)
+	ANKI_USE_RESULT Error getOrCreateSet(
+		U64 hash, const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS*& out)
 	{
 		out = tryFindSet(hash);
 		if(out == nullptr)
 		{
-			ANKI_CHECK(newSet(hash, inf, out));
+			ANKI_CHECK(newSet(hash, bindings, 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);
+	ANKI_USE_RESULT const DS* tryFindSet(U64 hash);
+	ANKI_USE_RESULT Error newSet(
+		U64 hash, const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS*& out);
+	void writeSet(const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS& set);
 };
 
 /// Cache entry. It's built around a specific descriptor set layout.
@@ -69,13 +74,16 @@ public:
 
 	U64 m_hash = 0; ///< Layout hash.
 	VkDescriptorSetLayout m_layoutHandle = {};
+	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U8> m_activeBindings = {false};
+	U32 m_minBinding = MAX_U32;
+	U32 m_maxBinding = 0;
 
 	// Cache the create info
-	Array<VkDescriptorPoolSize, DESCRIPTOR_TYPE_COUNT> m_poolSizesCreateInf = {};
+	Array<VkDescriptorPoolSize, U(DescriptorType::COUNT)> m_poolSizesCreateInf = {};
 	VkDescriptorPoolCreateInfo m_poolCreateInf = {};
 
-	DynamicArray<DSThreadAllocator*> m_threadCaches;
-	Mutex m_threadCachesMtx;
+	DynamicArray<DSThreadAllocator*> m_threadAllocs;
+	SpinLock m_threadAllocsMtx;
 
 	DSLayoutCacheEntry(DescriptorSetFactory* factory)
 		: m_factory(factory)
@@ -85,6 +93,8 @@ public:
 	~DSLayoutCacheEntry();
 
 	ANKI_USE_RESULT Error init(const DescriptorBinding* bindings, U bindingCount, U64 hash);
+
+	ANKI_USE_RESULT Error getOrCreateThreadAllocator(ThreadId tid, DSThreadAllocator*& alloc);
 };
 
 Error DSThreadAllocator::init()
@@ -100,7 +110,7 @@ Error DSThreadAllocator::createNewPool()
 	m_lastPoolFreeDSCount = m_lastPoolDSCount;
 
 	// Set the create info
-	Array<VkDescriptorPoolSize, DESCRIPTOR_TYPE_COUNT> poolSizes;
+	Array<VkDescriptorPoolSize, U(DescriptorType::COUNT)> poolSizes;
 	memcpy(&poolSizes[0],
 		&m_layoutEntry->m_poolSizesCreateInf[0],
 		sizeof(poolSizes[0]) * m_layoutEntry->m_poolCreateInf.poolSizeCount);
@@ -126,7 +136,7 @@ Error DSThreadAllocator::createNewPool()
 	return ErrorCode::NONE;
 }
 
-DS* DSThreadAllocator::tryFindSet(U64 hash)
+const DS* DSThreadAllocator::tryFindSet(U64 hash)
 {
 	ANKI_ASSERT(hash > 0);
 
@@ -148,9 +158,10 @@ DS* DSThreadAllocator::tryFindSet(U64 hash)
 	}
 }
 
-Error DSThreadAllocator::newSet(U64 hash, const DSWriteInfo& inf, DS*& out)
+Error DSThreadAllocator::newSet(
+	U64 hash, const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS*& out_)
 {
-	out = nullptr;
+	DS* out = nullptr;
 
 	// First try to see if there are unused to recycle
 	const U64 crntFrame = m_layoutEntry->m_factory->m_frameCount;
@@ -202,14 +213,77 @@ Error DSThreadAllocator::newSet(U64 hash, const DSWriteInfo& inf, DS*& out)
 	out->m_lastFrameUsed = m_layoutEntry->m_factory->m_frameCount;
 
 	// Finally, write it
-	writeSet(inf, *out);
+	writeSet(bindings, *out);
 
+	out_ = out;
 	return ErrorCode::NONE;
 }
 
-void DSThreadAllocator::writeSet(const DSWriteInfo& inf, DS& set)
+void DSThreadAllocator::writeSet(const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS& set)
 {
-	ANKI_ASSERT(!"TODO");
+	Array<VkWriteDescriptorSet, MAX_BINDINGS_PER_DESCRIPTOR_SET> writes;
+	U writeCount = 0;
+
+	Array<VkDescriptorImageInfo, MAX_TEXTURE_BINDINGS> tex;
+	U texCount = 0;
+	Array<VkDescriptorBufferInfo, MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS> buff;
+	U buffCount = 0;
+
+	VkWriteDescriptorSet writeTemplate = {};
+	writeTemplate.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+	writeTemplate.pNext = nullptr;
+	writeTemplate.dstSet = set.m_handle;
+	writeTemplate.descriptorCount = 1;
+
+	for(U i = m_layoutEntry->m_minBinding; i <= m_layoutEntry->m_maxBinding; ++i)
+	{
+		if(m_layoutEntry->m_activeBindings.get(i))
+		{
+			const AnyBinding& b = bindings[i];
+
+			VkWriteDescriptorSet& w = writes[writeCount++];
+			w = writeTemplate;
+			w.dstBinding = i;
+			w.descriptorType = convertDescriptorType(b.m_type);
+
+			switch(b.m_type)
+			{
+			case DescriptorType::TEXTURE:
+				tex[texCount].sampler = b.m_tex.m_sampler->m_handle;
+				tex[texCount].imageView = b.m_tex.m_tex->getOrCreateResourceGroupView(b.m_tex.m_aspect);
+				tex[texCount].imageLayout = b.m_tex.m_layout;
+
+				w.pImageInfo = &tex[texCount];
+
+				++texCount;
+				break;
+			case DescriptorType::UNIFORM_BUFFER:
+			case DescriptorType::STORAGE_BUFFER:
+				buff[buffCount].buffer = b.m_buff.m_buff->getHandle();
+				buff[buffCount].offset = b.m_buff.m_offset;
+				buff[buffCount].range = b.m_buff.m_range;
+
+				w.pBufferInfo = &buff[buffCount];
+
+				++buffCount;
+				break;
+			case DescriptorType::IMAGE:
+				tex[texCount].sampler = VK_NULL_HANDLE;
+				tex[texCount].imageView = b.m_image.m_tex->getOrCreateSingleSurfaceView(
+					TextureSurfaceInfo(b.m_image.m_level, 0, 0, 0), b.m_tex.m_aspect);
+				tex[texCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+				w.pImageInfo = &tex[texCount];
+
+				++texCount;
+				break;
+			default:
+				ANKI_ASSERT(0);
+			}
+		}
+	}
+
+	vkUpdateDescriptorSets(m_layoutEntry->m_factory->m_dev, writeCount, &writes[0], 0, nullptr);
 }
 
 Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount, U64 hash)
@@ -231,9 +305,14 @@ Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount
 
 		vk.binding = ak.m_binding;
 		vk.descriptorCount = 1;
-		vk.descriptorType = static_cast<VkDescriptorType>(ak.m_type);
+		vk.descriptorType = convertDescriptorType(ak.m_type);
 		vk.pImmutableSamplers = nullptr;
 		vk.stageFlags = convertShaderTypeBit(ak.m_stageMask);
+
+		ANKI_ASSERT(m_activeBindings.get(ak.m_binding) == false);
+		m_activeBindings.set(ak.m_binding);
+		m_minBinding = min<U32>(m_minBinding, ak.m_binding);
+		m_maxBinding = max<U32>(m_maxBinding, ak.m_binding);
 	}
 
 	ci.bindingCount = bindingCount;
@@ -248,7 +327,7 @@ Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount
 		U j;
 		for(j = 0; j < poolSizeCount; ++j)
 		{
-			if(m_poolSizesCreateInf[j].type == bindings[i].m_type)
+			if(m_poolSizesCreateInf[j].type == convertDescriptorType(bindings[i].m_type))
 			{
 				++m_poolSizesCreateInf[j].descriptorCount;
 				break;
@@ -257,7 +336,7 @@ Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount
 
 		if(j == poolSizeCount)
 		{
-			m_poolSizesCreateInf[poolSizeCount].type = static_cast<VkDescriptorType>(bindings[i].m_type);
+			m_poolSizesCreateInf[poolSizeCount].type = convertDescriptorType(bindings[i].m_type);
 
 			switch(m_poolSizesCreateInf[poolSizeCount].type)
 			{
@@ -290,6 +369,53 @@ Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount
 	return ErrorCode::NONE;
 }
 
+Error DSLayoutCacheEntry::getOrCreateThreadAllocator(ThreadId tid, DSThreadAllocator*& alloc)
+{
+	alloc = nullptr;
+
+	LockGuard<SpinLock> lock(m_threadAllocsMtx);
+
+	class Comp
+	{
+	public:
+		Bool operator()(const DSThreadAllocator* a, ThreadId tid) const
+		{
+			return a->m_tid < tid;
+		}
+
+		Bool operator()(ThreadId tid, const DSThreadAllocator* a) const
+		{
+			return tid < a->m_tid;
+		}
+	};
+
+	// Find using binary search
+	auto it = std::lower_bound(m_threadAllocs.getBegin(), m_threadAllocs.getEnd(), tid, Comp());
+
+	if(it != m_threadAllocs.getEnd())
+	{
+		alloc = *it;
+	}
+	else
+	{
+		// Need to create one
+
+		alloc = m_factory->m_alloc.newInstance<DSThreadAllocator>(this, tid);
+		ANKI_CHECK(alloc->init());
+
+		m_threadAllocs.resize(m_factory->m_alloc, m_threadAllocs.getSize() + 1);
+		m_threadAllocs[m_threadAllocs.getSize() - 1] = alloc;
+
+		// Sort for fast find
+		std::sort(m_threadAllocs.getBegin(),
+			m_threadAllocs.getEnd(),
+			[](const DSThreadAllocator* a, const DSThreadAllocator* b) { return a->m_tid < b->m_tid; });
+	}
+
+	ANKI_ASSERT(alloc);
+	return ErrorCode::NONE;
+}
+
 DescriptorSetFactory::~DescriptorSetFactory()
 {
 }
@@ -323,7 +449,7 @@ Error DescriptorSetFactory::newDescriptorSetLayout(const DescriptorSetLayoutInit
 	}
 
 	// Find or create the cache entry
-	LockGuard<Mutex> lock(m_cachesMtx);
+	LockGuard<SpinLock> lock(m_cachesMtx);
 
 	DSLayoutCacheEntry* cache = nullptr;
 	U cacheIdx = MAX_U;
@@ -356,4 +482,41 @@ Error DescriptorSetFactory::newDescriptorSetLayout(const DescriptorSetLayoutInit
 	return ErrorCode::NONE;
 }
 
+Error DescriptorSetFactory::newDescriptorSet(ThreadId tid, const DescriptorSetState& init, DescriptorSet& set)
+{
+	// Get cache entry
+	m_cachesMtx.lock();
+	DSLayoutCacheEntry& entry = *m_caches[init.m_layout.m_cacheEntryIdx];
+	m_cachesMtx.unlock();
+
+	// Get thread allocator
+	DSThreadAllocator* alloc;
+	ANKI_CHECK(entry.getOrCreateThreadAllocator(tid, alloc));
+
+	// Compute the hash
+	Array<U64, MAX_BINDINGS_PER_DESCRIPTOR_SET> uuids;
+	U uuidCount = 0;
+
+	const U minBinding = entry.m_minBinding;
+	const U maxBinding = entry.m_maxBinding;
+	for(U i = minBinding; i <= maxBinding; ++i)
+	{
+		if(entry.m_activeBindings.get(i))
+		{
+			uuids[uuidCount++] = init.m_bindings[i].m_uuids[0];
+			uuids[uuidCount++] = init.m_bindings[i].m_uuids[1];
+		}
+	}
+
+	U64 hash = computeHash(&uuids[0], uuidCount * sizeof(U64));
+
+	// Finally, allocate
+	const DS* s;
+	ANKI_CHECK(alloc->getOrCreateSet(hash, init.m_bindings, s));
+	set.m_handle = s->m_handle;
+	ANKI_ASSERT(set.m_handle != VK_NULL_HANDLE);
+
+	return ErrorCode::NONE;
+}
+
 } // end namespace anki

+ 83 - 28
src/anki/gr/vulkan/DescriptorSet.h

@@ -7,6 +7,10 @@
 
 #include <anki/gr/vulkan/Common.h>
 #include <anki/gr/Buffer.h>
+#include <anki/gr/Texture.h>
+#include <anki/gr/vulkan/TextureImpl.h>
+#include <anki/gr/Sampler.h>
+#include <anki/gr/vulkan/SamplerImpl.h>
 #include <anki/util/BitSet.h>
 
 namespace anki
@@ -22,7 +26,7 @@ class DSLayoutCacheEntry;
 class alignas(4) DescriptorBinding
 {
 public:
-	U8 m_type = MAX_U8;
+	DescriptorType m_type = DescriptorType::COUNT;
 	ShaderTypeBit m_stageMask = ShaderTypeBit::NONE;
 	U8 m_binding = MAX_U8;
 	U8 _m_padding = 0;
@@ -60,14 +64,16 @@ private:
 class TextureBinding
 {
 public:
-	TexturePtr m_tex;
-	SamplerPtr m_sampler;
+	TextureImpl* m_tex = nullptr;
+	SamplerImpl* m_sampler = nullptr;
+	DepthStencilAspectBit m_aspect = DepthStencilAspectBit::NONE;
+	VkImageLayout m_layout = VK_IMAGE_LAYOUT_MAX_ENUM;
 };
 
 class BufferBinding
 {
 public:
-	BufferPtr m_buff;
+	BufferImpl* m_buff = nullptr;
 	PtrSize m_offset = MAX_PTR_SIZE;
 	PtrSize m_range = 0;
 };
@@ -75,48 +81,98 @@ public:
 class ImageBinding
 {
 public:
-	TexturePtr m_tex;
+	TextureImpl* m_tex = nullptr;
 	U16 m_level = 0;
 };
 
-class DSWriteInfo
+class AnyBinding
 {
 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;
+	DescriptorType m_type = DescriptorType::COUNT;
+	Array<U64, 2> m_uuids = {};
+
+	TextureBinding m_tex;
+	BufferBinding m_buff;
+	ImageBinding m_image;
 };
 
 /// A state tracker of descriptors.
-class DescriptorSetState : private DSWriteInfo
+class DescriptorSetState
 {
+	friend class DescriptorSetFactory;
+
 public:
-	void bindUniformBuffer(U binding, const BufferPtr& buff, PtrSize offset, PtrSize range)
+	void setLayout(const DescriptorSetLayout& layout)
+	{
+		m_layout = layout;
+	}
+
+	void bindTexture(U binding, TexturePtr& tex, DepthStencilAspectBit aspect, VkImageLayout layout)
 	{
-		U realBinding = binding + MAX_TEXTURE_BINDINGS;
-		m_setBindings.set(realBinding);
-		m_uniformBuffers[binding].m_buff = buff;
-		m_uniformBuffers[binding].m_offset = offset;
-		m_uniformBuffers[binding].m_range = range;
+		m_bindings[binding].m_type = DescriptorType::TEXTURE;
+		m_bindings[binding].m_uuids[0] = m_bindings[binding].m_uuids[1] = tex->getUuid();
+
+		m_bindings[binding].m_tex.m_tex = tex->m_impl.get();
+		m_bindings[binding].m_tex.m_sampler = tex->m_impl->m_sampler->m_impl.get();
+		m_bindings[binding].m_tex.m_aspect = aspect;
+		m_bindings[binding].m_tex.m_layout = layout;
+	}
+
+	void bindTextureAndSampler(
+		U binding, TexturePtr& tex, SamplerPtr& sampler, DepthStencilAspectBit aspect, VkImageLayout layout)
+	{
+		m_bindings[binding].m_type = DescriptorType::TEXTURE;
+		m_bindings[binding].m_uuids[0] = tex->getUuid();
+		m_bindings[binding].m_uuids[1] = sampler->getUuid();
+
+		m_bindings[binding].m_tex.m_tex = tex->m_impl.get();
+		m_bindings[binding].m_tex.m_sampler = sampler->m_impl.get();
+		m_bindings[binding].m_tex.m_aspect = aspect;
+		m_bindings[binding].m_tex.m_layout = layout;
 	}
 
-	void bindStorageBuffer(U binding, const BufferPtr& buff, PtrSize offset, PtrSize range)
+	void bindUniformBuffer(U binding, BufferPtr& buff, PtrSize offset, PtrSize range)
 	{
-		U realBinding = binding + MAX_TEXTURE_BINDINGS + MAX_UNIFORM_BUFFER_BINDINGS;
-		m_setBindings.set(realBinding);
-		m_storageBuffers[binding].m_buff = buff;
-		m_storageBuffers[binding].m_offset = offset;
-		m_storageBuffers[binding].m_range = range;
+		m_bindings[binding].m_type = DescriptorType::UNIFORM_BUFFER;
+		m_bindings[binding].m_uuids[0] = m_bindings[binding].m_uuids[1] = buff->getUuid();
+
+		m_bindings[binding].m_buff.m_buff = buff->m_impl.get();
+		m_bindings[binding].m_buff.m_offset = offset;
+		m_bindings[binding].m_buff.m_range = range;
+	}
+
+	void bindStorageBuffer(U binding, BufferPtr& buff, PtrSize offset, PtrSize range)
+	{
+		m_bindings[binding].m_type = DescriptorType::STORAGE_BUFFER;
+		m_bindings[binding].m_uuids[0] = m_bindings[binding].m_uuids[1] = buff->getUuid();
+
+		m_bindings[binding].m_buff.m_buff = buff->m_impl.get();
+		m_bindings[binding].m_buff.m_offset = offset;
+		m_bindings[binding].m_buff.m_range = range;
+	}
+
+	void bindImage(U binding, TexturePtr& tex, U32 level)
+	{
+		m_bindings[binding].m_type = DescriptorType::IMAGE;
+		m_bindings[binding].m_uuids[0] = m_bindings[binding].m_uuids[1] = tex->getUuid();
+
+		m_bindings[binding].m_tex.m_tex = tex->m_impl.get();
+		m_bindings[binding].m_tex.m_sampler = nullptr;
+		m_bindings[binding].m_tex.m_aspect = DepthStencilAspectBit::NONE;
+		m_bindings[binding].m_tex.m_layout = VK_IMAGE_LAYOUT_GENERAL;
 	}
 
 private:
 	DescriptorSetLayout m_layout;
-	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U8> m_setBindings = {false};
+
+	Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> m_bindings;
 };
 
+/// Descriptor set thin wraper.
 class DescriptorSet
 {
+	friend class DescriptorSetFactory;
+
 public:
 	VkDescriptorSet getHandle() const
 	{
@@ -148,7 +204,8 @@ public:
 	/// @note It's thread-safe.
 	ANKI_USE_RESULT Error newDescriptorSetLayout(const DescriptorSetLayoutInitInfo& init, DescriptorSetLayout& layout);
 
-	void newDescriptorSet(const DescriptorSetState& init, DescriptorSet& set);
+	/// @note Obviously not thread-safe.
+	ANKI_USE_RESULT Error newDescriptorSet(ThreadId tid, const DescriptorSetState& init, DescriptorSet& set);
 
 	void endFrame()
 	{
@@ -161,9 +218,7 @@ private:
 	U64 m_frameCount = 0;
 
 	DynamicArray<DSLayoutCacheEntry*> m_caches;
-	Mutex m_cachesMtx;
-
-	void initThreadAllocator(DSThreadAllocator& alloc);
+	SpinLock m_cachesMtx; ///< Not a mutex because after a while there will be no reason to lock
 };
 /// @}
 

+ 5 - 5
src/anki/gr/vulkan/ShaderImpl.cpp

@@ -320,7 +320,7 @@ void ShaderImpl::doReflection(const std::vector<unsigned int>& spirv)
 	}};
 	Array2d<DescriptorBinding, MAX_DESCRIPTOR_SETS, MAX_BINDINGS_PER_DESCRIPTOR_SET> descriptors;
 
-	auto func = [&](const std::vector<spirv_cross::Resource>& resources, VkDescriptorType type) -> void {
+	auto func = [&](const std::vector<spirv_cross::Resource>& resources, DescriptorType type) -> void {
 		for(const spirv_cross::Resource& r : resources)
 		{
 			const U32 id = r.id;
@@ -340,10 +340,10 @@ void ShaderImpl::doReflection(const std::vector<unsigned int>& spirv)
 		}
 	};
 
-	func(rsrc.uniform_buffers, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
-	func(rsrc.sampled_images, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
-	func(rsrc.storage_buffers, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
-	func(rsrc.storage_images, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
+	func(rsrc.uniform_buffers, DescriptorType::UNIFORM_BUFFER);
+	func(rsrc.sampled_images, DescriptorType::TEXTURE);
+	func(rsrc.storage_buffers, DescriptorType::STORAGE_BUFFER);
+	func(rsrc.storage_images, DescriptorType::IMAGE);
 
 	for(U set = 0; set < MAX_DESCRIPTOR_SETS; ++set)
 	{

+ 0 - 2
src/anki/renderer/Is.cpp

@@ -23,7 +23,6 @@ public:
 	Vec4 m_projectionParams;
 	Vec4 m_rendererSizeTimePad1;
 	Vec4 m_nearFarClustererMagicPad1;
-	Mat4 m_viewMat;
 	Mat3x4 m_invViewRotation;
 	UVec4 m_tileCount;
 	Mat4 m_invViewProjMat;
@@ -213,7 +212,6 @@ void Is::updateCommonBlock(RenderingContext& ctx)
 
 	// Start writing
 	blk->m_projectionParams = fr.getProjectionParameters();
-	blk->m_viewMat = fr.getViewMatrix().getTransposed();
 	blk->m_nearFarClustererMagicPad1 = Vec4(
 		fr.getFrustum().getNear(), fr.getFrustum().getFar(), m_lightBin->getClusterer().getShaderMagicValue(), 0.0);