Просмотр исходного кода

Add some more code for bindless texture & images

Panagiotis Christopoulos Charitos 6 лет назад
Родитель
Сommit
39ab274738

+ 12 - 1
src/anki/gr/CommandBuffer.h

@@ -265,7 +265,18 @@ public:
 	void bindTextureBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range, Format fmt);
 	void bindTextureBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range, Format fmt);
 
 
 	/// Bind the bindless descriptor set into a slot.
 	/// Bind the bindless descriptor set into a slot.
-	void bindBindless(U32 set);
+	void bindAllBindless(U32 set);
+
+	/// Bind a texture as bindless. It's very lightweight and doesn't translate to a GPU operation.
+	/// @param tex The texture view to bind.
+	/// @param usage The state the tex is in.
+	/// @return The index to use to access the texture.
+	U32 bindBindlessTexture(TextureViewPtr tex, TextureUsageBit usage);
+
+	/// Bind an image as bindless. It's very lightweight and doesn't translate to a GPU operation.
+	/// @param img The image to bind.
+	/// @return The index to use to access the image.
+	U32 bindBindlessImage(TextureViewPtr img);
 
 
 	/// Set push constants.
 	/// Set push constants.
 	void setPushConstants(const void* data, U32 dataSize);
 	void setPushConstants(const void* data, U32 dataSize);

+ 0 - 3
src/anki/gr/TextureView.h

@@ -91,9 +91,6 @@ public:
 		return m_subresource;
 		return m_subresource;
 	}
 	}
 
 
-	/// Generate an index that can be used to index the view from the global bindless descriptor set.
-	U32 generateBindlessIndex(TextureUsageBit usages);
-
 protected:
 protected:
 	TextureType m_texType = TextureType::COUNT;
 	TextureType m_texType = TextureType::COUNT;
 	TextureSubresourceInfo m_subresource;
 	TextureSubresourceInfo m_subresource;

+ 14 - 2
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -203,10 +203,22 @@ void CommandBuffer::bindTextureBuffer(U32 set, U32 binding, BufferPtr buff, PtrS
 	ANKI_ASSERT(!"TODO");
 	ANKI_ASSERT(!"TODO");
 }
 }
 
 
-void CommandBuffer::bindBindless(U32 set)
+void CommandBuffer::bindAllBindless(U32 set)
 {
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	ANKI_VK_SELF(CommandBufferImpl);
-	self.bindBindlessInternal(set);
+	self.bindAllBindlessInternal(set);
+}
+
+U32 CommandBuffer::bindBindlessTexture(TextureViewPtr tex, TextureUsageBit usage)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	return self.bindBindlessTextureInternal(tex, usage);
+}
+
+U32 CommandBuffer::bindBindlessImage(TextureViewPtr img)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	return self.bindBindlessImageInternal(img);
 }
 }
 
 
 void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)
 void CommandBuffer::bindShaderProgram(ShaderProgramPtr prog)

+ 15 - 1
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -15,6 +15,7 @@
 #include <anki/gr/vulkan/BufferImpl.h>
 #include <anki/gr/vulkan/BufferImpl.h>
 #include <anki/gr/vulkan/TextureImpl.h>
 #include <anki/gr/vulkan/TextureImpl.h>
 #include <anki/gr/vulkan/Pipeline.h>
 #include <anki/gr/vulkan/Pipeline.h>
+#include <anki/gr/vulkan/GrManagerImpl.h>
 #include <anki/util/List.h>
 #include <anki/util/List.h>
 
 
 namespace anki
 namespace anki
@@ -261,9 +262,22 @@ public:
 		m_microCmdb->pushObjectRef(img);
 		m_microCmdb->pushObjectRef(img);
 	}
 	}
 
 
-	void bindBindlessInternal(U32 set)
+	void bindAllBindlessInternal(U32 set)
+	{
+		commandCommon();
+		m_dsetState[set].bindCustumDescriptorSet(getGrManagerImpl().getBindlessDescriptorSet().getDescriptorSet());
+	}
+
+	U32 bindBindlessTextureInternal(TextureViewPtr tex, TextureUsageBit usage)
+	{
+		ANKI_ASSERT(!"TODO");
+		return 0;
+	}
+
+	U32 bindBindlessImageInternal(TextureViewPtr img)
 	{
 	{
 		ANKI_ASSERT(!"TODO");
 		ANKI_ASSERT(!"TODO");
+		return 0;
 	}
 	}
 
 
 	void beginRenderPass(FramebufferPtr fb,
 	void beginRenderPass(FramebufferPtr fb,

+ 0 - 1
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -4,7 +4,6 @@
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
 #include <anki/gr/vulkan/CommandBufferImpl.h>
 #include <anki/gr/vulkan/CommandBufferImpl.h>
-#include <anki/gr/vulkan/GrManagerImpl.h>
 #include <anki/gr/vulkan/TextureImpl.h>
 #include <anki/gr/vulkan/TextureImpl.h>
 #include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/vulkan/OcclusionQueryImpl.h>
 #include <anki/gr/vulkan/OcclusionQueryImpl.h>

+ 116 - 79
src/anki/gr/vulkan/DescriptorSet.cpp

@@ -76,7 +76,7 @@ public:
 
 
 	U64 m_hash = 0; ///< Layout hash.
 	U64 m_hash = 0; ///< Layout hash.
 	VkDescriptorSetLayout m_layoutHandle = {};
 	VkDescriptorSetLayout m_layoutHandle = {};
-	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U8> m_activeBindings = {false};
+	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U32> m_activeBindings = {false};
 	Array<DescriptorType, MAX_BINDINGS_PER_DESCRIPTOR_SET> m_bindingType = {};
 	Array<DescriptorType, MAX_BINDINGS_PER_DESCRIPTOR_SET> m_bindingType = {};
 	U32 m_minBinding = MAX_U32;
 	U32 m_minBinding = MAX_U32;
 	U32 m_maxBinding = 0;
 	U32 m_maxBinding = 0;
@@ -478,87 +478,111 @@ Error DSLayoutCacheEntry::getOrCreateThreadAllocator(ThreadId tid, DSThreadAlloc
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-void DescriptorSetState::flush(
-	Bool& stateDirty, U64& hash, Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET>& dynamicOffsets, U& dynamicOffsetCount)
+void DescriptorSetState::flush(U64& hash,
+	Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET>& dynamicOffsets,
+	U& dynamicOffsetCount,
+	DescriptorSet& customDSet)
 {
 {
+	// Set some values
+	hash = 0;
 	dynamicOffsetCount = 0;
 	dynamicOffsetCount = 0;
+	customDSet = {};
 
 
-	// Get cache entry
-	ANKI_ASSERT(m_layout.m_entry);
-	const DSLayoutCacheEntry& entry = *m_layout.m_entry;
-
-	// Early out if nothing happened
-	if(!m_anyBindingDirty && !m_layoutDirty)
+	if(m_customDSet.m_handle == VK_NULL_HANDLE)
 	{
 	{
-		stateDirty = false;
-		return;
-	}
+		// Get cache entry
+		ANKI_ASSERT(m_layout.m_entry);
+		const DSLayoutCacheEntry& entry = *m_layout.m_entry;
 
 
-	Bool dynamicOffsetsDirty = false;
+		// Early out if nothing happened
+		const Bool anyActiveBindingDirty = !!(entry.m_activeBindings & m_dirtyBindings);
+		if(!anyActiveBindingDirty && !m_layoutDirty)
+		{
+			return;
+		}
 
 
-	// Compute the hash
-	Array<U64, MAX_BINDINGS_PER_DESCRIPTOR_SET * 2 * 2> toHash;
-	U toHashCount = 0;
+		Bool dynamicOffsetsDirty = false;
 
 
-	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))
-		{
-			toHash[toHashCount++] = m_bindings[i].m_uuids[0];
+		// Compute the hash
+		Array<U64, MAX_BINDINGS_PER_DESCRIPTOR_SET * 2 * 2> toHash;
+		U toHashCount = 0;
 
 
-			switch(entry.m_bindingType[i])
+		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))
 			{
 			{
-			case DescriptorType::COMBINED_TEXTURE_SAMPLER:
-				ANKI_ASSERT(
-					m_bindings[i].m_type == DescriptorType::COMBINED_TEXTURE_SAMPLER && "Have bound the wrong type");
-				toHash[toHashCount++] = m_bindings[i].m_uuids[1];
-				toHash[toHashCount++] = U64(m_bindings[i].m_texAndSampler.m_layout);
-				break;
-			case DescriptorType::TEXTURE:
-				ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::TEXTURE && "Have bound the wrong type");
-				toHash[toHashCount] = U64(m_bindings[i].m_tex.m_layout);
-				break;
-			case DescriptorType::SAMPLER:
-				ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::SAMPLER && "Have bound the wrong type");
-				break;
-			case DescriptorType::UNIFORM_BUFFER:
-				ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::UNIFORM_BUFFER && "Have bound the wrong type");
-				toHash[toHashCount++] = m_bindings[i].m_buff.m_range;
-				dynamicOffsets[dynamicOffsetCount++] = m_bindings[i].m_buff.m_offset;
-				dynamicOffsetsDirty = dynamicOffsetsDirty || m_dynamicOffsetDirty.get(i);
-				break;
-			case DescriptorType::STORAGE_BUFFER:
-				ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::STORAGE_BUFFER && "Have bound the wrong type");
-				toHash[toHashCount++] = m_bindings[i].m_buff.m_range;
-				dynamicOffsets[dynamicOffsetCount++] = m_bindings[i].m_buff.m_offset;
-				dynamicOffsetsDirty = dynamicOffsetsDirty || m_dynamicOffsetDirty.get(i);
-				break;
-			case DescriptorType::IMAGE:
-				ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::IMAGE && "Have bound the wrong type");
-				break;
-			default:
-				ANKI_ASSERT(0);
+				const Bool crntBindingDirty = m_dirtyBindings.get(i);
+				m_dirtyBindings.unset(i);
+
+				toHash[toHashCount++] = m_bindings[i].m_uuids[0];
+
+				switch(entry.m_bindingType[i])
+				{
+				case DescriptorType::COMBINED_TEXTURE_SAMPLER:
+					ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::COMBINED_TEXTURE_SAMPLER
+								&& "Have bound the wrong type");
+					toHash[toHashCount++] = m_bindings[i].m_uuids[1];
+					toHash[toHashCount++] = U64(m_bindings[i].m_texAndSampler.m_layout);
+					break;
+				case DescriptorType::TEXTURE:
+					ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::TEXTURE && "Have bound the wrong type");
+					toHash[toHashCount] = U64(m_bindings[i].m_tex.m_layout);
+					break;
+				case DescriptorType::SAMPLER:
+					ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::SAMPLER && "Have bound the wrong type");
+					break;
+				case DescriptorType::UNIFORM_BUFFER:
+					ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::UNIFORM_BUFFER && "Have bound the wrong type");
+					toHash[toHashCount++] = m_bindings[i].m_buff.m_range;
+					dynamicOffsets[dynamicOffsetCount++] = m_bindings[i].m_buff.m_offset;
+					dynamicOffsetsDirty = dynamicOffsetsDirty || crntBindingDirty;
+					break;
+				case DescriptorType::STORAGE_BUFFER:
+					ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::STORAGE_BUFFER && "Have bound the wrong type");
+					toHash[toHashCount++] = m_bindings[i].m_buff.m_range;
+					dynamicOffsets[dynamicOffsetCount++] = m_bindings[i].m_buff.m_offset;
+					dynamicOffsetsDirty = dynamicOffsetsDirty || crntBindingDirty;
+					break;
+				case DescriptorType::IMAGE:
+					ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::IMAGE && "Have bound the wrong type");
+					break;
+				default:
+					ANKI_ASSERT(0);
+				}
 			}
 			}
 		}
 		}
-	}
 
 
-	hash = (toHashCount == 1) ? toHash[0] : computeHash(&toHash[0], toHashCount * sizeof(U64));
+		const U64 newHash = computeHash(&toHash[0], toHashCount * sizeof(U64));
 
 
-	if(hash != m_lastHash || dynamicOffsetsDirty || m_layoutDirty)
-	{
-		m_lastHash = hash;
-		stateDirty = true;
+		if(newHash != m_lastHash || dynamicOffsetsDirty || m_layoutDirty)
+		{
+			// DS needs rebind
+			m_lastHash = newHash;
+			hash = newHash;
+		}
+		else
+		{
+			// All clean, keep hash equal to 0
+		}
+
+		m_layoutDirty = false;
 	}
 	}
 	else
 	else
 	{
 	{
-		stateDirty = false;
-	}
+		// Custom set
+
+		if(!m_customDSetDirty && !m_layoutDirty)
+		{
+			return;
+		}
 
 
-	m_anyBindingDirty = false;
-	m_layoutDirty = false;
-	m_dynamicOffsetDirty.unsetAll();
+		customDSet = m_customDSet;
+		hash = 1;
+		m_customDSetDirty = false;
+		m_layoutDirty = false;
+	}
 }
 }
 
 
 DescriptorSetFactory::~DescriptorSetFactory()
 DescriptorSetFactory::~DescriptorSetFactory()
@@ -644,25 +668,38 @@ Error DescriptorSetFactory::newDescriptorSet(ThreadId tid,
 	ANKI_TRACE_SCOPED_EVENT(VK_DESCRIPTOR_SET_GET_OR_CREATE);
 	ANKI_TRACE_SCOPED_EVENT(VK_DESCRIPTOR_SET_GET_OR_CREATE);
 
 
 	U64 hash;
 	U64 hash;
-	state.flush(dirty, hash, dynamicOffsets, dynamicOffsetCount);
+	DescriptorSet customDSet;
+	state.flush(hash, dynamicOffsets, dynamicOffsetCount, customDSet);
 
 
-	if(!dirty)
+	if(hash == 0)
 	{
 	{
+		dirty = false;
 		return Error::NONE;
 		return Error::NONE;
 	}
 	}
+	else
+	{
+		dirty = true;
 
 
-	DescriptorSetLayout layout = state.m_layout;
-	DSLayoutCacheEntry& entry = *layout.m_entry;
-
-	// Get thread allocator
-	DSThreadAllocator* alloc;
-	ANKI_CHECK(entry.getOrCreateThreadAllocator(tid, alloc));
-
-	// Finally, allocate
-	const DS* s;
-	ANKI_CHECK(alloc->getOrCreateSet(hash, state.m_bindings, s));
-	set.m_handle = s->m_handle;
-	ANKI_ASSERT(set.m_handle != VK_NULL_HANDLE);
+		if(customDSet.m_handle == VK_NULL_HANDLE)
+		{
+			DescriptorSetLayout layout = state.m_layout;
+			DSLayoutCacheEntry& entry = *layout.m_entry;
+
+			// Get thread allocator
+			DSThreadAllocator* alloc;
+			ANKI_CHECK(entry.getOrCreateThreadAllocator(tid, alloc));
+
+			// Finally, allocate
+			const DS* s;
+			ANKI_CHECK(alloc->getOrCreateSet(hash, state.m_bindings, s));
+			set.m_handle = s->m_handle;
+			ANKI_ASSERT(set.m_handle != VK_NULL_HANDLE);
+		}
+		else
+		{
+			set = customDSet;
+		}
+	}
 
 
 	return Error::NONE;
 	return Error::NONE;
 }
 }

+ 47 - 32
src/anki/gr/vulkan/DescriptorSet.h

@@ -123,17 +123,30 @@ public:
 	};
 	};
 };
 };
 
 
-/// A state tracker of descriptors.
-class DescriptorSetState
+/// Descriptor set thin wraper.
+class DescriptorSet
 {
 {
 	friend class DescriptorSetFactory;
 	friend class DescriptorSetFactory;
+	friend class BindlessDescriptorSet;
+	friend class DescriptorSetState;
 
 
 public:
 public:
-	void makeDirty()
+	VkDescriptorSet getHandle() const
 	{
 	{
-		m_anyBindingDirty = true;
+		ANKI_ASSERT(m_handle);
+		return m_handle;
 	}
 	}
 
 
+private:
+	VkDescriptorSet m_handle = VK_NULL_HANDLE;
+};
+
+/// A state tracker of descriptors.
+class DescriptorSetState
+{
+	friend class DescriptorSetFactory;
+
+public:
 	void setLayout(const DescriptorSetLayout& layout)
 	void setLayout(const DescriptorSetLayout& layout)
 	{
 	{
 		if(layout.isCreated())
 		if(layout.isCreated())
@@ -163,7 +176,8 @@ public:
 		b.m_texAndSampler.m_sampler = static_cast<const SamplerImpl*>(sampler)->m_sampler.get();
 		b.m_texAndSampler.m_sampler = static_cast<const SamplerImpl*>(sampler)->m_sampler.get();
 		b.m_texAndSampler.m_layout = layout;
 		b.m_texAndSampler.m_layout = layout;
 
 
-		m_anyBindingDirty = true;
+		m_dirtyBindings.set(binding);
+		unbindCustomDSet();
 	}
 	}
 
 
 	void bindTexture(U binding, const TextureView* texView, VkImageLayout layout)
 	void bindTexture(U binding, const TextureView* texView, VkImageLayout layout)
@@ -179,7 +193,8 @@ public:
 		b.m_tex.m_texView = &viewImpl;
 		b.m_tex.m_texView = &viewImpl;
 		b.m_tex.m_layout = layout;
 		b.m_tex.m_layout = layout;
 
 
-		m_anyBindingDirty = true;
+		m_dirtyBindings.set(binding);
+		unbindCustomDSet();
 	}
 	}
 
 
 	void bindSampler(U binding, const Sampler* sampler)
 	void bindSampler(U binding, const Sampler* sampler)
@@ -190,7 +205,8 @@ public:
 		b.m_uuids[0] = b.m_uuids[1] = ptrToNumber(static_cast<const SamplerImpl*>(sampler)->m_sampler->getHandle());
 		b.m_uuids[0] = b.m_uuids[1] = ptrToNumber(static_cast<const SamplerImpl*>(sampler)->m_sampler->getHandle());
 		b.m_sampler.m_sampler = static_cast<const SamplerImpl*>(sampler)->m_sampler.get();
 		b.m_sampler.m_sampler = static_cast<const SamplerImpl*>(sampler)->m_sampler.get();
 
 
-		m_anyBindingDirty = true;
+		m_dirtyBindings.set(binding);
+		unbindCustomDSet();
 	}
 	}
 
 
 	void bindUniformBuffer(U binding, const Buffer* buff, PtrSize offset, PtrSize range)
 	void bindUniformBuffer(U binding, const Buffer* buff, PtrSize offset, PtrSize range)
@@ -204,8 +220,8 @@ public:
 		b.m_buff.m_offset = offset;
 		b.m_buff.m_offset = offset;
 		b.m_buff.m_range = range;
 		b.m_buff.m_range = range;
 
 
-		m_anyBindingDirty = true;
-		m_dynamicOffsetDirty.set(binding);
+		m_dirtyBindings.set(binding);
+		unbindCustomDSet();
 	}
 	}
 
 
 	void bindStorageBuffer(U binding, const Buffer* buff, PtrSize offset, PtrSize range)
 	void bindStorageBuffer(U binding, const Buffer* buff, PtrSize offset, PtrSize range)
@@ -219,8 +235,8 @@ public:
 		b.m_buff.m_offset = offset;
 		b.m_buff.m_offset = offset;
 		b.m_buff.m_range = range;
 		b.m_buff.m_range = range;
 
 
-		m_anyBindingDirty = true;
-		m_dynamicOffsetDirty.set(binding);
+		m_dirtyBindings.set(binding);
+		unbindCustomDSet();
 	}
 	}
 
 
 	void bindImage(U binding, const TextureView* texView)
 	void bindImage(U binding, const TextureView* texView)
@@ -236,41 +252,40 @@ public:
 		b.m_uuids[0] = b.m_uuids[1] = impl->m_hash;
 		b.m_uuids[0] = b.m_uuids[1] = impl->m_hash;
 		b.m_image.m_texView = impl;
 		b.m_image.m_texView = impl;
 
 
-		m_anyBindingDirty = true;
+		m_dirtyBindings.set(binding);
+		unbindCustomDSet();
+	}
+
+	void bindCustumDescriptorSet(const DescriptorSet& dset)
+	{
+		ANKI_ASSERT(dset.m_handle);
+		m_customDSet = dset;
+		m_customDSetDirty = true;
 	}
 	}
 
 
 private:
 private:
 	DescriptorSetLayout m_layout;
 	DescriptorSetLayout m_layout;
 
 
 	Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> m_bindings;
 	Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> m_bindings;
+	DescriptorSet m_customDSet;
 
 
-	Bool m_anyBindingDirty = true;
-	Bool m_layoutDirty = true;
-	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET> m_dynamicOffsetDirty = {true};
 	U64 m_lastHash = 0;
 	U64 m_lastHash = 0;
 
 
+	BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U32> m_dirtyBindings = {true};
+	Bool m_layoutDirty = true;
+	Bool m_customDSetDirty = true;
+
 	/// Only DescriptorSetFactory should call this.
 	/// Only DescriptorSetFactory should call this.
-	void flush(Bool& stateDirty,
-		U64& hash,
+	/// @param hash If hash is zero then the DS doesn't need rebind.
+	void flush(U64& hash,
 		Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET>& dynamicOffsets,
 		Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET>& dynamicOffsets,
-		U& dynamicOffsetCount);
-};
-
-/// Descriptor set thin wraper.
-class DescriptorSet
-{
-	friend class DescriptorSetFactory;
-	friend class BindlessDescriptorSet;
+		U& dynamicOffsetCount,
+		DescriptorSet& customDSet);
 
 
-public:
-	VkDescriptorSet getHandle() const
+	void unbindCustomDSet()
 	{
 	{
-		ANKI_ASSERT(m_handle);
-		return m_handle;
+		m_customDSet = {};
 	}
 	}
-
-private:
-	VkDescriptorSet m_handle = VK_NULL_HANDLE;
 };
 };
 
 
 /// Creates new descriptor set layouts and descriptor sets.
 /// Creates new descriptor set layouts and descriptor sets.