فهرست منبع

Work on reflection

Panagiotis Christopoulos Charitos 5 سال پیش
والد
کامیت
7896c1cd6b

+ 37 - 37
src/anki/shader_compiler/ShaderProgramBinary.h

@@ -45,7 +45,7 @@ public:
 class ShaderProgramBinaryVariableInstance
 {
 public:
-	U32 m_index = MAX_U32; ///< Points to ShaderProgramBinary::m_variables.
+	U32 m_index = MAX_U32; ///< Points to ShaderProgramBinaryBlock::m_variables.
 	ShaderVariableBlockInfo m_blockInfo;
 
 	template<typename TSerializer, typename TClass>
@@ -68,121 +68,121 @@ public:
 	}
 };
 
-/// Sampler or texture or image.
-class ShaderProgramBinaryOpaque
+/// Storage or uniform block.
+class ShaderProgramBinaryBlock
 {
 public:
 	Array<char, MAX_SHADER_BINARY_NAME_LENGTH + 1> m_name = {};
-	ShaderVariableDataType m_type = ShaderVariableDataType::NONE;
+	WeakArray<ShaderProgramBinaryVariable> m_variables;
 	U32 m_binding = MAX_U32;
 	U32 m_set = MAX_U32;
 
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	{
-		s.doArray("m_name", offsetof(ShaderProgramBinaryOpaque, m_name), &self.m_name[0], self.m_name.getSize());
-		s.doValue("m_type", offsetof(ShaderProgramBinaryOpaque, m_type), self.m_type);
-		s.doValue("m_binding", offsetof(ShaderProgramBinaryOpaque, m_binding), self.m_binding);
-		s.doValue("m_set", offsetof(ShaderProgramBinaryOpaque, m_set), self.m_set);
+		s.doArray("m_name", offsetof(ShaderProgramBinaryBlock, m_name), &self.m_name[0], self.m_name.getSize());
+		s.doValue("m_variables", offsetof(ShaderProgramBinaryBlock, m_variables), self.m_variables);
+		s.doValue("m_binding", offsetof(ShaderProgramBinaryBlock, m_binding), self.m_binding);
+		s.doValue("m_set", offsetof(ShaderProgramBinaryBlock, m_set), self.m_set);
 	}
 
 	template<typename TDeserializer>
 	void deserialize(TDeserializer& deserializer)
 	{
-		serializeCommon<TDeserializer, ShaderProgramBinaryOpaque&>(deserializer, *this);
+		serializeCommon<TDeserializer, ShaderProgramBinaryBlock&>(deserializer, *this);
 	}
 
 	template<typename TSerializer>
 	void serialize(TSerializer& serializer) const
 	{
-		serializeCommon<TSerializer, const ShaderProgramBinaryOpaque&>(serializer, *this);
+		serializeCommon<TSerializer, const ShaderProgramBinaryBlock&>(serializer, *this);
 	}
 };
 
-/// Sampler or texture or image per variant.
-class ShaderProgramBinaryOpaqueInstance
+/// Storage or uniform block per variant.
+class ShaderProgramBinaryBlockInstance
 {
 public:
-	U32 m_index = MAX_U32; ///< Points to ShaderProgramBinary::m_opaques.
-	U32 m_arraySize = MAX_U32;
+	U32 m_index = MAX_U32; ///< Points to ShaderProgramBinary::m_uniformBlocks or m_storageBlocks.
+	WeakArray<ShaderProgramBinaryVariableInstance> m_variables;
+	U32 m_size = MAX_U32;
 
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	{
-		s.doValue("m_index", offsetof(ShaderProgramBinaryOpaqueInstance, m_index), self.m_index);
-		s.doValue("m_arraySize", offsetof(ShaderProgramBinaryOpaqueInstance, m_arraySize), self.m_arraySize);
+		s.doValue("m_index", offsetof(ShaderProgramBinaryBlockInstance, m_index), self.m_index);
+		s.doValue("m_variables", offsetof(ShaderProgramBinaryBlockInstance, m_variables), self.m_variables);
+		s.doValue("m_size", offsetof(ShaderProgramBinaryBlockInstance, m_size), self.m_size);
 	}
 
 	template<typename TDeserializer>
 	void deserialize(TDeserializer& deserializer)
 	{
-		serializeCommon<TDeserializer, ShaderProgramBinaryOpaqueInstance&>(deserializer, *this);
+		serializeCommon<TDeserializer, ShaderProgramBinaryBlockInstance&>(deserializer, *this);
 	}
 
 	template<typename TSerializer>
 	void serialize(TSerializer& serializer) const
 	{
-		serializeCommon<TSerializer, const ShaderProgramBinaryOpaqueInstance&>(serializer, *this);
+		serializeCommon<TSerializer, const ShaderProgramBinaryBlockInstance&>(serializer, *this);
 	}
 };
 
-/// Storage or uniform block.
-class ShaderProgramBinaryBlock
+/// Sampler or texture or image.
+class ShaderProgramBinaryOpaque
 {
 public:
 	Array<char, MAX_SHADER_BINARY_NAME_LENGTH + 1> m_name = {};
-	WeakArray<ShaderProgramBinaryVariable> m_variables;
+	ShaderVariableDataType m_type = ShaderVariableDataType::NONE;
 	U32 m_binding = MAX_U32;
 	U32 m_set = MAX_U32;
-	U32 m_size = MAX_U32;
 
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	{
-		s.doArray("m_name", offsetof(ShaderProgramBinaryBlock, m_name), &self.m_name[0], self.m_name.getSize());
-		s.doValue("m_variables", offsetof(ShaderProgramBinaryBlock, m_variables), self.m_variables);
-		s.doValue("m_binding", offsetof(ShaderProgramBinaryBlock, m_binding), self.m_binding);
-		s.doValue("m_set", offsetof(ShaderProgramBinaryBlock, m_set), self.m_set);
-		s.doValue("m_size", offsetof(ShaderProgramBinaryBlock, m_size), self.m_size);
+		s.doArray("m_name", offsetof(ShaderProgramBinaryOpaque, m_name), &self.m_name[0], self.m_name.getSize());
+		s.doValue("m_type", offsetof(ShaderProgramBinaryOpaque, m_type), self.m_type);
+		s.doValue("m_binding", offsetof(ShaderProgramBinaryOpaque, m_binding), self.m_binding);
+		s.doValue("m_set", offsetof(ShaderProgramBinaryOpaque, m_set), self.m_set);
 	}
 
 	template<typename TDeserializer>
 	void deserialize(TDeserializer& deserializer)
 	{
-		serializeCommon<TDeserializer, ShaderProgramBinaryBlock&>(deserializer, *this);
+		serializeCommon<TDeserializer, ShaderProgramBinaryOpaque&>(deserializer, *this);
 	}
 
 	template<typename TSerializer>
 	void serialize(TSerializer& serializer) const
 	{
-		serializeCommon<TSerializer, const ShaderProgramBinaryBlock&>(serializer, *this);
+		serializeCommon<TSerializer, const ShaderProgramBinaryOpaque&>(serializer, *this);
 	}
 };
 
-/// Storage or uniform block per variant.
-class ShaderProgramBinaryBlockInstance
+/// Sampler or texture or image per variant.
+class ShaderProgramBinaryOpaqueInstance
 {
 public:
-	U32 m_index = MAX_U32; ///< Points to ShaderProgramBinary::m_uniformBlocks or m_storageBlocks.
-	U32 m_size = MAX_U32;
+	U32 m_index = MAX_U32; ///< Points to ShaderProgramBinary::m_opaques.
+	U32 m_arraySize = MAX_U32;
 
 	template<typename TSerializer, typename TClass>
 	static void serializeCommon(TSerializer& s, TClass self)
 	{
-		s.doValue("m_index", offsetof(ShaderProgramBinaryBlockInstance, m_index), self.m_index);
-		s.doValue("m_size", offsetof(ShaderProgramBinaryBlockInstance, m_size), self.m_size);
+		s.doValue("m_index", offsetof(ShaderProgramBinaryOpaqueInstance, m_index), self.m_index);
+		s.doValue("m_arraySize", offsetof(ShaderProgramBinaryOpaqueInstance, m_arraySize), self.m_arraySize);
 	}
 
 	template<typename TDeserializer>
 	void deserialize(TDeserializer& deserializer)
 	{
-		serializeCommon<TDeserializer, ShaderProgramBinaryBlockInstance&>(deserializer, *this);
+		serializeCommon<TDeserializer, ShaderProgramBinaryOpaqueInstance&>(deserializer, *this);
 	}
 
 	template<typename TSerializer>
 	void serialize(TSerializer& serializer) const
 	{
-		serializeCommon<TSerializer, const ShaderProgramBinaryBlockInstance&>(serializer, *this);
+		serializeCommon<TSerializer, const ShaderProgramBinaryOpaqueInstance&>(serializer, *this);
 	}
 };
 

+ 13 - 13
src/anki/shader_compiler/ShaderProgramBinary.xml

@@ -15,41 +15,41 @@
 
 		<class name="ShaderProgramBinaryVariableInstance" comment="Storage or uniform variable per variant">
 			<members>
-				<member name="m_index" type="U32" constructor="= MAX_U32" comment="Points to ShaderProgramBinary::m_variables" />
+				<member name="m_index" type="U32" constructor="= MAX_U32" comment="Points to ShaderProgramBinaryBlock::m_variables" />
 				<member name="m_blockInfo" type="ShaderVariableBlockInfo" />
 			</members>
 		</class>
 
-		<class name="ShaderProgramBinaryOpaque" comment="Sampler or texture or image">
+		<class name="ShaderProgramBinaryBlock" comment="Storage or uniform block">
 			<members>
 				<member name="m_name" type="char" array_size="MAX_SHADER_BINARY_NAME_LENGTH + 1" constructor="= {}" />
-				<member name="m_type" type="ShaderVariableDataType" constructor="= ShaderVariableDataType::NONE" />
+				<member name="m_variables" type="WeakArray&lt;ShaderProgramBinaryVariable&gt;" />
 				<member name="m_binding" type="U32" constructor="= MAX_U32" />
 				<member name="m_set" type="U32" constructor="= MAX_U32" />
 			</members>
 		</class>
 
-		<class name="ShaderProgramBinaryOpaqueInstance" comment="Sampler or texture or image per variant">
+		<class name="ShaderProgramBinaryBlockInstance" comment="Storage or uniform block per variant">
 			<members>
-				<member name="m_index" type="U32" constructor="= MAX_U32" comment="Points to ShaderProgramBinary::m_opaques" />
-				<member name="m_arraySize" type="U32" constructor="= MAX_U32" />
+				<member name="m_index" type="U32" constructor="= MAX_U32" comment="Points to ShaderProgramBinary::m_uniformBlocks or m_storageBlocks" />
+				<member name="m_variables" type="WeakArray&lt;ShaderProgramBinaryVariableInstance&gt;" />
+				<member name="m_size" type="U32" constructor="= MAX_U32" />
 			</members>
 		</class>
 
-		<class name="ShaderProgramBinaryBlock" comment="Storage or uniform block">
+		<class name="ShaderProgramBinaryOpaque" comment="Sampler or texture or image">
 			<members>
 				<member name="m_name" type="char" array_size="MAX_SHADER_BINARY_NAME_LENGTH + 1" constructor="= {}" />
-				<member name="m_variables" type="WeakArray&lt;ShaderProgramBinaryVariable&gt;" />
+				<member name="m_type" type="ShaderVariableDataType" constructor="= ShaderVariableDataType::NONE" />
 				<member name="m_binding" type="U32" constructor="= MAX_U32" />
 				<member name="m_set" type="U32" constructor="= MAX_U32" />
-				<member name="m_size" type="U32" constructor="= MAX_U32" />
 			</members>
 		</class>
 
-		<class name="ShaderProgramBinaryBlockInstance" comment="Storage or uniform block per variant">
+		<class name="ShaderProgramBinaryOpaqueInstance" comment="Sampler or texture or image per variant">
 			<members>
-				<member name="m_index" type="U32" constructor="= MAX_U32" comment="Points to ShaderProgramBinary::m_uniformBlocks or m_storageBlocks" />
-				<member name="m_size" type="U32" constructor="= MAX_U32" />
+				<member name="m_index" type="U32" constructor="= MAX_U32" comment="Points to ShaderProgramBinary::m_opaques" />
+				<member name="m_arraySize" type="U32" constructor="= MAX_U32" />
 			</members>
 		</class>
 
@@ -70,7 +70,7 @@
 
 		<class name="ShaderProgramBinaryVariant">
 			<members>
-				<member name="m_codeBlockIndices" type="U32" array_size="U32(ShaderType::COUNT)" comment="Index in ShaderProgramBinary::m_codeBlocks" constructor="= {}" />
+				<member name="m_codeBlockIndices" type="U32" array_size="U32(ShaderType::COUNT)" comment="Index in ShaderProgramBinary::m_codeBlocks. MAX_U32 means no shader" constructor="= {}" />
 				<member name="m_uniformBlocks" type="WeakArray&lt;ShaderProgramBinaryBlockInstance&gt;" />
 				<member name="m_storageBlocks" type="WeakArray&lt;ShaderProgramBinaryBlockInstance&gt;" />
 				<member name="m_pushConstantBlock" type="ShaderProgramBinaryBlockInstance" pointer="true" constructor="= nullptr" />

+ 389 - 13
src/anki/shader_compiler/ShaderProgramCompiler.cpp

@@ -79,28 +79,49 @@ void ShaderProgramBinaryWrapper::cleanup()
 		}
 		m_alloc.getMemoryPool().free(m_binary->m_mutations.getBegin());
 
+		for(ShaderProgramBinaryBlock& block : m_binary->m_uniformBlocks)
+		{
+			m_alloc.getMemoryPool().free(block.m_variables.getBegin());
+		}
+		m_alloc.getMemoryPool().free(m_binary->m_uniformBlocks.getBegin());
+
+		for(ShaderProgramBinaryBlock& block : m_binary->m_storageBlocks)
+		{
+			m_alloc.getMemoryPool().free(block.m_variables.getBegin());
+		}
+		m_alloc.getMemoryPool().free(m_binary->m_storageBlocks.getBegin());
+
+		if(m_binary->m_pushConstantBlock)
+		{
+			m_alloc.getMemoryPool().free(m_binary->m_pushConstantBlock->m_variables.getBegin());
+			m_alloc.getMemoryPool().free(m_binary->m_pushConstantBlock);
+		}
+
+		m_alloc.getMemoryPool().free(m_binary->m_opaques.getBegin());
+		m_alloc.getMemoryPool().free(m_binary->m_constants.getBegin());
+
 		for(ShaderProgramBinaryVariant& variant : m_binary->m_variants)
 		{
-			for(ShaderProgramBinaryBlock& block : variant.m_reflection.m_uniformBlocks)
+			for(ShaderProgramBinaryBlockInstance& block : variant.m_uniformBlocks)
 			{
 				m_alloc.getMemoryPool().free(block.m_variables.getBegin());
 			}
 
-			for(ShaderProgramBinaryBlock& block : variant.m_reflection.m_storageBlocks)
+			for(ShaderProgramBinaryBlockInstance& block : variant.m_storageBlocks)
 			{
 				m_alloc.getMemoryPool().free(block.m_variables.getBegin());
 			}
 
-			if(variant.m_reflection.m_pushConstantBlock)
+			if(variant.m_pushConstantBlock)
 			{
-				m_alloc.getMemoryPool().free(variant.m_reflection.m_pushConstantBlock->m_variables.getBegin());
+				m_alloc.getMemoryPool().free(variant.m_pushConstantBlock->m_variables.getBegin());
 			}
 
-			m_alloc.getMemoryPool().free(variant.m_reflection.m_uniformBlocks.getBegin());
-			m_alloc.getMemoryPool().free(variant.m_reflection.m_storageBlocks.getBegin());
-			m_alloc.getMemoryPool().free(variant.m_reflection.m_pushConstantBlock);
-			m_alloc.getMemoryPool().free(variant.m_reflection.m_specializationConstants.getBegin());
-			m_alloc.getMemoryPool().free(variant.m_reflection.m_opaques.getBegin());
+			m_alloc.getMemoryPool().free(variant.m_uniformBlocks.getBegin());
+			m_alloc.getMemoryPool().free(variant.m_storageBlocks.getBegin());
+			m_alloc.getMemoryPool().free(variant.m_pushConstantBlock);
+			m_alloc.getMemoryPool().free(variant.m_constants.getBegin());
+			m_alloc.getMemoryPool().free(variant.m_opaques.getBegin());
 		}
 		m_alloc.getMemoryPool().free(m_binary->m_variants.getBegin());
 	}
@@ -151,8 +172,8 @@ static Error compileVariant(ConstWeakArray<MutatorValue> mutation,
 	ShaderProgramBinaryVariant& variant,
 	DynamicArrayAuto<ShaderProgramBinaryCodeBlock>& codeBlocks,
 	DynamicArrayAuto<U64>& codeBlockHashes,
-	GenericMemoryPoolAllocator<U8> tmpAlloc,
-	GenericMemoryPoolAllocator<U8> binaryAlloc)
+	GenericMemoryPoolAllocator<U8>& tmpAlloc,
+	GenericMemoryPoolAllocator<U8>& binaryAlloc)
 {
 	variant = {};
 
@@ -207,8 +228,361 @@ static Error compileVariant(ConstWeakArray<MutatorValue> mutation,
 		spirvBinaries[shaderType] = codeBlocks[variant.m_codeBlockIndices[shaderType]].m_binary;
 	}
 
-	// Do reflection
-	ANKI_CHECK(performSpirvReflection(variant.m_reflection, spirvBinaries, tmpAlloc, binaryAlloc));
+	return Error::NONE;
+}
+
+/// Will be called once per instance.
+class Refl final : public ShaderReflectionVisitorInterface
+{
+public:
+	GenericMemoryPoolAllocator<U8> m_alloc;
+
+	/// Will be stored in the binary
+	/// @{
+
+	/// [blockType][blockIdx]
+	Array<DynamicArrayAuto<ShaderProgramBinaryBlock>, 3> m_blocks = {{m_alloc, m_alloc, m_alloc}};
+
+	/// [blockType][blockIdx]
+	Array<DynamicArrayAuto<DynamicArrayAuto<ShaderProgramBinaryVariable>>, 3> m_vars = {
+		{{m_alloc}, {m_alloc}, {m_alloc}}};
+
+	DynamicArrayAuto<ShaderProgramBinaryOpaque> m_opaque = {m_alloc};
+	DynamicArrayAuto<ShaderProgramBinaryConstant> m_consts = {m_alloc};
+	/// @}
+
+	/// Will be stored in a variant
+	/// @{
+
+	/// [blockType][blockInstanceIdx]
+	Array<DynamicArrayAuto<ShaderProgramBinaryBlockInstance>, 3> m_blockInstances = {{m_alloc, m_alloc, m_alloc}};
+
+	DynamicArrayAuto<ShaderProgramBinaryOpaqueInstance> m_opaqueInstances = {m_alloc};
+	DynamicArrayAuto<ShaderProgramBinaryConstantInstance> m_constInstances = {m_alloc};
+	/// @}
+
+	Refl(const GenericMemoryPoolAllocator<U8>& alloc)
+		: m_alloc(alloc)
+	{
+	}
+
+	Error setCounts(
+		U32 uniformBlockCount, U32 storageBlockCount, U32 opaqueCount, Bool pushConstantBlock, U32 constCount) final
+	{
+		m_blockInstances[0].create(uniformBlockCount);
+		m_blockInstances[1].create(storageBlockCount);
+		if(pushConstantBlock)
+		{
+			m_blockInstances[2].create(1);
+		}
+		m_opaqueInstances.create(opaqueCount);
+		m_constInstances.create(constCount);
+		return Error::NONE;
+	}
+
+	Error visitUniformBlock(U32 idx, CString name, U32 set, U32 binding, U32 size, U32 varCount) final
+	{
+		return visitAnyBlock(idx, name, set, binding, size, varCount, 0);
+	}
+
+	Error visitUniformVariable(U32 blockIdx,
+		U32 idx,
+		CString name,
+		ShaderVariableDataType type,
+		const ShaderVariableBlockInfo& blockInfo) final
+	{
+		return visitAnyVariable(blockIdx, idx, name, type, blockInfo, 0);
+	}
+
+	Error visitStorageBlock(U32 idx, CString name, U32 set, U32 binding, U32 size, U32 varCount) final
+	{
+		return visitAnyBlock(idx, name, set, binding, size, varCount, 1);
+	}
+
+	Error visitStorageVariable(U32 blockIdx,
+		U32 idx,
+		CString name,
+		ShaderVariableDataType type,
+		const ShaderVariableBlockInfo& blockInfo) final
+	{
+		return visitAnyVariable(blockIdx, idx, name, type, blockInfo, 1);
+	}
+
+	Error visitPushConstantsBlock(CString name, U32 size, U32 varCount) final
+	{
+		return visitAnyBlock(0, name, 0, 0, size, varCount, 2);
+	}
+
+	Error visitPushConstant(
+		U32 idx, CString name, ShaderVariableDataType type, const ShaderVariableBlockInfo& blockInfo) final
+	{
+		return visitAnyVariable(0, idx, name, type, blockInfo, 2);
+	}
+
+	Error visitOpaque(
+		U32 instanceIdx, CString name, ShaderVariableDataType type, U32 set, U32 binding, U32 arraySize) final
+	{
+		// Find the opaque
+		U32 opaqueIdx = MAX_U32;
+		for(U32 i = 0; i < m_opaque.getSize(); ++i)
+		{
+			if(name == m_opaque[i].m_name.getBegin())
+			{
+				if(type != m_opaque[i].m_type || set != m_opaque[i].m_set || binding != m_opaque[i].m_binding)
+				{
+					ANKI_SHADER_COMPILER_LOGE(
+						"The set, binding and type can't difer between shader variants for opaque: %s", name.cstr());
+					return Error::USER_DATA;
+				}
+
+				opaqueIdx = i;
+				break;
+			}
+		}
+
+		// Create the opaque
+		if(opaqueIdx == MAX_U32)
+		{
+			ShaderProgramBinaryOpaque& o = *m_opaque.emplaceBack();
+			ANKI_CHECK(setName(name, o.m_name));
+			o.m_type = type;
+			o.m_binding = binding;
+			o.m_set = set;
+
+			opaqueIdx = m_opaque.getSize() - 1;
+		}
+
+		// Create the instance
+		ShaderProgramBinaryOpaqueInstance& instance = *m_opaqueInstances.emplaceBack();
+		instance.m_index = opaqueIdx;
+		instance.m_arraySize = arraySize;
+
+		return Error::NONE;
+	}
+
+	Error visitConstant(
+		U32 instanceIdx, CString name, ShaderVariableDataType type, U32 constantId, ShaderTypeBit stages) final
+	{
+		// Find const
+		U32 constIdx = MAX_U32;
+		for(U32 i = 0; i < m_consts.getSize(); ++i)
+		{
+			if(name == m_consts[i].m_name.getBegin())
+			{
+				if(type != m_consts[i].m_type || constantId != m_consts[i].m_constantId
+					|| m_consts[i].m_shaderStages != stages)
+				{
+					ANKI_SHADER_COMPILER_LOGE(
+						"The type, constantId and stages can't difer between shader variants for const: %s",
+						name.cstr());
+					return Error::USER_DATA;
+				}
+
+				constIdx = i;
+				break;
+			}
+		}
+
+		// Create the const
+		if(constIdx == MAX_U32)
+		{
+			ShaderProgramBinaryConstant& c = *m_consts.emplaceBack();
+			ANKI_CHECK(setName(name, c.m_name));
+			c.m_type = type;
+			c.m_constantId = constantId;
+			c.m_shaderStages = stages;
+
+			constIdx = m_consts.getSize() - 1;
+		}
+
+		// Create the instance
+		ShaderProgramBinaryConstantInstance& instance = *m_constInstances.emplaceBack();
+		instance.m_index = constIdx;
+
+		return Error::NONE;
+	}
+
+	static ANKI_USE_RESULT Error setName(CString in, Array<char, MAX_SHADER_BINARY_NAME_LENGTH + 1>& out)
+	{
+		if(in.getLength() + 1 > MAX_SHADER_BINARY_NAME_LENGTH)
+		{
+			ANKI_SHADER_COMPILER_LOGE("Name too long: %s", in.cstr());
+			return Error::USER_DATA;
+		}
+		else if(in.getLength() == 0)
+		{
+			ANKI_SHADER_COMPILER_LOGE("Found an empty string as name");
+			return Error::USER_DATA;
+		}
+		else
+		{
+			memcpy(out.getBegin(), in.getBegin(), in.getLength() + 1);
+		}
+		return Error::NONE;
+	}
+
+	static ANKI_USE_RESULT Error findBlock(
+		CString name, U32 set, U32 binding, ConstWeakArray<ShaderProgramBinaryBlock> arr, U32& idx)
+	{
+		idx = MAX_U32;
+
+		for(U32 i = 0; i < arr.getSize(); ++i)
+		{
+			const ShaderProgramBinaryBlock& block = arr[i];
+			if(block.m_name.getBegin() == name)
+			{
+				if(set != block.m_set || binding != block.m_binding)
+				{
+					ANKI_SHADER_COMPILER_LOGE(
+						"The set and binding can't difer between shader variants for block: %s", name.cstr());
+					return Error::USER_DATA;
+				}
+
+				idx = i;
+				break;
+			}
+
+			return Error::NONE;
+		}
+
+		return Error::NONE;
+	}
+
+	Error visitAnyBlock(U32 blockInstanceIdx, CString name, U32 set, U32 binding, U32 size, U32 varSize, U32 blockType)
+	{
+		// Init the block
+		U32 blockIdx;
+		ANKI_CHECK(findBlock(name, set, binding, m_blocks[blockType], blockIdx));
+		if(blockIdx == MAX_U32)
+		{
+			// Not found, create it
+			ShaderProgramBinaryBlock& block = *m_blocks[blockType].emplaceBack();
+			ANKI_CHECK(setName(name, block.m_name));
+			block.m_set = set;
+			block.m_binding = binding;
+			blockIdx = m_blocks[blockType].getSize() - 1;
+		}
+
+		// Init the instance
+		ShaderProgramBinaryBlockInstance& instance = m_blockInstances[blockType][blockInstanceIdx];
+		instance.m_index = blockIdx;
+		instance.m_size = size;
+		instance.m_variables.setArray(m_alloc.newArray<ShaderProgramBinaryVariableInstance>(varSize), varSize);
+
+		return Error::NONE;
+	}
+
+	Error visitAnyVariable(U32 blockInstanceIdx,
+		U32 varInstanceIdx,
+		CString name,
+		ShaderVariableDataType type,
+		const ShaderVariableBlockInfo& blockInfo,
+		U32 blockType)
+	{
+		// Find the variable
+		U32 varIdx = MAX_U32;
+		const U32 blockIdx = m_blockInstances[blockType][blockInstanceIdx].m_index;
+		for(U32 i = 0; i < m_vars[blockType][blockIdx].getSize(); ++i)
+		{
+			const ShaderProgramBinaryVariable& var = m_vars[blockType][blockIdx][i];
+			if(var.m_name.getBegin() == name)
+			{
+				if(var.m_type != type)
+				{
+					ANKI_SHADER_COMPILER_LOGE(
+						"The type should not differ between variants for variable: %s", name.cstr());
+					return Error::USER_DATA;
+				}
+
+				varIdx = i;
+				break;
+			}
+		}
+
+		// Create the variable
+		if(varIdx == MAX_U32)
+		{
+			ShaderProgramBinaryVariable& var = *m_vars[blockType][blockIdx].emplaceBack();
+			ANKI_CHECK(setName(name, var.m_name));
+			var.m_type = type;
+
+			varIdx = m_vars[blockType][blockIdx].getSize() - 1;
+		}
+
+		// Init the instance
+		ShaderProgramBinaryVariableInstance& instance =
+			m_blockInstances[blockType][blockInstanceIdx].m_variables[varInstanceIdx];
+		instance.m_blockInfo = blockInfo;
+		instance.m_index = varIdx;
+
+		return Error::NONE;
+	}
+};
+
+static Error doReflection(
+	ShaderProgramBinary& binary, GenericMemoryPoolAllocator<U8>& tmpAlloc, GenericMemoryPoolAllocator<U8>& binaryAlloc)
+{
+	ANKI_ASSERT(binary.m_variants.getSize() > 0);
+
+	Refl refl(binaryAlloc);
+
+	for(ShaderProgramBinaryVariant& variant : binary.m_variants)
+	{
+		Array<ConstWeakArray<U8, PtrSize>, U32(ShaderType::COUNT)> spirvs;
+		for(ShaderType stage : EnumIterable<ShaderType>())
+		{
+			if(variant.m_codeBlockIndices[stage] != MAX_U32)
+			{
+				spirvs[stage] = binary.m_codeBlocks[variant.m_codeBlockIndices[stage]].m_binary;
+			}
+		}
+
+		ANKI_CHECK(performSpirvReflection(spirvs, tmpAlloc, refl));
+
+		// Store the instances
+		if(refl.m_blockInstances[0].getSize())
+		{
+			ShaderProgramBinaryBlockInstance* instances;
+			U32 size, storageSize;
+			refl.m_blockInstances[0].moveAndReset(instances, size, storageSize);
+			variant.m_uniformBlocks.setArray(instances, size);
+		}
+
+		if(refl.m_blockInstances[1].getSize())
+		{
+			ShaderProgramBinaryBlockInstance* instances;
+			U32 size, storageSize;
+			refl.m_blockInstances[1].moveAndReset(instances, size, storageSize);
+			variant.m_storageBlocks.setArray(instances, size);
+		}
+
+		if(refl.m_blockInstances[2].getSize())
+		{
+			ShaderProgramBinaryBlockInstance* instances;
+			U32 size, storageSize;
+			refl.m_blockInstances[2].moveAndReset(instances, size, storageSize);
+			ANKI_ASSERT(size == 1);
+			variant.m_pushConstantBlock = instances;
+		}
+
+		if(refl.m_opaqueInstances.getSize())
+		{
+			ShaderProgramBinaryOpaqueInstance* instances;
+			U32 size, storageSize;
+			refl.m_opaqueInstances.moveAndReset(instances, size, storageSize);
+			variant.m_opaques.setArray(instances, size);
+		}
+
+		if(refl.m_constInstances.getSize())
+		{
+			ShaderProgramBinaryConstantInstance* instances;
+			U32 size, storageSize;
+			refl.m_constInstances.moveAndReset(instances, size, storageSize);
+			variant.m_constants.setArray(instances, size);
+		}
+	}
+
+	// TODO
 
 	return Error::NONE;
 }
@@ -414,6 +788,7 @@ Error compileShaderProgram(CString fname,
 
 #define ANKI_TAB "    "
 
+#if 0
 static void disassembleBlock(const ShaderProgramBinaryBlock& block, StringListAuto& lines)
 {
 	lines.pushBackSprintf(ANKI_TAB ANKI_TAB ANKI_TAB "%-32s set %4u binding %4u size %4u\n",
@@ -589,6 +964,7 @@ void dumpShaderProgramBinary(const ShaderProgramBinary& binary, StringAuto& huma
 
 	lines.join("", humanReadable);
 }
+#endif
 
 #undef ANKI_TAB
 

+ 31 - 22
src/anki/shader_compiler/ShaderProgramReflection.cpp

@@ -641,51 +641,60 @@ Error SpirvReflector::performSpirvReflection(Array<ConstWeakArray<U8, PtrSize>,
 	}
 
 	// Inform through the interface
-	interface.setUniformBlockCount(uniformBlocks.getSize());
-	for(const Block& block : uniformBlocks)
+	ANKI_CHECK(interface.setCounts(uniformBlocks.getSize(),
+		storageBlocks.getSize(),
+		opaques.getSize(),
+		pushConstantBlock.getSize() == 1,
+		specializationConstants.getSize()));
+
+	for(U32 i = 0; i < uniformBlocks.getSize(); ++i)
 	{
-		interface.visitUniformBlock(block.m_name, block.m_set, block.m_binding, block.m_size);
+		const Block& block = uniformBlocks[i];
+		ANKI_CHECK(interface.visitUniformBlock(
+			i, block.m_name, block.m_set, block.m_binding, block.m_size, block.m_vars.getSize()));
 
-		interface.setUniformBlockVariableCount(block.m_vars.getSize());
-		for(const Var& var : block.m_vars)
+		for(U32 j = 0; j < block.m_vars.getSize(); ++j)
 		{
-			interface.visitUniformVariable(var.m_name, var.m_type, var.m_blockInfo);
+			const Var& var = block.m_vars[j];
+			ANKI_CHECK(interface.visitUniformVariable(i, j, var.m_name, var.m_type, var.m_blockInfo));
 		}
 	}
 
-	interface.setStorageBlockCount(storageBlocks.getSize());
-	for(const Block& block : storageBlocks)
+	for(U32 i = 0; i < storageBlocks.getSize(); ++i)
 	{
-		interface.visitStorageBlock(block.m_name, block.m_set, block.m_binding, block.m_size);
+		const Block& block = storageBlocks[i];
+		ANKI_CHECK(interface.visitStorageBlock(
+			i, block.m_name, block.m_set, block.m_binding, block.m_size, block.m_vars.getSize()));
 
-		interface.setStorageBlockVariableCount(block.m_vars.getSize());
-		for(const Var& var : block.m_vars)
+		for(U32 j = 0; j < block.m_vars.getSize(); ++j)
 		{
-			interface.visitStorageVariable(var.m_name, var.m_type, var.m_blockInfo);
+			const Var& var = block.m_vars[j];
+			ANKI_CHECK(interface.visitStorageVariable(i, j, var.m_name, var.m_type, var.m_blockInfo));
 		}
 	}
 
 	if(pushConstantBlock.getSize() == 1)
 	{
-		interface.visitPushConstantsBlock(
-			pushConstantBlock[0].m_name, pushConstantBlock[0].m_size, pushConstantBlock[0].m_vars.getSize());
+		ANKI_CHECK(interface.visitPushConstantsBlock(
+			pushConstantBlock[0].m_name, pushConstantBlock[0].m_size, pushConstantBlock[0].m_vars.getSize()));
 
-		for(const Var& var : pushConstantBlock[0].m_vars)
+		for(U32 j = 0; j < pushConstantBlock[0].m_vars.getSize(); ++j)
 		{
-			interface.visitPushConstant(var.m_name, var.m_type, var.m_blockInfo);
+			const Var& var = pushConstantBlock[0].m_vars[j];
+			ANKI_CHECK(interface.visitPushConstant(j, var.m_name, var.m_type, var.m_blockInfo));
 		}
 	}
 
-	interface.setOpaqueCount(opaques.getSize());
-	for(const Opaque& o : opaques)
+	for(U32 i = 0; i < opaques.getSize(); ++i)
 	{
-		interface.visitOpaque(o.m_name, o.m_type, o.m_set, o.m_binding, o.m_arraySize);
+		const Opaque& o = opaques[i];
+		ANKI_CHECK(interface.visitOpaque(i, o.m_name, o.m_type, o.m_set, o.m_binding, o.m_arraySize));
 	}
 
-	interface.setConstantCount(specializationConstants.getSize());
-	for(const Const& c : specializationConstants)
+	for(U32 i = 0; i < specializationConstants.getSize(); ++i)
 	{
-		interface.visitConstant(c.m_name, c.m_type, c.m_constantId, c.m_shaderStages);
+		const Const& c = specializationConstants[i];
+		ANKI_CHECK(interface.visitConstant(i, c.m_name, c.m_type, c.m_constantId, c.m_shaderStages));
 	}
 
 	return Error::NONE;

+ 17 - 22
src/anki/shader_compiler/ShaderProgramReflection.h

@@ -20,36 +20,31 @@ namespace anki
 class ShaderReflectionVisitorInterface
 {
 public:
-	virtual void setUniformBlockCount(U32 count) = 0;
+	virtual ANKI_USE_RESULT Error setCounts(
+		U32 uniformBlockCount, U32 storageBlockCount, U32 opaqueCount, Bool pushConstantBlock, U32 constsCount) = 0;
 
-	virtual void visitUniformBlock(CString name, U32 set, U32 binding, U32 size) = 0;
+	virtual ANKI_USE_RESULT Error visitUniformBlock(
+		U32 idx, CString name, U32 set, U32 binding, U32 size, U32 varCount) = 0;
 
-	virtual void setUniformBlockVariableCount(U32 count) = 0;
+	virtual ANKI_USE_RESULT Error visitUniformVariable(
+		U32 blockIdx, U32 idx, CString name, ShaderVariableDataType type, const ShaderVariableBlockInfo& blockInfo) = 0;
 
-	virtual void visitUniformVariable(
-		CString name, ShaderVariableDataType type, const ShaderVariableBlockInfo& blockInfo) = 0;
+	virtual ANKI_USE_RESULT Error visitStorageBlock(
+		U32 idx, CString name, U32 set, U32 binding, U32 size, U32 varCount) = 0;
 
-	virtual void setStorageBlockCount(U32 count) = 0;
+	virtual ANKI_USE_RESULT Error visitStorageVariable(
+		U32 blockIdx, U32 idx, CString name, ShaderVariableDataType type, const ShaderVariableBlockInfo& blockInfo) = 0;
 
-	virtual void visitStorageBlock(CString name, U32 set, U32 binding, U32 size) = 0;
+	virtual ANKI_USE_RESULT Error visitPushConstantsBlock(CString name, U32 size, U32 varCount) = 0;
 
-	virtual void setStorageBlockVariableCount(U32 count) = 0;
+	virtual ANKI_USE_RESULT Error visitPushConstant(
+		U32 idx, CString name, ShaderVariableDataType type, const ShaderVariableBlockInfo& blockInfo) = 0;
 
-	virtual void visitStorageVariable(
-		CString name, ShaderVariableDataType type, const ShaderVariableBlockInfo& blockInfo) = 0;
+	virtual ANKI_USE_RESULT Error visitOpaque(
+		U32 idx, CString name, ShaderVariableDataType type, U32 set, U32 binding, U32 arraySize) = 0;
 
-	virtual void visitPushConstantsBlock(CString name, U32 size, U32 varCount) = 0;
-
-	virtual void visitPushConstant(
-		CString name, ShaderVariableDataType type, const ShaderVariableBlockInfo& blockInfo) = 0;
-
-	virtual void setOpaqueCount(U32 count) = 0;
-
-	virtual void visitOpaque(CString name, ShaderVariableDataType type, U32 set, U32 binding, U32 arraySize) = 0;
-
-	virtual void setConstantCount(U32 count) = 0;
-
-	virtual void visitConstant(CString name, ShaderVariableDataType type, U32 constantId, ShaderTypeBit stages) = 0;
+	virtual ANKI_USE_RESULT Error visitConstant(
+		U32 idx, CString name, ShaderVariableDataType type, U32 constantId, ShaderTypeBit stages) = 0;
 };
 
 /// Does reflection using SPIR-V.