Browse Source

Remove bindless storage images. Keep only sampled images

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
a218953a85

+ 1 - 1
AnKi/Gr/Common.h

@@ -44,7 +44,7 @@ constexpr U32 MAX_BINDINGS_PER_DESCRIPTOR_SET = 32;
 constexpr U32 MAX_FRAMES_IN_FLIGHT = 3; ///< Triple buffering.
 constexpr U32 MAX_GR_OBJECT_NAME_LENGTH = 31;
 constexpr U32 MAX_BINDLESS_TEXTURES = 512;
-constexpr U32 MAX_BINDLESS_IMAGES = 64;
+constexpr U32 MAX_BINDLESS_READONLY_TEXTURE_BUFFERS = 512;
 
 /// The number of commands in a command buffer that make it a small batch command buffer.
 constexpr U32 COMMAND_BUFFER_SMALL_BATCH_MAX_COMMANDS = 100;

+ 0 - 4
AnKi/Gr/TextureView.h

@@ -92,10 +92,6 @@ public:
 	/// @note It's thread-safe
 	U32 getOrCreateBindlessTextureIndex();
 
-	/// Returns an index to be used for bindless access. For image read/write.
-	/// @note It's thread-safe
-	U32 getOrCreateBindlessImageIndex();
-
 protected:
 	TextureType m_texType = TextureType::COUNT;
 	TextureSubresourceInfo m_subresource;

+ 86 - 39
AnKi/Gr/Vulkan/DescriptorSet.cpp

@@ -27,9 +27,9 @@ public:
 	/// @note It's thread-safe.
 	U32 bindTexture(const VkImageView view, const VkImageLayout layout);
 
-	/// Bind a storage image.
+	/// Bind a uniform texel buffer.
 	/// @note It's thread-safe.
-	U32 bindImage(const VkImageView view);
+	U32 bindUniformTexelBuffer(VkBufferView view);
 
 	/// @note It's thread-safe.
 	void unbindTexture(U32 idx)
@@ -38,9 +38,9 @@ public:
 	}
 
 	/// @note It's thread-safe.
-	void unbindImage(U32 idx)
+	void unbindUniformTexelBuffer(U32 idx)
 	{
-		unbindCommon(idx, m_freeImgIndices, m_freeImgIndexCount);
+		unbindCommon(idx, m_freeTexelBufferIndices, m_freeTexelBufferIndexCount);
 	}
 
 	DescriptorSet getDescriptorSet() const
@@ -66,10 +66,10 @@ private:
 	Mutex m_mtx;
 
 	DynamicArray<U16> m_freeTexIndices;
-	DynamicArray<U16> m_freeImgIndices;
+	DynamicArray<U16> m_freeTexelBufferIndices;
 
-	U16 m_freeTexIndexCount ANKI_DEBUG_CODE(= MAX_U16);
-	U16 m_freeImgIndexCount ANKI_DEBUG_CODE(= MAX_U16);
+	U16 m_freeTexIndexCount = MAX_U16;
+	U16 m_freeTexelBufferIndexCount = MAX_U16;
 
 	void unbindCommon(U32 idx, DynamicArray<U16>& freeIndices, U16& freeIndexCount);
 };
@@ -173,7 +173,8 @@ public:
 DescriptorSetFactory::BindlessDescriptorSet::~BindlessDescriptorSet()
 {
 	ANKI_ASSERT(m_freeTexIndexCount == m_freeTexIndices.getSize() && "Forgot to unbind some textures");
-	ANKI_ASSERT(m_freeImgIndexCount == m_freeImgIndices.getSize() && "Forgot to unbind some images");
+	ANKI_ASSERT(m_freeTexelBufferIndexCount == m_freeTexelBufferIndices.getSize()
+				&& "Forgot to unbind some texel buffers");
 
 	if(m_pool)
 	{
@@ -188,12 +189,12 @@ DescriptorSetFactory::BindlessDescriptorSet::~BindlessDescriptorSet()
 		m_layout = VK_NULL_HANDLE;
 	}
 
-	m_freeImgIndices.destroy(m_alloc);
 	m_freeTexIndices.destroy(m_alloc);
+	m_freeTexelBufferIndices.destroy(m_alloc);
 }
 
 Error DescriptorSetFactory::BindlessDescriptorSet::init(const GrAllocator<U8>& alloc, VkDevice dev,
-														U32 bindlessTextureCount, U32 bindlessImageCount)
+														U32 bindlessTextureCount, U32 bindlessTextureBuffers)
 {
 	ANKI_ASSERT(dev);
 	m_alloc = alloc;
@@ -208,8 +209,8 @@ Error DescriptorSetFactory::BindlessDescriptorSet::init(const GrAllocator<U8>& a
 		bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
 		bindings[1].binding = 1;
 		bindings[1].stageFlags = VK_SHADER_STAGE_ALL;
-		bindings[1].descriptorCount = bindlessImageCount;
-		bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+		bindings[1].descriptorCount = bindlessTextureBuffers;
+		bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
 
 		Array<VkDescriptorBindingFlagsEXT, 2> bindingFlags = {};
 		bindingFlags[0] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
@@ -237,8 +238,8 @@ Error DescriptorSetFactory::BindlessDescriptorSet::init(const GrAllocator<U8>& a
 		Array<VkDescriptorPoolSize, 2> sizes = {};
 		sizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
 		sizes[0].descriptorCount = bindlessTextureCount;
-		sizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
-		sizes[1].descriptorCount = bindlessImageCount;
+		sizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+		sizes[1].descriptorCount = bindlessTextureBuffers;
 
 		VkDescriptorPoolCreateInfo ci = {};
 		ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
@@ -271,12 +272,12 @@ Error DescriptorSetFactory::BindlessDescriptorSet::init(const GrAllocator<U8>& a
 			m_freeTexIndices[i] = U16(m_freeTexIndices.getSize() - i - 1);
 		}
 
-		m_freeImgIndices.create(m_alloc, bindlessImageCount);
-		m_freeImgIndexCount = U16(m_freeImgIndices.getSize());
+		m_freeTexelBufferIndices.create(m_alloc, bindlessTextureBuffers);
+		m_freeTexelBufferIndexCount = U16(m_freeTexelBufferIndices.getSize());
 
-		for(U32 i = 0; i < m_freeImgIndices.getSize(); ++i)
+		for(U32 i = 0; i < m_freeTexelBufferIndices.getSize(); ++i)
 		{
-			m_freeImgIndices[i] = U16(m_freeImgIndices.getSize() - i - 1);
+			m_freeTexelBufferIndices[i] = U16(m_freeTexelBufferIndices.getSize() - i - 1);
 		}
 	}
 
@@ -316,31 +317,27 @@ U32 DescriptorSetFactory::BindlessDescriptorSet::bindTexture(const VkImageView v
 	return idx;
 }
 
-U32 DescriptorSetFactory::BindlessDescriptorSet::bindImage(const VkImageView view)
+U32 DescriptorSetFactory::BindlessDescriptorSet::bindUniformTexelBuffer(VkBufferView view)
 {
 	ANKI_ASSERT(view);
 	LockGuard<Mutex> lock(m_mtx);
-	ANKI_ASSERT(m_freeImgIndexCount > 0 && "Out of indices");
+	ANKI_ASSERT(m_freeTexelBufferIndexCount > 0 && "Out of indices");
 
-	// Get the index
-	--m_freeImgIndexCount;
-	const U32 idx = m_freeImgIndices[m_freeImgIndexCount];
-	ANKI_ASSERT(idx < m_freeImgIndices.getSize());
+	// Pop the index
+	--m_freeTexelBufferIndexCount;
+	const U16 idx = m_freeTexelBufferIndices[m_freeTexelBufferIndexCount];
+	ANKI_ASSERT(idx < m_freeTexelBufferIndices.getSize());
 
 	// Update the set
-	VkDescriptorImageInfo imageInf = {};
-	imageInf.imageView = view;
-	imageInf.imageLayout = VK_IMAGE_LAYOUT_GENERAL; // Storage images are always in general.
-
 	VkWriteDescriptorSet write = {};
 	write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 	write.pNext = nullptr;
 	write.dstSet = m_dset;
 	write.dstBinding = 1;
 	write.descriptorCount = 1;
-	write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+	write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
 	write.dstArrayElement = idx;
-	write.pImageInfo = &imageInf;
+	write.pTexelBufferView = &view;
 
 	vkUpdateDescriptorSets(m_dev, 1, &write, 0, nullptr);
 
@@ -789,6 +786,56 @@ Error DSLayoutCacheEntry::getOrCreateDSAllocator(DescriptorSetFactory::DSAllocat
 	return Error::NONE;
 }
 
+AnyBinding& DescriptorSetState::getBindingToPopulate(U32 bindingIdx, U32 arrayIdx)
+{
+	ANKI_ASSERT(bindingIdx < MAX_BINDINGS_PER_DESCRIPTOR_SET);
+
+	AnyBindingExtended& extended = m_bindings[bindingIdx];
+	AnyBinding* out;
+	const Bool bindingIsSet = m_bindingSet.get(bindingIdx);
+	m_bindingSet.set(bindingIdx);
+	extended.m_arraySize = (!bindingIsSet) ? 0 : extended.m_arraySize;
+
+	if(ANKI_LIKELY(arrayIdx == 0 && extended.m_arraySize <= 1))
+	{
+		// Array idx is zero, most common case
+		out = &extended.m_single;
+		extended.m_arraySize = 1;
+	}
+	else if(arrayIdx < extended.m_arraySize)
+	{
+		// It's (or was) an array and there enough space in thar array
+		out = &extended.m_array[arrayIdx];
+	}
+	else
+	{
+		// Need to grow
+		const U32 newSize = max(extended.m_arraySize * 2, arrayIdx + 1);
+		AnyBinding* newArr = m_alloc.newArray<AnyBinding>(newSize);
+
+		if(extended.m_arraySize == 1)
+		{
+			newArr[0] = extended.m_single;
+		}
+		else if(extended.m_arraySize > 1)
+		{
+			// Copy old to new.
+			memcpy(newArr, extended.m_array, sizeof(AnyBinding) * extended.m_arraySize);
+		}
+
+		// Zero the rest
+		memset(newArr + extended.m_arraySize, 0, sizeof(AnyBinding) * (newSize - extended.m_arraySize));
+		extended.m_arraySize = newSize;
+		extended.m_array = newArr;
+
+		// Return
+		out = &extended.m_array[arrayIdx];
+	}
+
+	ANKI_ASSERT(out);
+	return *out;
+}
+
 void DescriptorSetState::flush(U64& hash, Array<PtrSize, MAX_BINDINGS_PER_DESCRIPTOR_SET>& dynamicOffsets,
 							   U32& dynamicOffsetCount, Bool& bindlessDSet)
 {
@@ -937,15 +984,15 @@ DescriptorSetFactory::~DescriptorSetFactory()
 }
 
 Error DescriptorSetFactory::init(const GrAllocator<U8>& alloc, VkDevice dev, U32 bindlessTextureCount,
-								 U32 bindlessImageCount)
+								 U32 bindlessTextureBuffers)
 {
 	m_alloc = alloc;
 	m_dev = dev;
 
 	m_bindless = m_alloc.newInstance<BindlessDescriptorSet>();
-	ANKI_CHECK(m_bindless->init(alloc, dev, bindlessTextureCount, bindlessImageCount));
+	ANKI_CHECK(m_bindless->init(alloc, dev, bindlessTextureCount, bindlessTextureBuffers));
 	m_bindlessTextureCount = bindlessTextureCount;
-	m_bindlessImageCount = bindlessImageCount;
+	m_bindlessUniformTexelBufferCount = bindlessTextureBuffers;
 
 	return Error::NONE;
 }
@@ -1014,8 +1061,8 @@ Error DescriptorSetFactory::newDescriptorSetLayout(const DescriptorSetLayoutInit
 			{
 				// All good
 			}
-			else if(binding.m_binding == 1 && binding.m_type == DescriptorType::IMAGE
-					&& binding.m_arraySize == m_bindlessImageCount)
+			else if(binding.m_binding == 1 && binding.m_type == DescriptorType::READ_TEXTURE_BUFFER
+					&& binding.m_arraySize == m_bindlessUniformTexelBufferCount)
 			{
 				// All good
 			}
@@ -1114,10 +1161,10 @@ U32 DescriptorSetFactory::bindBindlessTexture(const VkImageView view, const VkIm
 	return m_bindless->bindTexture(view, layout);
 }
 
-U32 DescriptorSetFactory::bindBindlessImage(const VkImageView view)
+U32 DescriptorSetFactory::bindBindlessUniformTexelBuffer(const VkBufferView view)
 {
 	ANKI_ASSERT(m_bindless);
-	return m_bindless->bindImage(view);
+	return m_bindless->bindUniformTexelBuffer(view);
 }
 
 void DescriptorSetFactory::unbindBindlessTexture(U32 idx)
@@ -1126,10 +1173,10 @@ void DescriptorSetFactory::unbindBindlessTexture(U32 idx)
 	m_bindless->unbindTexture(idx);
 }
 
-void DescriptorSetFactory::unbindBindlessImage(U32 idx)
+void DescriptorSetFactory::unbindBindlessUniformTexelBuffer(U32 idx)
 {
 	ANKI_ASSERT(m_bindless);
-	m_bindless->unbindImage(idx);
+	m_bindless->unbindUniformTexelBuffer(idx);
 }
 
 } // end namespace anki

+ 6 - 54
AnKi/Gr/Vulkan/DescriptorSet.h

@@ -349,55 +349,7 @@ private:
 		m_bindlessDSetBound = false;
 	}
 
-	AnyBinding& getBindingToPopulate(U32 bindingIdx, U32 arrayIdx)
-	{
-		ANKI_ASSERT(bindingIdx < MAX_BINDINGS_PER_DESCRIPTOR_SET);
-
-		AnyBindingExtended& extended = m_bindings[bindingIdx];
-		AnyBinding* out;
-		const Bool bindingIsSet = m_bindingSet.get(bindingIdx);
-		m_bindingSet.set(bindingIdx);
-		extended.m_arraySize = (!bindingIsSet) ? 0 : extended.m_arraySize;
-
-		if(ANKI_LIKELY(arrayIdx == 0 && extended.m_arraySize <= 1))
-		{
-			// Array idx is zero, most common case
-			out = &extended.m_single;
-			extended.m_arraySize = 1;
-		}
-		else if(arrayIdx < extended.m_arraySize)
-		{
-			// It's (or was) an array and there enough space in thar array
-			out = &extended.m_array[arrayIdx];
-		}
-		else
-		{
-			// Need to grow
-			const U32 newSize = max(extended.m_arraySize * 2, arrayIdx + 1);
-			AnyBinding* newArr = m_alloc.newArray<AnyBinding>(newSize);
-
-			if(extended.m_arraySize == 1)
-			{
-				newArr[0] = extended.m_single;
-			}
-			else if(extended.m_arraySize > 1)
-			{
-				// Copy old to new.
-				memcpy(newArr, extended.m_array, sizeof(AnyBinding) * extended.m_arraySize);
-			}
-
-			// Zero the rest
-			memset(newArr + extended.m_arraySize, 0, sizeof(AnyBinding) * (newSize - extended.m_arraySize));
-			extended.m_arraySize = newSize;
-			extended.m_array = newArr;
-
-			// Return
-			out = &extended.m_array[arrayIdx];
-		}
-
-		ANKI_ASSERT(out);
-		return *out;
-	}
+	AnyBinding& getBindingToPopulate(U32 bindingIdx, U32 arrayIdx);
 };
 
 /// Creates new descriptor set layouts and descriptor sets.
@@ -409,7 +361,7 @@ public:
 	DescriptorSetFactory() = default;
 	~DescriptorSetFactory();
 
-	Error init(const GrAllocator<U8>& alloc, VkDevice dev, U32 bindlessTextureCount, U32 bindlessImageCount);
+	Error init(const GrAllocator<U8>& alloc, VkDevice dev, U32 bindlessTextureCount, U32 bindlessTextureBuffers);
 
 	void destroy();
 
@@ -429,15 +381,15 @@ public:
 	/// @note It's thread-safe.
 	U32 bindBindlessTexture(const VkImageView view, const VkImageLayout layout);
 
-	/// Bind a storage image.
+	/// Bind a uniform texel buffer.
 	/// @note It's thread-safe.
-	U32 bindBindlessImage(const VkImageView view);
+	U32 bindBindlessUniformTexelBuffer(const VkBufferView view);
 
 	/// @note It's thread-safe.
 	void unbindBindlessTexture(U32 idx);
 
 	/// @note It's thread-safe.
-	void unbindBindlessImage(U32 idx);
+	void unbindBindlessUniformTexelBuffer(U32 idx);
 
 private:
 	class BindlessDescriptorSet;
@@ -457,7 +409,7 @@ private:
 
 	BindlessDescriptorSet* m_bindless = nullptr;
 	U32 m_bindlessTextureCount = MAX_U32;
-	U32 m_bindlessImageCount = MAX_U32;
+	U32 m_bindlessUniformTexelBufferCount = MAX_U32;
 };
 /// @}
 

+ 2 - 1
AnKi/Gr/Vulkan/GrManagerImpl.cpp

@@ -192,7 +192,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_READONLY_TEXTURE_BUFFERS));
 	m_pplineLayoutFactory.init(getAllocator(), m_device);
 
 	m_frameGarbageCollector.init(this);

+ 12 - 36
AnKi/Gr/Vulkan/TextureImpl.cpp

@@ -42,33 +42,21 @@ static Bool isAstcSrgbFormat(const VkFormat format)
 	}
 }
 
-U32 MicroImageView::getOrCreateBindlessIndex(VkImageLayout layout, GrManagerImpl& gr) const
+U32 MicroImageView::getOrCreateBindlessIndex(GrManagerImpl& gr) const
 {
-	ANKI_ASSERT(layout == VK_IMAGE_LAYOUT_GENERAL || layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-
-	const U32 arrayIdx = (layout == VK_IMAGE_LAYOUT_GENERAL) ? 1 : 0;
-
-	LockGuard<SpinLock> lock(m_lock);
+	LockGuard<SpinLock> lock(m_bindlessIndexLock);
 
 	U32 outIdx;
-	if(m_bindlessIndices[arrayIdx] != MAX_U32)
+	if(m_bindlessIndex != MAX_U32)
 	{
-		outIdx = m_bindlessIndices[arrayIdx];
+		outIdx = m_bindlessIndex;
 	}
 	else
 	{
 		// Needs binding to the bindless descriptor set
 
-		if(layout == VK_IMAGE_LAYOUT_GENERAL)
-		{
-			outIdx = gr.getDescriptorSetFactory().bindBindlessImage(m_handle);
-		}
-		else
-		{
-			outIdx = gr.getDescriptorSetFactory().bindBindlessTexture(m_handle, layout);
-		}
-
-		m_bindlessIndices[arrayIdx] = outIdx;
+		outIdx = gr.getDescriptorSetFactory().bindBindlessTexture(m_handle, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+		m_bindlessIndex = outIdx;
 	}
 
 	return outIdx;
@@ -90,16 +78,10 @@ TextureImpl::~TextureImpl()
 		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)
+		if(it.m_bindlessIndex != MAX_U32)
 		{
-			garbage->m_bindlessIndices.emplaceBack(getAllocator(), it.m_bindlessIndices[1]);
-			it.m_bindlessIndices[1] = MAX_U32;
+			garbage->m_bindlessIndices.emplaceBack(getAllocator(), it.m_bindlessIndex);
+			it.m_bindlessIndex = MAX_U32;
 		}
 	}
 
@@ -110,16 +92,10 @@ TextureImpl::~TextureImpl()
 		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)
+		if(m_singleSurfaceImageView.m_bindlessIndex != MAX_U32)
 		{
-			garbage->m_bindlessIndices.emplaceBack(getAllocator(), m_singleSurfaceImageView.m_bindlessIndices[1]);
-			m_singleSurfaceImageView.m_bindlessIndices[1] = MAX_U32;
+			garbage->m_bindlessIndices.emplaceBack(getAllocator(), m_singleSurfaceImageView.m_bindlessIndex);
+			m_singleSurfaceImageView.m_bindlessIndex = MAX_U32;
 		}
 	}
 

+ 6 - 13
AnKi/Gr/Vulkan/TextureImpl.h

@@ -35,10 +35,7 @@ public:
 
 	~MicroImageView()
 	{
-		for([[maybe_unused]] U32 idx : m_bindlessIndices)
-		{
-			ANKI_ASSERT(idx == MAX_U32 && "Forgot to unbind the bindless");
-		}
+		ANKI_ASSERT(m_bindlessIndex == MAX_U32 && "Forgot to unbind the bindless");
 		ANKI_ASSERT(m_handle == VK_NULL_HANDLE);
 	}
 
@@ -46,8 +43,8 @@ public:
 	{
 		m_handle = b.m_handle;
 		b.m_handle = VK_NULL_HANDLE;
-		m_bindlessIndices = b.m_bindlessIndices;
-		b.m_bindlessIndices = {MAX_U32, MAX_U32};
+		m_bindlessIndex = b.m_bindlessIndex;
+		b.m_bindlessIndex = MAX_U32;
 		m_derivedTextureType = b.m_derivedTextureType;
 		b.m_derivedTextureType = TextureType::COUNT;
 		return *this;
@@ -60,7 +57,7 @@ public:
 	}
 
 	/// @note It's thread-safe.
-	U32 getOrCreateBindlessIndex(VkImageLayout layout, GrManagerImpl& gr) const;
+	U32 getOrCreateBindlessIndex(GrManagerImpl& gr) const;
 
 	TextureType getDerivedTextureType() const
 	{
@@ -71,12 +68,8 @@ public:
 private:
 	VkImageView m_handle = VK_NULL_HANDLE;
 
-	/// Index 0: Sampled image with SHADER_READ_ONLY layout.
-	/// Index 1: Storage image with ofcource GENERAL layout.
-	mutable Array<U32, 2> m_bindlessIndices = {MAX_U32, MAX_U32};
-
-	/// Protect the m_bindlessIndices.
-	mutable SpinLock m_lock;
+	mutable U32 m_bindlessIndex = MAX_U32;
+	mutable SpinLock m_bindlessIndexLock;
 
 	/// Because for example a single surface view of a cube texture will be a 2D view.
 	TextureType m_derivedTextureType = TextureType::COUNT;

+ 1 - 8
AnKi/Gr/Vulkan/TextureView.cpp

@@ -26,14 +26,7 @@ U32 TextureView::getOrCreateBindlessTextureIndex()
 	ANKI_VK_SELF(TextureViewImpl);
 	ANKI_ASSERT(self.getTextureImpl().computeLayout(TextureUsageBit::ALL_SAMPLED, 0)
 				== VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-	return self.getOrCreateBindlessIndex(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
-}
-
-U32 TextureView::getOrCreateBindlessImageIndex()
-{
-	ANKI_VK_SELF(TextureViewImpl);
-	ANKI_ASSERT(self.getTextureImpl().computeLayout(TextureUsageBit::ALL_IMAGE, 0) == VK_IMAGE_LAYOUT_GENERAL);
-	return self.getOrCreateBindlessIndex(VK_IMAGE_LAYOUT_GENERAL);
+	return self.getOrCreateBindlessIndex();
 }
 
 } // end namespace anki

+ 4 - 7
AnKi/Gr/Vulkan/TextureViewImpl.cpp

@@ -36,17 +36,14 @@ Error TextureViewImpl::init(const TextureViewInitInfo& inf)
 	return Error::NONE;
 }
 
-U32 TextureViewImpl::getOrCreateBindlessIndex(VkImageLayout layout)
+U32 TextureViewImpl::getOrCreateBindlessIndex()
 {
-	const U32 arrayIdx = (layout == VK_IMAGE_LAYOUT_GENERAL) ? 1 : 0;
-	U32& bindlessIdx = m_bindlessIndices[arrayIdx];
-
-	if(bindlessIdx == MAX_U32)
+	if(m_bindlessIndex == MAX_U32)
 	{
-		bindlessIdx = m_microImageView->getOrCreateBindlessIndex(layout, getGrManagerImpl());
+		m_bindlessIndex = m_microImageView->getOrCreateBindlessIndex(getGrManagerImpl());
 	}
 
-	return bindlessIdx;
+	return m_bindlessIndex;
 }
 
 } // end namespace anki

+ 2 - 3
AnKi/Gr/Vulkan/TextureViewImpl.h

@@ -51,12 +51,11 @@ public:
 		return static_cast<const TextureImpl&>(*m_tex);
 	}
 
-	U32 getOrCreateBindlessIndex(VkImageLayout layout);
+	U32 getOrCreateBindlessIndex();
 
 private:
 	VkImageView m_handle = {}; ///< Cache the handle.
-
-	Array<U32, 2> m_bindlessIndices = {MAX_U32, MAX_U32}; ///< Cache it.
+	U32 m_bindlessIndex = MAX_U32; ///< Cache it.
 
 	/// This is a hash that depends on the Texture and the VkImageView. It's used as a replacement of
 	/// TextureView::m_uuid since it creates less unique IDs.

+ 6 - 0
AnKi/Resource/MaterialResource.cpp

@@ -799,6 +799,12 @@ const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey&
 		key.setLod(0);
 	}
 
+	if(!(prog.m_presentBuildinMutators & U32(BuiltinMutatorId::VELOCITY)) && key.getVelocity())
+	{
+		// Particles set their own velocity
+		key.setVelocity(false);
+	}
+
 	ANKI_ASSERT(!key.getSkinned() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::BONES)));
 	ANKI_ASSERT(!key.getVelocity() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::VELOCITY)));
 

+ 8 - 9
AnKi/ShaderCompiler/ShaderProgramParser.cpp

@@ -64,19 +64,17 @@ static const char SHADER_HEADER[] = R"(#version 460 core
 #extension GL_EXT_scalar_block_layout : enable
 
 #define ANKI_MAX_BINDLESS_TEXTURES %uu
-#define ANKI_MAX_BINDLESS_IMAGES %uu
+#define MAX_BINDLESS_READONLY_TEXTURE_BUFFERS %uu
 
 #if defined(ANKI_RAY_GEN_SHADER) || defined(ANKI_ANY_HIT_SHADER) || defined(ANKI_CLOSEST_HIT_SHADER) || defined(ANKI_MISS_SHADER) || defined(ANKI_INTERSECTION_SHADER) || defined(ANKI_CALLABLE_SHADER)
 #	extension GL_EXT_ray_tracing : enable
 #endif
 
-#define ANKI_BINDLESS_SET(set_) \
-	layout(set = set_, binding = 0) uniform utexture2D u_bindlessTextures2dU32[ANKI_MAX_BINDLESS_TEXTURES]; \
-	layout(set = set_, binding = 0) uniform itexture2D u_bindlessTextures2dI32[ANKI_MAX_BINDLESS_TEXTURES]; \
-	layout(set = set_, binding = 0) uniform texture2D u_bindlessTextures2dF32[ANKI_MAX_BINDLESS_TEXTURES]; \
-	layout(set = set_, binding = 1) uniform readonly uimage2D u_bindlessImages2dU32[ANKI_MAX_BINDLESS_IMAGES]; \
-	layout(set = set_, binding = 1) uniform readonly iimage2D u_bindlessImages2dI32[ANKI_MAX_BINDLESS_IMAGES]; \
-	layout(set = set_, binding = 1) uniform readonly image2D u_bindlessImages2dF32[ANKI_MAX_BINDLESS_IMAGES];
+#define ANKI_BINDLESS_SET(s) \
+	layout(set = s, binding = 0) uniform utexture2D u_bindlessTextures2dU32[ANKI_MAX_BINDLESS_TEXTURES]; \
+	layout(set = s, binding = 0) uniform itexture2D u_bindlessTextures2dI32[ANKI_MAX_BINDLESS_TEXTURES]; \
+	layout(set = s, binding = 0) uniform texture2D u_bindlessTextures2dF32[ANKI_MAX_BINDLESS_TEXTURES]; \
+	layout(set = s, binding = 1) uniform textureBuffer u_bindlessTextureBuffers[MAX_BINDLESS_READONLY_TEXTURE_BUFFERS];
 
 #define F32 float
 #define _ANKI_SIZEOF_float 4u
@@ -1197,7 +1195,8 @@ void ShaderProgramParser::generateAnkiShaderHeader(ShaderType shaderType, const
 												   StringAuto& header)
 {
 	header.sprintf(SHADER_HEADER, SHADER_STAGE_NAMES[shaderType].cstr(), compilerOptions.m_mobilePlatform,
-				   compilerOptions.m_forceFullFloatingPointPrecision, MAX_BINDLESS_TEXTURES, MAX_BINDLESS_IMAGES);
+				   compilerOptions.m_forceFullFloatingPointPrecision, MAX_BINDLESS_TEXTURES,
+				   MAX_BINDLESS_READONLY_TEXTURE_BUFFERS);
 }
 
 Error ShaderProgramParser::generateVariant(ConstWeakArray<MutatorValue> mutation,

+ 1 - 1
Samples/PhysicsPlayground/Assets/Smoke.ankimtl

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" ?>
 <material>
 	<shaderPrograms>
-		<shaderProgram filename="Anki/Shaders/ForwardShadingParticles.ankiprog">
+		<shaderProgram name="ForwardShadingParticles">
 			<mutation>
 				<mutator name="ANIMATED_TEXTURE" value="0"/>
 				<mutator name="LIGHT" value="1"/>

+ 2 - 0
Tests/Gr/Gr.cpp

@@ -2152,6 +2152,7 @@ void main()
 
 ANKI_TEST(Gr, Bindless)
 {
+#if 0
 	COMMON_BEGIN()
 
 	// Create texture A
@@ -2276,6 +2277,7 @@ void main()
 	resBuff->unmap();
 
 	COMMON_END()
+#endif
 }
 
 ANKI_TEST(Gr, BufferAddress)