Browse Source

Make vertex bindings just semantics

Panagiotis Christopoulos Charitos 1 year ago
parent
commit
4c010d251b
54 changed files with 558 additions and 453 deletions
  1. 0 1
      AnKi/Gr.h
  2. 5 5
      AnKi/Gr/CMakeLists.txt
  3. 1 1
      AnKi/Gr/CommandBuffer.h
  4. 35 2
      AnKi/Gr/Common.cpp
  5. 73 3
      AnKi/Gr/Common.h
  6. 0 0
      AnKi/Gr/Common/Format.def.h
  7. 67 3
      AnKi/Gr/Common/Functions.cpp
  8. 4 1
      AnKi/Gr/Common/Functions.h
  9. 0 0
      AnKi/Gr/Common/InstantiationMacros.def.h
  10. 1 1
      AnKi/Gr/D3D/D3DCommandBuffer.cpp
  11. 3 9
      AnKi/Gr/RenderGraph.cpp
  12. 3 1
      AnKi/Gr/Shader.h
  13. 0 0
      AnKi/Gr/ShaderVariableDataType.def.h
  14. 2 2
      AnKi/Gr/Vulkan/VkCommandBuffer.cpp
  15. 3 19
      AnKi/Gr/Vulkan/VkCommon.h
  16. 8 8
      AnKi/Gr/Vulkan/VkDescriptorSet.cpp
  17. 5 6
      AnKi/Gr/Vulkan/VkDescriptorSet.h
  18. 14 14
      AnKi/Gr/Vulkan/VkPipeline.cpp
  19. 25 18
      AnKi/Gr/Vulkan/VkPipeline.h
  20. 2 219
      AnKi/Gr/Vulkan/VkShader.cpp
  21. 1 19
      AnKi/Gr/Vulkan/VkShader.h
  22. 30 50
      AnKi/Gr/Vulkan/VkShaderProgram.cpp
  23. 2 12
      AnKi/Gr/Vulkan/VkShaderProgram.h
  24. 1 1
      AnKi/Gr/Vulkan/VkSwapchainFactory.cpp
  25. 1 1
      AnKi/Gr/Vulkan/VkTexture.h
  26. 1 1
      AnKi/Renderer/Dbg.cpp
  27. 1 1
      AnKi/Renderer/IndirectDiffuseProbes.cpp
  28. 1 1
      AnKi/Renderer/RtShadows.cpp
  29. 2 2
      AnKi/Renderer/Utils/Drawer.cpp
  30. 2 2
      AnKi/Renderer/Utils/GpuVisibility.cpp
  31. 3 3
      AnKi/Resource/MaterialResource.cpp
  32. 2 2
      AnKi/Resource/MaterialResource.h
  33. 2 2
      AnKi/Resource/MeshBinary.h
  34. 2 2
      AnKi/Resource/MeshBinary.xml
  35. 4 1
      AnKi/Resource/ShaderProgramResource.cpp
  36. 1 1
      AnKi/Resource/ShaderProgramResource.h
  37. 3 1
      AnKi/ShaderCompiler/ShaderProgramBinary.h
  38. 3 2
      AnKi/ShaderCompiler/ShaderProgramBinary.xml
  39. 10 18
      AnKi/ShaderCompiler/ShaderProgramBinaryExtra.h
  40. 217 0
      AnKi/ShaderCompiler/ShaderProgramCompiler.cpp
  41. 2 2
      AnKi/ShaderCompiler/ShaderProgramCompiler.h
  42. 1 1
      AnKi/Shaders/ForwardShadingFog.ankiprog
  43. 1 1
      AnKi/Shaders/ForwardShadingGenericTransparent.ankiprog
  44. 1 1
      AnKi/Shaders/ForwardShadingParticles.ankiprog
  45. 1 1
      AnKi/Shaders/GBufferGeneric.ankiprog
  46. 1 1
      AnKi/Shaders/GBufferGpuParticles.ankiprog
  47. 1 1
      AnKi/Shaders/Include/MaterialTypes.h
  48. 0 0
      AnKi/Shaders/Include/UnifiedGeometryTypes.def.h
  49. 1 1
      AnKi/Shaders/MaterialShadersCommon.hlsl
  50. 3 3
      AnKi/Ui/Canvas.cpp
  51. 1 1
      AnKi/Window/InputSdl.cpp
  52. 0 0
      AnKi/Window/KeyCode.def.h
  53. 1 1
      AnKi/Window/KeyCode.h
  54. 4 4
      Tests/Gr/Gr.cpp

+ 0 - 1
AnKi/Gr.h

@@ -23,7 +23,6 @@
 #include <AnKi/Gr/GrUpscaler.h>
 
 #include <AnKi/Gr/Utils/StackGpuMemoryPool.h>
-#include <AnKi/Gr/Utils/Functions.h>
 
 /// @defgroup graphics Graphics API abstraction
 

+ 5 - 5
AnKi/Gr/CMakeLists.txt

@@ -6,7 +6,7 @@ set(backend_sources
 	RenderGraph.cpp
 	ShaderProgram.cpp
 	Utils/StackGpuMemoryPool.cpp
-	Utils/Functions.cpp
+	Common/Functions.cpp
 	Utils/SegregatedListsGpuMemoryPool.cpp)
 
 set(backend_headers
@@ -15,7 +15,6 @@ set(backend_headers
 	CommandBuffer.h
 	Common.h
 	Fence.h
-	Format.defs.h
 	Framebuffer.h
 	GrManager.h
 	GrObject.h
@@ -25,15 +24,16 @@ set(backend_headers
 	Sampler.h
 	Shader.h
 	ShaderProgram.h
-	ShaderVariableDataType.defs.h
+	ShaderVariableDataType.def.h
 	Texture.h
 	TextureView.h
 	TimestampQuery.h
 	PipelineQuery.h
 	GrUpscaler.h
 	Utils/StackGpuMemoryPool.h
-	Utils/Functions.h
-	Utils/InstantiationMacros.h
+	Common/Functions.h
+	Common/InstantiationMacros.def.h
+	Common/Format.def.h
 	Utils/SegregatedListsGpuMemoryPool.h)
 
 if(VULKAN)

+ 1 - 1
AnKi/Gr/CommandBuffer.h

@@ -102,7 +102,7 @@ public:
 	void bindVertexBuffer(U32 binding, Buffer* buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate = VertexStepRate::kVertex);
 
 	/// Setup a vertex attribute.
-	void setVertexAttribute(U32 location, U32 buffBinding, Format fmt, PtrSize relativeOffset);
+	void setVertexAttribute(VertexAttribute attribute, U32 buffBinding, Format fmt, PtrSize relativeOffset);
 
 	/// Bind index buffer.
 	void bindIndexBuffer(Buffer* buff, PtrSize offset, IndexType type);

+ 35 - 2
AnKi/Gr/Common.cpp

@@ -13,7 +13,7 @@ namespace anki {
 inline constexpr ShaderVariableDataTypeInfo kShaderVariableDataTypeInfos[] = {
 #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) {ANKI_STRINGIZE(type), sizeof(type), false, isIntagralType},
 #define ANKI_SVDT_MACRO_OPAQUE(constant, type) {ANKI_STRINGIZE(type), kMaxU32, true, false},
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 #undef ANKI_SVDT_MACRO_OPAQUE
 };
@@ -39,7 +39,7 @@ FormatInfo getFormatInfo(Format fmt)
 		out = {componentCount,      texelSize, blockWidth, blockHeight, blockSize, shaderType, DepthStencilAspectBit::k##depthStencil, \
 			   ANKI_STRINGIZE(type)}; \
 		break;
-#include <AnKi/Gr/Format.defs.h>
+#include <AnKi/Gr/Common/Format.def.h>
 #undef ANKI_FORMAT_DEF
 
 	default:
@@ -123,4 +123,37 @@ U32 computeMaxMipmapCount3d(U32 w, U32 h, U32 d, U32 minSizeOfLastMip)
 	return count;
 }
 
+#if ANKI_ASSERTIONS_ENABLED
+void ShaderReflection::validate() const
+{
+	for(U32 set = 0; set < kMaxDescriptorSets; ++set)
+	{
+		const Bool setExists = m_descriptorSetMask.get(set);
+		for(U32 binding = 0; binding < kMaxBindingsPerDescriptorSet; ++binding)
+		{
+			const U32 arraySize = m_descriptorArraySizes[set][binding];
+			const DescriptorType type = m_descriptorTypes[set][binding];
+
+			if(!setExists)
+			{
+				ANKI_ASSERT(arraySize == 0 && type == DescriptorType::kCount);
+			}
+			else if(arraySize != 0)
+			{
+				ANKI_ASSERT(type != DescriptorType::kCount);
+			}
+			else if(type != DescriptorType::kCount)
+			{
+				ANKI_ASSERT(arraySize > 0);
+			}
+		}
+	}
+
+	for(VertexAttribute semantic : EnumIterable<VertexAttribute>())
+	{
+		ANKI_ASSERT(!m_vertexAttributeMask.get(semantic) || m_vertexAttributeLocations[semantic] != kMaxU8);
+	}
+}
+#endif
+
 } // end namespace anki

+ 73 - 3
AnKi/Gr/Common.h

@@ -57,7 +57,6 @@ private:
 ANKI_DEFINE_SUBMODULE_UTIL_CONTAINERS(Gr, GrMemoryPool)
 
 // Some constants
-constexpr U32 kMaxVertexAttributes = 8;
 constexpr U32 kMaxColorRenderTargets = 4;
 constexpr U32 kMaxDescriptorSets = 3; ///< Groups that can be bound at the same time.
 constexpr U32 kMaxBindingsPerDescriptorSet = 32;
@@ -405,7 +404,7 @@ enum class Format : U32
 	kNone = 0,
 
 #define ANKI_FORMAT_DEF(type, id, componentCount, texelSize, blockWidth, blockHeight, blockSize, shaderType, depthStencil) k##type = id,
-#include <AnKi/Gr/Format.defs.h>
+#include <AnKi/Gr/Common/Format.def.h>
 #undef ANKI_FORMAT_DEF
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Format)
@@ -597,7 +596,7 @@ enum class ShaderVariableDataType : U8
 
 #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) k##type,
 #define ANKI_SVDT_MACRO_OPAQUE(constant, type) k##constant,
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 #undef ANKI_SVDT_MACRO_OPAQUE
 
@@ -844,6 +843,77 @@ enum class GpuQueueType : U8
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(GpuQueueType)
 
+enum class VertexAttribute : U8
+{
+	kPosition,
+	kNormal,
+	kTexCoord,
+	kColor,
+	kMisc0,
+	kMisc1,
+	kMisc2,
+	kMisc3,
+
+	kCount,
+	kFirst = 0
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VertexAttribute)
+
+enum class DescriptorType : U8
+{
+	kTexture,
+	kSampler,
+	kUniformBuffer,
+	kStorageBuffer,
+	kStorageImage,
+	kReadTexelBuffer,
+	kReadWriteTexelBuffer,
+	kAccelerationStructure,
+
+	kCount,
+	kFirst = 0
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(DescriptorType)
+
+class ShaderReflection
+{
+public:
+	Array2d<U16, kMaxDescriptorSets, kMaxBindingsPerDescriptorSet> m_descriptorArraySizes;
+	Array2d<DescriptorType, kMaxDescriptorSets, kMaxBindingsPerDescriptorSet> m_descriptorTypes;
+	BitSet<kMaxDescriptorSets, U8> m_descriptorSetMask = {false};
+
+	Array<U8, U32(VertexAttribute::kCount)> m_vertexAttributeLocations; ///< Only for Vulkan.
+	BitSet<U32(VertexAttribute::kCount), U8> m_vertexAttributeMask = {false};
+
+	BitSet<kMaxColorRenderTargets, U8> m_colorAttachmentWritemask = {false};
+
+	U8 m_pushConstantsSize = 0;
+	Bool m_discards = false;
+
+	ShaderReflection()
+	{
+		for(auto& it : m_descriptorArraySizes)
+		{
+			it.fill(0);
+		}
+
+		for(auto& it : m_descriptorTypes)
+		{
+			it.fill(DescriptorType::kCount);
+		}
+
+		m_vertexAttributeLocations.fill(kMaxU8);
+	}
+
+#if ANKI_ASSERTIONS_ENABLED
+	void validate() const;
+#else
+	void validate() const
+	{
+	}
+#endif
+};
+
 /// Clear values for textures or attachments.
 class ClearValue
 {

+ 0 - 0
AnKi/Gr/Format.defs.h → AnKi/Gr/Common/Format.def.h


+ 67 - 3
AnKi/Gr/Utils/Functions.cpp → AnKi/Gr/Common/Functions.cpp

@@ -3,7 +3,7 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#include <AnKi/Gr/Utils/Functions.h>
+#include <AnKi/Gr/Common/Functions.h>
 
 namespace anki {
 
@@ -94,7 +94,7 @@ public:
 	public: \
 		static constexpr Bool kValue = rowCount * columnCount > 4; \
 	};
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 
 template<typename T, Bool isMatrix = IsShaderVarDataTypeAMatrix<T>::kValue>
@@ -129,7 +129,7 @@ void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlo
 	case ShaderVariableDataType::k##type: \
 		WriteShaderBlockMemory<type>()(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); \
 		break;
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 
 	default:
@@ -137,4 +137,68 @@ void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlo
 	}
 }
 
+Error linkShaderReflection(const ShaderReflection& a, const ShaderReflection& b, ShaderReflection& c_)
+{
+	ShaderReflection c;
+	c.m_descriptorSetMask = a.m_descriptorSetMask | b.m_descriptorSetMask;
+
+	for(U32 set = 0; set < kMaxDescriptorSets; ++set)
+	{
+		if(!c.m_descriptorSetMask.get(set))
+		{
+			continue;
+		}
+
+		for(U32 binding = 0; binding < kMaxBindingsPerDescriptorSet; ++binding)
+		{
+			const Bool bindingExists = a.m_descriptorArraySizes[set][binding] > 0 || b.m_descriptorArraySizes[set][binding] > 0;
+			if(!bindingExists)
+			{
+				continue;
+			}
+
+			const Bool sizeCorrect = a.m_descriptorArraySizes[set][binding] == 0 || b.m_descriptorArraySizes[set][binding] == 0
+									 || a.m_descriptorArraySizes[set][binding] == b.m_descriptorArraySizes[set][binding];
+
+			if(!sizeCorrect)
+			{
+				ANKI_GR_LOGE("Can't link shader reflection because of different array size. Set %u binding %u", set, binding);
+				return Error::kFunctionFailed;
+			}
+
+			const Bool typeCorrect = a.m_descriptorTypes[set][binding] == DescriptorType::kCount
+									 || b.m_descriptorTypes[set][binding] == DescriptorType::kCount
+									 || a.m_descriptorTypes[set][binding] == b.m_descriptorTypes[set][binding];
+
+			if(!typeCorrect)
+			{
+				ANKI_GR_LOGE("Can't link shader reflection because of different array size. Set %u binding %u", set, binding);
+				return Error::kFunctionFailed;
+			}
+
+			c.m_descriptorArraySizes[set][binding] = max(a.m_descriptorArraySizes[set][binding], b.m_descriptorArraySizes[set][binding]);
+			c.m_descriptorTypes[set][binding] = min(a.m_descriptorTypes[set][binding], b.m_descriptorTypes[set][binding]);
+		}
+	}
+
+	c.m_vertexAttributeLocations = (a.m_vertexAttributeMask.getAnySet()) ? a.m_vertexAttributeLocations : b.m_vertexAttributeLocations;
+	c.m_vertexAttributeMask = a.m_vertexAttributeMask | b.m_vertexAttributeMask;
+
+	c.m_colorAttachmentWritemask = a.m_colorAttachmentWritemask | b.m_colorAttachmentWritemask;
+
+	const Bool pushConstantsCorrect = a.m_pushConstantsSize == 0 || b.m_pushConstantsSize == 0 || a.m_pushConstantsSize == b.m_pushConstantsSize;
+	if(!pushConstantsCorrect)
+	{
+		ANKI_GR_LOGE("Can't link shader reflection because of different push constants size");
+		return Error::kFunctionFailed;
+	}
+
+	c.m_pushConstantsSize = max(a.m_pushConstantsSize, b.m_pushConstantsSize);
+
+	c.m_discards = a.m_discards || b.m_discards;
+
+	c_ = c;
+	return Error::kNone;
+}
+
 } // end namespace anki

+ 4 - 1
AnKi/Gr/Utils/Functions.h → AnKi/Gr/Common/Functions.h

@@ -37,11 +37,14 @@ ShaderVariableDataType getShaderVariableTypeFromTypename();
 		return ShaderVariableDataType::k##type; \
 	}
 
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 
 /// Populate the memory of a variable that is inside a shader block.
 void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount,
 							void* buffBegin, const void* buffEnd);
 
+/// Combine shader reflection.
+Error linkShaderReflection(const ShaderReflection& a, const ShaderReflection& b, ShaderReflection& c);
+
 } // end namespace anki

+ 0 - 0
AnKi/Gr/Utils/InstantiationMacros.h → AnKi/Gr/Common/InstantiationMacros.def.h


+ 1 - 1
AnKi/Gr/D3D/D3DCommandBuffer.cpp

@@ -31,7 +31,7 @@ void CommandBuffer::bindVertexBuffer(U32 binding, Buffer* buff, PtrSize offset,
 	ANKI_ASSERT(!"TODO");
 }
 
-void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, Format fmt, PtrSize relativeOffset)
+void CommandBuffer::setVertexAttribute(VertexAttribute attribute, U32 buffBinding, Format fmt, PtrSize relativeOffset)
 {
 	ANKI_ASSERT(!"TODO");
 }

+ 3 - 9
AnKi/Gr/RenderGraph.cpp

@@ -1377,20 +1377,14 @@ void RenderGraph::recordAndSubmitCommandBuffers(FencePtr* optionalFence)
 					{
 						const Pass& pass = m_ctx->m_passes[passIdx];
 
-						Vec3 passColor;
+						const Vec3 passColor = (pass.m_framebuffer) ? Vec3(0.0f, 1.0f, 0.0f) : Vec3(1.0f, 1.0f, 0.0f);
+						cmdb->pushDebugMarker(pass.m_name, passColor);
+
 						if(pass.m_framebuffer)
 						{
 							cmdb->beginRenderPass(pass.m_framebuffer.get(), pass.m_colorUsages, pass.m_dsUsage, pass.m_fbRenderArea[0],
 												  pass.m_fbRenderArea[1], pass.m_fbRenderArea[2], pass.m_fbRenderArea[3]);
-
-							passColor = Vec3(0.0f, 1.0f, 0.0f);
 						}
-						else
-						{
-							passColor = Vec3(1.0f, 1.0f, 0.0f);
-						}
-
-						cmdb->pushDebugMarker(pass.m_name, passColor);
 
 						{
 							ANKI_TRACE_SCOPED_EVENT(GrRenderGraphCallback);

+ 3 - 1
AnKi/Gr/Shader.h

@@ -61,7 +61,9 @@ class ShaderInitInfo : public GrBaseInitInfo
 {
 public:
 	ShaderType m_shaderType = ShaderType::kCount;
-	ConstWeakArray<U8> m_binary = {};
+	ConstWeakArray<U8> m_binary;
+
+	ShaderReflection m_reflection;
 
 	/// @note It's OK to have entries in that array with consts that do not appear in the shader.
 	ConstWeakArray<ShaderSpecializationConstValue> m_constValues;

+ 0 - 0
AnKi/Gr/ShaderVariableDataType.defs.h → AnKi/Gr/ShaderVariableDataType.def.h


+ 2 - 2
AnKi/Gr/Vulkan/VkCommandBuffer.cpp

@@ -48,11 +48,11 @@ void CommandBuffer::bindVertexBuffer(U32 binding, Buffer* buff, PtrSize offset,
 	vkCmdBindVertexBuffers(self.m_handle, binding, 1, &vkbuff, &offset);
 }
 
-void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, Format fmt, PtrSize relativeOffset)
+void CommandBuffer::setVertexAttribute(VertexAttribute attribute, U32 buffBinding, Format fmt, PtrSize relativeOffset)
 {
 	ANKI_VK_SELF(CommandBufferImpl);
 	self.commandCommon();
-	self.m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset);
+	self.m_state.setVertexAttribute(attribute, buffBinding, fmt, relativeOffset);
 }
 
 void CommandBuffer::bindIndexBuffer(Buffer* buff, PtrSize offset, IndexType type)

+ 3 - 19
AnKi/Gr/Vulkan/VkCommon.h

@@ -48,22 +48,6 @@ class GrManagerImpl;
 ANKI_PURE GrManagerImpl& getGrManagerImpl();
 ANKI_PURE VkDevice getVkDevice();
 
-enum class DescriptorType : U8
-{
-	kTexture,
-	kSampler,
-	kUniformBuffer,
-	kStorageBuffer,
-	kImage,
-	kReadTextureBuffer,
-	kReadWriteTextureBuffer,
-	kAccelerationStructure,
-
-	kCount,
-	kFirst = 0
-};
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(DescriptorType)
-
 enum class VulkanExtensions : U64
 {
 	kNone = 0,
@@ -271,16 +255,16 @@ static_assert(!(BufferUsageBit::kAll & PrivateBufferUsageBit::kAllPrivate), "Upd
 	case DescriptorType::kUniformBuffer:
 		out = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
 		break;
-	case DescriptorType::kReadTextureBuffer:
+	case DescriptorType::kReadTexelBuffer:
 		out = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
 		break;
-	case DescriptorType::kReadWriteTextureBuffer:
+	case DescriptorType::kReadWriteTexelBuffer:
 		out = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
 		break;
 	case DescriptorType::kStorageBuffer:
 		out = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
 		break;
-	case DescriptorType::kImage:
+	case DescriptorType::kStorageImage:
 		out = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
 		break;
 	case DescriptorType::kAccelerationStructure:

+ 8 - 8
AnKi/Gr/Vulkan/VkDescriptorSet.cpp

@@ -26,9 +26,9 @@ public:
 		m_descriptorCount[DescriptorType::kSampler] = 8;
 		m_descriptorCount[DescriptorType::kUniformBuffer] = 8;
 		m_descriptorCount[DescriptorType::kStorageBuffer] = 64;
-		m_descriptorCount[DescriptorType::kImage] = 8;
-		m_descriptorCount[DescriptorType::kReadTextureBuffer] = 32;
-		m_descriptorCount[DescriptorType::kReadWriteTextureBuffer] = 8;
+		m_descriptorCount[DescriptorType::kStorageImage] = 8;
+		m_descriptorCount[DescriptorType::kReadTexelBuffer] = 32;
+		m_descriptorCount[DescriptorType::kReadWriteTexelBuffer] = 8;
 		m_descriptorCount[DescriptorType::kAccelerationStructure] = 8;
 		static_assert(decltype(m_descriptorCount)::getSize() == 8);
 
@@ -489,7 +489,7 @@ Bool DSStateTracker::flush(DSAllocator& allocator, VkDescriptorSet& dsHandle)
 				{
 				case DescriptorType::kTexture:
 				case DescriptorType::kSampler:
-				case DescriptorType::kImage:
+				case DescriptorType::kStorageImage:
 				{
 					writeInfo.pImageInfo = &b.m_image;
 					break;
@@ -500,8 +500,8 @@ Bool DSStateTracker::flush(DSAllocator& allocator, VkDescriptorSet& dsHandle)
 					writeInfo.pBufferInfo = &b.m_buffer;
 					break;
 				}
-				case DescriptorType::kReadTextureBuffer:
-				case DescriptorType::kReadWriteTextureBuffer:
+				case DescriptorType::kReadTexelBuffer:
+				case DescriptorType::kReadWriteTexelBuffer:
 				{
 					writeInfo.pTexelBufferView = &b.m_bufferView;
 					break;
@@ -589,7 +589,7 @@ Error DSLayoutFactory::getOrCreateDescriptorSetLayout(const WeakArray<DSBinding>
 			{
 				// All good
 			}
-			else if(binding.m_binding == 1 && binding.m_type == DescriptorType::kReadTextureBuffer
+			else if(binding.m_binding == 1 && binding.m_type == DescriptorType::kReadTexelBuffer
 					&& binding.m_arraySize == DSBindless::getSingleton().getMaxTexelBufferCount())
 			{
 				// All good
@@ -642,7 +642,7 @@ Error DSLayoutFactory::getOrCreateDescriptorSetLayout(const WeakArray<DSBinding>
 				vk.descriptorCount = ak.m_arraySize;
 				vk.descriptorType = convertDescriptorType(ak.m_type);
 				vk.pImmutableSamplers = nullptr;
-				vk.stageFlags = convertShaderTypeBit(ak.m_stageMask);
+				vk.stageFlags = VK_SHADER_STAGE_ALL;
 
 				ANKI_ASSERT(layout->m_activeBindings.get(ak.m_binding) == false);
 				layout->m_activeBindings.set(ak.m_binding);

+ 5 - 6
AnKi/Gr/Vulkan/VkDescriptorSet.h

@@ -221,7 +221,7 @@ public:
 		ANKI_ASSERT(buff && range > 0);
 		Binding b;
 		zeroMemory(b);
-		b.m_type = DescriptorType::kReadTextureBuffer;
+		b.m_type = DescriptorType::kReadTexelBuffer;
 		b.m_bufferView = static_cast<const BufferImpl*>(buff)->getOrCreateBufferView(fmt, offset, range);
 		setBinding(binding, arrayIdx, b);
 	}
@@ -233,7 +233,7 @@ public:
 		ANKI_ASSERT(impl->getTextureImpl().isSubresourceGoodForImageLoadStore(impl->getSubresource()));
 		Binding b;
 		zeroMemory(b);
-		b.m_type = DescriptorType::kImage;
+		b.m_type = DescriptorType::kStorageImage;
 		b.m_image.imageView = impl->getHandle();
 		b.m_image.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
 		setBinding(binding, arrayIdx, b);
@@ -325,15 +325,14 @@ private:
 	void setBinding(U32 bindingIdx, U32 arrayIdx, const Binding& b);
 };
 
-class alignas(8) DSBinding
+class alignas(4) DSBinding
 {
 public:
-	U32 m_arraySize = 0;
-	ShaderTypeBit m_stageMask = ShaderTypeBit::kNone;
+	U16 m_arraySize = 0;
 	DescriptorType m_type = DescriptorType::kCount;
 	U8 m_binding = kMaxU8;
 };
-static_assert(sizeof(DSBinding) == 8, "Should be packed because it will be hashed");
+static_assert(sizeof(DSBinding) == 4, "Should be packed because it will be hashed");
 
 class DSLayoutFactory : public MakeSingleton<DSLayoutFactory>
 {

+ 14 - 14
AnKi/Gr/Vulkan/VkPipeline.cpp

@@ -5,7 +5,7 @@
 
 #include <AnKi/Gr/Vulkan/VkPipeline.h>
 #include <AnKi/Gr/Vulkan/VkGrManager.h>
-#include <AnKi/Gr/Utils/Functions.h>
+#include <AnKi/Gr/Common/Functions.h>
 #include <AnKi/Util/Tracer.h>
 
 namespace anki {
@@ -16,7 +16,7 @@ void PipelineStateTracker::reset()
 	m_hashes = {};
 	m_dirty = {};
 	m_set = {};
-	m_shaderAttributeMask.unsetAll();
+	m_shaderVertexAttributeMask.unsetAll();
 	m_shaderColorAttachmentWritemask.unsetAll();
 	m_fbDepth = false;
 	m_fbStencil = false;
@@ -47,9 +47,9 @@ Bool PipelineStateTracker::updateHashes()
 	// Vertex
 	if(m_dirty.m_attribs.getAnySet() || m_dirty.m_vertBindings.getAnySet())
 	{
-		for(U i = 0; i < kMaxVertexAttributes; ++i)
+		for(VertexAttribute i : EnumIterable<VertexAttribute>())
 		{
-			if(m_shaderAttributeMask.get(i))
+			if(m_shaderVertexAttributeMask.get(i))
 			{
 				ANKI_ASSERT(m_set.m_attribs.get(i) && "Forgot to set the attribute");
 
@@ -155,11 +155,11 @@ void PipelineStateTracker::updateSuperHash()
 	buff[count++] = m_hashes.m_rpass;
 
 	// Vertex
-	if(!!m_shaderAttributeMask)
+	if(!!m_shaderVertexAttributeMask)
 	{
-		for(U i = 0; i < kMaxVertexAttributes; ++i)
+		for(VertexAttribute i : EnumIterable<VertexAttribute>())
 		{
-			if(m_shaderAttributeMask.get(i))
+			if(m_shaderVertexAttributeMask.get(i))
 			{
 				buff[count++] = m_hashes.m_vertexAttribs[i];
 			}
@@ -224,16 +224,16 @@ const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateIn
 	vertCi.pVertexAttributeDescriptions = &m_ci.m_attribs[0];
 	vertCi.pVertexBindingDescriptions = &m_ci.m_vertBindings[0];
 
-	BitSet<kMaxVertexAttributes, U8> bindingSet = {false};
-	for(U32 i = 0; i < kMaxVertexAttributes; ++i)
+	BitSet<U32(VertexAttribute::kCount), U8> bindingSet = {false};
+	for(VertexAttribute semantic : EnumIterable<VertexAttribute>())
 	{
-		if(m_shaderAttributeMask.get(i))
+		if(m_shaderVertexAttributeMask.get(semantic))
 		{
 			VkVertexInputAttributeDescription& attrib = m_ci.m_attribs[vertCi.vertexAttributeDescriptionCount++];
-			attrib.binding = m_state.m_vertex.m_attributes[i].m_binding;
-			attrib.format = convertFormat(m_state.m_vertex.m_attributes[i].m_format);
-			attrib.location = i;
-			attrib.offset = U32(m_state.m_vertex.m_attributes[i].m_offset);
+			attrib.binding = m_state.m_vertex.m_attributes[semantic].m_binding;
+			attrib.format = convertFormat(m_state.m_vertex.m_attributes[semantic].m_format);
+			attrib.location = m_semanticToVertexAttributeLocation[semantic];
+			attrib.offset = U32(m_state.m_vertex.m_attributes[semantic].m_offset);
 
 			if(!bindingSet.get(attrib.binding))
 			{

+ 25 - 18
AnKi/Gr/Vulkan/VkPipeline.h

@@ -58,12 +58,12 @@ static_assert(sizeof(VertexAttributeBindingPipelineState) == 2 * sizeof(PtrSize)
 class VertexPipelineState
 {
 public:
-	Array<VertexBufferBindingPipelineState, kMaxVertexAttributes> m_bindings;
-	Array<VertexAttributeBindingPipelineState, kMaxVertexAttributes> m_attributes;
+	Array<VertexBufferBindingPipelineState, U32(VertexAttribute::kCount)> m_bindings;
+	Array<VertexAttributeBindingPipelineState, U32(VertexAttribute::kCount)> m_attributes;
 };
 static_assert(sizeof(VertexPipelineState)
-				  == sizeof(VertexBufferBindingPipelineState) * kMaxVertexAttributes
-						 + sizeof(VertexAttributeBindingPipelineState) * kMaxVertexAttributes,
+				  == sizeof(VertexBufferBindingPipelineState) * U32(VertexAttribute::kCount)
+						 + sizeof(VertexAttributeBindingPipelineState) * U32(VertexAttribute::kCount),
 			  "Packed because it will be hashed");
 
 class InputAssemblerPipelineState
@@ -176,18 +176,18 @@ public:
 		m_set.m_vertBindings.set(binding);
 	}
 
-	void setVertexAttribute(U32 location, U32 buffBinding, const Format fmt, PtrSize relativeOffset)
+	void setVertexAttribute(VertexAttribute semantic, U32 buffBinding, const Format fmt, PtrSize relativeOffset)
 	{
 		VertexAttributeBindingPipelineState b;
 		b.m_binding = U8(buffBinding);
 		b.m_format = fmt;
 		b.m_offset = relativeOffset;
-		if(m_state.m_vertex.m_attributes[location] != b)
+		if(m_state.m_vertex.m_attributes[semantic] != b)
 		{
-			m_state.m_vertex.m_attributes[location] = b;
-			m_dirty.m_attribs.set(location);
+			m_state.m_vertex.m_attributes[semantic] = b;
+			m_dirty.m_attribs.set(semantic);
 		}
-		m_set.m_attribs.set(location);
+		m_set.m_attribs.set(semantic);
 	}
 
 	void setPrimitiveRestart(Bool enable)
@@ -342,7 +342,13 @@ public:
 		if(prog != m_state.m_prog)
 		{
 			m_shaderColorAttachmentWritemask = prog->getReflectionInfo().m_colorAttachmentWritemask;
-			m_shaderAttributeMask = prog->getReflectionInfo().m_attributeMask;
+
+			if(!!(prog->getShaderTypes() & ShaderTypeBit::kVertex))
+			{
+				m_shaderVertexAttributeMask = prog->getReflectionInfo().m_vertexAttributeMask;
+				m_semanticToVertexAttributeLocation = prog->getReflectionInfo().m_vertexAttributeLocations;
+			}
+
 			m_state.m_prog = prog;
 			m_dirty.m_prog = true;
 		}
@@ -439,8 +445,8 @@ private:
 		Bool m_color : 1 = true;
 
 		// Vertex
-		BitSet<kMaxVertexAttributes, U8> m_attribs = {true};
-		BitSet<kMaxVertexAttributes, U8> m_vertBindings = {true};
+		BitSet<U32(VertexAttribute::kCount), U8> m_attribs = {true};
+		BitSet<U32(VertexAttribute::kCount), U8> m_vertBindings = {true};
 
 		BitSet<kMaxColorRenderTargets, U8> m_colAttachments = {true};
 	} m_dirty;
@@ -448,13 +454,14 @@ private:
 	class SetBits
 	{
 	public:
-		BitSet<kMaxVertexAttributes, U8> m_attribs = {false};
-		BitSet<kMaxVertexAttributes, U8> m_vertBindings = {false};
+		BitSet<U32(VertexAttribute::kCount), U8> m_attribs = {false};
+		BitSet<U32(VertexAttribute::kCount), U8> m_vertBindings = {false};
 	} m_set;
 
 	// Shader info
-	BitSet<kMaxVertexAttributes, U8> m_shaderAttributeMask = {false};
+	BitSet<U32(VertexAttribute::kCount), U8> m_shaderVertexAttributeMask = {false};
 	BitSet<kMaxColorRenderTargets, U8> m_shaderColorAttachmentWritemask = {false};
+	Array<U8, U32(VertexAttribute::kCount)> m_semanticToVertexAttributeLocation;
 
 	// Renderpass info
 	Bool m_fbDepth : 1 = false;
@@ -467,7 +474,7 @@ private:
 	public:
 		U64 m_prog;
 		U64 m_rpass;
-		Array<U64, kMaxVertexAttributes> m_vertexAttribs;
+		Array<U64, U32(VertexAttribute::kCount)> m_vertexAttribs;
 		U64 m_ia;
 		U64 m_raster;
 		U64 m_depth;
@@ -488,8 +495,8 @@ private:
 	class CreateInfo
 	{
 	public:
-		Array<VkVertexInputBindingDescription, kMaxVertexAttributes> m_vertBindings;
-		Array<VkVertexInputAttributeDescription, kMaxVertexAttributes> m_attribs;
+		Array<VkVertexInputBindingDescription, U32(VertexAttribute::kCount)> m_vertBindings;
+		Array<VkVertexInputAttributeDescription, U32(VertexAttribute::kCount)> m_attribs;
 		VkPipelineVertexInputStateCreateInfo m_vert;
 		VkPipelineInputAssemblyStateCreateInfo m_ia;
 		VkPipelineViewportStateCreateInfo m_vp;

+ 2 - 219
AnKi/Gr/Vulkan/VkShader.cpp

@@ -5,7 +5,6 @@
 
 #include <AnKi/Gr/Vulkan/VkShader.h>
 #include <AnKi/Gr/Vulkan/VkGrManager.h>
-#include <SpirvCross/spirv_cross.hpp>
 
 #define ANKI_DUMP_SHADERS 0
 
@@ -28,48 +27,12 @@ Shader* Shader::newInstance(const ShaderInitInfo& init)
 	return impl;
 }
 
-template<typename TFunc>
-static void visitSpirv(ConstWeakArray<U32> spv, TFunc func)
-{
-	ANKI_ASSERT(spv.getSize() > 5);
-
-	const U32* it = &spv[5];
-	do
-	{
-		const U32 instructionCount = *it >> 16u;
-		const U32 opcode = *it & 0xFFFFu;
-
-		func(opcode);
-
-		it += instructionCount;
-	} while(it < spv.getEnd());
-
-	ANKI_ASSERT(it == spv.getEnd());
-}
-
-class ShaderImpl::SpecConstsVector
-{
-public:
-	spirv_cross::SmallVector<spirv_cross::SpecializationConstant> m_vec;
-};
-
 ShaderImpl::~ShaderImpl()
 {
 	if(m_handle)
 	{
 		vkDestroyShaderModule(getVkDevice(), m_handle, nullptr);
 	}
-
-	if(m_specConstInfo.pMapEntries)
-	{
-		deleteArray(GrMemoryPool::getSingleton(), const_cast<VkSpecializationMapEntry*>(m_specConstInfo.pMapEntries), m_specConstInfo.mapEntryCount);
-	}
-
-	if(m_specConstInfo.pData)
-	{
-		deleteArray(GrMemoryPool::getSingleton(), static_cast<I32*>(const_cast<void*>(m_specConstInfo.pData)),
-					m_specConstInfo.dataSize / sizeof(I32));
-	}
 }
 
 Error ShaderImpl::init(const ShaderInitInfo& inf)
@@ -78,6 +41,8 @@ Error ShaderImpl::init(const ShaderInitInfo& inf)
 	ANKI_ASSERT(m_handle == VK_NULL_HANDLE);
 	m_shaderType = inf.m_shaderType;
 	m_shaderBinarySize = U32(inf.m_binary.getSizeInBytes());
+	m_reflection = inf.m_reflection;
+	m_reflection.validate();
 
 #if ANKI_DUMP_SHADERS
 	{
@@ -95,189 +60,7 @@ Error ShaderImpl::init(const ShaderInitInfo& inf)
 
 	ANKI_VK_CHECK(vkCreateShaderModule(getVkDevice(), &ci, nullptr, &m_handle));
 
-	// Get reflection info
-	SpecConstsVector specConstIds;
-	doReflection(inf.m_binary, specConstIds);
-
-	// Set spec info
-	if(specConstIds.m_vec.size())
-	{
-		const U32 constCount = U32(specConstIds.m_vec.size());
-
-		m_specConstInfo.mapEntryCount = constCount;
-		m_specConstInfo.pMapEntries = newArray<VkSpecializationMapEntry>(GrMemoryPool::getSingleton(), constCount);
-		m_specConstInfo.dataSize = constCount * sizeof(U32);
-		m_specConstInfo.pData = newArray<U32>(GrMemoryPool::getSingleton(), constCount);
-
-		U32 count = 0;
-		for(const spirv_cross::SpecializationConstant& sconst : specConstIds.m_vec)
-		{
-			// Set the entry
-			VkSpecializationMapEntry& entry = const_cast<VkSpecializationMapEntry&>(m_specConstInfo.pMapEntries[count]);
-			entry.constantID = sconst.constant_id;
-			entry.offset = count * sizeof(U32);
-			entry.size = sizeof(U32);
-
-			// Find the value
-			const ShaderSpecializationConstValue* val = nullptr;
-			for(const ShaderSpecializationConstValue& v : inf.m_constValues)
-			{
-				if(v.m_constantId == entry.constantID)
-				{
-					val = &v;
-					break;
-				}
-			}
-			ANKI_ASSERT(val && "Contant ID wasn't found in the init info");
-
-			// Copy the data
-			U8* data = static_cast<U8*>(const_cast<void*>(m_specConstInfo.pData));
-			data += entry.offset;
-			*reinterpret_cast<U32*>(data) = val->m_uint;
-
-			++count;
-		}
-	}
-
 	return Error::kNone;
 }
 
-void ShaderImpl::doReflection(ConstWeakArray<U8> spirv, SpecConstsVector& specConstIds)
-{
-	spirv_cross::Compiler spvc(reinterpret_cast<const uint32_t*>(&spirv[0]), spirv.getSize() / sizeof(unsigned int));
-	spirv_cross::ShaderResources rsrc = spvc.get_shader_resources();
-	spirv_cross::ShaderResources rsrcActive = spvc.get_shader_resources(spvc.get_active_interface_variables());
-
-	Array<U32, kMaxDescriptorSets> counts = {};
-	Array2d<DSBinding, kMaxDescriptorSets, kMaxBindingsPerDescriptorSet> descriptors;
-
-	auto func = [&](const spirv_cross::SmallVector<spirv_cross::Resource>& resources, const DescriptorType origType) -> void {
-		for(const spirv_cross::Resource& r : resources)
-		{
-			const U32 id = r.id;
-			const U32 set = spvc.get_decoration(id, spv::Decoration::DecorationDescriptorSet);
-			ANKI_ASSERT(set < kMaxDescriptorSets);
-			const U32 binding = spvc.get_decoration(id, spv::Decoration::DecorationBinding);
-			ANKI_ASSERT(binding < kMaxBindingsPerDescriptorSet);
-
-			const spirv_cross::SPIRType& typeInfo = spvc.get_type(r.type_id);
-			U32 arraySize = 1;
-			if(typeInfo.array.size() != 0)
-			{
-				ANKI_ASSERT(typeInfo.array.size() == 1 && "Only 1D arrays are supported");
-				arraySize = typeInfo.array[0];
-				ANKI_ASSERT(arraySize > 0);
-			}
-
-			m_descriptorSetMask.set(set);
-			m_activeBindingMask[set].set(set);
-
-			// Images are special, they might be texel buffers
-			DescriptorType type = origType;
-			if(type == DescriptorType::kTexture)
-			{
-				if(typeInfo.image.dim == spv::DimBuffer && typeInfo.image.sampled == 1)
-				{
-					type = DescriptorType::kReadTextureBuffer;
-				}
-				else if(typeInfo.image.dim == spv::DimBuffer && typeInfo.image.sampled == 2)
-				{
-					type = DescriptorType::kReadWriteTextureBuffer;
-				}
-			}
-
-			// Check that there are no other descriptors with the same binding
-			U32 foundIdx = kMaxU32;
-			for(U32 i = 0; i < counts[set]; ++i)
-			{
-				if(descriptors[set][i].m_binding == binding)
-				{
-					foundIdx = i;
-					break;
-				}
-			}
-
-			if(foundIdx == kMaxU32)
-			{
-				// New binding, init it
-				DSBinding& descriptor = descriptors[set][counts[set]++];
-				descriptor.m_binding = U8(binding);
-				descriptor.m_type = type;
-				descriptor.m_stageMask = ShaderTypeBit(1 << m_shaderType);
-				descriptor.m_arraySize = arraySize;
-			}
-			else
-			{
-				// Same binding, make sure the type is compatible
-				ANKI_ASSERT(type == descriptors[set][foundIdx].m_type && "Same binding different type");
-				ANKI_ASSERT(arraySize == descriptors[set][foundIdx].m_arraySize && "Same binding different array size");
-			}
-		}
-	};
-
-	func(rsrc.uniform_buffers, DescriptorType::kUniformBuffer);
-	func(rsrc.separate_images, DescriptorType::kTexture); // This also handles texture buffers
-	func(rsrc.separate_samplers, DescriptorType::kSampler);
-	func(rsrc.storage_buffers, DescriptorType::kStorageBuffer);
-	func(rsrc.storage_images, DescriptorType::kImage);
-	func(rsrc.acceleration_structures, DescriptorType::kAccelerationStructure);
-
-	for(U32 set = 0; set < kMaxDescriptorSets; ++set)
-	{
-		if(counts[set])
-		{
-			m_bindings[set].resize(counts[set]);
-			memcpy(&m_bindings[set][0], &descriptors[set][0], counts[set] * sizeof(DSBinding));
-		}
-	}
-
-	// Color attachments
-	if(m_shaderType == ShaderType::kFragment)
-	{
-		for(const spirv_cross::Resource& r : rsrc.stage_outputs)
-		{
-			const U32 id = r.id;
-			const U32 location = spvc.get_decoration(id, spv::Decoration::DecorationLocation);
-
-			m_colorAttachmentWritemask.set(location);
-		}
-	}
-
-	// Attribs
-	if(m_shaderType == ShaderType::kVertex)
-	{
-		for(const spirv_cross::Resource& r : rsrcActive.stage_inputs)
-		{
-			const U32 id = r.id;
-			const U32 location = spvc.get_decoration(id, spv::Decoration::DecorationLocation);
-
-			m_attributeMask.set(location);
-		}
-	}
-
-	// Spec consts
-	specConstIds.m_vec = spvc.get_specialization_constants();
-
-	// Push consts
-	if(rsrc.push_constant_buffers.size() == 1)
-	{
-		const U32 blockSize = U32(spvc.get_declared_struct_size(spvc.get_type(rsrc.push_constant_buffers[0].base_type_id)));
-		ANKI_ASSERT(blockSize > 0);
-		ANKI_ASSERT(blockSize % 16 == 0 && "Should be aligned");
-		ANKI_ASSERT(blockSize <= getGrManagerImpl().getDeviceCapabilities().m_pushConstantsSize);
-		m_pushConstantsSize = blockSize;
-	}
-
-	// Discards?
-	if(m_shaderType == ShaderType::kFragment)
-	{
-		visitSpirv(ConstWeakArray<U32>(reinterpret_cast<const U32*>(&spirv[0]), spirv.getSize() / sizeof(U32)), [this](U32 cmd) {
-			if(cmd == spv::OpKill)
-			{
-				m_hasDiscard = true;
-			}
-		});
-	}
-}
-
 } // end namespace anki

+ 1 - 19
AnKi/Gr/Vulkan/VkShader.h

@@ -19,13 +19,7 @@ class ShaderImpl final : public Shader
 {
 public:
 	VkShaderModule m_handle = VK_NULL_HANDLE;
-
-	Array<GrDynamicArray<DSBinding>, kMaxDescriptorSets> m_bindings;
-	BitSet<kMaxColorRenderTargets, U8> m_colorAttachmentWritemask = {false};
-	BitSet<kMaxVertexAttributes, U8> m_attributeMask = {false};
-	BitSet<kMaxDescriptorSets, U8> m_descriptorSetMask = {false};
-	Array<BitSet<kMaxBindingsPerDescriptorSet, U8>, kMaxDescriptorSets> m_activeBindingMask = {{{false}, {false}, {false}}};
-	U32 m_pushConstantsSize = 0;
+	ShaderReflection m_reflection;
 
 	ShaderImpl(CString name)
 		: Shader(name)
@@ -35,18 +29,6 @@ public:
 	~ShaderImpl();
 
 	Error init(const ShaderInitInfo& init);
-
-	const VkSpecializationInfo* getSpecConstInfo() const
-	{
-		return (m_specConstInfo.mapEntryCount) ? &m_specConstInfo : nullptr;
-	}
-
-private:
-	VkSpecializationInfo m_specConstInfo = {};
-
-	class SpecConstsVector; ///< Wrap this into a class to avoid forward declarations of std::vector and spirv_cross.
-
-	void doReflection(ConstWeakArray<U8> spirv, SpecConstsVector& specConstIds);
 };
 /// @}
 

+ 30 - 50
AnKi/Gr/Vulkan/VkShaderProgram.cpp

@@ -7,6 +7,7 @@
 #include <AnKi/Gr/Vulkan/VkShader.h>
 #include <AnKi/Gr/Vulkan/VkGrManager.h>
 #include <AnKi/Gr/Vulkan/VkPipeline.h>
+#include <AnKi/Gr/Common/Functions.h>
 
 namespace anki {
 
@@ -117,55 +118,44 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 
 	ANKI_ASSERT(m_shaders.getSize() > 0);
 
-	// Merge bindings
+	// Link reflection
+	//
+	Bool firstLink = true;
+	for(ShaderPtr& shader : m_shaders)
+	{
+		m_shaderTypes |= ShaderTypeBit(1 << shader->getShaderType());
+
+		const ShaderImpl& simpl = static_cast<const ShaderImpl&>(*shader);
+		if(firstLink)
+		{
+			m_refl = simpl.m_reflection;
+			firstLink = false;
+		}
+		else
+		{
+			ANKI_CHECK(linkShaderReflection(m_refl, simpl.m_reflection, m_refl));
+		}
+
+		m_refl.validate();
+	}
+
+	// Get bindings
 	//
 	Array2d<DSBinding, kMaxDescriptorSets, kMaxBindingsPerDescriptorSet> bindings;
 	Array<U32, kMaxDescriptorSets> counts = {};
 	U32 descriptorSetCount = 0;
 	for(U32 set = 0; set < kMaxDescriptorSets; ++set)
 	{
-		for(ShaderPtr& shader : m_shaders)
+		for(U8 binding = 0; m_refl.m_descriptorSetMask.get(set) && binding < kMaxBindingsPerDescriptorSet; ++binding)
 		{
-			m_shaderTypes |= ShaderTypeBit(1 << shader->getShaderType());
-
-			const ShaderImpl& simpl = static_cast<const ShaderImpl&>(*shader);
-
-			m_refl.m_activeBindingMask[set] |= simpl.m_activeBindingMask[set];
-
-			for(U32 i = 0; i < simpl.m_bindings[set].getSize(); ++i)
+			if(m_refl.m_descriptorArraySizes[set][binding])
 			{
-				Bool bindingFound = false;
-				for(U32 j = 0; j < counts[set]; ++j)
-				{
-					if(bindings[set][j].m_binding == simpl.m_bindings[set][i].m_binding)
-					{
-						// Found the binding
-
-						ANKI_ASSERT(bindings[set][j].m_type == simpl.m_bindings[set][i].m_type);
-
-						bindings[set][j].m_stageMask |= simpl.m_bindings[set][i].m_stageMask;
+				DSBinding b;
+				b.m_arraySize = m_refl.m_descriptorArraySizes[set][binding];
+				b.m_binding = binding;
+				b.m_type = m_refl.m_descriptorTypes[set][binding];
 
-						bindingFound = true;
-						break;
-					}
-				}
-
-				if(!bindingFound)
-				{
-					// New binding
-
-					bindings[set][counts[set]++] = simpl.m_bindings[set][i];
-				}
-			}
-
-			if(simpl.m_pushConstantsSize > 0)
-			{
-				if(m_refl.m_pushConstantsSize > 0)
-				{
-					ANKI_ASSERT(m_refl.m_pushConstantsSize == simpl.m_pushConstantsSize);
-				}
-
-				m_refl.m_pushConstantsSize = max(m_refl.m_pushConstantsSize, simpl.m_pushConstantsSize);
+				bindings[set][counts[set]++] = b;
 			}
 		}
 
@@ -197,13 +187,6 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 	const Bool graphicsProg = !!(m_shaderTypes & ShaderTypeBit::kAllGraphics);
 	if(graphicsProg)
 	{
-		if(inf.m_graphicsShaders[ShaderType::kVertex])
-		{
-			m_refl.m_attributeMask = static_cast<const ShaderImpl&>(*inf.m_graphicsShaders[ShaderType::kVertex]).m_attributeMask;
-		}
-
-		m_refl.m_colorAttachmentWritemask = static_cast<const ShaderImpl&>(*inf.m_graphicsShaders[ShaderType::kFragment]).m_colorAttachmentWritemask;
-
 		const U32 attachmentCount = m_refl.m_colorAttachmentWritemask.getSetBitCount();
 		for(U32 i = 0; i < attachmentCount; ++i)
 		{
@@ -225,7 +208,6 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 			createInf.stage = VkShaderStageFlagBits(convertShaderTypeBit(ShaderTypeBit(1 << shader->getShaderType())));
 			createInf.pName = "main";
 			createInf.module = shaderImpl.m_handle;
-			createInf.pSpecializationInfo = shaderImpl.getSpecConstInfo();
 		}
 	}
 
@@ -262,7 +244,6 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 		ci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
 		ci.stage.pName = "main";
 		ci.stage.module = shaderImpl.m_handle;
-		ci.stage.pSpecializationInfo = shaderImpl.getSpecConstInfo();
 
 		ANKI_TRACE_SCOPED_EVENT(VkPipelineCreate);
 		ANKI_VK_CHECK(vkCreateComputePipelines(getVkDevice(), getGrManagerImpl().getPipelineCache(), 1, &ci, nullptr, &m_compute.m_ppline));
@@ -286,7 +267,6 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 			stage.stage = VkShaderStageFlagBits(convertShaderTypeBit(ShaderTypeBit(1 << impl.getShaderType())));
 			stage.pName = "main";
 			stage.module = impl.m_handle;
-			stage.pSpecializationInfo = impl.getSpecConstInfo();
 		}
 
 		// Create groups

+ 2 - 12
AnKi/Gr/Vulkan/VkShaderProgram.h

@@ -17,16 +17,6 @@ class PipelineFactory;
 /// @addtogroup vulkan
 /// @{
 
-class ShaderProgramReflectionInfo
-{
-public:
-	BitSet<kMaxColorRenderTargets, U8> m_colorAttachmentWritemask = {false};
-	BitSet<kMaxVertexAttributes, U8> m_attributeMask = {false};
-	BitSet<kMaxDescriptorSets, U8> m_descriptorSetMask = {false};
-	Array<BitSet<kMaxBindingsPerDescriptorSet, U8>, kMaxDescriptorSets> m_activeBindingMask = {{{false}, {false}, {false}}};
-	U32 m_pushConstantsSize = 0;
-};
-
 /// Shader program implementation.
 class ShaderProgramImpl final : public ShaderProgram
 {
@@ -63,7 +53,7 @@ public:
 		return *m_descriptorSetLayouts[set];
 	}
 
-	const ShaderProgramReflectionInfo& getReflectionInfo() const
+	const ShaderReflection& getReflectionInfo() const
 	{
 		return m_refl;
 	}
@@ -116,7 +106,7 @@ private:
 	PipelineLayout m_pplineLayout = {};
 	Array<const DSLayout*, kMaxDescriptorSets> m_descriptorSetLayouts = {};
 
-	ShaderProgramReflectionInfo m_refl;
+	ShaderReflection m_refl;
 
 	class
 	{

+ 1 - 1
AnKi/Gr/Vulkan/VkSwapchainFactory.cpp

@@ -84,7 +84,7 @@ Error MicroSwapchain::initInternal()
 	case id: \
 		akFormat = Format::k##type; \
 		break;
-#include <AnKi/Gr/Format.defs.h>
+#include <AnKi/Gr/Common/Format.def.h>
 #undef ANKI_FORMAT_DEF
 			default:
 				akFormat = Format::kNone;

+ 1 - 1
AnKi/Gr/Vulkan/VkTexture.h

@@ -7,7 +7,7 @@
 
 #include <AnKi/Gr/Texture.h>
 #include <AnKi/Gr/Vulkan/VkGpuMemoryManager.h>
-#include <AnKi/Gr/Utils/Functions.h>
+#include <AnKi/Gr/Common/Functions.h>
 #include <AnKi/Util/HashMap.h>
 
 namespace anki {

+ 1 - 1
AnKi/Renderer/Dbg.cpp

@@ -192,7 +192,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 
 		cmdb.setPushConstants(&unis, sizeof(unis));
 		cmdb.bindVertexBuffer(0, m_cubeVertsBuffer.get(), 0, sizeof(Vec3));
-		cmdb.setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
+		cmdb.setVertexAttribute(VertexAttribute::kPosition, 0, Format::kR32G32B32_Sfloat, 0);
 		cmdb.bindIndexBuffer(m_cubeIndicesBuffer.get(), 0, IndexType::kU16);
 
 		cmdb.bindUavBuffer(0, 2, GpuSceneArrays::RenderableBoundingVolumeGBuffer::getSingleton().getBufferOffsetRange());

+ 1 - 1
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -463,7 +463,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 					dsInfo.m_gbufferRenderTargetSubresourceInfos[2].m_firstFace = faceIdx;
 					dsInfo.m_gbufferDepthRenderTarget = gbufferDepthRt;
 					dsInfo.m_directionalLightShadowmapRenderTarget = shadowsRt;
-					dsInfo.m_skyLutRenderTarget = getRenderer().getSky().getSkyLutRt();
+					dsInfo.m_skyLutRenderTarget = (getRenderer().getSky().isEnabled()) ? getRenderer().getSky().getSkyLutRt() : RenderTargetHandle();
 					dsInfo.m_globalRendererConsts = rctx.m_globalRenderingConstsBuffer;
 					dsInfo.m_renderpassContext = &rgraphCtx;
 

+ 1 - 1
AnKi/Renderer/RtShadows.cpp

@@ -324,7 +324,7 @@ void RtShadows::populateRenderGraph(RenderingContext& ctx)
 #define ANKI_UNIFIED_GEOM_FORMAT(fmt, shaderType) \
 	cmdb.bindReadOnlyTextureBuffer(U32(MaterialSet::kGlobal), U32(MaterialBinding::kUnifiedGeometry_##fmt), \
 								   &UnifiedGeometryBuffer::getSingleton().getBuffer(), 0, kMaxPtrSize, Format::k##fmt);
-#include <AnKi/Shaders/Include/UnifiedGeometryTypes.defs.h>
+#include <AnKi/Shaders/Include/UnifiedGeometryTypes.def.h>
 
 			constexpr U32 kSet = 2;
 

+ 2 - 2
AnKi/Renderer/Utils/Drawer.cpp

@@ -57,7 +57,7 @@ void RenderableDrawer::setState(const RenderableDrawerArguments& args, CommandBu
 #define ANKI_UNIFIED_GEOM_FORMAT(fmt, shaderType) \
 	cmdb.bindReadOnlyTextureBuffer(U32(MaterialSet::kGlobal), U32(MaterialBinding::kUnifiedGeometry_##fmt), \
 								   &UnifiedGeometryBuffer::getSingleton().getBuffer(), 0, kMaxPtrSize, Format::k##fmt);
-#include <AnKi/Shaders/Include/UnifiedGeometryTypes.defs.h>
+#include <AnKi/Shaders/Include/UnifiedGeometryTypes.def.h>
 
 	cmdb.bindUavBuffer(U32(MaterialSet::kGlobal), U32(MaterialBinding::kMeshletBoundingVolumes),
 					   UnifiedGeometryBuffer::getSingleton().getBufferOffsetRange());
@@ -107,7 +107,7 @@ void RenderableDrawer::drawMdi(const RenderableDrawerArguments& args, CommandBuf
 
 	const Bool meshShaderHwSupport = GrManager::getSingleton().getDeviceCapabilities().m_meshShaders;
 
-	cmdb.setVertexAttribute(0, 0, Format::kR32G32B32A32_Uint, 0);
+	cmdb.setVertexAttribute(VertexAttribute::kMisc0, 0, Format::kR32G32B32A32_Uint, 0);
 
 	RenderStateBucketContainer::getSingleton().iterateBucketsPerformanceOrder(
 		args.m_renderingTechinuqe,

+ 2 - 2
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -421,8 +421,8 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 		cmdb.bindUavBuffer(0, 0, aabbsBuffer);
 		cmdb.bindUavBuffer(0, 1, GpuSceneArrays::Renderable::getSingleton().getBufferOffsetRange());
 		cmdb.bindUavBuffer(0, 2, GpuSceneArrays::MeshLod::getSingleton().getBufferOffsetRange());
-		cmdb.bindUavBuffer(0, 3, GpuSceneBuffer::getSingleton().getBufferOffsetRange());
-		cmdb.bindUavBuffer(0, 4, GpuSceneArrays::Transform::getSingleton().getBufferOffsetRange());
+		cmdb.bindUavBuffer(0, 3, GpuSceneArrays::Transform::getSingleton().getBufferOffsetRange());
+		cmdb.bindUavBuffer(0, 4, GpuSceneBuffer::getSingleton().getBufferOffsetRange());
 		if(gatherType & 1u)
 		{
 			cmdb.bindUavBuffer(0, 5, out.m_legacy.m_renderableInstancesBuffer);

+ 3 - 3
AnKi/Resource/MaterialResource.cpp

@@ -32,7 +32,7 @@ public:
 	public: \
 		static constexpr Bool kValue = rowCount * columnCount > 1; \
 	};
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 
 template<typename T, Bool isArray = IsShaderVarDataTypeAnArray<T>::kValue>
@@ -469,7 +469,7 @@ Error MaterialResource::parseInput(XmlElement inputEl, Bool async, BitSet<128>&
 	case ShaderVariableDataType::k##type: \
 		ANKI_CHECK(GetAttribute<type>()(inputEl, foundVar->ANKI_CONCATENATE(m_, type))); \
 		break;
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 		default:
 			ANKI_ASSERT(0);
@@ -499,7 +499,7 @@ void MaterialResource::prefillLocalUniforms()
 		ANKI_ASSERT(var.m_offsetInLocalUniforms + sizeof(type) <= m_localUniformsSize); \
 		memcpy(static_cast<U8*>(m_prefilledLocalUniforms) + var.m_offsetInLocalUniforms, &var.m_##type, sizeof(type)); \
 		break;
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 		default:
 			ANKI_ASSERT(0);

+ 2 - 2
AnKi/Resource/MaterialResource.h

@@ -93,7 +93,7 @@ protected:
 	union
 	{
 #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) type ANKI_CONCATENATE(m_, type);
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 	};
 
@@ -111,7 +111,7 @@ protected:
 	}
 
 #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) ANKI_SPECIALIZE_GET_VALUE(type, ANKI_CONCATENATE(m_, type))
-#include <AnKi/Gr/ShaderVariableDataType.defs.h>
+#include <AnKi/Gr/ShaderVariableDataType.def.h>
 #undef ANKI_SVDT_MACRO
 
 #undef ANKI_SPECIALIZE_GET_VALUE

+ 2 - 2
AnKi/Resource/MeshBinary.h

@@ -170,8 +170,8 @@ class MeshBinaryHeader
 public:
 	Array<U8, 8> m_magic;
 	MeshBinaryFlag m_flags;
-	Array<MeshBinaryVertexBuffer, kMaxVertexAttributes> m_vertexBuffers;
-	Array<MeshBinaryVertexAttribute, kMaxVertexAttributes> m_vertexAttributes;
+	Array<MeshBinaryVertexBuffer, U32(VertexAttribute::kCount)> m_vertexBuffers;
+	Array<MeshBinaryVertexAttribute, U32(VertexAttribute::kCount)> m_vertexAttributes;
 	IndexType m_indexType;
 	Array<U8, 3> m_padding;
 

+ 2 - 2
AnKi/Resource/MeshBinary.xml

@@ -59,8 +59,8 @@ ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MeshBinaryFlag)
 			<members>
 				<member name="m_magic" type="U8" array_size="8"/>
 				<member name="m_flags" type="MeshBinaryFlag"/>
-				<member name="m_vertexBuffers" type="MeshBinaryVertexBuffer" array_size="kMaxVertexAttributes"/>
-				<member name="m_vertexAttributes" type="MeshBinaryVertexAttribute" array_size="kMaxVertexAttributes"/>
+				<member name="m_vertexBuffers" type="MeshBinaryVertexBuffer" array_size="U32(VertexAttribute::kCount)"/>
+				<member name="m_vertexAttributes" type="MeshBinaryVertexAttribute" array_size="U32(VertexAttribute::kCount)"/>
 				<member name="m_indexType" type="IndexType"/>
 				<member name="m_padding" type="U8" array_size="3"/>
 				<member name="m_meshletPrimitiveFormat" type="Format" comment="The format of the 3 indices that make a primitive"/>

+ 4 - 1
AnKi/Resource/ShaderProgramResource.cpp

@@ -210,7 +210,10 @@ ShaderProgramResourceVariant* ShaderProgramResource::createNewVariant(const Shad
 			const ResourceString shaderName = (progName + "_" + m_binary->m_techniques[techniqueIdx].m_name.getBegin()).cstr();
 			ShaderInitInfo inf(shaderName);
 			inf.m_shaderType = shaderType;
-			inf.m_binary = m_binary->m_codeBlocks[binaryVariant->m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[shaderType]].m_binary;
+			const ShaderProgramBinaryCodeBlock& binBlock =
+				m_binary->m_codeBlocks[binaryVariant->m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[shaderType]];
+			inf.m_binary = binBlock.m_binary;
+			inf.m_reflection = binBlock.m_reflection;
 			ShaderPtr shader = GrManager::getSingleton().newShader(inf);
 			shaderRefs[shaderType] = shader;
 

+ 1 - 1
AnKi/Resource/ShaderProgramResource.h

@@ -7,7 +7,7 @@
 
 #include <AnKi/Resource/ResourceObject.h>
 #include <AnKi/ShaderCompiler/ShaderProgramCompiler.h>
-#include <AnKi/Gr/Utils/Functions.h>
+#include <AnKi/Gr/Common/Functions.h>
 #include <AnKi/Gr/ShaderProgram.h>
 #include <AnKi/Util/BitSet.h>
 #include <AnKi/Util/String.h>

+ 3 - 1
AnKi/ShaderCompiler/ShaderProgramBinary.h

@@ -71,18 +71,20 @@ public:
 	}
 };
 
-/// Contains the IR (SPIR-V).
+/// Contains the IR (SPIR-V or DXIL).
 class ShaderProgramBinaryCodeBlock
 {
 public:
 	WeakArray<U8> m_binary;
 	U64 m_hash = 0;
+	ShaderReflection m_reflection;
 
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	{
 		s.doValue("m_binary", offsetof(ShaderProgramBinaryCodeBlock, m_binary), self.m_binary);
 		s.doValue("m_hash", offsetof(ShaderProgramBinaryCodeBlock, m_hash), self.m_hash);
+		s.doValue("m_reflection", offsetof(ShaderProgramBinaryCodeBlock, m_reflection), self.m_reflection);
 	}
 
 	template<typename TDeserializer>

+ 3 - 2
AnKi/ShaderCompiler/ShaderProgramBinary.xml

@@ -21,11 +21,12 @@
 				<member name="m_size" type="U32" />
 			</members>
 		</class>
-
-		<class name="ShaderProgramBinaryCodeBlock" comment="Contains the IR (SPIR-V)">
+		
+		<class name="ShaderProgramBinaryCodeBlock" comment="Contains the IR (SPIR-V or DXIL)">
 			<members>
 				<member name="m_binary" type="WeakArray&lt;U8&gt;" />
 				<member name="m_hash" type="U64" constructor="= 0" />
+				<member name="m_reflection" type="ShaderReflection" />
 			</members>
 		</class>
 

+ 10 - 18
AnKi/ShaderCompiler/ShaderProgramBinaryExtra.h

@@ -8,37 +8,29 @@
 
 namespace anki {
 
-/// Serialize/deserialize ShaderVariableBlockInfo
-template<typename TSerializer, typename TShaderVariableBlockInfo>
-void serializeShaderVariableBlockInfo(TShaderVariableBlockInfo x, TSerializer& s)
-{
-	s.doValue("m_offset", offsetof(ShaderVariableBlockInfo, m_offset), x.m_offset);
-	s.doValue("m_arraySize", offsetof(ShaderVariableBlockInfo, m_arraySize), x.m_arraySize);
-	s.doValue("m_arrayStride", offsetof(ShaderVariableBlockInfo, m_arrayStride), x.m_arrayStride);
-	s.doValue("m_matrixStride", offsetof(ShaderVariableBlockInfo, m_matrixStride), x.m_matrixStride);
-}
-
-/// Serialize ShaderVariableBlockInfo
+/// Serialize ShaderReflection
 template<>
-class SerializeFunctor<ShaderVariableBlockInfo>
+class SerializeFunctor<ShaderReflection>
 {
 public:
 	template<typename TSerializer>
-	void operator()(const ShaderVariableBlockInfo& x, TSerializer& serializer)
+	void operator()(const ShaderReflection& x, TSerializer& serializer)
 	{
-		serializeShaderVariableBlockInfo<TSerializer, const ShaderVariableBlockInfo&>(x, serializer);
+		const U8* arr = reinterpret_cast<const U8*>(&x);
+		serializer.doArray("binblob", 0, arr, sizeof(ShaderReflection));
 	}
 };
 
-/// Deserialize ShaderVariableBlockInfo
+/// Deserialize ShaderReflection
 template<>
-class DeserializeFunctor<ShaderVariableBlockInfo>
+class DeserializeFunctor<ShaderReflection>
 {
 public:
 	template<typename TDeserializer>
-	void operator()(ShaderVariableBlockInfo& x, TDeserializer& deserialize)
+	void operator()(ShaderReflection& x, TDeserializer& deserializer)
 	{
-		serializeShaderVariableBlockInfo<TDeserializer, ShaderVariableBlockInfo&>(x, deserialize);
+		U8* arr = reinterpret_cast<U8*>(&x);
+		deserializer.doArray("binblob", 0, arr, sizeof(ShaderReflection));
 	}
 };
 

+ 217 - 0
AnKi/ShaderCompiler/ShaderProgramCompiler.cpp

@@ -8,6 +8,7 @@
 #include <AnKi/ShaderCompiler/Dxc.h>
 #include <AnKi/Util/Serializer.h>
 #include <AnKi/Util/HashMap.h>
+#include <SpirvCross/spirv_cross.hpp>
 
 namespace anki {
 
@@ -93,6 +94,214 @@ static Bool spinDials(ShaderCompilerDynamicArray<U32>& dials, ConstWeakArray<Sha
 	return done;
 }
 
+template<typename TFunc>
+static void visitSpirv(ConstWeakArray<U32> spv, TFunc func)
+{
+	ANKI_ASSERT(spv.getSize() > 5);
+
+	const U32* it = &spv[5];
+	do
+	{
+		const U32 instructionCount = *it >> 16u;
+		const U32 opcode = *it & 0xFFFFu;
+
+		func(opcode);
+
+		it += instructionCount;
+	} while(it < spv.getEnd());
+
+	ANKI_ASSERT(it == spv.getEnd());
+}
+
+static Error doReflectionSpirv(ConstWeakArray<U8> spirv, ShaderType type, ShaderReflection& refl, ShaderCompilerString& errorStr)
+{
+	spirv_cross::Compiler spvc(reinterpret_cast<const U32*>(&spirv[0]), spirv.getSize() / sizeof(U32));
+	spirv_cross::ShaderResources rsrc = spvc.get_shader_resources();
+	spirv_cross::ShaderResources rsrcActive = spvc.get_shader_resources(spvc.get_active_interface_variables());
+
+	auto func = [&](const spirv_cross::SmallVector<spirv_cross::Resource>& resources, const DescriptorType origType) -> Error {
+		for(const spirv_cross::Resource& r : resources)
+		{
+			const U32 id = r.id;
+
+			const U32 set = spvc.get_decoration(id, spv::Decoration::DecorationDescriptorSet);
+			const U32 binding = spvc.get_decoration(id, spv::Decoration::DecorationBinding);
+			if(set >= kMaxDescriptorSets || binding >= kMaxBindingsPerDescriptorSet)
+			{
+				errorStr.sprintf("Exceeded set or binding for: %s", r.name.c_str());
+				return Error::kUserData;
+			}
+
+			const spirv_cross::SPIRType& typeInfo = spvc.get_type(r.type_id);
+			U32 arraySize = 1;
+			if(typeInfo.array.size() != 0)
+			{
+				if(typeInfo.array.size() != 1 || (arraySize = typeInfo.array[0]) == 0)
+				{
+					errorStr.sprintf("Only 1D arrays are supported: %s", r.name.c_str());
+					return Error::kUserData;
+				}
+			}
+
+			refl.m_descriptorSetMask.set(set);
+
+			// Images are special, they might be texel buffers
+			DescriptorType type = origType;
+			if(type == DescriptorType::kTexture)
+			{
+				if(typeInfo.image.dim == spv::DimBuffer && typeInfo.image.sampled == 1)
+				{
+					type = DescriptorType::kReadTexelBuffer;
+				}
+				else if(typeInfo.image.dim == spv::DimBuffer && typeInfo.image.sampled == 2)
+				{
+					type = DescriptorType::kReadWriteTexelBuffer;
+				}
+			}
+
+			// Check that there are no other descriptors with the same binding
+			if(refl.m_descriptorTypes[set][binding] == DescriptorType::kCount)
+			{
+				// New binding, init it
+				refl.m_descriptorTypes[set][binding] = type;
+				refl.m_descriptorArraySizes[set][binding] = U16(arraySize);
+			}
+			else
+			{
+				// Same binding, make sure the type is compatible
+				if(refl.m_descriptorTypes[set][binding] != type || refl.m_descriptorArraySizes[set][binding] != arraySize)
+				{
+					errorStr.sprintf("Descriptor with same binding but different type or array size: %s", r.name.c_str());
+					return Error::kUserData;
+				}
+			}
+		}
+
+		return Error::kNone;
+	};
+
+	Error err = Error::kNone;
+	err = func(rsrc.uniform_buffers, DescriptorType::kUniformBuffer);
+	if(!err)
+	{
+		err = func(rsrc.separate_images, DescriptorType::kTexture); // This also handles texture buffers
+	}
+	if(!err)
+	{
+		err = func(rsrc.separate_samplers, DescriptorType::kSampler);
+	}
+	if(!err)
+	{
+		err = func(rsrc.storage_buffers, DescriptorType::kStorageBuffer);
+	}
+	if(!err)
+	{
+		err = func(rsrc.storage_images, DescriptorType::kStorageImage);
+	}
+	if(!err)
+	{
+		err = func(rsrc.acceleration_structures, DescriptorType::kAccelerationStructure);
+	}
+
+	// Color attachments
+	if(type == ShaderType::kFragment)
+	{
+		for(const spirv_cross::Resource& r : rsrc.stage_outputs)
+		{
+			const U32 id = r.id;
+			const U32 location = spvc.get_decoration(id, spv::Decoration::DecorationLocation);
+
+			refl.m_colorAttachmentWritemask.set(location);
+		}
+	}
+
+	// Push consts
+	if(rsrc.push_constant_buffers.size() == 1)
+	{
+		const U32 blockSize = U32(spvc.get_declared_struct_size(spvc.get_type(rsrc.push_constant_buffers[0].base_type_id)));
+		if(blockSize == 0 || (blockSize % 16) != 0 || blockSize > kMaxU8)
+		{
+			errorStr.sprintf("Incorrect push constants size");
+			return Error::kUserData;
+		}
+
+		refl.m_pushConstantsSize = U8(blockSize);
+	}
+
+	// Attribs
+	if(type == ShaderType::kVertex)
+	{
+		for(const spirv_cross::Resource& r : rsrcActive.stage_inputs)
+		{
+			VertexAttribute a = VertexAttribute::kCount;
+#define ANKI_ATTRIB_NAME(x) "in.var." #x
+			if(r.name == ANKI_ATTRIB_NAME(POSITION))
+			{
+				a = VertexAttribute::kPosition;
+			}
+			else if(r.name == ANKI_ATTRIB_NAME(NORMAL))
+			{
+				a = VertexAttribute::kNormal;
+			}
+			else if(r.name == ANKI_ATTRIB_NAME(TEXCOORD0) || r.name == ANKI_ATTRIB_NAME(TEXCOORD))
+			{
+				a = VertexAttribute::kTexCoord;
+			}
+			else if(r.name == ANKI_ATTRIB_NAME(COLOR))
+			{
+				a = VertexAttribute::kColor;
+			}
+			else if(r.name == ANKI_ATTRIB_NAME(MISC0) || r.name == ANKI_ATTRIB_NAME(MISC))
+			{
+				a = VertexAttribute::kMisc0;
+			}
+			else if(r.name == ANKI_ATTRIB_NAME(MISC1))
+			{
+				a = VertexAttribute::kMisc1;
+			}
+			else if(r.name == ANKI_ATTRIB_NAME(MISC2))
+			{
+				a = VertexAttribute::kMisc2;
+			}
+			else if(r.name == ANKI_ATTRIB_NAME(MISC3))
+			{
+				a = VertexAttribute::kMisc3;
+			}
+			else
+			{
+				errorStr.sprintf("Unexpected attribute name: %s", r.name.c_str());
+				return Error::kUserData;
+			}
+#undef ANKI_ATTRIB_NAME
+
+			refl.m_vertexAttributeMask.set(a);
+
+			const U32 id = r.id;
+			const U32 location = spvc.get_decoration(id, spv::Decoration::DecorationLocation);
+			if(location > kMaxU8)
+			{
+				errorStr.sprintf("Too high location value for attribute: %s", r.name.c_str());
+				return Error::kUserData;
+			}
+
+			refl.m_vertexAttributeLocations[a] = U8(location);
+		}
+	}
+
+	// Discards?
+	if(type == ShaderType::kFragment)
+	{
+		visitSpirv(ConstWeakArray<U32>(reinterpret_cast<const U32*>(&spirv[0]), spirv.getSize() / sizeof(U32)), [&](U32 cmd) {
+			if(cmd == spv::OpKill)
+			{
+				refl.m_discards = true;
+			}
+		});
+	}
+
+	return Error::kNone;
+}
+
 static void compileVariantAsync(const ShaderProgramParser& parser, ShaderProgramBinaryMutation& mutation,
 								ShaderCompilerDynamicArray<ShaderProgramBinaryVariant>& variants,
 								ShaderCompilerDynamicArray<ShaderProgramBinaryCodeBlock>& codeBlocks,
@@ -195,6 +404,13 @@ static void compileVariantAsync(const ShaderProgramParser& parser, ShaderProgram
 
 				const U64 newHash = computeHash(spirv.getBegin(), spirv.getSizeInBytes());
 
+				ShaderReflection refl;
+				err = doReflectionSpirv(spirv, shaderType, refl, compilerErrorLog);
+				if(err)
+				{
+					break;
+				}
+
 				// Add the binary if not already there
 				{
 					LockGuard lock(*ctx.m_mtx);
@@ -217,6 +433,7 @@ static void compileVariantAsync(const ShaderProgramParser& parser, ShaderProgram
 						auto& codeBlock = *ctx.m_codeBlocks->emplaceBack();
 						spirv.moveAndReset(codeBlock.m_binary);
 						codeBlock.m_hash = newHash;
+						codeBlock.m_reflection = refl;
 
 						ctx.m_sourceCodeHashes->emplaceBack(sourceCodeHash);
 						ANKI_ASSERT(ctx.m_sourceCodeHashes->getSize() == ctx.m_codeBlocks->getSize());

+ 2 - 2
AnKi/ShaderCompiler/ShaderProgramCompiler.h

@@ -14,8 +14,8 @@ namespace anki {
 /// @addtogroup shader_compiler
 /// @{
 
-inline constexpr const char* kShaderBinaryMagic = "ANKISP0"; // WARNING: If changed change kShaderBinaryVersion
-constexpr U32 kShaderBinaryVersion = 0;
+inline constexpr const char* kShaderBinaryMagic = "ANKISP1"; // WARNING: If changed change kShaderBinaryVersion
+constexpr U32 kShaderBinaryVersion = 1;
 
 template<typename TFile>
 Error deserializeShaderProgramBinaryFromAnyFile(TFile& file, ShaderProgramBinary*& binary, BaseMemoryPool& pool)

+ 1 - 1
AnKi/Shaders/ForwardShadingFog.ankiprog

@@ -14,7 +14,7 @@
 
 struct VertIn
 {
-	[[vk::location(0)]] UVec4 m_gpuSceneRenderable : RENDERABLE;
+	UVec4 m_gpuSceneRenderable : MISC0;
 	U32 m_svVertexId : SV_VERTEXID;
 };
 

+ 1 - 1
AnKi/Shaders/ForwardShadingGenericTransparent.ankiprog

@@ -16,7 +16,7 @@
 
 struct VertIn
 {
-	[[vk::location(0)]] UVec4 m_gpuSceneRenderable : RENDERABLE;
+	UVec4 m_gpuSceneRenderable : MISC0;
 	U32 m_svVertexId : SV_VERTEXID;
 };
 

+ 1 - 1
AnKi/Shaders/ForwardShadingParticles.ankiprog

@@ -10,7 +10,7 @@
 
 struct VertIn
 {
-	[[vk::location(0)]] UVec4 m_gpuSceneRenderable : RENDERABLE;
+	UVec4 m_gpuSceneRenderable : MISC0;
 	U32 m_svVertexId : SV_VERTEXID;
 };
 

+ 1 - 1
AnKi/Shaders/GBufferGeneric.ankiprog

@@ -89,7 +89,7 @@
 struct VertIn
 {
 	U32 m_svVertexId : SV_VERTEXID;
-	[[vk::location(0)]] UVec4 m_instanceData : INSTANCE_DATA;
+	[[vk::location(0)]] UVec4 m_instanceData : MISC0;
 };
 
 struct VertOut

+ 1 - 1
AnKi/Shaders/GBufferGpuParticles.ankiprog

@@ -17,7 +17,7 @@
 struct VertIn
 {
 	U32 m_svVertexId : SV_VERTEXID;
-	[[vk::location(0)]] UVec4 m_gpuSceneRenderable : RENDERABLE;
+	UVec4 m_gpuSceneRenderable : MISC0;
 };
 
 struct VertOut

+ 1 - 1
AnKi/Shaders/Include/MaterialTypes.h

@@ -42,7 +42,7 @@ enum class MaterialBinding : U32
 
 	// Texture buffer bindings pointing to unified geom buffer:
 #define ANKI_UNIFIED_GEOM_FORMAT(fmt, shaderType) kUnifiedGeometry_##fmt,
-#include <AnKi/Shaders/Include/UnifiedGeometryTypes.defs.h>
+#include <AnKi/Shaders/Include/UnifiedGeometryTypes.def.h>
 
 	kMeshletBoundingVolumes, ///< Points to the unified geom buffer
 	kMeshletGeometryDescriptors, ///< Points to the unified geom buffer

+ 0 - 0
AnKi/Shaders/Include/UnifiedGeometryTypes.defs.h → AnKi/Shaders/Include/UnifiedGeometryTypes.def.h


+ 1 - 1
AnKi/Shaders/MaterialShadersCommon.hlsl

@@ -22,7 +22,7 @@ ANKI_BINDLESS_SET(MaterialSet::kBindless)
 // Unified geom:
 #define ANKI_UNIFIED_GEOM_FORMAT(fmt, shaderType) \
 	[[vk::binding(MaterialBinding::kUnifiedGeometry_##fmt, MaterialSet::kGlobal)]] Buffer<shaderType> g_unifiedGeom_##fmt;
-#include <AnKi/Shaders/Include/UnifiedGeometryTypes.defs.h>
+#include <AnKi/Shaders/Include/UnifiedGeometryTypes.def.h>
 
 [[vk::binding(MaterialBinding::kMeshletBoundingVolumes, MaterialSet::kGlobal)]] StructuredBuffer<MeshletBoundingVolume> g_meshletBoundingVolumes;
 [[vk::binding(MaterialBinding::kMeshletGeometryDescriptors, MaterialSet::kGlobal)]] StructuredBuffer<MeshletGeometryDescriptor>

+ 3 - 3
AnKi/Ui/Canvas.cpp

@@ -220,9 +220,9 @@ void Canvas::appendToCommandBufferInternal(CommandBuffer& cmdb)
 	cmdb.setViewport(0, 0, U32(fbWidth), U32(fbHeight));
 
 	cmdb.bindVertexBuffer(0, &vertsToken.getBuffer(), vertsToken.getOffset(), sizeof(ImDrawVert));
-	cmdb.setVertexAttribute(0, 0, Format::kR32G32_Sfloat, 0);
-	cmdb.setVertexAttribute(1, 0, Format::kR8G8B8A8_Unorm, sizeof(Vec2) * 2);
-	cmdb.setVertexAttribute(2, 0, Format::kR32G32_Sfloat, sizeof(Vec2));
+	cmdb.setVertexAttribute(VertexAttribute::kPosition, 0, Format::kR32G32_Sfloat, 0);
+	cmdb.setVertexAttribute(VertexAttribute::kColor, 0, Format::kR8G8B8A8_Unorm, sizeof(Vec2) * 2);
+	cmdb.setVertexAttribute(VertexAttribute::kTexCoord, 0, Format::kR32G32_Sfloat, sizeof(Vec2));
 
 	cmdb.bindIndexBuffer(&indicesToken.getBuffer(), indicesToken.getOffset(), IndexType::kU16);
 

+ 1 - 1
AnKi/Window/InputSdl.cpp

@@ -40,7 +40,7 @@ static KeyCode sdlKeytoAnKi(SDL_Keycode sdlk)
 	case SDLK_##sdl: \
 		akk = KeyCode::k##ak; \
 		break;
-#include <AnKi/Window/KeyCode.defs.h>
+#include <AnKi/Window/KeyCode.def.h>
 #undef ANKI_KEY_CODE
 	}
 

+ 0 - 0
AnKi/Window/KeyCode.defs.h → AnKi/Window/KeyCode.def.h


+ 1 - 1
AnKi/Window/KeyCode.h

@@ -15,7 +15,7 @@ enum class KeyCode
 	kUnknown = 0,
 
 #define ANKI_KEY_CODE(ak, sdl) k##ak,
-#include <AnKi/Window/KeyCode.defs.h>
+#include <AnKi/Window/KeyCode.def.h>
 #undef ANKI_KEY_CODE
 
 	kCount,

+ 4 - 4
Tests/Gr/Gr.cpp

@@ -978,9 +978,9 @@ ANKI_TEST(Gr, DrawWithVertex)
 
 		cmdb->bindVertexBuffer(0, b.get(), 0, sizeof(Vert));
 		cmdb->bindVertexBuffer(1, c.get(), 0, sizeof(Vec3));
-		cmdb->setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
-		cmdb->setVertexAttribute(1, 0, Format::kR8G8B8_Unorm, sizeof(Vec3));
-		cmdb->setVertexAttribute(2, 1, Format::kR32G32B32_Sfloat, 0);
+		cmdb->setVertexAttribute(VertexAttribute::kPosition, 0, Format::kR32G32B32_Sfloat, 0);
+		cmdb->setVertexAttribute(VertexAttribute::kColor, 0, Format::kR8G8B8_Unorm, sizeof(Vec3));
+		cmdb->setVertexAttribute(VertexAttribute::kMisc0, 1, Format::kR32G32B32_Sfloat, 0);
 
 		cmdb->setViewport(0, 0, g_win->getWidth(), g_win->getHeight());
 		cmdb->setPolygonOffset(0.0, 0.0);
@@ -1248,7 +1248,7 @@ static void drawOffscreenDrawcalls([[maybe_unused]] GrManager& gr, ShaderProgram
 	*color = Vec4(0.0, 1.0, 0.0, 0.0);
 
 	cmdb->bindVertexBuffer(0, vertBuff.get(), 0, sizeof(Vec3));
-	cmdb->setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
+	cmdb->setVertexAttribute(VertexAttribute::kPosition, 0, Format::kR32G32B32_Sfloat, 0);
 	cmdb->bindShaderProgram(prog.get());
 	cmdb->bindIndexBuffer(indexBuff.get(), 0, IndexType::kU16);
 	cmdb->setViewport(0, 0, viewPortSize, viewPortSize);