Browse Source

Change the way VRS is calculated for SSR

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
d16ffdfda6

+ 0 - 1
AnKi/Renderer/ConfigVars.defs.h

@@ -38,7 +38,6 @@ ANKI_CONFIG_VAR_U32(RSsrMaxSteps, 64, 1, 256, "Max SSR raymarching steps")
 ANKI_CONFIG_VAR_BOOL(RSsrStochastic, false, "Stochastic reflections")
 ANKI_CONFIG_VAR_BOOL(RSsrStochastic, false, "Stochastic reflections")
 ANKI_CONFIG_VAR_F32(RSsrRoughnessCutoff, ((ANKI_PLATFORM_MOBILE) ? 0.7f : 1.0f), 0.0f, 1.0f,
 ANKI_CONFIG_VAR_F32(RSsrRoughnessCutoff, ((ANKI_PLATFORM_MOBILE) ? 0.7f : 1.0f), 0.0f, 1.0f,
 					"Materials with roughness higher that this value will fallback to probe reflections")
 					"Materials with roughness higher that this value will fallback to probe reflections")
-ANKI_CONFIG_VAR_F32(RSsrVrsThreshold, 0.05f, 0.0f, 1.0f, "Threshold under which a lower shading rate will be applied")
 
 
 // GI probes
 // GI probes
 ANKI_CONFIG_VAR_U32(RIndirectDiffuseProbeTileResolution, ((ANKI_PLATFORM_MOBILE) ? 16 : 32), 8, 32,
 ANKI_CONFIG_VAR_U32(RIndirectDiffuseProbeTileResolution, ((ANKI_PLATFORM_MOBILE) ? 16 : 32), 8, 32,

+ 7 - 90
AnKi/Renderer/IndirectSpecular.cpp

@@ -11,6 +11,7 @@
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Renderer/ProbeReflections.h>
 #include <AnKi/Renderer/ProbeReflections.h>
 #include <AnKi/Renderer/MotionVectors.h>
 #include <AnKi/Renderer/MotionVectors.h>
+#include <AnKi/Renderer/VrsSriGeneration.h>
 #include <AnKi/Core/ConfigSet.h>
 #include <AnKi/Core/ConfigSet.h>
 
 
 namespace anki {
 namespace anki {
@@ -65,51 +66,6 @@ Error IndirectSpecular::initInternal()
 	m_prog->getOrCreateVariant(variantInit, variant);
 	m_prog->getOrCreateVariant(variantInit, variant);
 	m_grProg = variant->getProgram();
 	m_grProg = variant->getProgram();
 
 
-	// Init VRS SRI generation
-	const Bool enableVrs = getGrManager().getDeviceCapabilities().m_vrs && getConfig().getRVrs() && !preferCompute;
-	if(enableVrs)
-	{
-		m_vrs.m_sriTexelDimension = getGrManager().getDeviceCapabilities().m_minShadingRateImageTexelSize;
-		ANKI_ASSERT(m_vrs.m_sriTexelDimension == 8 || m_vrs.m_sriTexelDimension == 16);
-
-		const UVec2 rez = (size + m_vrs.m_sriTexelDimension - 1) / m_vrs.m_sriTexelDimension;
-		m_vrs.m_rtHandle =
-			m_r->create2DRenderTargetDescription(rez.x(), rez.y(), Format::R8_UINT, "IndirectSpecularVrsSri");
-		m_vrs.m_rtHandle.bake();
-
-		ANKI_CHECK(getResourceManager().loadResource("ShaderBinaries/IndirectSpecularVrsSriGeneration.ankiprogbin",
-													 m_vrs.m_prog));
-
-		ShaderProgramResourceVariantInitInfo variantInit(m_vrs.m_prog);
-		variantInit.addMutation("SRI_TEXEL_DIMENSION", m_vrs.m_sriTexelDimension);
-
-		if(m_vrs.m_sriTexelDimension == 16 && getGrManager().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
-			variantInit.addMutation("SHARED_MEMORY", 0);
-		}
-		else if(m_vrs.m_sriTexelDimension == 8 && getGrManager().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
-			variantInit.addMutation("SHARED_MEMORY", 0);
-		}
-		else
-		{
-			variantInit.addMutation("SHARED_MEMORY", 1);
-		}
-
-		const ShaderProgramResourceVariant* variant;
-		m_vrs.m_prog->getOrCreateVariant(variantInit, variant);
-		m_vrs.m_grProg = variant->getProgram();
-
-		ANKI_CHECK(getResourceManager().loadResource("ShaderBinaries/VrsSriVisualizeRenderTarget.ankiprogbin",
-													 m_vrs.m_visualizeProg));
-		m_vrs.m_visualizeProg->getOrCreateVariant(variant);
-		m_vrs.m_visualizeGrProg = variant->getProgram();
-	}
-
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
@@ -142,8 +98,8 @@ void IndirectSpecular::populateRenderGraph(RenderingContext& ctx)
 
 
 		if(enableVrs)
 		if(enableVrs)
 		{
 		{
-			m_fbDescr.m_shadingRateAttachmentTexelWidth = m_vrs.m_sriTexelDimension;
-			m_fbDescr.m_shadingRateAttachmentTexelHeight = m_vrs.m_sriTexelDimension;
+			m_fbDescr.m_shadingRateAttachmentTexelWidth = m_r->getVrsSriGeneration().getSriTexelDimension();
+			m_fbDescr.m_shadingRateAttachmentTexelHeight = m_r->getVrsSriGeneration().getSriTexelDimension();
 		}
 		}
 		else
 		else
 		{
 		{
@@ -154,41 +110,6 @@ void IndirectSpecular::populateRenderGraph(RenderingContext& ctx)
 		m_fbDescr.bake();
 		m_fbDescr.bake();
 	}
 	}
 
 
-	// VRS SRI
-	if(enableVrs)
-	{
-		m_runCtx.m_sriRt = rgraph.newRenderTarget(m_vrs.m_rtHandle);
-
-		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("IndirectSpecular VRS SRI gen");
-
-		pass.newDependency(RenderPassDependency(m_runCtx.m_sriRt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
-		pass.newDependency(RenderPassDependency(m_runCtx.m_rts[READ], TextureUsageBit::SAMPLED_COMPUTE));
-
-		pass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
-			const UVec2 viewport = m_r->getInternalResolution() / 2u;
-
-			CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-
-			cmdb->bindShaderProgram(m_vrs.m_grProg);
-
-			rgraphCtx.bindColorTexture(0, 0, m_runCtx.m_rts[READ]);
-			cmdb->bindSampler(0, 1, m_r->getSamplers().m_nearestNearestClamp);
-			rgraphCtx.bindImage(0, 2, m_runCtx.m_sriRt);
-
-			class
-			{
-			public:
-				Vec4 m_v4;
-			} pc;
-
-			pc.m_v4 = Vec4(1.0f / Vec2(viewport), getConfig().getRSsrVrsThreshold(), 0.0f);
-
-			cmdb->setPushConstants(&pc, sizeof(pc));
-
-			dispatchPPCompute(cmdb, m_vrs.m_sriTexelDimension, m_vrs.m_sriTexelDimension, viewport.x(), viewport.y());
-		});
-	}
-
 	// Create pass
 	// Create pass
 	{
 	{
 		RenderPassDescriptionBase* ppass;
 		RenderPassDescriptionBase* ppass;
@@ -206,7 +127,8 @@ void IndirectSpecular::populateRenderGraph(RenderingContext& ctx)
 		{
 		{
 			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSR");
 			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("SSR");
 			pass.setFramebufferInfo(m_fbDescr, {m_runCtx.m_rts[WRITE]}, {},
 			pass.setFramebufferInfo(m_fbDescr, {m_runCtx.m_rts[WRITE]}, {},
-									(enableVrs) ? m_runCtx.m_sriRt : RenderTargetHandle());
+									(enableVrs) ? m_r->getVrsSriGeneration().getDownscaledSriRt()
+												: RenderTargetHandle());
 
 
 			ppass = &pass;
 			ppass = &pass;
 			readUsage = TextureUsageBit::SAMPLED_FRAGMENT;
 			readUsage = TextureUsageBit::SAMPLED_FRAGMENT;
@@ -214,7 +136,8 @@ void IndirectSpecular::populateRenderGraph(RenderingContext& ctx)
 
 
 			if(enableVrs)
 			if(enableVrs)
 			{
 			{
-				ppass->newDependency(RenderPassDependency(m_runCtx.m_sriRt, TextureUsageBit::FRAMEBUFFER_SHADING_RATE));
+				ppass->newDependency(RenderPassDependency(m_r->getVrsSriGeneration().getDownscaledSriRt(),
+														  TextureUsageBit::FRAMEBUFFER_SHADING_RATE));
 			}
 			}
 		}
 		}
 
 
@@ -308,12 +231,6 @@ void IndirectSpecular::getDebugRenderTarget(CString rtName, RenderTargetHandle&
 	{
 	{
 		handle = m_runCtx.m_rts[WRITE];
 		handle = m_runCtx.m_rts[WRITE];
 	}
 	}
-	else
-	{
-		ANKI_ASSERT(rtName == "IndirectSpecularVrsSri");
-		handle = m_runCtx.m_sriRt;
-		optionalShaderProgram = m_vrs.m_visualizeGrProg;
-	}
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 0 - 15
AnKi/Renderer/IndirectSpecular.h

@@ -20,7 +20,6 @@ public:
 		: RendererObject(r)
 		: RendererObject(r)
 	{
 	{
 		registerDebugRenderTarget("SSR");
 		registerDebugRenderTarget("SSR");
-		registerDebugRenderTarget("IndirectSpecularVrsSri");
 	}
 	}
 
 
 	~IndirectSpecular();
 	~IndirectSpecular();
@@ -49,24 +48,10 @@ private:
 
 
 	ImageResourcePtr m_noiseImage;
 	ImageResourcePtr m_noiseImage;
 
 
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		ShaderProgramPtr m_grProg;
-		RenderTargetDescription m_rtHandle;
-
-		ShaderProgramResourcePtr m_visualizeProg;
-		ShaderProgramPtr m_visualizeGrProg;
-
-		U32 m_sriTexelDimension = 16;
-	} m_vrs;
-
 	class
 	class
 	{
 	{
 	public:
 	public:
 		Array<RenderTargetHandle, 2> m_rts;
 		Array<RenderTargetHandle, 2> m_rts;
-		RenderTargetHandle m_sriRt;
 	} m_runCtx;
 	} m_runCtx;
 
 
 	ANKI_USE_RESULT Error initInternal();
 	ANKI_USE_RESULT Error initInternal();

+ 71 - 25
AnKi/Renderer/VrsSriGeneration.cpp

@@ -13,7 +13,8 @@ namespace anki {
 VrsSriGeneration::VrsSriGeneration(Renderer* r)
 VrsSriGeneration::VrsSriGeneration(Renderer* r)
 	: RendererObject(r)
 	: RendererObject(r)
 {
 {
-	registerDebugRenderTarget("VRS");
+	registerDebugRenderTarget("VrsSri");
+	registerDebugRenderTarget("VrsSriDownscaled");
 }
 }
 
 
 VrsSriGeneration::~VrsSriGeneration()
 VrsSriGeneration::~VrsSriGeneration()
@@ -43,16 +44,17 @@ Error VrsSriGeneration::initInternal()
 
 
 	ANKI_R_LOGV("Intializing VRS SRI generation. SRI resolution %ux%u", rez.x(), rez.y());
 	ANKI_R_LOGV("Intializing VRS SRI generation. SRI resolution %ux%u", rez.x(), rez.y());
 
 
-	// SRI
-	const TextureUsageBit texUsage = TextureUsageBit::FRAMEBUFFER_SHADING_RATE | TextureUsageBit::IMAGE_COMPUTE_WRITE
-									 | TextureUsageBit::SAMPLED_FRAGMENT;
+	// Create textures
+	const TextureUsageBit texUsage =
+		TextureUsageBit::FRAMEBUFFER_SHADING_RATE | TextureUsageBit::IMAGE_COMPUTE_WRITE | TextureUsageBit::ALL_SAMPLED;
 	TextureInitInfo sriInitInfo =
 	TextureInitInfo sriInitInfo =
-		m_r->create2DRenderTargetInitInfo(rez.x(), rez.y(), Format::R8_UINT, texUsage, "VRS SRI");
+		m_r->create2DRenderTargetInitInfo(rez.x(), rez.y(), Format::R8_UINT, texUsage, "VrsSri");
 	m_sriTex = m_r->createAndClearRenderTarget(sriInitInfo, TextureUsageBit::FRAMEBUFFER_SHADING_RATE);
 	m_sriTex = m_r->createAndClearRenderTarget(sriInitInfo, TextureUsageBit::FRAMEBUFFER_SHADING_RATE);
 
 
-	// Descr
-	m_fbDescr.m_colorAttachmentCount = 1;
-	m_fbDescr.bake();
+	const UVec2 rezDownscaled = (m_r->getInternalResolution() / 2 + m_sriTexelDimension - 1) / m_sriTexelDimension;
+	sriInitInfo = m_r->create2DRenderTargetInitInfo(rezDownscaled.x(), rezDownscaled.y(), Format::R8_UINT, texUsage,
+													"VrsSriDownscaled");
+	m_downscaledSriTex = m_r->createAndClearRenderTarget(sriInitInfo, TextureUsageBit::FRAMEBUFFER_SHADING_RATE);
 
 
 	// Load programs
 	// Load programs
 	ANKI_CHECK(getResourceManager().loadResource("ShaderBinaries/VrsSriGenerationCompute.ankiprogbin", m_prog));
 	ANKI_CHECK(getResourceManager().loadResource("ShaderBinaries/VrsSriGenerationCompute.ankiprogbin", m_prog));
@@ -85,14 +87,26 @@ Error VrsSriGeneration::initInternal()
 	m_visualizeProg->getOrCreateVariant(variant);
 	m_visualizeProg->getOrCreateVariant(variant);
 	m_visualizeGrProg = variant->getProgram();
 	m_visualizeGrProg = variant->getProgram();
 
 
+	ANKI_CHECK(getResourceManager().loadResource("ShaderBinaries/VrsSriDownscale.ankiprogbin", m_downscaleProg));
+	m_downscaleProg->getOrCreateVariant(variant);
+	m_downscaleGrProg = variant->getProgram();
+
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
 void VrsSriGeneration::getDebugRenderTarget(CString rtName, RenderTargetHandle& handle,
 void VrsSriGeneration::getDebugRenderTarget(CString rtName, RenderTargetHandle& handle,
 											ShaderProgramPtr& optionalShaderProgram) const
 											ShaderProgramPtr& optionalShaderProgram) const
 {
 {
-	ANKI_ASSERT(rtName == "VRS");
-	handle = m_runCtx.m_rt;
+	if(rtName == "VrsSri")
+	{
+		handle = m_runCtx.m_rt;
+	}
+	else
+	{
+		ANKI_ASSERT(rtName == "VrsSriDownscaled");
+		handle = m_runCtx.m_downscaledRt;
+	}
+
 	optionalShaderProgram = m_visualizeGrProg;
 	optionalShaderProgram = m_visualizeGrProg;
 }
 }
 
 
@@ -107,10 +121,13 @@ void VrsSriGeneration::importRenderTargets(RenderingContext& ctx)
 	if(m_sriTexImportedOnce)
 	if(m_sriTexImportedOnce)
 	{
 	{
 		m_runCtx.m_rt = ctx.m_renderGraphDescr.importRenderTarget(m_sriTex);
 		m_runCtx.m_rt = ctx.m_renderGraphDescr.importRenderTarget(m_sriTex);
+		m_runCtx.m_downscaledRt = ctx.m_renderGraphDescr.importRenderTarget(m_downscaledSriTex);
 	}
 	}
 	else
 	else
 	{
 	{
 		m_runCtx.m_rt = ctx.m_renderGraphDescr.importRenderTarget(m_sriTex, TextureUsageBit::FRAMEBUFFER_SHADING_RATE);
 		m_runCtx.m_rt = ctx.m_renderGraphDescr.importRenderTarget(m_sriTex, TextureUsageBit::FRAMEBUFFER_SHADING_RATE);
+		m_runCtx.m_downscaledRt =
+			ctx.m_renderGraphDescr.importRenderTarget(m_downscaledSriTex, TextureUsageBit::FRAMEBUFFER_SHADING_RATE);
 		m_sriTexImportedOnce = true;
 		m_sriTexImportedOnce = true;
 	}
 	}
 }
 }
@@ -125,26 +142,55 @@ void VrsSriGeneration::populateRenderGraph(RenderingContext& ctx)
 
 
 	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
 	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
 
 
-	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("VRS SRI generation");
+	// SRI generation
+	{
+		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("VRS SRI generation");
+
+		pass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
+		pass.newDependency(
+			RenderPassDependency(m_r->getTemporalAA().getTonemappedRt(), TextureUsageBit::SAMPLED_COMPUTE));
 
 
-	pass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
-	pass.newDependency(RenderPassDependency(m_r->getTemporalAA().getTonemappedRt(), TextureUsageBit::SAMPLED_COMPUTE));
+		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+			CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
 
-	pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
-		CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+			cmdb->bindShaderProgram(m_grProg);
 
 
-		cmdb->bindShaderProgram(m_grProg);
+			rgraphCtx.bindColorTexture(0, 0, m_r->getTemporalAA().getTonemappedRt());
+			cmdb->bindSampler(0, 1, m_r->getSamplers().m_nearestNearestClamp);
+			rgraphCtx.bindImage(0, 2, m_runCtx.m_rt);
+			const Vec4 pc(1.0f / Vec2(m_r->getInternalResolution()), getConfig().getRVrsThreshold(), 0.0f);
+			cmdb->setPushConstants(&pc, sizeof(pc));
 
 
-		rgraphCtx.bindColorTexture(0, 0, m_r->getTemporalAA().getTonemappedRt());
-		cmdb->bindSampler(0, 1, m_r->getSamplers().m_nearestNearestClamp);
-		rgraphCtx.bindImage(0, 2, m_runCtx.m_rt);
-		const Vec4 pc(1.0f / Vec2(m_r->getInternalResolution()), getConfig().getRVrsThreshold(), 0.0f);
-		cmdb->setPushConstants(&pc, sizeof(pc));
+			const U32 fakeWorkgroupSizeXorY = m_sriTexelDimension;
+			dispatchPPCompute(cmdb, fakeWorkgroupSizeXorY, fakeWorkgroupSizeXorY, m_r->getInternalResolution().x(),
+							  m_r->getInternalResolution().y());
+		});
+	}
+
+	// Downscale
+	{
+		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("VRS SRI downscale");
+
+		pass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::SAMPLED_COMPUTE));
+		pass.newDependency(RenderPassDependency(m_runCtx.m_downscaledRt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
+
+		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+			const UVec2 rezDownscaled =
+				(m_r->getInternalResolution() / 2 + m_sriTexelDimension - 1) / m_sriTexelDimension;
 
 
-		const U32 fakeWorkgroupSizeXorY = m_sriTexelDimension;
-		dispatchPPCompute(cmdb, fakeWorkgroupSizeXorY, fakeWorkgroupSizeXorY, m_r->getInternalResolution().x(),
-						  m_r->getInternalResolution().y());
-	});
+			CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+
+			cmdb->bindShaderProgram(m_downscaleGrProg);
+
+			rgraphCtx.bindColorTexture(0, 0, m_runCtx.m_rt);
+			cmdb->bindSampler(0, 1, m_r->getSamplers().m_nearestNearestClamp);
+			rgraphCtx.bindImage(0, 2, m_runCtx.m_downscaledRt);
+			const Vec4 pc(1.0f / Vec2(rezDownscaled), 0.0f, 0.0f);
+			cmdb->setPushConstants(&pc, sizeof(pc));
+
+			dispatchPPCompute(cmdb, 8, 8, rezDownscaled.x(), rezDownscaled.y());
+		});
+	}
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 10 - 1
AnKi/Renderer/VrsSriGeneration.h

@@ -31,6 +31,11 @@ public:
 		return m_runCtx.m_rt;
 		return m_runCtx.m_rt;
 	}
 	}
 
 
+	RenderTargetHandle getDownscaledSriRt() const
+	{
+		return m_runCtx.m_downscaledRt;
+	}
+
 	U32 getSriTexelDimension() const
 	U32 getSriTexelDimension() const
 	{
 	{
 		return m_sriTexelDimension;
 		return m_sriTexelDimension;
@@ -43,9 +48,12 @@ public:
 	ShaderProgramResourcePtr m_visualizeProg;
 	ShaderProgramResourcePtr m_visualizeProg;
 	ShaderProgramPtr m_visualizeGrProg;
 	ShaderProgramPtr m_visualizeGrProg;
 
 
+	ShaderProgramResourcePtr m_downscaleProg;
+	ShaderProgramPtr m_downscaleGrProg;
+
 	TexturePtr m_sriTex;
 	TexturePtr m_sriTex;
+	TexturePtr m_downscaledSriTex;
 	Bool m_sriTexImportedOnce = false;
 	Bool m_sriTexImportedOnce = false;
-	FramebufferDescription m_fbDescr;
 
 
 	U32 m_sriTexelDimension = 16;
 	U32 m_sriTexelDimension = 16;
 
 
@@ -53,6 +61,7 @@ public:
 	{
 	{
 	public:
 	public:
 		RenderTargetHandle m_rt;
 		RenderTargetHandle m_rt;
+		RenderTargetHandle m_downscaledRt;
 	} m_runCtx;
 	} m_runCtx;
 
 
 	ANKI_USE_RESULT Error initInternal();
 	ANKI_USE_RESULT Error initInternal();

+ 0 - 166
AnKi/Shaders/IndirectSpecularVrsSriGeneration.ankiprog

@@ -1,166 +0,0 @@
-// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki mutator SRI_TEXEL_DIMENSION 8 16
-#pragma anki mutator SHARED_MEMORY 0 1
-
-#pragma anki start comp
-
-#include <AnKi/Shaders/Functions.glsl>
-#include <AnKi/Shaders/TonemappingFunctions.glsl>
-
-layout(set = 0, binding = 0) uniform ANKI_RP texture2D u_inputTex;
-layout(set = 0, binding = 1) uniform sampler u_nearestClampSampler;
-
-#if SRI_TEXEL_DIMENSION == 8
-const UVec2 REGION_SIZE = UVec2(2u, 2u);
-#else
-const UVec2 REGION_SIZE = UVec2(2u, 4u);
-#endif
-
-const UVec2 WORKGROUP_SIZE = UVec2(SRI_TEXEL_DIMENSION) / REGION_SIZE;
-layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 2) uniform writeonly uimage2D u_sriImg;
-
-layout(push_constant, std140, row_major) uniform b_pc
-{
-	Vec2 u_oneOverViewportSize;
-	F32 u_threshold;
-	F32 u_padding0;
-};
-
-#if SHARED_MEMORY
-// Ideally, we'd be able to calculate the min/max/average using subgroup operations, but there's no guarantee
-// subgroupSize is large enough so we need shared memory as a fallback. We need gl_NumSubgroups entries, but it is not a
-// constant, so estimate it assuming a subgroupSize of at least 8.
-const U32 SHARED_MEMORY_ENTRIES = WORKGROUP_SIZE.x * WORKGROUP_SIZE.y / 8u;
-shared F32 s_averageLuma[SHARED_MEMORY_ENTRIES];
-shared Vec2 s_maxDerivative[SHARED_MEMORY_ENTRIES];
-#endif
-
-F32 sampleLuma(Vec2 uv, I32 offsetX, I32 offsetY)
-{
-	uv += Vec2(offsetX, offsetY) * u_oneOverViewportSize;
-	const Vec3 color = textureLod(sampler2D(u_inputTex, u_nearestClampSampler), uv, 0.0).xyz;
-	const F32 luma = computeLuminance(color);
-
-	return (2.0f * luma) / (1.0f + luma);
-}
-
-void main()
-{
-	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) * Vec2(REGION_SIZE) + 0.5) * u_oneOverViewportSize;
-
-#if SRI_TEXEL_DIMENSION == 8
-	// Get positions
-	// l0.z  l0.w
-	// l0.x  l0.y
-	Vec4 l0;
-	l0.x = sampleLuma(uv, 0, 0);
-	l0.y = sampleLuma(uv, 1, 0);
-	l0.z = sampleLuma(uv, 0, 1);
-	l0.w = sampleLuma(uv, 1, 1);
-
-	// Calculate derivatives.
-	Vec2 a = Vec2(l0.y, l0.z);
-	Vec2 b = Vec2(l0.x, l0.w);
-	const Vec2 dx = abs(a - b);
-
-	a = Vec2(l0.z, l0.w);
-	b = Vec2(l0.x, l0.y);
-	const Vec2 dy = abs(a - b);
-
-	F32 maxDerivativeX = max(dx.x, dx.y);
-	F32 maxDerivativeY = max(dy.x, dy.y);
-
-	F32 averageLuma = (l0.x + l0.y + l0.z + l0.w) / 4.0;
-#else
-	// Get luminance.
-	//       l2.z
-	// l1.z  l1.w  l2.y
-	// l1.x  l1.y
-	// l0.z  l0.w  l2.x
-	// l0.x  l0.y
-	Vec4 l0;
-	l0.x = sampleLuma(uv, 0, 0);
-	l0.y = sampleLuma(uv, 1, 0);
-	l0.z = sampleLuma(uv, 0, 1);
-	l0.w = sampleLuma(uv, 1, 1);
-
-	Vec4 l1;
-	l1.x = sampleLuma(uv, 0, 2);
-	l1.y = sampleLuma(uv, 1, 2);
-	l1.z = sampleLuma(uv, 0, 3);
-	l1.w = sampleLuma(uv, 1, 3);
-
-	Vec3 l2;
-	l2.x = sampleLuma(uv, 2, 1);
-	l2.y = sampleLuma(uv, 2, 3);
-	l2.z = sampleLuma(uv, 1, 4);
-
-	// Calculate derivatives.
-	Vec4 a = Vec4(l0.y, l2.x, l1.y, l2.y);
-	Vec4 b = Vec4(l0.x, l0.w, l1.x, l1.w);
-	const Vec4 dx = abs(a - b);
-
-	a = Vec4(l0.z, l0.w, l1.z, l2.z);
-	b = Vec4(l0.x, l0.y, l1.x, l1.w);
-	const Vec4 dy = abs(a - b);
-
-	F32 maxDerivativeX = max(max(dx.x, dx.y), max(dx.z, dx.w));
-	F32 maxDerivativeY = max(max(dy.x, dy.y), max(dy.z, dy.w));
-
-	const Vec4 sumL0L1 = l0 + l1;
-	F32 averageLuma = (sumL0L1.x + sumL0L1.y + sumL0L1.z + sumL0L1.w) / 8.0;
-#endif
-
-	maxDerivativeX = subgroupMax(maxDerivativeX);
-	maxDerivativeY = subgroupMax(maxDerivativeY);
-	averageLuma = subgroupAdd(averageLuma);
-
-#if SHARED_MEMORY
-	// Store results in shared memory.
-	ANKI_BRANCH if(subgroupElect())
-	{
-		s_maxDerivative[gl_SubgroupID] = Vec2(maxDerivativeX, maxDerivativeY);
-		s_maxDerivative[gl_SubgroupID] = Vec2(maxDerivativeX, maxDerivativeY);
-	}
-
-	memoryBarrierShared();
-	barrier();
-#endif
-
-	// Write the result
-	ANKI_BRANCH if(gl_LocalInvocationIndex == 0u)
-	{
-		// Get max across all subgroups.
-#if SHARED_MEMORY
-		Vec2 maxDerivative = s_maxDerivative[0];
-
-		for(U32 i = 1u; i < gl_NumSubgroups; ++i)
-		{
-			maxDerivative = max(maxDerivative, s_maxDerivative[i]);
-		}
-#else
-		const Vec2 maxDerivative = Vec2(maxDerivativeX, maxDerivativeY);
-#endif
-
-		// Determine shading rate.
-		const F32 avgLuma = averageLuma / F32(WORKGROUP_SIZE.x * WORKGROUP_SIZE.y);
-		const Vec2 lumaDiff = maxDerivative / avgLuma;
-		const F32 threshold1 = u_threshold;
-		const F32 threshold2 = threshold1 * 0.4;
-
-		UVec2 rate;
-		rate.x = (lumaDiff.x > threshold1) ? 1u : ((lumaDiff.x > threshold2) ? 2u : 4u);
-		rate.y = (lumaDiff.y > threshold1) ? 1u : ((lumaDiff.y > threshold2) ? 2u : 4u);
-
-		const UVec2 outTexelCoord = gl_WorkGroupID.xy;
-		imageStore(u_sriImg, IVec2(outTexelCoord), UVec4(encodeVrsRate(rate)));
-	}
-}
-
-#pragma anki end

+ 37 - 0
AnKi/Shaders/VrsSriDownscale.ankiprog

@@ -0,0 +1,37 @@
+// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki start comp
+
+#include <AnKi/Shaders/Functions.glsl>
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+layout(binding = 0) uniform utexture2D u_inputTex;
+layout(binding = 1) uniform sampler u_nearestAnyClampSampler;
+layout(binding = 2) uniform uimage2D u_outputImage;
+
+layout(push_constant, std140) uniform b_pc
+{
+	Vec2 u_oneOverViewportSize;
+	F32 u_padding0;
+	F32 u_padding1;
+};
+
+void main()
+{
+	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) * u_oneOverViewportSize;
+
+	const UVec4 rates = textureGather(usampler2D(u_inputTex, u_nearestAnyClampSampler), uv, 0);
+
+	UVec2 rate = decodeVrsRate(rates[0]);
+	rate = max(rate, decodeVrsRate(rates[1]));
+	rate = max(rate, decodeVrsRate(rates[2]));
+	rate = max(rate, decodeVrsRate(rates[3]));
+
+	imageStore(u_outputImage, IVec2(gl_GlobalInvocationID.xy), UVec4(encodeVrsRate(rate)));
+}
+
+#pragma anki end

+ 0 - 170
AnKi/Shaders/VrsSriGeneration.glsl

@@ -1,170 +0,0 @@
-// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki mutator SRI_TEXEL_DIMENSION 8 16
-#pragma anki mutator SHARED_MEMORY 0 1
-
-#include <AnKi/Shaders/Functions.glsl>
-#include <AnKi/Shaders/TonemappingFunctions.glsl>
-
-// Find the maximum luma derivative in x and y, relative to the average luma of the block.
-// Each thread handles a 2x2 region when using 8x8 VRS tiles and a 2x4 region when using 16x16 VRS tiles.
-
-layout(set = 0, binding = 0) uniform ANKI_RP texture2D u_inputTex;
-layout(set = 0, binding = 1) uniform sampler u_nearestClampSampler;
-
-#if SRI_TEXEL_DIMENSION == 8
-const UVec2 REGION_SIZE = UVec2(2u, 2u);
-#else
-const UVec2 REGION_SIZE = UVec2(2u, 4u);
-#endif
-
-const UVec2 WORKGROUP_SIZE = UVec2(SRI_TEXEL_DIMENSION) / REGION_SIZE;
-layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 2) uniform writeonly uimage2D u_sriImg;
-
-layout(push_constant, std430) uniform b_pc
-{
-	Vec2 u_oneOverViewportSize;
-	F32 u_threshold;
-	F32 u_padding0;
-};
-
-#if SHARED_MEMORY
-// Ideally, we'd be able to calculate the min/max/average using subgroup operations, but there's no guarantee
-// subgroupSize is large enough so we need shared memory as a fallback. We need gl_NumSubgroups entries, but it is not a
-// constant, so estimate it assuming a subgroupSize of at least 8.
-const U32 SHARED_MEMORY_ENTRIES = WORKGROUP_SIZE.x * WORKGROUP_SIZE.y / 8u;
-shared F32 s_averageLuma[SHARED_MEMORY_ENTRIES];
-shared Vec2 s_maxDerivative[SHARED_MEMORY_ENTRIES];
-#endif
-
-#define sampleLuma(offsetX, offsetY) \
-	computeLuminance( \
-		textureLodOffset(sampler2D(u_inputTex, u_nearestClampSampler), uv, 0.0, IVec2(offsetX, offsetY)).xyz)
-
-void main()
-{
-	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) * Vec2(REGION_SIZE) + 0.5) * u_oneOverViewportSize;
-
-#if SRI_TEXEL_DIMENSION == 8
-	// Get luminance.
-	//       l1.y
-	// l0.z  l0.w  l1.x
-	// l0.x  l0.y
-	Vec4 l0;
-	l0.x = sampleLuma(0, 0);
-	l0.y = sampleLuma(1, 0);
-	l0.z = sampleLuma(0, 1);
-	l0.w = sampleLuma(1, 1);
-
-	Vec2 l1;
-	l1.x = sampleLuma(2, 1);
-	l1.y = sampleLuma(1, 2);
-
-	// Calculate derivatives.
-	Vec2 a = Vec2(l0.y, l1.x);
-	Vec2 b = Vec2(l0.x, l0.w);
-	const Vec2 dx = abs(a - b);
-
-	a = Vec2(l0.z, l1.y);
-	b = Vec2(l0.x, l0.w);
-	const Vec2 dy = abs(a - b);
-
-	F32 maxDerivativeX = max(dx.x, dx.y);
-	F32 maxDerivativeY = max(dy.x, dy.y);
-
-	// Calculate average luma.
-	F32 averageLuma = (l0.x + l0.y + l0.z + l0.w) / 4.0;
-#else
-	// Get luminance.
-	//       l2.z
-	// l1.z  l1.w  l2.y
-	// l1.x  l1.y
-	// l0.z  l0.w  l2.x
-	// l0.x  l0.y
-	Vec4 l0;
-	l0.x = sampleLuma(0, 0);
-	l0.y = sampleLuma(1, 0);
-	l0.z = sampleLuma(0, 1);
-	l0.w = sampleLuma(1, 1);
-
-	Vec4 l1;
-	l1.x = sampleLuma(0, 2);
-	l1.y = sampleLuma(1, 2);
-	l1.z = sampleLuma(0, 3);
-	l1.w = sampleLuma(1, 3);
-
-	Vec3 l2;
-	l2.x = sampleLuma(2, 1);
-	l2.y = sampleLuma(2, 3);
-	l2.z = sampleLuma(1, 4);
-
-	// Calculate derivatives.
-	Vec4 a = Vec4(l0.y, l2.x, l1.y, l2.y);
-	Vec4 b = Vec4(l0.x, l0.w, l1.x, l1.w);
-	const Vec4 dx = abs(a - b);
-
-	a = Vec4(l0.z, l0.w, l1.z, l2.z);
-	b = Vec4(l0.x, l0.y, l1.x, l1.w);
-	const Vec4 dy = abs(a - b);
-
-	F32 maxDerivativeX = max(max(dx.x, dx.y), max(dx.z, dx.w));
-	F32 maxDerivativeY = max(max(dy.x, dy.y), max(dy.z, dy.w));
-
-	// Calculate average luma.
-	const Vec4 sumL0L1 = l0 + l1;
-	F32 averageLuma = (sumL0L1.x + sumL0L1.y + sumL0L1.z + sumL0L1.w) / 8.0;
-#endif
-
-	// Share values in subgroup.
-	maxDerivativeX = subgroupMax(maxDerivativeX);
-	maxDerivativeY = subgroupMax(maxDerivativeY);
-	averageLuma = subgroupAdd(averageLuma);
-
-#if SHARED_MEMORY
-	// Store results in shared memory.
-	ANKI_BRANCH if(subgroupElect())
-	{
-		s_averageLuma[gl_SubgroupID] = averageLuma;
-		s_maxDerivative[gl_SubgroupID] = Vec2(maxDerivativeX, maxDerivativeY);
-	}
-
-	memoryBarrierShared();
-	barrier();
-#endif
-
-	// Write the result
-	ANKI_BRANCH if(gl_LocalInvocationIndex == 0u)
-	{
-		// Get max across all subgroups.
-#if SHARED_MEMORY
-		averageLuma = s_averageLuma[0];
-		Vec2 maxDerivative = s_maxDerivative[0];
-
-		for(U32 i = 1u; i < gl_NumSubgroups; ++i)
-		{
-			averageLuma += s_averageLuma[i];
-			maxDerivative = max(maxDerivative, s_maxDerivative[i]);
-		}
-#else
-		const Vec2 maxDerivative = Vec2(maxDerivativeX, maxDerivativeY);
-#endif
-
-		// Determine shading rate.
-		const F32 avgLuma = averageLuma / F32(WORKGROUP_SIZE.x * WORKGROUP_SIZE.y);
-		const Vec2 lumaDiff = maxDerivative / avgLuma;
-		const F32 threshold1 = u_threshold;
-		const F32 threshold2 = threshold1 * 0.4;
-
-		UVec2 rate;
-		rate.x = (lumaDiff.x > threshold1) ? 1u : ((lumaDiff.x > threshold2) ? 2u : 4u);
-		rate.y = (lumaDiff.y > threshold1) ? 1u : ((lumaDiff.y > threshold2) ? 2u : 4u);
-
-		const UVec2 outTexelCoord = gl_WorkGroupID.xy;
-		imageStore(u_sriImg, IVec2(outTexelCoord), UVec4(encodeVrsRate(rate)));
-	}
-}

+ 167 - 1
AnKi/Shaders/VrsSriGenerationCompute.ankiprog

@@ -3,6 +3,172 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
+#pragma anki mutator SRI_TEXEL_DIMENSION 8 16
+#pragma anki mutator SHARED_MEMORY 0 1
+
 #pragma anki start comp
 #pragma anki start comp
-#include <AnKi/Shaders/VrsSriGeneration.glsl>
+
+#include <AnKi/Shaders/Functions.glsl>
+#include <AnKi/Shaders/TonemappingFunctions.glsl>
+
+// Find the maximum luma derivative in x and y, relative to the average luma of the block.
+// Each thread handles a 2x2 region when using 8x8 VRS tiles and a 2x4 region when using 16x16 VRS tiles.
+
+layout(set = 0, binding = 0) uniform ANKI_RP texture2D u_inputTex;
+layout(set = 0, binding = 1) uniform sampler u_nearestClampSampler;
+
+#if SRI_TEXEL_DIMENSION == 8
+const UVec2 REGION_SIZE = UVec2(2u, 2u);
+#else
+const UVec2 REGION_SIZE = UVec2(2u, 4u);
+#endif
+
+const UVec2 WORKGROUP_SIZE = UVec2(SRI_TEXEL_DIMENSION) / REGION_SIZE;
+layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
+
+layout(set = 0, binding = 2) uniform writeonly uimage2D u_sriImg;
+
+layout(push_constant, std430) uniform b_pc
+{
+	Vec2 u_oneOverViewportSize;
+	F32 u_threshold;
+	F32 u_padding0;
+};
+
+#if SHARED_MEMORY
+// Ideally, we'd be able to calculate the min/max/average using subgroup operations, but there's no guarantee
+// subgroupSize is large enough so we need shared memory as a fallback. We need gl_NumSubgroups entries, but it is not a
+// constant, so estimate it assuming a subgroupSize of at least 8.
+const U32 SHARED_MEMORY_ENTRIES = WORKGROUP_SIZE.x * WORKGROUP_SIZE.y / 8u;
+shared F32 s_averageLuma[SHARED_MEMORY_ENTRIES];
+shared Vec2 s_maxDerivative[SHARED_MEMORY_ENTRIES];
+#endif
+
+#define sampleLuma(offsetX, offsetY) \
+	computeLuminance( \
+		textureLodOffset(sampler2D(u_inputTex, u_nearestClampSampler), uv, 0.0, IVec2(offsetX, offsetY)).xyz)
+
+void main()
+{
+	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) * Vec2(REGION_SIZE) + 0.5) * u_oneOverViewportSize;
+
+#if SRI_TEXEL_DIMENSION == 8
+	// Get luminance.
+	//       l1.y
+	// l0.z  l0.w  l1.x
+	// l0.x  l0.y
+	Vec4 l0;
+	l0.x = sampleLuma(0, 0);
+	l0.y = sampleLuma(1, 0);
+	l0.z = sampleLuma(0, 1);
+	l0.w = sampleLuma(1, 1);
+
+	Vec2 l1;
+	l1.x = sampleLuma(2, 1);
+	l1.y = sampleLuma(1, 2);
+
+	// Calculate derivatives.
+	Vec2 a = Vec2(l0.y, l1.x);
+	Vec2 b = Vec2(l0.x, l0.w);
+	const Vec2 dx = abs(a - b);
+
+	a = Vec2(l0.z, l1.y);
+	b = Vec2(l0.x, l0.w);
+	const Vec2 dy = abs(a - b);
+
+	F32 maxDerivativeX = max(dx.x, dx.y);
+	F32 maxDerivativeY = max(dy.x, dy.y);
+
+	// Calculate average luma.
+	F32 averageLuma = (l0.x + l0.y + l0.z + l0.w) / 4.0;
+#else
+	// Get luminance.
+	//       l2.z
+	// l1.z  l1.w  l2.y
+	// l1.x  l1.y
+	// l0.z  l0.w  l2.x
+	// l0.x  l0.y
+	Vec4 l0;
+	l0.x = sampleLuma(0, 0);
+	l0.y = sampleLuma(1, 0);
+	l0.z = sampleLuma(0, 1);
+	l0.w = sampleLuma(1, 1);
+
+	Vec4 l1;
+	l1.x = sampleLuma(0, 2);
+	l1.y = sampleLuma(1, 2);
+	l1.z = sampleLuma(0, 3);
+	l1.w = sampleLuma(1, 3);
+
+	Vec3 l2;
+	l2.x = sampleLuma(2, 1);
+	l2.y = sampleLuma(2, 3);
+	l2.z = sampleLuma(1, 4);
+
+	// Calculate derivatives.
+	Vec4 a = Vec4(l0.y, l2.x, l1.y, l2.y);
+	Vec4 b = Vec4(l0.x, l0.w, l1.x, l1.w);
+	const Vec4 dx = abs(a - b);
+
+	a = Vec4(l0.z, l0.w, l1.z, l2.z);
+	b = Vec4(l0.x, l0.y, l1.x, l1.w);
+	const Vec4 dy = abs(a - b);
+
+	F32 maxDerivativeX = max(max(dx.x, dx.y), max(dx.z, dx.w));
+	F32 maxDerivativeY = max(max(dy.x, dy.y), max(dy.z, dy.w));
+
+	// Calculate average luma.
+	const Vec4 sumL0L1 = l0 + l1;
+	F32 averageLuma = (sumL0L1.x + sumL0L1.y + sumL0L1.z + sumL0L1.w) / 8.0;
+#endif
+
+	// Share values in subgroup.
+	maxDerivativeX = subgroupMax(maxDerivativeX);
+	maxDerivativeY = subgroupMax(maxDerivativeY);
+	averageLuma = subgroupAdd(averageLuma);
+
+#if SHARED_MEMORY
+	// Store results in shared memory.
+	ANKI_BRANCH if(subgroupElect())
+	{
+		s_averageLuma[gl_SubgroupID] = averageLuma;
+		s_maxDerivative[gl_SubgroupID] = Vec2(maxDerivativeX, maxDerivativeY);
+	}
+
+	memoryBarrierShared();
+	barrier();
+#endif
+
+	// Write the result
+	ANKI_BRANCH if(gl_LocalInvocationIndex == 0u)
+	{
+		// Get max across all subgroups.
+#if SHARED_MEMORY
+		averageLuma = s_averageLuma[0];
+		Vec2 maxDerivative = s_maxDerivative[0];
+
+		for(U32 i = 1u; i < gl_NumSubgroups; ++i)
+		{
+			averageLuma += s_averageLuma[i];
+			maxDerivative = max(maxDerivative, s_maxDerivative[i]);
+		}
+#else
+		const Vec2 maxDerivative = Vec2(maxDerivativeX, maxDerivativeY);
+#endif
+
+		// Determine shading rate.
+		const F32 avgLuma = averageLuma / F32(WORKGROUP_SIZE.x * WORKGROUP_SIZE.y);
+		const Vec2 lumaDiff = maxDerivative / avgLuma;
+		const F32 threshold1 = u_threshold;
+		const F32 threshold2 = threshold1 * 0.4;
+
+		UVec2 rate;
+		rate.x = (lumaDiff.x > threshold1) ? 1u : ((lumaDiff.x > threshold2) ? 2u : 4u);
+		rate.y = (lumaDiff.y > threshold1) ? 1u : ((lumaDiff.y > threshold2) ? 2u : 4u);
+
+		const UVec2 outTexelCoord = gl_WorkGroupID.xy;
+		imageStore(u_sriImg, IVec2(outTexelCoord), UVec4(encodeVrsRate(rate)));
+	}
+}
+
 #pragma anki end
 #pragma anki end

+ 2 - 2
Samples/Common/SampleApp.cpp

@@ -95,11 +95,11 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 		}
 		}
 		else if(idx == 1)
 		else if(idx == 1)
 		{
 		{
-			renderer.setCurrentDebugRenderTarget("IndirectSpecularVrsSri");
+			renderer.setCurrentDebugRenderTarget("VrsSriDownscaled");
 		}
 		}
 		else if(idx == 2)
 		else if(idx == 2)
 		{
 		{
-			renderer.setCurrentDebugRenderTarget("VRS");
+			renderer.setCurrentDebugRenderTarget("VrsSri");
 		}
 		}
 		else
 		else
 		{
 		{

+ 1 - 1
Sandbox/Main.cpp

@@ -389,7 +389,7 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 		}
 		}
 		else if(idx == 2)
 		else if(idx == 2)
 		{
 		{
-			renderer.setCurrentDebugRenderTarget("VRS");
+			renderer.setCurrentDebugRenderTarget("VrsSri");
 		}
 		}
 		else
 		else
 		{
 		{