Преглед на файлове

Refactor shader program loading to accept arbitary combinations of techniques

Panagiotis Christopoulos Charitos преди 2 години
родител
ревизия
154b4771d4

+ 2 - 1
AnKi/Core/GpuMemory/GpuSceneBuffer.cpp

@@ -68,8 +68,9 @@ GpuSceneMicroPatcher::~GpuSceneMicroPatcher()
 Error GpuSceneMicroPatcher::init()
 {
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/GpuSceneMicroPatching.ankiprogbin", m_copyProgram));
+	ShaderProgramResourceVariantInitInfo varInit(m_copyProgram);
 	const ShaderProgramResourceVariant* variant;
-	m_copyProgram->getOrCreateVariant(variant);
+	m_copyProgram->getOrCreateVariant(varInit, variant);
 	m_grProgram.reset(&variant->getProgram());
 
 	return Error::kNone;

+ 5 - 8
AnKi/Renderer/ClusterBinning.cpp

@@ -33,14 +33,11 @@ Error ClusterBinning::init()
 
 	for(GpuSceneNonRenderableObjectType type : EnumIterable<GpuSceneNonRenderableObjectType>())
 	{
-		ShaderProgramResourceVariantInitInfo inf(m_binningProg);
-		inf.addMutation("OBJECT_TYPE", MutatorValue(type));
-		const ShaderProgramResourceVariant* variant;
-		m_binningProg->getOrCreateVariant(inf, variant);
-		m_binningGrProgs[type].reset(&variant->getProgram());
-
-		ANKI_CHECK(loadShaderProgram("ShaderBinaries/ClusterBinningPackVisibles.ankiprogbin",
-									 Array<SubMutation, 1>{{{"OBJECT_TYPE", MutatorValue(type)}}}, m_packingProg, m_packingGrProgs[type]));
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/ClusterBinning.ankiprogbin", {{"OBJECT_TYPE", MutatorValue(type)}}, m_binningProg,
+									 m_binningGrProgs[type]));
+
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/ClusterBinningPackVisibles.ankiprogbin", {{"OBJECT_TYPE", MutatorValue(type)}}, m_packingProg,
+									 m_packingGrProgs[type]));
 	}
 
 	return Error::kNone;

+ 1 - 1
AnKi/Renderer/DepthDownscale.cpp

@@ -53,7 +53,7 @@ Error DepthDownscale::initInternal()
 	}
 
 	// Progs
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/DepthDownscale.ankiprogbin", Array<SubMutation, 1>{{{"WAVE_OPERATIONS", 1}}}, m_prog, m_grProg));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/DepthDownscale.ankiprogbin", {{"WAVE_OPERATIONS", 1}}, m_prog, m_grProg));
 
 	// Counter buffer
 	if(preferCompute)

+ 6 - 15
AnKi/Renderer/FinalComposite.cpp

@@ -33,24 +33,15 @@ Error FinalComposite::initInternal()
 	m_fbDescr.bake();
 
 	// Progs
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/FinalComposite.ankiprogbin", m_prog));
-
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
-	variantInitInfo.addMutation("FILM_GRAIN", (g_filmGrainStrengthCVar.get() > 0.0) ? 1 : 0);
-	variantInitInfo.addMutation("BLOOM_ENABLED", 1);
-
-	for(U32 dbg = 0; dbg < 2; ++dbg)
+	for(MutatorValue dbg = 0; dbg < 2; ++dbg)
 	{
-		const ShaderProgramResourceVariant* variant;
-		variantInitInfo.addMutation("DBG_ENABLED", dbg);
-		m_prog->getOrCreateVariant(variantInitInfo, variant);
-		m_grProgs[dbg].reset(&variant->getProgram());
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/FinalComposite.ankiprogbin",
+									 {{"FILM_GRAIN", (g_filmGrainStrengthCVar.get() > 0.0) ? 1 : 0}, {"BLOOM_ENABLED", 1}, {"DBG_ENABLED", dbg}},
+									 m_prog, m_grProgs[dbg]));
 	}
 
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/VisualizeRenderTarget.ankiprogbin", m_defaultVisualizeRenderTargetProg));
-	const ShaderProgramResourceVariant* variant;
-	m_defaultVisualizeRenderTargetProg->getOrCreateVariant(variant);
-	m_defaultVisualizeRenderTargetGrProg.reset(&variant->getProgram());
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/VisualizeRenderTarget.ankiprogbin", m_defaultVisualizeRenderTargetProg,
+								 m_defaultVisualizeRenderTargetGrProg));
 
 	return Error::kNone;
 }

+ 4 - 11
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -148,17 +148,10 @@ Error IndirectDiffuseProbes::initLightShading()
 
 Error IndirectDiffuseProbes::initIrradiance()
 {
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/IrradianceDice.ankiprogbin", m_irradiance.m_prog));
-
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_irradiance.m_prog);
-	variantInitInfo.addMutation("WORKGROUP_SIZE_XY", m_tileSize);
-	variantInitInfo.addMutation("LIGHT_SHADING_TEX", 0);
-	variantInitInfo.addMutation("STORE_LOCATION", 0);
-	variantInitInfo.addMutation("SECOND_BOUNCE", 1);
-
-	const ShaderProgramResourceVariant* variant;
-	m_irradiance.m_prog->getOrCreateVariant(variantInitInfo, variant);
-	m_irradiance.m_grProg.reset(&variant->getProgram());
+	ANKI_CHECK(
+		loadShaderProgram("ShaderBinaries/IrradianceDice.ankiprogbin",
+						  {{"WORKGROUP_SIZE_XY", MutatorValue(m_tileSize)}, {"LIGHT_SHADING_TEX", 0}, {"STORE_LOCATION", 0}, {"SECOND_BOUNCE", 1}},
+						  m_irradiance.m_prog, m_irradiance.m_grProg));
 
 	return Error::kNone;
 }

+ 1 - 1
AnKi/Renderer/IndirectSpecular.cpp

@@ -58,7 +58,7 @@ Error IndirectSpecular::initInternal()
 	m_fbDescr.bake();
 
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/IndirectSpecular.ankiprogbin",
-								 Array<SubMutation, 2>{{{"EXTRA_REJECTION", false}, {"STOCHASTIC", g_ssrStochasticCVar.get()}}}, m_prog, m_grProg));
+								 {{"EXTRA_REJECTION", false}, {"STOCHASTIC", g_ssrStochasticCVar.get()}}, m_prog, m_grProg));
 
 	return Error::kNone;
 }

+ 3 - 7
AnKi/Renderer/LightShading.cpp

@@ -87,14 +87,10 @@ Error LightShading::initSkybox()
 {
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/LightShadingSkybox.ankiprogbin", m_skybox.m_prog));
 
-	for(U32 method = 0; method < 2; ++method)
+	for(MutatorValue method = 0; method < 2; ++method)
 	{
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_skybox.m_prog);
-		variantInitInfo.addMutation("METHOD", method);
-		const ShaderProgramResourceVariant* variant;
-		m_skybox.m_prog->getOrCreateVariant(variantInitInfo, variant);
-
-		m_skybox.m_grProgs[method].reset(&variant->getProgram());
+		ANKI_CHECK(
+			loadShaderProgram("ShaderBinaries/LightShadingSkybox.ankiprogbin", {{"METHOD", method}}, m_skybox.m_prog, m_skybox.m_grProgs[method]));
 	}
 
 	return Error::kNone;

+ 0 - 1
AnKi/Renderer/MainRenderer.cpp

@@ -55,7 +55,6 @@ Error MainRenderer::init(const MainRendererInitInfo& inf)
 	{
 		ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/Blit.ankiprogbin", m_blitProg));
 		ShaderProgramResourceVariantInitInfo varInit(m_blitProg);
-		varInit.requestShaderTypes(ShaderTypeBit::kFragment | ShaderTypeBit::kVertex);
 		const ShaderProgramResourceVariant* variant;
 		m_blitProg->getOrCreateVariant(varInit, variant);
 		m_blitGrProg.reset(&variant->getProgram());

+ 6 - 12
AnKi/Renderer/ProbeReflections.cpp

@@ -133,18 +133,12 @@ Error ProbeReflections::initIrradiance()
 
 	// Create prog
 	{
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/IrradianceDice.ankiprogbin", m_irradiance.m_prog));
-
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_irradiance.m_prog);
-
-		variantInitInfo.addMutation("WORKGROUP_SIZE_XY", U32(m_irradiance.m_workgroupSize));
-		variantInitInfo.addMutation("LIGHT_SHADING_TEX", 1);
-		variantInitInfo.addMutation("STORE_LOCATION", 1);
-		variantInitInfo.addMutation("SECOND_BOUNCE", 0);
-
-		const ShaderProgramResourceVariant* variant;
-		m_irradiance.m_prog->getOrCreateVariant(variantInitInfo, variant);
-		m_irradiance.m_grProg.reset(&variant->getProgram());
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/IrradianceDice.ankiprogbin",
+									 {{"WORKGROUP_SIZE_XY", MutatorValue(m_irradiance.m_workgroupSize)},
+									  {"LIGHT_SHADING_TEX", 1},
+									  {"STORE_LOCATION", 1},
+									  {"SECOND_BOUNCE", 0}},
+									 m_irradiance.m_prog, m_irradiance.m_grProg));
 	}
 
 	// Create buff

+ 44 - 12
AnKi/Renderer/RendererObject.cpp

@@ -20,7 +20,7 @@ void RendererObject::registerDebugRenderTarget(CString rtName)
 	getRenderer().registerDebugRenderTarget(this, rtName);
 }
 
-Error RendererObject::loadShaderProgram(CString filename, ConstWeakArray<SubMutation> mutators, ShaderProgramResourcePtr& rsrc,
+Error RendererObject::loadShaderProgram(CString filename, std::initializer_list<SubMutation> mutators, ShaderProgramResourcePtr& rsrc,
 										ShaderProgramPtr& grProg, CString technique, ShaderTypeBit shaderTypes)
 {
 	if(!rsrc.isCreated())
@@ -34,31 +34,63 @@ Error RendererObject::loadShaderProgram(CString filename, ConstWeakArray<SubMuta
 		initInf.addMutation(pair.m_mutatorName, pair.m_value);
 	}
 
-	if(technique)
+	if(technique.isEmpty())
 	{
-		initInf.requestTechnique(technique);
+		technique = "Unnamed";
 	}
 
-	if(!!shaderTypes)
+	if(!shaderTypes)
 	{
-		initInf.requestShaderTypes(shaderTypes);
-	}
-	else if(rsrc->getBinary().m_shaderTypes == (ShaderTypeBit::kCompute | ShaderTypeBit::kFragment | ShaderTypeBit::kVertex))
-	{
-		if(g_preferComputeCVar.get())
+		U32 techniqueIdx = kMaxU32;
+		for(U32 i = 0; i < rsrc->getBinary().m_techniques.getSize(); ++i)
+		{
+			if(technique == rsrc->getBinary().m_techniques[i].m_name.getBegin())
+			{
+				techniqueIdx = i;
+				break;
+			}
+		}
+		ANKI_ASSERT(techniqueIdx != kMaxU32);
+		const ShaderTypeBit techniqueShaderTypes = rsrc->getBinary().m_techniques[techniqueIdx].m_shaderTypes;
+
+		if(techniqueShaderTypes == (ShaderTypeBit::kCompute | ShaderTypeBit::kFragment | ShaderTypeBit::kVertex))
+		{
+			if(g_preferComputeCVar.get())
+			{
+				shaderTypes = ShaderTypeBit::kCompute;
+			}
+			else
+			{
+				shaderTypes = ShaderTypeBit::kFragment | ShaderTypeBit::kVertex;
+			}
+		}
+		else if(techniqueShaderTypes == ShaderTypeBit::kCompute)
 		{
-			initInf.requestShaderTypes(ShaderTypeBit::kCompute);
+			shaderTypes = techniqueShaderTypes;
+		}
+		else if(techniqueShaderTypes == (ShaderTypeBit::kFragment | ShaderTypeBit::kVertex))
+		{
+			shaderTypes = techniqueShaderTypes;
 		}
 		else
 		{
-			initInf.requestShaderTypes(ShaderTypeBit::kFragment | ShaderTypeBit::kVertex);
+			ANKI_ASSERT(!"Can't figure out a sensible default");
 		}
 	}
 
+	initInf.requestTechniqueAndTypes(shaderTypes, technique);
+
 	const ShaderProgramResourceVariant* variant;
 	rsrc->getOrCreateVariant(initInf, variant);
 
-	grProg.reset(&variant->getProgram());
+	if(variant)
+	{
+		grProg.reset(&variant->getProgram());
+	}
+	else
+	{
+		grProg.reset(nullptr);
+	}
 
 	return Error::kNone;
 }

+ 2 - 2
AnKi/Renderer/RendererObject.h

@@ -96,8 +96,8 @@ protected:
 		MutatorValue m_value;
 	};
 
-	static Error loadShaderProgram(CString filename, ConstWeakArray<SubMutation> mutators, ShaderProgramResourcePtr& rsrc, ShaderProgramPtr& grProg,
-								   CString technique = {}, ShaderTypeBit shaderTypes = ShaderTypeBit::kNone);
+	static Error loadShaderProgram(CString filename, std::initializer_list<SubMutation> mutators, ShaderProgramResourcePtr& rsrc,
+								   ShaderProgramPtr& grProg, CString technique = {}, ShaderTypeBit shaderTypes = ShaderTypeBit::kNone);
 
 	static void zeroBuffer(Buffer* buff);
 };

+ 12 - 26
AnKi/Renderer/RtShadows.cpp

@@ -54,33 +54,27 @@ Error RtShadows::initInternal()
 	{
 		ShaderProgramResourceVariantInitInfo variantInitInfo(m_rayGenAndMissProg);
 		variantInitInfo.addMutation("RAYS_PER_PIXEL", g_rtShadowsRaysPerPixelCVar.get());
-		variantInitInfo.requestTechnique("RtShadows");
-
-		variantInitInfo.requestShaderTypes(ShaderTypeBit::kRayGen);
+		variantInitInfo.requestTechniqueAndTypes(ShaderTypeBit::kRayGen, "RtShadows");
 		const ShaderProgramResourceVariant* variant;
 		m_rayGenAndMissProg->getOrCreateVariant(variantInitInfo, variant);
 		m_rtLibraryGrProg.reset(&variant->getProgram());
 		m_rayGenShaderGroupIdx = variant->getShaderGroupHandleIndex();
 
-		variantInitInfo.requestShaderTypes(ShaderTypeBit::kMiss);
-		m_rayGenAndMissProg->getOrCreateVariant(variantInitInfo, variant);
+		ShaderProgramResourceVariantInitInfo variantInitInfo2(m_rayGenAndMissProg);
+		variantInitInfo2.addMutation("RAYS_PER_PIXEL", g_rtShadowsRaysPerPixelCVar.get());
+		variantInitInfo2.requestTechniqueAndTypes(ShaderTypeBit::kMiss, "RtShadows");
+		m_rayGenAndMissProg->getOrCreateVariant(variantInitInfo2, variant);
 		m_missShaderGroupIdx = variant->getShaderGroupHandleIndex();
 	}
 
 	// Denoise program
 	if(!m_useSvgf)
 	{
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/RtShadowsDenoise.ankiprogbin", m_denoiseProg));
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_denoiseProg);
-		variantInitInfo.addMutation("BLUR_ORIENTATION", 0);
-
-		const ShaderProgramResourceVariant* variant;
-		m_denoiseProg->getOrCreateVariant(variantInitInfo, variant);
-		m_grDenoiseHorizontalProg.reset(&variant->getProgram());
+		ANKI_CHECK(
+			loadShaderProgram("ShaderBinaries/RtShadowsDenoise.ankiprogbin", {{"BLUR_ORIENTATION", 0}}, m_denoiseProg, m_grDenoiseHorizontalProg));
 
-		variantInitInfo.addMutation("BLUR_ORIENTATION", 1);
-		m_denoiseProg->getOrCreateVariant(variantInitInfo, variant);
-		m_grDenoiseVerticalProg.reset(&variant->getProgram());
+		ANKI_CHECK(
+			loadShaderProgram("ShaderBinaries/RtShadowsDenoise.ankiprogbin", {{"BLUR_ORIENTATION", 1}}, m_denoiseProg, m_grDenoiseVerticalProg));
 	}
 
 	// SVGF variance program
@@ -92,17 +86,9 @@ Error RtShadows::initInternal()
 	// SVGF atrous program
 	if(m_useSvgf)
 	{
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/RtShadowsSvgfAtrous.ankiprogbin", m_svgfAtrousProg));
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_svgfAtrousProg);
-		variantInitInfo.addMutation("LAST_PASS", 0);
-
-		const ShaderProgramResourceVariant* variant;
-		m_svgfAtrousProg->getOrCreateVariant(variantInitInfo, variant);
-		m_svgfAtrousGrProg.reset(&variant->getProgram());
-
-		variantInitInfo.addMutation("LAST_PASS", 1);
-		m_svgfAtrousProg->getOrCreateVariant(variantInitInfo, variant);
-		m_svgfAtrousLastPassGrProg.reset(&variant->getProgram());
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/RtShadowsSvgfAtrous.ankiprogbin", {{"LAST_PASS", 0}}, m_svgfAtrousProg, m_svgfAtrousGrProg));
+		ANKI_CHECK(
+			loadShaderProgram("ShaderBinaries/RtShadowsSvgfAtrous.ankiprogbin", {{"LAST_PASS", 1}}, m_svgfAtrousProg, m_svgfAtrousLastPassGrProg));
 	}
 
 	// Upscale program

+ 5 - 17
AnKi/Renderer/Scale.cpp

@@ -47,7 +47,6 @@ Error Scale::init()
 		return Error::kNone;
 	}
 
-	const Bool preferCompute = g_preferComputeCVar.get();
 	const U32 dlssQuality = g_dlssQualityCVar.get();
 	const U32 fsrQuality = g_fsrQualityCVar.get();
 
@@ -83,18 +82,12 @@ Error Scale::init()
 	// Scale programs
 	if(m_upscalingMethod == UpscalingMethod::kBilinear)
 	{
-		const CString shaderFname = (preferCompute) ? "ShaderBinaries/BlitCompute.ankiprogbin" : "ShaderBinaries/BlitRaster.ankiprogbin";
-
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource(shaderFname, m_scaleProg));
-
-		const ShaderProgramResourceVariant* variant;
-		m_scaleProg->getOrCreateVariant(variant);
-		m_scaleGrProg.reset(&variant->getProgram());
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/Blit.ankiprogbin", m_scaleProg, m_scaleGrProg));
 	}
 	else if(m_upscalingMethod == UpscalingMethod::kFsr)
 	{
-		const Array<SubMutation, 2> mutation = {{{"SHARPEN", 0}, {"FSR_QUALITY", MutatorValue(fsrQuality - 1)}}};
-		ANKI_CHECK(loadShaderProgram("ShaderBinaries/Fsr.ankiprogbin", mutation, m_scaleProg, m_scaleGrProg));
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/Fsr.ankiprogbin", {{"SHARPEN", 0}, {"FSR_QUALITY", MutatorValue(fsrQuality - 1)}}, m_scaleProg,
+									 m_scaleGrProg));
 	}
 	else if(m_upscalingMethod == UpscalingMethod::kGr)
 	{
@@ -110,18 +103,13 @@ Error Scale::init()
 	// Sharpen programs
 	if(m_sharpenMethod == SharpenMethod::kRcas)
 	{
-		const Array<SubMutation, 2> mutation = {{{"SHARPEN", 1}, {"FSR_QUALITY", 0}}};
-		ANKI_CHECK(loadShaderProgram("ShaderBinaries/Fsr.ankiprogbin", mutation, m_sharpenProg, m_sharpenGrProg));
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/Fsr.ankiprogbin", {{"SHARPEN", 1}, {"FSR_QUALITY", 0}}, m_sharpenProg, m_sharpenGrProg));
 	}
 
 	// Tonemapping programs
 	if(m_neeedsTonemapping)
 	{
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource(
-			(preferCompute) ? "ShaderBinaries/TonemapCompute.ankiprogbin" : "ShaderBinaries/TonemapRaster.ankiprogbin", m_tonemapProg));
-		const ShaderProgramResourceVariant* variant;
-		m_tonemapProg->getOrCreateVariant(variant);
-		m_tonemapGrProg.reset(&variant->getProgram());
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/Tonemap.ankiprogbin", m_tonemapProg, m_tonemapGrProg));
 	}
 
 	// Descriptors

+ 3 - 4
AnKi/Renderer/ShadowmapsResolve.cpp

@@ -44,10 +44,9 @@ Error ShadowmapsResolve::initInternal()
 	m_fbDescr.bake();
 
 	// Prog
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/ShadowmapsResolve.ankiprogbin",
-								 Array<SubMutation, 2>{{{"PCF", g_shadowMappingPcfCVar.get() != 0},
-														{"DIRECTIONAL_LIGHT_SHADOW_RESOLVED", getRenderer().getRtShadowsEnabled()}}},
-								 m_prog, m_grProg));
+	ANKI_CHECK(loadShaderProgram(
+		"ShaderBinaries/ShadowmapsResolve.ankiprogbin",
+		{{"PCF", g_shadowMappingPcfCVar.get() != 0}, {"DIRECTIONAL_LIGHT_SHADOW_RESOLVED", getRenderer().getRtShadowsEnabled()}}, m_prog, m_grProg));
 
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("EngineAssets/BlueNoise_Rgba8_64x64.png", m_noiseImage));
 

+ 3 - 6
AnKi/Renderer/Ssao.cpp

@@ -47,12 +47,9 @@ Error Ssao::initInternal()
 	m_fbDescr.m_colorAttachmentCount = 1;
 	m_fbDescr.bake();
 
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", Array<SubMutation, 1>{{{"SAMPLE_COUNT", 3}}}, m_prog, m_grProg, "Ssao"));
-
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", Array<SubMutation, 1>{{{"SAMPLE_COUNT", 5}}}, m_prog, m_denoiseGrProgs[0],
-								 "SsaoDenoiseHorizontal"));
-	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", Array<SubMutation, 1>{{{"SAMPLE_COUNT", 5}}}, m_prog, m_denoiseGrProgs[1],
-								 "SsaoDenoiseVertical"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", {{"SAMPLE_COUNT", 3}}, m_prog, m_grProg, "Ssao"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", {{"SAMPLE_COUNT", 5}}, m_prog, m_denoiseGrProgs[0], "SsaoDenoiseHorizontal"));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/Ssao.ankiprogbin", {{"SAMPLE_COUNT", 5}}, m_prog, m_denoiseGrProgs[1], "SsaoDenoiseVertical"));
 
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("EngineAssets/BlueNoise_Rgba8_64x64.png", m_noiseImage));
 

+ 1 - 4
AnKi/Renderer/TemporalAA.cpp

@@ -29,10 +29,7 @@ Error TemporalAA::initInternal()
 {
 	ANKI_R_LOGV("Initializing TAA");
 
-	{
-		const Array<SubMutation, 2> mutation = {{{"VARIANCE_CLIPPING", 1}, {"YCBCR", 0}}};
-		ANKI_CHECK(loadShaderProgram("ShaderBinaries/TemporalAA.ankiprogbin", mutation, m_prog, m_grProg));
-	}
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/TemporalAA.ankiprogbin", {{"VARIANCE_CLIPPING", 1}, {"YCBCR", 0}}, m_prog, m_grProg));
 
 	for(U i = 0; i < 2; ++i)
 	{

+ 11 - 26
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -24,10 +24,9 @@ Error GpuVisibility::init()
 		{
 			for(MutatorValue genHash = 0; genHash < 2; ++genHash)
 			{
-				ANKI_CHECK(loadShaderProgram(
-					"ShaderBinaries/GpuVisibility.ankiprogbin",
-					Array<SubMutation, 4>{{{"HZB_TEST", hzb}, {"DISTANCE_TEST", 0}, {"GATHER_AABBS", gatherAabbs}, {"HASH_VISIBLES", genHash}}},
-					m_prog, m_frustumGrProgs[hzb][gatherAabbs][genHash]));
+				ANKI_CHECK(loadShaderProgram("ShaderBinaries/GpuVisibility.ankiprogbin",
+											 {{"HZB_TEST", hzb}, {"DISTANCE_TEST", 0}, {"GATHER_AABBS", gatherAabbs}, {"HASH_VISIBLES", genHash}},
+											 m_prog, m_frustumGrProgs[hzb][gatherAabbs][genHash]));
 			}
 		}
 	}
@@ -36,10 +35,9 @@ Error GpuVisibility::init()
 	{
 		for(MutatorValue genHash = 0; genHash < 2; ++genHash)
 		{
-			ANKI_CHECK(loadShaderProgram(
-				"ShaderBinaries/GpuVisibility.ankiprogbin",
-				Array<SubMutation, 4>{{{"HZB_TEST", 0}, {"DISTANCE_TEST", 1}, {"GATHER_AABBS", gatherAabbs}, {"HASH_VISIBLES", genHash}}}, m_prog,
-				m_distGrProgs[gatherAabbs][genHash]));
+			ANKI_CHECK(loadShaderProgram("ShaderBinaries/GpuVisibility.ankiprogbin",
+										 {{"HZB_TEST", 0}, {"DISTANCE_TEST", 1}, {"GATHER_AABBS", gatherAabbs}, {"HASH_VISIBLES", genHash}}, m_prog,
+										 m_distGrProgs[gatherAabbs][genHash]));
 		}
 	}
 
@@ -347,28 +345,15 @@ Error GpuVisibilityNonRenderables::init()
 {
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/GpuVisibilityNonRenderables.ankiprogbin", m_prog));
 
-	for(U32 hzb = 0; hzb < 2; ++hzb)
+	for(MutatorValue hzb = 0; hzb < 2; ++hzb)
 	{
 		for(GpuSceneNonRenderableObjectType type : EnumIterable<GpuSceneNonRenderableObjectType>())
 		{
-			for(U32 cpuFeedback = 0; cpuFeedback < 2; ++cpuFeedback)
+			for(MutatorValue cpuFeedback = 0; cpuFeedback < 2; ++cpuFeedback)
 			{
-				ShaderProgramResourceVariantInitInfo variantInit(m_prog);
-				variantInit.addMutation("HZB_TEST", hzb);
-				variantInit.addMutation("OBJECT_TYPE", U32(type));
-				variantInit.addMutation("CPU_FEEDBACK", cpuFeedback);
-
-				const ShaderProgramResourceVariant* variant;
-				m_prog->getOrCreateVariant(variantInit, variant);
-
-				if(variant)
-				{
-					m_grProgs[hzb][type][cpuFeedback].reset(&variant->getProgram());
-				}
-				else
-				{
-					m_grProgs[hzb][type][cpuFeedback].reset(nullptr);
-				}
+				ANKI_CHECK(loadShaderProgram("ShaderBinaries/GpuVisibilityNonRenderables.ankiprogbin",
+											 {{"HZB_TEST", hzb}, {"OBJECT_TYPE", MutatorValue(type)}, {"CPU_FEEDBACK", cpuFeedback}}, m_prog,
+											 m_grProgs[hzb][type][cpuFeedback]));
 			}
 		}
 	}

+ 2 - 10
AnKi/Renderer/Utils/HzbGenerator.cpp

@@ -44,16 +44,8 @@ Error HzbGenerator::init()
 		m_maxSampler = GrManager::getSingleton().newSampler(sinit);
 	}
 
-	{
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/HzbGenPyramid.ankiprogbin", m_genPyramidProg));
-
-		ShaderProgramResourceVariantInitInfo variantInit(m_genPyramidProg);
-		variantInit.addMutation("REDUCTION_TYPE", 1);
-		variantInit.addMutation("MIN_MAX_SAMPLER", m_maxSampler.isCreated());
-		const ShaderProgramResourceVariant* variant;
-		m_genPyramidProg->getOrCreateVariant(variantInit, variant);
-		m_genPyramidGrProg.reset(&variant->getProgram());
-	}
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/HzbGenPyramid.ankiprogbin", {{"REDUCTION_TYPE", 1}, {"MIN_MAX_SAMPLER", m_maxSampler.isCreated()}},
+								 m_genPyramidProg, m_genPyramidGrProg));
 
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/HzbMaxDepth.ankiprogbin", m_maxDepthProg, m_maxDepthGrProg));
 	ANKI_CHECK(loadShaderProgram("ShaderBinaries/HzbMaxDepthProject.ankiprogbin", m_maxBoxProg, m_maxBoxGrProg));

+ 6 - 21
AnKi/Renderer/Utils/TraditionalDeferredShading.cpp

@@ -18,18 +18,10 @@ namespace anki {
 Error TraditionalDeferredLightShading::init()
 {
 	// Init progs
+	for(MutatorValue specular = 0; specular <= 1; ++specular)
 	{
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/TraditionalDeferredShading.ankiprogbin", m_lightProg));
-
-		for(U32 specular = 0; specular <= 1; ++specular)
-		{
-			ShaderProgramResourceVariantInitInfo variantInitInfo(m_lightProg);
-			variantInitInfo.addMutation("SPECULAR", specular);
-
-			const ShaderProgramResourceVariant* variant;
-			m_lightProg->getOrCreateVariant(variantInitInfo, variant);
-			m_lightGrProg[specular].reset(&variant->getProgram());
-		}
+		ANKI_CHECK(loadShaderProgram("ShaderBinaries/TraditionalDeferredShading.ankiprogbin", {{"SPECULAR", specular}}, m_lightProg,
+									 m_lightGrProg[specular]));
 	}
 
 	// Shadow sampler
@@ -43,17 +35,10 @@ Error TraditionalDeferredLightShading::init()
 	}
 
 	// Skybox
+	for(MutatorValue i = 0; i < m_skyboxGrProgs.getSize(); ++i)
 	{
-		ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/TraditionalDeferredShadingSkybox.ankiprogbin", m_skyboxProg));
-
-		for(U32 i = 0; i < m_skyboxGrProgs.getSize(); ++i)
-		{
-			ShaderProgramResourceVariantInitInfo variantInitInfo(m_skyboxProg);
-			variantInitInfo.addMutation("METHOD", i);
-			const ShaderProgramResourceVariant* variant;
-			m_skyboxProg->getOrCreateVariant(variantInitInfo, variant);
-			m_skyboxGrProgs[i].reset(&variant->getProgram());
-		}
+		ANKI_CHECK(
+			loadShaderProgram("ShaderBinaries/TraditionalDeferredShadingSkybox.ankiprogbin", {{"METHOD", i}}, m_skyboxProg, m_skyboxGrProgs[i]));
 	}
 
 	return Error::kNone;

+ 1 - 6
AnKi/Renderer/VolumetricFog.cpp

@@ -29,12 +29,7 @@ Error VolumetricFog::init()
 	ANKI_R_LOGV("Initializing volumetric fog. Resolution %ux%ux%u", m_volumeSize[0], m_volumeSize[1], m_volumeSize[2]);
 
 	// Shaders
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/VolumetricFogAccumulation.ankiprogbin", m_prog));
-
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
-	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(variantInitInfo, variant);
-	m_grProg.reset(&variant->getProgram());
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/VolumetricFogAccumulation.ankiprogbin", m_prog, m_grProg));
 
 	// RT descr
 	m_rtDescr = getRenderer().create2DRenderTargetDescription(m_volumeSize[0], m_volumeSize[1], Format::kR16G16B16A16_Sfloat, "Fog");

+ 1 - 8
AnKi/Renderer/VolumetricLightingAccumulation.cpp

@@ -44,14 +44,7 @@ Error VolumetricLightingAccumulation::init()
 	ANKI_CHECK(ResourceManager::getSingleton().loadResource("EngineAssets/BlueNoise_Rgba8_64x64.png", m_noiseImage));
 
 	// Shaders
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/VolumetricLightingAccumulation.ankiprogbin", m_prog));
-
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
-	variantInitInfo.addMutation("ENABLE_SHADOWS", 1);
-
-	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(variantInitInfo, variant);
-	m_grProg.reset(&variant->getProgram());
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/VolumetricLightingAccumulation.ankiprogbin", {{"ENABLE_SHADOWS", 1}}, m_prog, m_grProg));
 
 	// Create RTs
 	TextureInitInfo texinit = getRenderer().create2DRenderTargetInitInfo(m_volumeSize[0], m_volumeSize[1], Format::kR16G16B16A16_Sfloat,

+ 4 - 11
AnKi/Renderer/VrsSriGeneration.cpp

@@ -53,14 +53,12 @@ Error VrsSriGeneration::initInternal()
 
 	if(m_sriTexelDimension == 16 && GrManager::getSingleton().getDeviceCapabilities().m_minSubgroupSize >= 32)
 	{
-		// Algorithm's workgroup size is 32, GPU's subgroup size is min 32 -> each workgroup has 1 subgroup -> No need
-		// for shared mem
+		// Algorithm's workgroup size is 32, GPU's subgroup size is min 32 -> each workgroup has 1 subgroup -> No need for shared mem
 		variantInit.addMutation("SHARED_MEMORY", 0);
 	}
 	else if(m_sriTexelDimension == 8 && GrManager::getSingleton().getDeviceCapabilities().m_minSubgroupSize >= 16)
 	{
-		// Algorithm's workgroup size is 16, GPU's subgroup size is min 16 -> each workgroup has 1 subgroup -> No need
-		// for shared mem
+		// Algorithm's workgroup size is 16, GPU's subgroup size is min 16 -> each workgroup has 1 subgroup -> No need for shared mem
 		variantInit.addMutation("SHARED_MEMORY", 0);
 	}
 	else
@@ -74,13 +72,8 @@ Error VrsSriGeneration::initInternal()
 	m_prog->getOrCreateVariant(variantInit, variant);
 	m_grProg.reset(&variant->getProgram());
 
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/VrsSriVisualizeRenderTarget.ankiprogbin", m_visualizeProg));
-	m_visualizeProg->getOrCreateVariant(variant);
-	m_visualizeGrProg.reset(&variant->getProgram());
-
-	ANKI_CHECK(ResourceManager::getSingleton().loadResource("ShaderBinaries/VrsSriDownscale.ankiprogbin", m_downscaleProg));
-	m_downscaleProg->getOrCreateVariant(variant);
-	m_downscaleGrProg.reset(&variant->getProgram());
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/VrsSriVisualizeRenderTarget.ankiprogbin", m_visualizeProg, m_visualizeGrProg));
+	ANKI_CHECK(loadShaderProgram("ShaderBinaries/VrsSriDownscale.ankiprogbin", m_downscaleProg, m_downscaleGrProg));
 
 	return Error::kNone;
 }

+ 7 - 11
AnKi/Resource/MaterialResource.cpp

@@ -551,39 +551,35 @@ const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey&
 	case RenderingTechnique::kGBuffer:
 		if(key.getMeshShaders())
 		{
-			initInfo.requestShaderTypes(ShaderTypeBit::kAllModernGeometry | ShaderTypeBit::kFragment);
+			initInfo.requestTechniqueAndTypes(ShaderTypeBit::kAllModernGeometry | ShaderTypeBit::kFragment, "GBuffer");
 		}
 		else
 		{
-			initInfo.requestShaderTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kFragment);
+			initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kFragment, "GBuffer");
 		}
-		initInfo.requestTechnique("GBuffer");
 		break;
 	case RenderingTechnique::kDepth:
 		if(key.getMeshShaders())
 		{
-			initInfo.requestShaderTypes(ShaderTypeBit::kAllModernGeometry | ShaderTypeBit::kFragment);
+			initInfo.requestTechniqueAndTypes(ShaderTypeBit::kAllModernGeometry | ShaderTypeBit::kFragment, "Shadows");
 		}
 		else
 		{
-			initInfo.requestShaderTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kFragment);
+			initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kFragment, "Shadows");
 		}
-		initInfo.requestTechnique("Shadows");
 		break;
 	case RenderingTechnique::kForward:
 		if(key.getMeshShaders())
 		{
-			initInfo.requestShaderTypes(ShaderTypeBit::kAllModernGeometry | ShaderTypeBit::kFragment);
+			initInfo.requestTechniqueAndTypes(ShaderTypeBit::kAllModernGeometry | ShaderTypeBit::kFragment, "Forward");
 		}
 		else
 		{
-			initInfo.requestShaderTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kFragment);
+			initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kFragment, "Forward");
 		}
-		initInfo.requestTechnique("Forward");
 		break;
 	case RenderingTechnique::kRtShadow:
-		initInfo.requestShaderTypes(ShaderTypeBit::kAllHit);
-		initInfo.requestTechnique("RtShadows");
+		initInfo.requestTechniqueAndTypes(ShaderTypeBit::kAllHit, "RtShadows");
 		break;
 	}
 

+ 61 - 43
AnKi/Resource/ShaderProgramResource.cpp

@@ -54,62 +54,45 @@ void ShaderProgramResource::getOrCreateVariant(const ShaderProgramResourceVarian
 	// Sanity checks
 	ANKI_ASSERT(info.m_setMutators.getSetBitCount() == m_binary->m_mutators.getSize());
 
-	// Find the technique
-	const CString techniqueName = info.m_techniqueName.getBegin();
-	U32 techniqueIdx = kMaxU32;
-	for(U32 i = 0; i < m_binary->m_techniques.getSize(); ++i)
+	// User didn't provided Try to guess some defaults
+	if(!info.m_shaderTypes)
 	{
-		if(m_binary->m_techniques[i].m_name.getBegin() == techniqueName)
+		U32 techniqueIdx = kMaxU32;
+		for(U32 i = 0; i < m_binary->m_techniques.getSize(); ++i)
 		{
-			techniqueIdx = i;
-			break;
+			if(CString("Unnamed") == m_binary->m_techniques[i].m_name.getBegin())
+			{
+				techniqueIdx = i;
+				break;
+			}
 		}
-	}
-	ANKI_ASSERT(techniqueIdx != kMaxU32 && "Technique not found");
-	const ShaderProgramBinaryTechnique& technique = m_binary->m_techniques[techniqueIdx];
-
-	// Find the shader stages
-	if(info.m_shaderTypes == ShaderTypeBit::kNone)
-	{
-		// Try to guess the shader types
+		ANKI_ASSERT(techniqueIdx != kMaxU32);
+		const ShaderTypeBit techniqueShaderTypes = m_binary->m_techniques[techniqueIdx].m_shaderTypes;
 
-		if(technique.m_shaderTypes == ShaderTypeBit::kCompute)
-		{
-			// Only compute
-		}
-		else if((technique.m_shaderTypes & ~(ShaderTypeBit::kAllLegacyGeometry | ShaderTypeBit::kFragment)) == ShaderTypeBit::kNone)
+		if(techniqueShaderTypes == (ShaderTypeBit::kFragment | ShaderTypeBit::kVertex))
 		{
-			// Only legacy geometry
+			info.requestTechniqueAndTypes(techniqueShaderTypes, "Unnamed");
 		}
-		else if((technique.m_shaderTypes & ~(ShaderTypeBit::kAllModernGeometry | ShaderTypeBit::kFragment)) == ShaderTypeBit::kNone)
+		else if(techniqueShaderTypes == ShaderTypeBit::kCompute)
 		{
-			// Only modern geometry
-		}
-		else if((technique.m_shaderTypes & ~ShaderTypeBit::kAllHit) == ShaderTypeBit::kNone)
-		{
-			// Only hit
-		}
-		else if(technique.m_shaderTypes == ShaderTypeBit::kMiss)
-		{
-			// Only miss
-		}
-		else if(technique.m_shaderTypes == ShaderTypeBit::kRayGen)
-		{
-			// Only ray gen
+			info.requestTechniqueAndTypes(techniqueShaderTypes, "Unnamed");
 		}
 		else
 		{
 			ANKI_ASSERT(!"Can't figure out a sensible default");
 		}
-
-		info.m_shaderTypes = technique.m_shaderTypes;
 	}
 
-	ANKI_ASSERT((info.m_shaderTypes & technique.m_shaderTypes) == info.m_shaderTypes);
-
 	// Compute variant hash
 	U64 hash = computeHash(&info.m_shaderTypes, sizeof(info.m_shaderTypes));
-	hash = appendHash(techniqueName.cstr(), techniqueName.getLength(), hash);
+
+	for(ShaderType stype : EnumBitsIterable<ShaderType, ShaderTypeBit>(info.m_shaderTypes))
+	{
+		const PtrSize len = strlen(info.m_techniqueNames[stype].getBegin());
+		ANKI_ASSERT(len > 0);
+		hash = appendHash(info.m_techniqueNames[stype].getBegin(), len, hash);
+	}
+
 	if(m_binary->m_mutators.getSize())
 	{
 		hash = appendHash(info.m_mutation.getBegin(), m_binary->m_mutators.getSize() * sizeof(info.m_mutation[0]), hash);
@@ -145,7 +128,7 @@ void ShaderProgramResource::getOrCreateVariant(const ShaderProgramResourceVarian
 	}
 
 	// Create
-	ShaderProgramResourceVariant* v = createNewVariant(info, techniqueIdx);
+	ShaderProgramResourceVariant* v = createNewVariant(info);
 	if(v)
 	{
 		m_variants.emplace(hash, v);
@@ -157,7 +140,23 @@ void ShaderProgramResource::getOrCreateVariant(const ShaderProgramResourceVarian
 	}
 }
 
-ShaderProgramResourceVariant* ShaderProgramResource::createNewVariant(const ShaderProgramResourceVariantInitInfo& info, U32 techniqueIdx) const
+U32 ShaderProgramResource::findTechnique(CString name) const
+{
+	U32 techniqueIdx = kMaxU32;
+	for(U32 i = 0; i < m_binary->m_techniques.getSize(); ++i)
+	{
+		if(m_binary->m_techniques[i].m_name.getBegin() == name)
+		{
+			techniqueIdx = i;
+			break;
+		}
+	}
+	ANKI_ASSERT(techniqueIdx != kMaxU32 && "Technique not found");
+
+	return techniqueIdx;
+}
+
+ShaderProgramResourceVariant* ShaderProgramResource::createNewVariant(const ShaderProgramResourceVariantInitInfo& info) const
 {
 	// Get the binary program variant
 	const ShaderProgramBinaryVariant* binaryVariant = nullptr;
@@ -203,6 +202,11 @@ ShaderProgramResourceVariant* ShaderProgramResource::createNewVariant(const Shad
 		Array<ShaderPtr, U32(ShaderType::kCount)> shaderRefs; // Just for refcounting
 		for(ShaderType shaderType : EnumBitsIterable<ShaderType, ShaderTypeBit>(info.m_shaderTypes))
 		{
+			const ShaderTypeBit shaderBit = ShaderTypeBit(1 << shaderType);
+
+			const U32 techniqueIdx = findTechnique(info.m_techniqueNames[shaderType].getBegin());
+			ANKI_ASSERT(!!(m_binary->m_techniques[techniqueIdx].m_shaderTypes & shaderBit));
+
 			const ResourceString shaderName = (progName + "_" + m_binary->m_techniques[techniqueIdx].m_name.getBegin()).cstr();
 			ShaderInitInfo inf(shaderName);
 			inf.m_shaderType = shaderType;
@@ -210,7 +214,6 @@ ShaderProgramResourceVariant* ShaderProgramResource::createNewVariant(const Shad
 			ShaderPtr shader = GrManager::getSingleton().newShader(inf);
 			shaderRefs[shaderType] = shader;
 
-			const ShaderTypeBit shaderBit = ShaderTypeBit(1 << shaderType);
 			if(!!(shaderBit & ShaderTypeBit::kAllGraphics))
 			{
 				progInf.m_graphicsShaders[shaderType] = shader.get();
@@ -232,6 +235,21 @@ ShaderProgramResourceVariant* ShaderProgramResource::createNewVariant(const Shad
 	{
 		ANKI_ASSERT(!!(info.m_shaderTypes & ShaderTypeBit::kAllRayTracing));
 
+		U32 techniqueIdx = kMaxU32;
+		for(ShaderType shaderType : EnumBitsIterable<ShaderType, ShaderTypeBit>(info.m_shaderTypes))
+		{
+			const U32 idx = findTechnique(info.m_techniqueNames[shaderType].getBegin());
+			if(techniqueIdx == kMaxU32)
+			{
+				techniqueIdx = idx;
+			}
+			else
+			{
+				ANKI_ASSERT(idx == techniqueIdx && "Can't mix and match different techniques in ray tracing");
+			}
+		}
+		ANKI_ASSERT(techniqueIdx != kMaxU32);
+
 		// Find the library
 		const CString libName = m_binary->m_techniques[techniqueIdx].m_name.getBegin();
 		ANKI_ASSERT(libName.getLength() > 0);

+ 15 - 21
AnKi/Resource/ShaderProgramResource.h

@@ -57,15 +57,12 @@ class ShaderProgramResourceVariantInitInfo
 
 public:
 	ShaderProgramResourceVariantInitInfo()
-		: ShaderProgramResourceVariantInitInfo(ShaderProgramResourcePtr())
 	{
 	}
 
 	ShaderProgramResourceVariantInitInfo(const ShaderProgramResourcePtr& ptr)
 		: m_ptr(ptr)
 	{
-		Char name[] = "Unnamed";
-		memcpy(m_techniqueName.getBegin(), name, sizeof(name));
 	}
 
 	~ShaderProgramResourceVariantInitInfo()
@@ -74,18 +71,19 @@ public:
 
 	ShaderProgramResourceVariantInitInfo& addMutation(CString name, MutatorValue t);
 
-	/// Request a technique. If not set it will choose the "Unnamed" technique.
-	void requestTechnique(CString technique)
+	/// Request a non default technique and specific shaders.
+	void requestTechniqueAndTypes(ShaderTypeBit types, CString technique = "Unnamed")
 	{
-		const U32 len = technique.getLength();
-		ANKI_ASSERT(len <= kMaxTechniqueNameLength);
-		memcpy(m_techniqueName.getBegin(), technique.cstr(), len + 1);
-	}
+		ANKI_ASSERT(types != ShaderTypeBit::kNone);
+		ANKI_ASSERT(!(m_shaderTypes & types) && "Shader types already requested. Possibly programmer's error");
+		m_shaderTypes |= types;
 
-	/// Request specific shader types. You can ommit it if the program only contains one group of stages.
-	void requestShaderTypes(ShaderTypeBit types)
-	{
-		m_shaderTypes = types;
+		const U32 len = technique.getLength();
+		ANKI_ASSERT(len > 0 && len <= kMaxTechniqueNameLength);
+		for(ShaderType type : EnumBitsIterable<ShaderType, ShaderTypeBit>(types))
+		{
+			memcpy(m_techniqueNames[type].getBegin(), technique.cstr(), len + 1);
+		}
 	}
 
 private:
@@ -97,7 +95,7 @@ private:
 	Array<MutatorValue, kMaxMutators> m_mutation; ///< The order of storing the values is important. It will be hashed.
 	BitSet<kMaxMutators> m_setMutators = {false};
 
-	Array<Char, kMaxTechniqueNameLength + 1> m_techniqueName;
+	Array<Array<Char, kMaxTechniqueNameLength + 1>, U32(ShaderType::kCount)> m_techniqueNames = {};
 	ShaderTypeBit m_shaderTypes = ShaderTypeBit::kNone;
 };
 
@@ -134,19 +132,15 @@ public:
 	/// @note It's thread-safe.
 	void getOrCreateVariant(const ShaderProgramResourceVariantInitInfo& info, const ShaderProgramResourceVariant*& variant) const;
 
-	/// @copydoc getOrCreateVariant
-	void getOrCreateVariant(const ShaderProgramResourceVariant*& variant) const
-	{
-		getOrCreateVariant(ShaderProgramResourceVariantInitInfo(), variant);
-	}
-
 private:
 	ShaderProgramBinary* m_binary = nullptr;
 
 	mutable ResourceHashMap<U64, ShaderProgramResourceVariant*> m_variants;
 	mutable RWMutex m_mtx;
 
-	ShaderProgramResourceVariant* createNewVariant(const ShaderProgramResourceVariantInitInfo& info, U32 techniqueIdx) const;
+	ShaderProgramResourceVariant* createNewVariant(const ShaderProgramResourceVariantInitInfo& info) const;
+
+	U32 findTechnique(CString name) const;
 };
 
 inline ShaderProgramResourceVariantInitInfo& ShaderProgramResourceVariantInitInfo::addMutation(CString name, MutatorValue t)