Browse Source

Add support for separate image samplers

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
d8b08de18a

+ 31 - 0
shaders/Common.glsl

@@ -73,3 +73,34 @@ const U32 UBO_MAX_SIZE = 16384u;
 #endif
 
 #define CALC_BITANGENT_IN_VERT 1
+
+// Convenience functions to combine image and samplers
+sampler2D combineImageSampler(texture2D tex, sampler sampl)
+{
+	return sampler2D(tex, sampl);
+}
+
+sampler3D combineImageSampler(texture3D tex, sampler sampl)
+{
+	return sampler3D(tex, sampl);
+}
+
+samplerCube combineImageSampler(textureCube tex, sampler sampl)
+{
+	return samplerCube(tex, sampl);
+}
+
+sampler2DArray combineImageSampler(texture2DArray tex, sampler sampl)
+{
+	return sampler2DArray(tex, sampl);
+}
+
+samplerCubeArray combineImageSampler(textureCubeArray tex, sampler sampl)
+{
+	return samplerCubeArray(tex, sampl);
+}
+
+sampler2DShadow combineImageSampler(texture2D tex, samplerShadow sampl)
+{
+	return sampler2DShadow(tex, sampl);
+}

+ 13 - 0
src/anki/gr/CommandBuffer.h

@@ -227,6 +227,19 @@ public:
 	/// @param usage The state the tex is in.
 	void bindTextureAndSampler(U32 set, U32 binding, TextureViewPtr texView, SamplerPtr sampler, TextureUsageBit usage);
 
+	/// Bind sampler.
+	/// @param set The set to bind to.
+	/// @param binding The binding to bind to.
+	/// @param sampler The sampler to override the default sampler of the tex.
+	void bindSampler(U32 set, U32 binding, SamplerPtr sampler);
+
+	/// Bind a texture.
+	/// @param set The set to bind to.
+	/// @param binding The binding to bind to.
+	/// @param texView The texture view to bind.
+	/// @param usage The state the tex is in.
+	void bindTexture(U32 set, U32 binding, TextureViewPtr texView, TextureUsageBit usage);
+
 	/// Bind uniform buffer.
 	/// @param set The set to bind to.
 	/// @param binding The binding to bind to.

+ 2 - 0
src/anki/gr/Common.h

@@ -299,7 +299,9 @@ public:
 
 enum class DescriptorType : U8
 {
+	COMBINED_TEXTURE_SAMPLER,
 	TEXTURE,
+	SAMPLER,
 	UNIFORM_BUFFER,
 	STORAGE_BUFFER,
 	IMAGE,

+ 14 - 6
src/anki/gr/Enums.h

@@ -483,10 +483,15 @@ enum class ShaderVariableDataType : U8
 	VEC4,
 	MAT3,
 	MAT4,
-	SAMPLER_2D,
-	SAMPLER_3D,
-	SAMPLER_2D_ARRAY,
-	SAMPLER_CUBE,
+	COMBINED_TEXTURE_SAMPLER_2D,
+	COMBINED_TEXTURE_SAMPLER_3D,
+	COMBINED_TEXTURE_SAMPLER_2D_ARRAY,
+	COMBINED_TEXTURE_SAMPLER_CUBE,
+	TEXTURE_2D,
+	TEXTURE_3D,
+	TEXTURE_2D_ARRAY,
+	TEXTURE_CUBE,
+	SAMPLER,
 
 	NUMERICS_FIRST = INT,
 	NUMERICS_LAST = MAT4,
@@ -494,8 +499,11 @@ enum class ShaderVariableDataType : U8
 	MATRIX_FIRST = MAT3,
 	MATRIX_LAST = MAT4,
 
-	SAMPLERS_FIRST = SAMPLER_2D,
-	SAMPLERS_LAST = SAMPLER_CUBE
+	COMBINED_TEXTURE_SAMPLERS_FIRST = COMBINED_TEXTURE_SAMPLER_2D,
+	COMBINED_TEXTURE_SAMPLERS_LAST = COMBINED_TEXTURE_SAMPLER_CUBE,
+
+	TEXTURE_FIRST = TEXTURE_2D,
+	TEXTURE_LAST = TEXTURE_CUBE,
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderVariableDataType, inline)
 

+ 22 - 0
src/anki/gr/RenderGraph.h

@@ -155,6 +155,17 @@ public:
 		m_commandBuffer->bindTextureAndSampler(set, binding, view, sampler, usage);
 	}
 
+	/// Convenience method.
+	void bindTexture(U32 set, U32 binding, RenderTargetHandle handle, const TextureSubresourceInfo& subresource)
+	{
+		TexturePtr tex;
+		TextureUsageBit usage;
+		getRenderTargetState(handle, subresource, tex, usage);
+		TextureViewInitInfo viewInit(tex, subresource, "TmpRenderGraph");
+		TextureViewPtr view = m_commandBuffer->getManager().newTextureView(viewInit);
+		m_commandBuffer->bindTexture(set, binding, view, usage);
+	}
+
 	/// Convenience method to bind the whole texture as color.
 	void bindColorTextureAndSampler(U32 set, U32 binding, RenderTargetHandle handle, const SamplerPtr& sampler)
 	{
@@ -166,6 +177,17 @@ public:
 		m_commandBuffer->bindTextureAndSampler(set, binding, view, sampler, usage);
 	}
 
+	/// Convenience method to bind the whole texture as color.
+	void bindColorTexture(U32 set, U32 binding, RenderTargetHandle handle)
+	{
+		TexturePtr tex = getTexture(handle);
+		TextureViewInitInfo viewInit(tex); // Use the whole texture
+		TextureUsageBit usage;
+		getRenderTargetState(handle, viewInit, tex, usage);
+		TextureViewPtr view = m_commandBuffer->getManager().newTextureView(viewInit);
+		m_commandBuffer->bindTexture(set, binding, view, usage);
+	}
+
 	/// Convenience method.
 	void bindImage(U32 set, U32 binding, RenderTargetHandle handle, const TextureSubresourceInfo& subresource)
 	{

+ 1 - 0
src/anki/gr/ShaderCompiler.cpp

@@ -66,6 +66,7 @@ static const char* SHADER_HEADER = R"(#version 450 core
 #		extension GL_KHR_shader_subgroup_ballot : require
 #		extension GL_KHR_shader_subgroup_shuffle : require
 #		extension GL_KHR_shader_subgroup_arithmetic : require
+#		extension GL_EXT_samplerless_texture_functions : require
 #	endif
 #endif
 

+ 12 - 0
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -168,6 +168,18 @@ void CommandBuffer::bindTextureAndSampler(
 	self.bindTextureAndSamplerInternal(set, binding, texView, sampler, usage);
 }
 
+void CommandBuffer::bindTexture(U32 set, U32 binding, TextureViewPtr texView, TextureUsageBit usage)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindTextureInternal(set, binding, texView, usage);
+}
+
+void CommandBuffer::bindSampler(U32 set, U32 binding, SamplerPtr sampler)
+{
+	ANKI_VK_SELF(CommandBufferImpl);
+	self.bindSamplerInternal(set, binding, sampler);
+}
+
 void CommandBuffer::bindUniformBuffer(U32 set, U32 binding, BufferPtr buff, PtrSize offset, PtrSize range)
 {
 	ANKI_VK_SELF(CommandBufferImpl);

+ 20 - 0
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -234,6 +234,26 @@ public:
 		m_microCmdb->pushObjectRef(sampler);
 	}
 
+	void bindTextureInternal(U32 set, U32 binding, TextureViewPtr& texView, TextureUsageBit usage)
+	{
+		commandCommon();
+		const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
+		const TextureImpl& tex = static_cast<const TextureImpl&>(*view.m_tex);
+		ANKI_ASSERT(tex.isSubresourceGoodForSampling(view.getSubresource()));
+		const VkImageLayout lay = tex.computeLayout(usage, 0);
+
+		m_dsetState[set].bindTexture(binding, &view, lay);
+
+		m_microCmdb->pushObjectRef(texView);
+	}
+
+	void bindSamplerInternal(U32 set, U32 binding, SamplerPtr& sampler)
+	{
+		commandCommon();
+		m_dsetState[set].bindSampler(binding, sampler.get());
+		m_microCmdb->pushObjectRef(sampler);
+	}
+
 	void bindImage(U32 set, U32 binding, TextureViewPtr& img)
 	{
 		commandCommon();

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

@@ -199,9 +199,15 @@ ANKI_USE_RESULT inline VkDescriptorType convertDescriptorType(DescriptorType ak)
 	VkDescriptorType out;
 	switch(ak)
 	{
-	case DescriptorType::TEXTURE:
+	case DescriptorType::COMBINED_TEXTURE_SAMPLER:
 		out = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
 		break;
+	case DescriptorType::TEXTURE:
+		out = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
+		break;
+	case DescriptorType::SAMPLER:
+		out = VK_DESCRIPTOR_TYPE_SAMPLER;
+		break;
 	case DescriptorType::UNIFORM_BUFFER:
 		out = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
 		break;

+ 21 - 3
src/anki/gr/vulkan/DescriptorSet.cpp

@@ -284,13 +284,31 @@ void DSThreadAllocator::writeSet(const Array<AnyBinding, MAX_BINDINGS_PER_DESCRI
 
 			switch(b.m_type)
 			{
+			case DescriptorType::COMBINED_TEXTURE_SAMPLER:
+				tex[texCount].sampler = b.m_texAndSampler.m_sampler->getHandle();
+				tex[texCount].imageView = b.m_texAndSampler.m_texView->m_handle;
+				tex[texCount].imageLayout = b.m_texAndSampler.m_layout;
+
+				w.pImageInfo = &tex[texCount];
+
+				++texCount;
+				break;
 			case DescriptorType::TEXTURE:
-				tex[texCount].sampler = b.m_tex.m_sampler->getHandle();
+				tex[texCount].sampler = VK_NULL_HANDLE;
 				tex[texCount].imageView = b.m_tex.m_texView->m_handle;
 				tex[texCount].imageLayout = b.m_tex.m_layout;
 
 				w.pImageInfo = &tex[texCount];
 
+				++texCount;
+				break;
+			case DescriptorType::SAMPLER:
+				tex[texCount].sampler = b.m_sampler.m_sampler->getHandle();
+				tex[texCount].imageView = VK_NULL_HANDLE;
+				tex[texCount].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+
+				w.pImageInfo = &tex[texCount];
+
 				++texCount;
 				break;
 			case DescriptorType::UNIFORM_BUFFER:
@@ -492,9 +510,9 @@ void DescriptorSetState::flush(
 
 			switch(entry.m_bindingType[i])
 			{
-			case DescriptorType::TEXTURE:
+			case DescriptorType::COMBINED_TEXTURE_SAMPLER:
 				toHash[toHashCount++] = m_bindings[i].m_uuids[1];
-				toHash[toHashCount++] = U64(m_bindings[i].m_tex.m_layout);
+				toHash[toHashCount++] = U64(m_bindings[i].m_texAndSampler.m_layout);
 				break;
 			case DescriptorType::UNIFORM_BUFFER:
 			case DescriptorType::STORAGE_BUFFER:

+ 46 - 4
src/anki/gr/vulkan/DescriptorSet.h

@@ -72,7 +72,7 @@ private:
 	DSLayoutCacheEntry* m_entry = nullptr;
 };
 
-class TextureBinding
+class TextureSamplerBinding
 {
 public:
 	const TextureViewImpl* m_texView;
@@ -80,6 +80,19 @@ public:
 	VkImageLayout m_layout;
 };
 
+class TextureBinding
+{
+public:
+	const TextureViewImpl* m_texView;
+	VkImageLayout m_layout;
+};
+
+class SamplerBinding
+{
+public:
+	const MicroSampler* m_sampler;
+};
+
 class BufferBinding
 {
 public:
@@ -102,7 +115,9 @@ public:
 
 	union
 	{
+		TextureSamplerBinding m_texAndSampler;
 		TextureBinding m_tex;
+		SamplerBinding m_sampler;
 		BufferBinding m_buff;
 		ImageBinding m_image;
 	};
@@ -135,17 +150,44 @@ public:
 
 		AnyBinding& b = m_bindings[binding];
 		b = {};
-		b.m_type = DescriptorType::TEXTURE;
+		b.m_type = DescriptorType::COMBINED_TEXTURE_SAMPLER;
 		b.m_uuids[0] = viewImpl.m_hash;
-		b.m_uuids[1] = sampler->getUuid();
+		b.m_uuids[1] = ptrToNumber(static_cast<const SamplerImpl*>(sampler)->m_sampler->getHandle());
+
+		b.m_texAndSampler.m_texView = &viewImpl;
+		b.m_texAndSampler.m_sampler = static_cast<const SamplerImpl*>(sampler)->m_sampler.get();
+		b.m_texAndSampler.m_layout = layout;
+
+		m_anyBindingDirty = true;
+	}
+
+	void bindTexture(U binding, const TextureView* texView, VkImageLayout layout)
+	{
+		const TextureViewImpl& viewImpl = static_cast<const TextureViewImpl&>(*texView);
+		ANKI_ASSERT(viewImpl.m_tex->isSubresourceGoodForSampling(viewImpl.getSubresource()));
+
+		AnyBinding& b = m_bindings[binding];
+		b = {};
+		b.m_type = DescriptorType::TEXTURE;
+		b.m_uuids[0] = b.m_uuids[1] = viewImpl.m_hash;
 
 		b.m_tex.m_texView = &viewImpl;
-		b.m_tex.m_sampler = static_cast<const SamplerImpl*>(sampler)->m_sampler.get();
 		b.m_tex.m_layout = layout;
 
 		m_anyBindingDirty = true;
 	}
 
+	void bindSampler(U binding, const Sampler* sampler)
+	{
+		AnyBinding& b = m_bindings[binding];
+		b = {};
+		b.m_type = DescriptorType::SAMPLER;
+		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();
+
+		m_anyBindingDirty = true;
+	}
+
 	void bindUniformBuffer(U binding, const Buffer* buff, PtrSize offset, PtrSize range)
 	{
 		AnyBinding& b = m_bindings[binding];

+ 3 - 1
src/anki/gr/vulkan/ShaderImpl.cpp

@@ -156,7 +156,9 @@ void ShaderImpl::doReflection(ConstWeakArray<U8> spirv, SpecConstsVector& specCo
 	};
 
 	func(rsrc.uniform_buffers, DescriptorType::UNIFORM_BUFFER);
-	func(rsrc.sampled_images, DescriptorType::TEXTURE);
+	func(rsrc.sampled_images, DescriptorType::COMBINED_TEXTURE_SAMPLER);
+	func(rsrc.separate_images, DescriptorType::TEXTURE);
+	func(rsrc.separate_samplers, DescriptorType::SAMPLER);
 	func(rsrc.storage_buffers, DescriptorType::STORAGE_BUFFER);
 	func(rsrc.storage_images, DescriptorType::IMAGE);
 

+ 4 - 4
src/anki/resource/MaterialResource.cpp

@@ -479,10 +479,10 @@ Error MaterialResource::parseInputs(XmlElement inputsEl, Bool async)
 				case ShaderVariableDataType::MAT4:
 					ANKI_CHECK(inputEl.getAttributeMatrix("value", mtlVar.m_mat4));
 					break;
-				case ShaderVariableDataType::SAMPLER_2D:
-				case ShaderVariableDataType::SAMPLER_2D_ARRAY:
-				case ShaderVariableDataType::SAMPLER_3D:
-				case ShaderVariableDataType::SAMPLER_CUBE:
+				case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_2D:
+				case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_2D_ARRAY:
+				case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_3D:
+				case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_CUBE:
 				{
 					CString texfname;
 					ANKI_CHECK(inputEl.getAttributeText("value", texfname));

+ 2 - 2
src/anki/resource/MaterialResource.h

@@ -126,8 +126,8 @@ template<>
 inline const TextureResourcePtr& MaterialVariable::getValue() const
 {
 	ANKI_ASSERT(m_input);
-	ANKI_ASSERT(m_input->getShaderVariableDataType() >= ShaderVariableDataType::SAMPLERS_FIRST
-				&& m_input->getShaderVariableDataType() <= ShaderVariableDataType::SAMPLERS_LAST);
+	ANKI_ASSERT(m_input->getShaderVariableDataType() >= ShaderVariableDataType::COMBINED_TEXTURE_SAMPLERS_FIRST
+				&& m_input->getShaderVariableDataType() <= ShaderVariableDataType::COMBINED_TEXTURE_SAMPLERS_LAST);
 	ANKI_ASSERT(m_builtin == BuiltinMaterialVariableId::NONE);
 	return m_tex;
 }

+ 5 - 5
src/anki/resource/ShaderProgramPreProcessor.cpp

@@ -79,15 +79,15 @@ static ANKI_USE_RESULT Error computeShaderVariableDataType(const CString& str, S
 	}
 	else if(str == "sampler2D")
 	{
-		out = ShaderVariableDataType::SAMPLER_2D;
+		out = ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_2D;
 	}
 	else if(str == "sampler2DArray")
 	{
-		out = ShaderVariableDataType::SAMPLER_2D_ARRAY;
+		out = ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_2D_ARRAY;
 	}
 	else if(str == "samplerCube")
 	{
-		out = ShaderVariableDataType::SAMPLER_CUBE;
+		out = ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_CUBE;
 	}
 	else
 	{
@@ -593,8 +593,8 @@ Error ShaderProgramPreprocessor::parsePragmaInput(
 
 	// Append to source
 
-	const Bool isSampler = input.m_dataType >= ShaderVariableDataType::SAMPLERS_FIRST
-						   && input.m_dataType <= ShaderVariableDataType::SAMPLERS_LAST;
+	const Bool isSampler = input.m_dataType >= ShaderVariableDataType::COMBINED_TEXTURE_SAMPLERS_FIRST
+						   && input.m_dataType <= ShaderVariableDataType::COMBINED_TEXTURE_SAMPLERS_LAST;
 
 	if(input.m_const)
 	{

+ 2 - 2
src/anki/resource/ShaderProgramResource.h

@@ -114,8 +114,8 @@ private:
 
 	Bool isTexture() const
 	{
-		return m_dataType >= ShaderVariableDataType::SAMPLERS_FIRST
-			   && m_dataType <= ShaderVariableDataType::SAMPLERS_LAST;
+		return m_dataType >= ShaderVariableDataType::COMBINED_TEXTURE_SAMPLERS_FIRST
+			   && m_dataType <= ShaderVariableDataType::COMBINED_TEXTURE_SAMPLERS_LAST;
 	}
 
 	Bool inBlock() const

+ 4 - 4
src/anki/scene/components/RenderComponent.cpp

@@ -258,10 +258,10 @@ void MaterialRenderComponent::allocateAndSetupUniforms(U set,
 
 			break;
 		}
-		case ShaderVariableDataType::SAMPLER_2D:
-		case ShaderVariableDataType::SAMPLER_2D_ARRAY:
-		case ShaderVariableDataType::SAMPLER_3D:
-		case ShaderVariableDataType::SAMPLER_CUBE:
+		case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_2D:
+		case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_2D_ARRAY:
+		case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_3D:
+		case ShaderVariableDataType::COMBINED_TEXTURE_SAMPLER_CUBE:
 		{
 			ctx.m_commandBuffer->bindTextureAndSampler(set,
 				progVariant.getTextureUnit(progvar),