Browse Source

Remove the rewrite_mutation and replace it with skip_mutation. This fixes a bug with alpha test as well

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
3b4feab878

+ 17 - 0
AnKi/Resource/MaterialResource.cpp

@@ -383,6 +383,11 @@ Error MaterialResource::createVars(Program& prog)
 	{
 		const ShaderProgramResourceVariant* variant;
 		prog.m_prog->getOrCreateVariant(initInfo, variant);
+		if(!variant)
+		{
+			// Skipped variant
+			continue;
+		}
 
 		// Add opaque vars
 		for(const ShaderProgramBinaryOpaqueInstance& instance : variant->getBinaryVariant().m_opaques)
@@ -785,8 +790,15 @@ const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey&
 	ANKI_ASSERT(m_techniqueToProgram[key.getRenderingTechnique()] != MAX_U8);
 	const Program& prog = m_programs[m_techniqueToProgram[key.getRenderingTechnique()]];
 
+	// Sanitize the key
 	key.setLod(min<U32>(prog.m_lodCount - 1, key.getLod()));
 
+	if(key.getRenderingTechnique() == RenderingTechnique::GBUFFER_EARLY_Z
+	   || key.getRenderingTechnique() == RenderingTechnique::SHADOW)
+	{
+		key.setLod(0);
+	}
+
 	ANKI_ASSERT(!key.getSkinned() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::BONES)));
 	ANKI_ASSERT(!key.getVelocity() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::VELOCITY)));
 
@@ -838,6 +850,11 @@ const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey&
 	const ShaderProgramResourceVariant* progVariant;
 	prog.m_prog->getOrCreateVariant(initInfo, progVariant);
 
+	if(!progVariant)
+	{
+		ANKI_RESOURCE_LOGF("Fetched skipped mutation on program %s", getFilename().cstr());
+	}
+
 	variant.m_prog = progVariant->getProgram();
 
 	if(!!(RenderingTechniqueBit(1 << key.getRenderingTechnique()) & RenderingTechniqueBit::ALL_RT))

+ 27 - 17
AnKi/Resource/ShaderProgramResource.cpp

@@ -230,11 +230,10 @@ void ShaderProgramResource::getOrCreateVariant(const ShaderProgramResourceVarian
 		RLockGuard<RWMutex> lock(m_mtx);
 
 		auto it = m_variants.find(hash);
-		variant = (it != m_variants.getEnd()) ? *it : nullptr;
-
-		if(variant != nullptr)
+		if(it != m_variants.getEnd())
 		{
 			// Done
+			variant = *it;
 			return;
 		}
 	}
@@ -244,22 +243,24 @@ void ShaderProgramResource::getOrCreateVariant(const ShaderProgramResourceVarian
 
 	// Check again
 	auto it = m_variants.find(hash);
-	variant = (it != m_variants.getEnd()) ? *it : nullptr;
-	if(variant != nullptr)
+	if(it != m_variants.getEnd())
 	{
 		// Done
+		variant = *it;
 		return;
 	}
 
 	// Create
-	ShaderProgramResourceVariant* v = getAllocator().newInstance<ShaderProgramResourceVariant>();
-	initVariant(info, *v);
-	m_variants.emplace(getAllocator(), hash, v);
+	ShaderProgramResourceVariant* v = createNewVariant(info);
+	if(v)
+	{
+		m_variants.emplace(getAllocator(), hash, v);
+	}
 	variant = v;
 }
 
-void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitInfo& info,
-										ShaderProgramResourceVariant& variant) const
+ShaderProgramResourceVariant*
+ShaderProgramResource::createNewVariant(const ShaderProgramResourceVariantInitInfo& info) const
 {
 	const ShaderProgramBinary& binary = m_binary.getBinary();
 
@@ -277,6 +278,12 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 		{
 			if(mutation.m_hash == mutationHash)
 			{
+				if(mutation.m_variantIndex == MAX_U32)
+				{
+					// Skipped mutation, nothing to create
+					return nullptr;
+				}
+
 				binaryVariant = &binary.m_variants[mutation.m_variantIndex];
 				break;
 			}
@@ -288,7 +295,8 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 		binaryVariant = &binary.m_variants[0];
 	}
 	ANKI_ASSERT(binaryVariant);
-	variant.m_binaryVariant = binaryVariant;
+	ShaderProgramResourceVariant* variant = getAllocator().newInstance<ShaderProgramResourceVariant>();
+	variant->m_binaryVariant = binaryVariant;
 
 	// Set the constant values
 	Array<ShaderSpecializationConstValue, 64> constValues;
@@ -325,7 +333,7 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 			if(binaryVariant->m_workgroupSizes[i] != MAX_U32)
 			{
 				// Size didn't come from specialization const
-				variant.m_workgroupSizes[i] = binaryVariant->m_workgroupSizes[i];
+				variant->m_workgroupSizes[i] = binaryVariant->m_workgroupSizes[i];
 			}
 			else
 			{
@@ -350,13 +358,13 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 						const I32 value = info.m_constantValues[i].m_ivec4[component];
 						ANKI_ASSERT(value > 0);
 
-						variant.m_workgroupSizes[i] = U32(value);
+						variant->m_workgroupSizes[i] = U32(value);
 						break;
 					}
 				}
 			}
 
-			ANKI_ASSERT(variant.m_workgroupSizes[i] != MAX_U32);
+			ANKI_ASSERT(variant->m_workgroupSizes[i] != MAX_U32);
 		}
 	}
 
@@ -402,7 +410,7 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 		}
 
 		// Create the program
-		variant.m_prog = getManager().getGrManager().newShaderProgram(progInf);
+		variant->m_prog = getManager().getGrManager().newShaderProgram(progInf);
 	}
 	else
 	{
@@ -424,11 +432,13 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 		}
 		ANKI_ASSERT(foundLib);
 
-		variant.m_prog = foundLib->getShaderProgram();
+		variant->m_prog = foundLib->getShaderProgram();
 
 		// Set the group handle index
-		variant.m_shaderGroupHandleIndex = foundLib->getShaderGroupHandleIndex(getFilename(), mutationHash);
+		variant->m_shaderGroupHandleIndex = foundLib->getShaderGroupHandleIndex(getFilename(), mutationHash);
 	}
+
+	return variant;
 }
 
 } // end namespace anki

+ 3 - 2
AnKi/Resource/ShaderProgramResource.h

@@ -238,7 +238,8 @@ public:
 		return m_binary.getBinary();
 	}
 
-	/// Get or create a graphics shader program variant.
+	/// Get or create a graphics shader program variant. If returned variant is nullptr then it means that the mutation
+	/// is skipped and thus incorrect.
 	/// @note It's thread-safe.
 	void getOrCreateVariant(const ShaderProgramResourceVariantInitInfo& info,
 							const ShaderProgramResourceVariant*& variant) const;
@@ -272,7 +273,7 @@ private:
 
 	ShaderTypeBit m_shaderStages = ShaderTypeBit::NONE;
 
-	void initVariant(const ShaderProgramResourceVariantInitInfo& info, ShaderProgramResourceVariant& variant) const;
+	ShaderProgramResourceVariant* createNewVariant(const ShaderProgramResourceVariantInitInfo& info) const;
 
 	static ANKI_USE_RESULT Error parseConst(CString constName, U32& componentIdx, U32& componentCount, CString& name);
 };

+ 11 - 48
AnKi/ShaderCompiler/ShaderProgramCompiler.cpp

@@ -1056,8 +1056,7 @@ Error compileShaderProgramInternal(CString fname, ShaderProgramFilesystemInterfa
 	if(parser.getMutators().getSize() > 0)
 	{
 		// Initialize
-		DynamicArrayAuto<MutatorValue> originalMutationValues(tempAllocator, parser.getMutators().getSize());
-		DynamicArrayAuto<MutatorValue> rewrittenMutationValues(tempAllocator, parser.getMutators().getSize());
+		DynamicArrayAuto<MutatorValue> mutationValues(tempAllocator, parser.getMutators().getSize());
 		DynamicArrayAuto<U32> dials(tempAllocator, parser.getMutators().getSize(), 0);
 		DynamicArrayAuto<ShaderProgramBinaryVariant> variants(binaryAllocator);
 		DynamicArrayAuto<ShaderProgramBinaryCodeBlock> codeBlocks(binaryAllocator);
@@ -1079,30 +1078,28 @@ Error compileShaderProgramInternal(CString fname, ShaderProgramFilesystemInterfa
 			// Create the mutation
 			for(U32 i = 0; i < parser.getMutators().getSize(); ++i)
 			{
-				originalMutationValues[i] = parser.getMutators()[i].getValues()[dials[i]];
-				rewrittenMutationValues[i] = originalMutationValues[i];
+				mutationValues[i] = parser.getMutators()[i].getValues()[dials[i]];
 			}
 
 			ShaderProgramBinaryMutation& mutation = mutations[mutationCount++];
-			binaryAllocator.newArray(originalMutationValues.getSize(), mutation.m_values);
-			memcpy(mutation.m_values.getBegin(), originalMutationValues.getBegin(),
-				   originalMutationValues.getSizeInBytes());
+			binaryAllocator.newArray(mutationValues.getSize(), mutation.m_values);
+			memcpy(mutation.m_values.getBegin(), mutationValues.getBegin(), mutationValues.getSizeInBytes());
 
-			mutation.m_hash = computeHash(originalMutationValues.getBegin(), originalMutationValues.getSizeInBytes());
+			mutation.m_hash = computeHash(mutationValues.getBegin(), mutationValues.getSizeInBytes());
 			ANKI_ASSERT(mutation.m_hash > 0);
 
-			const Bool rewritten = parser.rewriteMutation(
-				WeakArray<MutatorValue>(rewrittenMutationValues.getBegin(), rewrittenMutationValues.getSize()));
-
-			// Create the variant
-			if(!rewritten)
+			if(parser.skipMutation(mutationValues))
+			{
+				mutation.m_variantIndex = MAX_U32;
+			}
+			else
 			{
 				// New and unique mutation and thus variant, add it
 
 				ShaderProgramBinaryVariant& variant = *variants.emplaceBack();
 				baseVariant = (baseVariant == nullptr) ? variants.getBegin() : baseVariant;
 
-				compileVariantAsync(originalMutationValues, parser, variant, codeBlocks, codeBlockHashes, tempAllocator,
+				compileVariantAsync(mutationValues, parser, variant, codeBlocks, codeBlockHashes, tempAllocator,
 									binaryAllocator, taskManager, mtx, errorAtomic);
 
 				mutation.m_variantIndex = variants.getSize() - 1;
@@ -1110,40 +1107,6 @@ Error compileShaderProgramInternal(CString fname, ShaderProgramFilesystemInterfa
 				ANKI_ASSERT(mutationHashToIdx.find(mutation.m_hash) == mutationHashToIdx.getEnd());
 				mutationHashToIdx.emplace(mutation.m_hash, mutationCount - 1);
 			}
-			else
-			{
-				// Check if the rewritten mutation exists
-				const U64 otherMutationHash =
-					computeHash(rewrittenMutationValues.getBegin(), rewrittenMutationValues.getSizeInBytes());
-				auto it = mutationHashToIdx.find(otherMutationHash);
-
-				ShaderProgramBinaryVariant* variant = nullptr;
-				if(it == mutationHashToIdx.getEnd())
-				{
-					// Rewrite variant not found, create it
-
-					variant = variants.emplaceBack();
-					baseVariant = (baseVariant == nullptr) ? variants.getBegin() : baseVariant;
-
-					compileVariantAsync(originalMutationValues, parser, *variant, codeBlocks, codeBlockHashes,
-										tempAllocator, binaryAllocator, taskManager, mtx, errorAtomic);
-
-					ShaderProgramBinaryMutation& otherMutation = mutations[mutationCount++];
-					binaryAllocator.newArray(rewrittenMutationValues.getSize(), otherMutation.m_values);
-					memcpy(otherMutation.m_values.getBegin(), rewrittenMutationValues.getBegin(),
-						   rewrittenMutationValues.getSizeInBytes());
-
-					mutation.m_hash = otherMutationHash;
-					mutation.m_variantIndex = variants.getSize() - 1;
-
-					it = mutationHashToIdx.emplace(otherMutationHash, mutationCount - 1);
-				}
-
-				// Setup the new mutation
-				mutation.m_variantIndex = mutations[*it].m_variantIndex;
-
-				mutationHashToIdx.emplace(mutation.m_hash, U32(&mutation - mutations.getBegin()));
-			}
 		} while(!spinDials(dials, parser.getMutators()));
 
 		ANKI_ASSERT(mutationCount == mutations.getSize());

+ 62 - 146
AnKi/ShaderCompiler/ShaderProgramParser.cpp

@@ -281,6 +281,17 @@ Vec4 pow(Vec4 a, F32 b)
 
 static const U64 SHADER_HEADER_HASH = computeHash(SHADER_HEADER, sizeof(SHADER_HEADER));
 
+class ShaderProgramParser::PartialMutationSkip
+{
+public:
+	DynamicArrayAuto<MutatorValue> m_partialMutation;
+
+	PartialMutationSkip(const GenericMemoryPoolAllocator<U8>& alloc)
+		: m_partialMutation(alloc)
+	{
+	}
+};
+
 ShaderProgramParser::ShaderProgramParser(CString fname, ShaderProgramFilesystemInterface* fsystem,
 										 GenericMemoryPoolAllocator<U8> alloc,
 										 const ShaderCompilerOptions& compilerOptions)
@@ -567,143 +578,60 @@ Error ShaderProgramParser::parsePragmaReflect(const StringAuto* begin, const Str
 	return Error::NONE;
 }
 
-Error ShaderProgramParser::parsePragmaRewriteMutation(const StringAuto* begin, const StringAuto* end, CString line,
-													  CString fname)
+Error ShaderProgramParser::parsePragmaSkipMutation(const StringAuto* begin, const StringAuto* end, CString line,
+												   CString fname)
 {
 	ANKI_ASSERT(begin && end);
 
 	// Some basic sanity checks
 	const U tokenCount = U(end - begin);
-	constexpr U minTokenCount = 2 + 1 + 2; // Mutator + value + "to" + mutator + value
-	if(tokenCount < minTokenCount)
+	// One pair doesn't make sence so it's: mutator_name_0 + mutator_value_0 + mutator_name_1 + mutator_value_1
+	constexpr U minTokenCount = 2 + 2;
+	if(tokenCount < minTokenCount || (tokenCount % 2) != 0)
 	{
 		ANKI_PP_ERROR_MALFORMED();
 	}
 
-	MutationRewrite& rewrite = *m_mutationRewrites.emplaceBack(m_alloc);
-	Bool servingFrom = true;
+	PartialMutationSkip& skip = *m_skipMutations.emplaceBack(m_alloc);
+	skip.m_partialMutation.create(m_mutators.getSize(), std::numeric_limits<MutatorValue>::max());
 
 	do
 	{
-		if(*begin == "to")
+		// Get mutator name
+		const CString mutatorName = *begin;
+		U32 mutatorIndex = MAX_U32;
+		for(U32 i = 0; i < m_mutators.getSize(); ++i)
 		{
-			if(servingFrom == false)
+			if(m_mutators[i].m_name == mutatorName)
 			{
-				ANKI_PP_ERROR_MALFORMED();
+				mutatorIndex = i;
+				break;
 			}
-
-			servingFrom = false;
 		}
-		else
-		{
-			// Mutator & value
-
-			// Get mutator and value
-			const CString mutatorName = *begin;
-			++begin;
-			if(begin == end)
-			{
-				ANKI_PP_ERROR_MALFORMED();
-			}
-			const CString valueStr = *begin;
-			MutatorValue value;
-			if(valueStr.toNumber(value))
-			{
-				ANKI_PP_ERROR_MALFORMED_MSG("Malformed value");
-			}
-
-			// Get or create new record
-			if(servingFrom)
-			{
-				MutationRewrite::Record& rec = *rewrite.m_records.emplaceBack();
-				for(U32 i = 0; i < m_mutators.getSize(); ++i)
-				{
-					if(m_mutators[i].getName() == mutatorName)
-					{
-						rec.m_mutatorIndex = i;
-						break;
-					}
-				}
 
-				if(rec.m_mutatorIndex == MAX_U32)
-				{
-					ANKI_PP_ERROR_MALFORMED_MSG("Mutator not found");
-				}
-
-				if(!mutatorHasValue(m_mutators[rec.m_mutatorIndex], value))
-				{
-					ANKI_PP_ERROR_MALFORMED_MSG("Incorect value for mutator");
-				}
-
-				rec.m_valueFrom = value;
-			}
-			else
-			{
-				Bool found = false;
-				for(MutationRewrite::Record& rec : rewrite.m_records)
-				{
-					if(m_mutators[rec.m_mutatorIndex].m_name == mutatorName)
-					{
-						if(!mutatorHasValue(m_mutators[rec.m_mutatorIndex], value))
-						{
-							ANKI_PP_ERROR_MALFORMED_MSG("Incorect value for mutator");
-						}
-
-						rec.m_valueTo = value;
-						found = true;
-						break;
-					}
-				}
-
-				if(!found)
-				{
-					ANKI_PP_ERROR_MALFORMED();
-				}
-			}
+		if(mutatorIndex == MAX_U32)
+		{
+			ANKI_PP_ERROR_MALFORMED_MSG("Mutator not found");
 		}
 
+		// Get mutator value
 		++begin;
-	} while(begin < end && !tokenIsComment(*begin));
-
-	// Sort for some later cross checking
-	std::sort(rewrite.m_records.getBegin(), rewrite.m_records.getEnd(),
-			  [](const MutationRewrite::Record& a, const MutationRewrite::Record& b) {
-				  return a.m_mutatorIndex < b.m_mutatorIndex;
-			  });
-
-	// More cross checking
-	for(U32 i = 1; i < rewrite.m_records.getSize(); ++i)
-	{
-		if(rewrite.m_records[i - 1].m_mutatorIndex == rewrite.m_records[i].m_mutatorIndex)
+		const CString valueStr = *begin;
+		MutatorValue value;
+		if(valueStr.toNumber(value))
 		{
-			ANKI_PP_ERROR_MALFORMED_MSG("Mutator appeared more than once");
+			ANKI_PP_ERROR_MALFORMED_MSG("Malformed mutator value");
 		}
-	}
 
-	for(U32 i = 0; i < m_mutationRewrites.getSize() - 1; ++i)
-	{
-		const MutationRewrite& other = m_mutationRewrites[i];
-
-		if(other.m_records.getSize() != rewrite.m_records.getSize())
+		if(!mutatorHasValue(m_mutators[mutatorIndex], value))
 		{
-			continue;
+			ANKI_PP_ERROR_MALFORMED_MSG("Mutator value incorrect");
 		}
 
-		Bool same = true;
-		for(U32 j = 0; j < rewrite.m_records.getSize(); ++j)
-		{
-			if(rewrite.m_records[j] != other.m_records[j])
-			{
-				same = false;
-				break;
-			}
-		}
+		skip.m_partialMutation[mutatorIndex] = value;
 
-		if(same)
-		{
-			ANKI_PP_ERROR_MALFORMED_MSG("Mutation already exists");
-		}
-	}
+		++begin;
+	} while(begin < end && !tokenIsComment(*begin));
 
 	return Error::NONE;
 }
@@ -823,10 +751,10 @@ Error ShaderProgramParser::parseLine(CString line, CString fname, Bool& foundPra
 				ANKI_CHECK(checkNoActiveStruct());
 				ANKI_CHECK(parsePragmaEnd(token + 1, end, line, fname));
 			}
-			else if(*token == "rewrite_mutation")
+			else if(*token == "skip_mutation")
 			{
 				ANKI_CHECK(checkNoActiveStruct());
-				ANKI_CHECK(parsePragmaRewriteMutation(token + 1, end, line, fname));
+				ANKI_CHECK(parsePragmaSkipMutation(token + 1, end, line, fname));
 			}
 			else if(*token == "library")
 			{
@@ -1324,54 +1252,42 @@ Error ShaderProgramParser::generateVariant(ConstWeakArray<MutatorValue> mutation
 	return Error::NONE;
 }
 
-Bool ShaderProgramParser::rewriteMutation(WeakArray<MutatorValue> mutation) const
+Bool ShaderProgramParser::mutatorHasValue(const ShaderProgramParserMutator& mutator, MutatorValue value)
 {
-	// Checks
-	ANKI_ASSERT(mutation.getSize() == m_mutators.getSize());
-	for(U32 i = 0; i < mutation.getSize(); ++i)
+	for(MutatorValue v : mutator.m_values)
 	{
-		ANKI_ASSERT(mutatorHasValue(m_mutators[i], mutation[i]));
+		if(value == v)
+		{
+			return true;
+		}
 	}
 
-	// Early exit
-	if(mutation.getSize() == 0)
-	{
-		return false;
-	}
+	return false;
+}
+
+Bool ShaderProgramParser::skipMutation(ConstWeakArray<MutatorValue> mutation) const
+{
+	ANKI_ASSERT(mutation.getSize() == m_mutators.getSize());
 
-	// Find if mutation exists
-	for(const MutationRewrite& rewrite : m_mutationRewrites)
+	for(const PartialMutationSkip& skip : m_skipMutations)
 	{
-		Bool found = true;
-		for(U32 i = 0; i < rewrite.m_records.getSize(); ++i)
+		Bool doSkip = true;
+		for(U32 i = 0; i < m_mutators.getSize(); ++i)
 		{
-			if(rewrite.m_records[i].m_valueFrom != mutation[rewrite.m_records[i].m_mutatorIndex])
+			if(skip.m_partialMutation[i] == std::numeric_limits<MutatorValue>::max())
 			{
-				found = false;
-				break;
+				// Don't care
+				continue;
 			}
-		}
 
-		if(found)
-		{
-			// Rewrite it
-			for(U32 i = 0; i < rewrite.m_records.getSize(); ++i)
+			if(skip.m_partialMutation[i] != mutation[i])
 			{
-				mutation[rewrite.m_records[i].m_mutatorIndex] = rewrite.m_records[i].m_valueTo;
+				doSkip = false;
+				break;
 			}
-
-			return true;
 		}
-	}
-
-	return false;
-}
 
-Bool ShaderProgramParser::mutatorHasValue(const ShaderProgramParserMutator& mutator, MutatorValue value)
-{
-	for(MutatorValue v : mutator.m_values)
-	{
-		if(value == v)
+		if(doSkip)
 		{
 			return true;
 		}

+ 7 - 32
AnKi/ShaderCompiler/ShaderProgramParser.h

@@ -106,13 +106,12 @@ private:
 /// #include {<> | ""}
 /// #pragma once
 /// #pragma anki mutator NAME VALUE0 [VALUE1 [VALUE2] ...]
-/// #pragma anki rewrite_mutation NAME_A VALUE0 NAME_B VALUE1 [NAME_C VALUE3...] to
-///                               NAME_A VALUE4 NAME_B VALUE5 [NAME_C VALUE6...]
 /// #pragma anki start {vert | tessc | tesse | geom | frag | comp | rgen | ahit | chit | miss | int | call}
 /// #pragma anki end
 /// #pragma anki library "name"
 /// #pragma anki ray_type NUMBER
 /// #pragma anki reflect NAME
+/// #pragma anki skip_mutation MUTATOR0 VALUE0 MUTATOR1 VALUE1 [MUTATOR2 VALUE2 ...]
 ///
 /// #pragma anki struct NAME
 /// #	pragma anki member [ANKI_RP] TYPE NAME [if MUTATOR_NAME is MUTATOR_VALUE]
@@ -135,9 +134,8 @@ public:
 	/// Parse the file and its includes.
 	ANKI_USE_RESULT Error parse();
 
-	/// Given a mutation convert it to something acceptable. This will reduce the variants.
-	/// @return true if the mutation was rewritten.
-	Bool rewriteMutation(WeakArray<MutatorValue> mutation) const;
+	/// Returns true if the mutation should be skipped.
+	Bool skipMutation(ConstWeakArray<MutatorValue> mutation) const;
 
 	/// Get the source (and a few more things) given a list of mutators.
 	ANKI_USE_RESULT Error generateVariant(ConstWeakArray<MutatorValue> mutation,
@@ -188,30 +186,7 @@ private:
 	using Member = ShaderProgramParserMember;
 	using GhostStruct = ShaderProgramParserGhostStruct;
 
-	class MutationRewrite
-	{
-	public:
-		class Record
-		{
-		public:
-			U32 m_mutatorIndex = MAX_U32;
-			MutatorValue m_valueFrom = getMaxNumericLimit<MutatorValue>();
-			MutatorValue m_valueTo = getMaxNumericLimit<MutatorValue>();
-
-			Bool operator!=(const Record& b) const
-			{
-				return !(m_mutatorIndex == b.m_mutatorIndex && m_valueFrom == b.m_valueFrom
-						 && m_valueTo == b.m_valueTo);
-			}
-		};
-
-		DynamicArrayAuto<Record> m_records;
-
-		MutationRewrite(GenericMemoryPoolAllocator<U8> alloc)
-			: m_records(alloc)
-		{
-		}
-	};
+	class PartialMutationSkip;
 
 	static constexpr U32 MAX_INCLUDE_DEPTH = 8;
 
@@ -224,7 +199,7 @@ private:
 	U64 m_codeSourceHash = 0;
 
 	DynamicArrayAuto<Mutator> m_mutators = {m_alloc};
-	DynamicArrayAuto<MutationRewrite> m_mutationRewrites = {m_alloc};
+	DynamicArrayAuto<PartialMutationSkip> m_skipMutations = {m_alloc};
 
 	ShaderTypeBit m_shaderTypes = ShaderTypeBit::NONE;
 	Bool m_insideShader = false;
@@ -246,8 +221,8 @@ private:
 											 CString fname);
 	ANKI_USE_RESULT Error parsePragmaStart(const StringAuto* begin, const StringAuto* end, CString line, CString fname);
 	ANKI_USE_RESULT Error parsePragmaEnd(const StringAuto* begin, const StringAuto* end, CString line, CString fname);
-	ANKI_USE_RESULT Error parsePragmaRewriteMutation(const StringAuto* begin, const StringAuto* end, CString line,
-													 CString fname);
+	ANKI_USE_RESULT Error parsePragmaSkipMutation(const StringAuto* begin, const StringAuto* end, CString line,
+												  CString fname);
 	ANKI_USE_RESULT Error parsePragmaLibraryName(const StringAuto* begin, const StringAuto* end, CString line,
 												 CString fname);
 	ANKI_USE_RESULT Error parsePragmaRayType(const StringAuto* begin, const StringAuto* end, CString line,

+ 12 - 25
AnKi/Shaders/GBufferGeneric.ankiprog

@@ -16,28 +16,15 @@
 #pragma anki mutator EMISSIVE_TEX 0 1
 #pragma anki mutator ALPHA_TEST 0 1
 
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 1 DIFFUSE_TEX 1 ALPHA_TEST 0 to ANKI_TECHNIQUE 1 DIFFUSE_TEX 0 ALPHA_TEST 0
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 2 DIFFUSE_TEX 1 ALPHA_TEST 0 to ANKI_TECHNIQUE 2 DIFFUSE_TEX 0 ALPHA_TEST 0
+#pragma anki skip_mutation ALPHA_TEST 1 DIFFUSE_TEX 0
+#pragma anki skip_mutation ANKI_VELOCITY 1 ANKI_TECHNIQUE 1
+#pragma anki skip_mutation ANKI_VELOCITY 1 ANKI_TECHNIQUE 2
+#pragma anki skip_mutation ANKI_LOD 1 ANKI_TECHNIQUE 1
+#pragma anki skip_mutation ANKI_LOD 2 ANKI_TECHNIQUE 1
+#pragma anki skip_mutation ANKI_LOD 1 ANKI_TECHNIQUE 2
+#pragma anki skip_mutation ANKI_LOD 2 ANKI_TECHNIQUE 2
 
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 1 SPECULAR_TEX 1 to ANKI_TECHNIQUE 1 SPECULAR_TEX 0
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 2 SPECULAR_TEX 1 to ANKI_TECHNIQUE 2 SPECULAR_TEX 0
-
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 1 NORMAL_TEX 1 to ANKI_TECHNIQUE 1 NORMAL_TEX 0
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 2 NORMAL_TEX 1 to ANKI_TECHNIQUE 2 NORMAL_TEX 0
-
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 1 ROUGHNESS_TEX 1 to ANKI_TECHNIQUE 1 ROUGHNESS_TEX 0
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 2 ROUGHNESS_TEX 1 to ANKI_TECHNIQUE 2 ROUGHNESS_TEX 0
-
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 1 METAL_TEX 1 to ANKI_TECHNIQUE 1 METAL_TEX 0
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 2 METAL_TEX 1 to ANKI_TECHNIQUE 2 METAL_TEX 0
-
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 1 EMISSIVE_TEX 1 to ANKI_TECHNIQUE 1 EMISSIVE_TEX 0
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 2 EMISSIVE_TEX 1 to ANKI_TECHNIQUE 2 EMISSIVE_TEX 0
-
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 1 PARALLAX 1 to ANKI_TECHNIQUE 1 PARALLAX 0
-#pragma anki rewrite_mutation ANKI_TECHNIQUE 2 PARALLAX 1 to ANKI_TECHNIQUE 2 PARALLAX 0
-
-#pragma anki rewrite_mutation ALPHA_TEST 1 DIFFUSE_TEX 0 to ALPHA_TEST 0 DIFFUSE_TEX 0
+#define REALLY_ALPHA_TEST (ALPHA_TEST && DIFFUSE_TEX)
 
 #include <AnKi/Shaders/GBufferCommon.glsl>
 
@@ -109,7 +96,7 @@ ANKI_RP Vec3 g_normal = in_normal;
 ANKI_RP Vec4 g_tangent = in_tangent;
 #endif
 
-#if ANKI_TECHNIQUE == RENDERING_TECHNIQUE_GBUFFER || ALPHA_TEST
+#if ANKI_TECHNIQUE == RENDERING_TECHNIQUE_GBUFFER || REALLY_ALPHA_TEST
 Vec2 g_uv = in_uv;
 #endif
 
@@ -213,7 +200,7 @@ void main()
 	gl_Position = u_globalUniforms.m_viewProjectionMatrix
 				  * Vec4(u_renderableGpuViews[gl_InstanceIndex].m_worldTransform * Vec4(g_position, 1.0), 1.0);
 
-#	if ALPHA_TEST
+#	if REALLY_ALPHA_TEST
 	out_uv = g_uv;
 #	endif
 #endif
@@ -330,7 +317,7 @@ void main()
 #	endif
 
 #	if DIFFUSE_TEX
-#		if ALPHA_TEST
+#		if REALLY_ALPHA_TEST
 	const ANKI_RP Vec4 diffColorA = texture(u_bindlessTextures2dF32[localUniforms.m_diffTex], u_globalSampler, uv);
 	doAlphaText(diffColorA.a);
 	const ANKI_RP Vec3 diffColor = diffColorA.rgb;
@@ -387,7 +374,7 @@ void main()
 	out_gbuffer3 = Vec2(0.0);
 #endif
 
-#if ANKI_TECHNIQUE != RENDERING_TECHNIQUE_GBUFFER && ALPHA_TEST
+#if ANKI_TECHNIQUE != RENDERING_TECHNIQUE_GBUFFER && REALLY_ALPHA_TEST
 	doAlphaText(texture(u_bindlessTextures2dF32[localUniforms.m_diffTex], u_globalSampler, in_uv).a);
 #endif
 }