Browse Source

Add a raster path on a couple of passes

Panagiotis Christopoulos Charitos 4 years ago
parent
commit
0929f2141f

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

@@ -8,6 +8,7 @@ ANKI_CONFIG_VAR_GROUP(R)
 ANKI_CONFIG_VAR_U8(RTextureAnisotropy, 8, 1, 16, "Texture anisotropy for the main passes")
 ANKI_CONFIG_VAR_U32(RTileSize, 64, 8, 256, "Tile lighting tile size")
 ANKI_CONFIG_VAR_U32(RZSplitCount, 64, 8, 1024, "Clusterer number of Z splits")
+ANKI_CONFIG_VAR_BOOL(RPreferCompute, !ANKI_OS_ANDROID, "Prefer compute shaders")
 
 ANKI_CONFIG_VAR_F32(RInternalRenderScaling, 1.0f, 0.5f, 1.0f,
 					"A factor over the requested swapchain resolution. Applies to all passes up to TAA")

+ 111 - 31
AnKi/Renderer/Scale.cpp

@@ -35,16 +35,32 @@ Error Scale::init()
 		return Error::NONE;
 	}
 
-	ANKI_R_LOGI("Initializing (up|down)scale pass");
-
+	const Bool preferCompute = getConfig().getRPreferCompute();
 	const U32 fsrQuality = getConfig().getRFsr();
 	m_fsr = fsrQuality != 0;
 
 	// Program
 	if(needsScaling)
 	{
-		ANKI_CHECK(getResourceManager().loadResource((m_fsr) ? "Shaders/Fsr.ankiprog" : "Shaders/BlitCompute.ankiprog",
-													 m_scaleProg));
+		CString shaderFname;
+		if(m_fsr && preferCompute)
+		{
+			shaderFname = "Shaders/FsrCompute.ankiprog";
+		}
+		else if(m_fsr)
+		{
+			shaderFname = "Shaders/FsrRaster.ankiprog";
+		}
+		else if(preferCompute)
+		{
+			shaderFname = "Shaders/BlitCompute.ankiprog";
+		}
+		else
+		{
+			shaderFname = "Shaders/BlitRaster.ankiprog";
+		}
+
+		ANKI_CHECK(getResourceManager().loadResource(shaderFname, m_scaleProg));
 		const ShaderProgramResourceVariant* variant;
 		if(m_fsr)
 		{
@@ -62,7 +78,8 @@ Error Scale::init()
 
 	if(needsSharpening)
 	{
-		ANKI_CHECK(getResourceManager().loadResource("Shaders/Fsr.ankiprog", m_sharpenProg));
+		ANKI_CHECK(getResourceManager().loadResource(
+			(preferCompute) ? "Shaders/FsrCompute.ankiprog" : "Shaders/FsrRaster.ankiprog", m_sharpenProg));
 		ShaderProgramResourceVariantInitInfo variantInitInfo(m_sharpenProg);
 		variantInitInfo.addMutation("SHARPEN", 1);
 		variantInitInfo.addMutation("FSR_QUALITY", 0);
@@ -71,12 +88,15 @@ Error Scale::init()
 		m_sharpenGrProg = variant->getProgram();
 	}
 
-	// The RT desc
+	// Descriptors
 	m_rtDesc =
 		m_r->create2DRenderTargetDescription(m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y(),
 											 LIGHT_SHADING_COLOR_ATTACHMENT_PIXEL_FORMAT, "Scaled");
 	m_rtDesc.bake();
 
+	m_fbDescr.m_colorAttachmentCount = 1;
+	m_fbDescr.bake();
+
 	return Error::NONE;
 }
 
@@ -89,49 +109,88 @@ void Scale::populateRenderGraph(RenderingContext& ctx)
 		return;
 	}
 
+	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
+	const Bool preferCompute = getConfig().getRPreferCompute();
+
 	if(doScaling())
 	{
-		RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
-
 		m_runCtx.m_scaledRt = rgraph.newRenderTarget(m_rtDesc);
 
-		ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Scale");
-		pass.newDependency(
-			RenderPassDependency(m_r->getTemporalAA().getTonemappedRt(), TextureUsageBit::SAMPLED_COMPUTE));
-		pass.newDependency(RenderPassDependency(m_runCtx.m_scaledRt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
+		if(preferCompute)
+		{
+			ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Scale");
+			pass.newDependency(
+				RenderPassDependency(m_r->getTemporalAA().getTonemappedRt(), TextureUsageBit::SAMPLED_COMPUTE));
+			pass.newDependency(RenderPassDependency(m_runCtx.m_scaledRt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
+
+			pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+				runScaling(rgraphCtx);
+			});
+		}
+		else
+		{
+			GraphicsRenderPassDescription& pass = ctx.m_renderGraphDescr.newGraphicsRenderPass("Scale");
+			pass.setFramebufferInfo(m_fbDescr, {m_runCtx.m_scaledRt}, {});
+
+			pass.newDependency(
+				RenderPassDependency(m_r->getTemporalAA().getTonemappedRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+			pass.newDependency(
+				RenderPassDependency(m_runCtx.m_scaledRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
 
-		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
-			runScaling(rgraphCtx);
-		});
+			pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+				runScaling(rgraphCtx);
+			});
+		}
 	}
 
 	if(doSharpening())
 	{
-		RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
-
 		m_runCtx.m_sharpenedRt = rgraph.newRenderTarget(m_rtDesc);
 
-		ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Sharpen");
-		pass.newDependency(
-			RenderPassDependency((!doScaling()) ? m_r->getTemporalAA().getTonemappedRt() : m_runCtx.m_scaledRt,
-								 TextureUsageBit::SAMPLED_COMPUTE));
-		pass.newDependency(RenderPassDependency(m_runCtx.m_sharpenedRt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
-
-		pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
-			runSharpening(rgraphCtx);
-		});
+		if(preferCompute)
+		{
+			ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Sharpen");
+			pass.newDependency(
+				RenderPassDependency((!doScaling()) ? m_r->getTemporalAA().getTonemappedRt() : m_runCtx.m_scaledRt,
+									 TextureUsageBit::SAMPLED_COMPUTE));
+			pass.newDependency(RenderPassDependency(m_runCtx.m_sharpenedRt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
+
+			pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+				runSharpening(rgraphCtx);
+			});
+		}
+		else
+		{
+			GraphicsRenderPassDescription& pass = ctx.m_renderGraphDescr.newGraphicsRenderPass("Sharpen");
+			pass.setFramebufferInfo(m_fbDescr, {m_runCtx.m_sharpenedRt}, {});
+
+			pass.newDependency(
+				RenderPassDependency((!doScaling()) ? m_r->getTemporalAA().getTonemappedRt() : m_runCtx.m_scaledRt,
+									 TextureUsageBit::SAMPLED_FRAGMENT));
+			pass.newDependency(
+				RenderPassDependency(m_runCtx.m_sharpenedRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
+
+			pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+				runSharpening(rgraphCtx);
+			});
+		}
 	}
 }
 
 void Scale::runScaling(RenderPassWorkContext& rgraphCtx)
 {
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+	const Bool preferCompute = getConfig().getRPreferCompute();
 
 	cmdb->bindShaderProgram(m_scaleGrProg);
 
 	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
 	rgraphCtx.bindColorTexture(0, 1, m_r->getTemporalAA().getTonemappedRt());
-	rgraphCtx.bindImage(0, 2, m_runCtx.m_scaledRt);
+
+	if(preferCompute)
+	{
+		rgraphCtx.bindImage(0, 2, m_runCtx.m_scaledRt);
+	}
 
 	if(m_fsr)
 	{
@@ -155,7 +214,7 @@ void Scale::runScaling(RenderPassWorkContext& rgraphCtx)
 
 		cmdb->setPushConstants(&pc, sizeof(pc));
 	}
-	else
+	else if(preferCompute)
 	{
 		class
 		{
@@ -169,18 +228,31 @@ void Scale::runScaling(RenderPassWorkContext& rgraphCtx)
 		cmdb->setPushConstants(&pc, sizeof(pc));
 	}
 
-	dispatchPPCompute(cmdb, 8, 8, m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y());
+	if(preferCompute)
+	{
+		dispatchPPCompute(cmdb, 8, 8, m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y());
+	}
+	else
+	{
+		cmdb->setViewport(0, 0, m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y());
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);
+	}
 }
 
 void Scale::runSharpening(RenderPassWorkContext& rgraphCtx)
 {
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+	const Bool preferCompute = getConfig().getRPreferCompute();
 
 	cmdb->bindShaderProgram(m_sharpenGrProg);
 
 	cmdb->bindSampler(0, 0, m_r->getSamplers().m_trilinearClamp);
 	rgraphCtx.bindColorTexture(0, 1, (!doScaling()) ? m_r->getTemporalAA().getTonemappedRt() : m_runCtx.m_scaledRt);
-	rgraphCtx.bindImage(0, 2, m_runCtx.m_sharpenedRt);
+
+	if(preferCompute)
+	{
+		rgraphCtx.bindImage(0, 2, m_runCtx.m_sharpenedRt);
+	}
 
 	class
 	{
@@ -199,7 +271,15 @@ void Scale::runSharpening(RenderPassWorkContext& rgraphCtx)
 
 	cmdb->setPushConstants(&pc, sizeof(pc));
 
-	dispatchPPCompute(cmdb, 8, 8, m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y());
+	if(preferCompute)
+	{
+		dispatchPPCompute(cmdb, 8, 8, m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y());
+	}
+	else
+	{
+		cmdb->setViewport(0, 0, m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y());
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);
+	}
 }
 
 } // end namespace anki

+ 1 - 0
AnKi/Renderer/Scale.h

@@ -38,6 +38,7 @@ private:
 	ShaderProgramResourcePtr m_sharpenProg;
 	ShaderProgramPtr m_sharpenGrProg;
 
+	FramebufferDescription m_fbDescr;
 	RenderTargetDescription m_rtDesc;
 
 	Bool m_fsr = false;

+ 57 - 17
AnKi/Renderer/ShadowmapsResolve.cpp

@@ -32,14 +32,25 @@ Error ShadowmapsResolve::initInternal()
 	width = min(m_r->getInternalResolution().x(), getAlignedRoundUp(4, width));
 	U32 height = U32(getConfig().getRSmResolveFactor() * F32(m_r->getInternalResolution().y()));
 	height = min(m_r->getInternalResolution().y(), getAlignedRoundUp(4, height));
-	ANKI_R_LOGI("Initializing shadow resolve pass. Size %ux%u", width, height);
 
 	m_rtDescr = m_r->create2DRenderTargetDescription(width, height, Format::R8G8B8A8_UNORM, "SM resolve");
 	m_rtDescr.bake();
 
-	ANKI_CHECK(getResourceManager().loadResource("Shaders/ShadowmapsResolve.ankiprog", m_prog));
+	// Create FB descr
+	m_fbDescr.m_colorAttachmentCount = 1;
+	m_fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::CLEAR;
+	m_fbDescr.bake();
+
+	// Prog
+	ANKI_CHECK(getResourceManager().loadResource((getConfig().getRPreferCompute())
+													 ? "Shaders/ShadowmapsResolveCompute.ankiprog"
+													 : "Shaders/ShadowmapsResolveRaster.ankiprog",
+												 m_prog));
 	ShaderProgramResourceVariantInitInfo variantInitInfo(m_prog);
-	variantInitInfo.addConstant("FB_SIZE", UVec2(width, height));
+	if(getConfig().getRPreferCompute())
+	{
+		variantInitInfo.addConstant("FB_SIZE", UVec2(width, height));
+	}
 	variantInitInfo.addConstant("TILE_COUNTS", m_r->getTileCounts());
 	variantInitInfo.addConstant("Z_SPLIT_COUNT", m_r->getZSplitCount());
 	variantInitInfo.addConstant("TILE_SIZE", m_r->getTileSize());
@@ -55,18 +66,39 @@ void ShadowmapsResolve::populateRenderGraph(RenderingContext& ctx)
 	RenderGraphDescription& rgraph = ctx.m_renderGraphDescr;
 	m_runCtx.m_rt = rgraph.newRenderTarget(m_rtDescr);
 
-	ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("SM resolve");
-	rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
-		run(ctx, rgraphCtx);
-	});
+	if(getConfig().getRPreferCompute())
+	{
+		ComputeRenderPassDescription& rpass = rgraph.newComputeRenderPass("SM resolve");
+
+		rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
+			run(ctx, rgraphCtx);
+		});
+
+		rpass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
+		rpass.newDependency(RenderPassDependency(m_r->getGBuffer().getDepthRt(), TextureUsageBit::SAMPLED_COMPUTE));
+		rpass.newDependency(
+			RenderPassDependency(m_r->getShadowMapping().getShadowmapRt(), TextureUsageBit::SAMPLED_COMPUTE));
 
-	rpass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
-	rpass.newDependency(RenderPassDependency(m_r->getGBuffer().getDepthRt(), TextureUsageBit::SAMPLED_COMPUTE));
-	rpass.newDependency(
-		RenderPassDependency(m_r->getShadowMapping().getShadowmapRt(), TextureUsageBit::SAMPLED_COMPUTE));
+		rpass.newDependency(
+			RenderPassDependency(ctx.m_clusteredShading.m_clustersBufferHandle, BufferUsageBit::STORAGE_COMPUTE_READ));
+	}
+	else
+	{
+		GraphicsRenderPassDescription& rpass = rgraph.newGraphicsRenderPass("SM resolve");
+		rpass.setFramebufferInfo(m_fbDescr, {m_runCtx.m_rt}, {});
 
-	rpass.newDependency(
-		RenderPassDependency(ctx.m_clusteredShading.m_clustersBufferHandle, BufferUsageBit::STORAGE_COMPUTE_READ));
+		rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
+			run(ctx, rgraphCtx);
+		});
+
+		rpass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
+		rpass.newDependency(RenderPassDependency(m_r->getGBuffer().getDepthRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+		rpass.newDependency(
+			RenderPassDependency(m_r->getShadowMapping().getShadowmapRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+
+		rpass.newDependency(
+			RenderPassDependency(ctx.m_clusteredShading.m_clustersBufferHandle, BufferUsageBit::STORAGE_FRAGMENT_READ));
+	}
 }
 
 void ShadowmapsResolve::run(const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx)
@@ -82,11 +114,19 @@ void ShadowmapsResolve::run(const RenderingContext& ctx, RenderPassWorkContext&
 	rgraphCtx.bindColorTexture(0, 3, m_r->getShadowMapping().getShadowmapRt());
 	bindStorage(cmdb, 0, 4, rsrc.m_clustersToken);
 
-	rgraphCtx.bindImage(0, 5, m_runCtx.m_rt, TextureSubresourceInfo());
-	cmdb->bindSampler(0, 6, m_r->getSamplers().m_trilinearClamp);
-	rgraphCtx.bindTexture(0, 7, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
+	cmdb->bindSampler(0, 5, m_r->getSamplers().m_trilinearClamp);
+	rgraphCtx.bindTexture(0, 6, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
 
-	dispatchPPCompute(cmdb, 8, 8, m_rtDescr.m_width, m_rtDescr.m_height);
+	if(getConfig().getRPreferCompute())
+	{
+		rgraphCtx.bindImage(0, 7, m_runCtx.m_rt, TextureSubresourceInfo());
+		dispatchPPCompute(cmdb, 8, 8, m_rtDescr.m_width, m_rtDescr.m_height);
+	}
+	else
+	{
+		cmdb->setViewport(0, 0, m_rtDescr.m_width, m_rtDescr.m_height);
+		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);
+	}
 }
 
 } // end namespace anki

+ 1 - 0
AnKi/Renderer/ShadowmapsResolve.h

@@ -46,6 +46,7 @@ public:
 	ShaderProgramResourcePtr m_prog;
 	ShaderProgramPtr m_grProg;
 	RenderTargetDescription m_rtDescr;
+	FramebufferDescription m_fbDescr;
 
 	class
 	{

+ 0 - 0
AnKi/Shaders/BlitGraphics.ankiprog → AnKi/Shaders/BlitRaster.ankiprog


+ 18 - 9
AnKi/Shaders/Fsr.ankiprog → AnKi/Shaders/Fsr.glsl

@@ -6,13 +6,16 @@
 #pragma anki mutator SHARPEN 0 1
 #pragma anki mutator FSR_QUALITY 0 1
 
-#pragma anki start comp
-
 #include <AnKi/Shaders/Functions.glsl>
 
 layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
 layout(set = 0, binding = 1) uniform ANKI_RP texture2D u_tex;
+#if defined(ANKI_COMPUTE_SHADER)
 layout(set = 0, binding = 2) writeonly uniform ANKI_RP image2D u_outImg;
+layout(local_size_x = 8, local_size_y = 8) in;
+#else
+layout(location = 0) out Vec3 out_color;
+#endif
 
 layout(push_constant, std430) uniform b_pc
 {
@@ -69,25 +72,31 @@ AH3 FsrEasuSampleH(AF2 p)
 #include <ThirdParty/FidelityFX/ffx_fsr1.h>
 // FSR end
 
-layout(local_size_x = 8, local_size_y = 8) in;
-
 void main()
 {
+#if defined(ANKI_COMPUTE_SHADER)
 	if(skipOutOfBoundsInvocations(UVec2(8u), u_viewportSize))
 	{
 		return;
 	}
 
+	const UVec2 uv = gl_GlobalInvocationID.xy;
+#else
+	const UVec2 uv = UVec2(gl_FragCoord.xy);
+#endif
+
 	HVec3 color;
 #if SHARPEN
-	FsrRcasH(color.r, color.g, color.b, gl_GlobalInvocationID.xy, u_fsrConsts0);
+	FsrRcasH(color.r, color.g, color.b, uv, u_fsrConsts0);
 #elif FSR_QUALITY == 0
-	FsrEasuL(color, gl_GlobalInvocationID.xy, u_fsrConsts0, u_fsrConsts1, u_fsrConsts2, u_fsrConsts3);
+	FsrEasuL(color, uv, u_fsrConsts0, u_fsrConsts1, u_fsrConsts2, u_fsrConsts3);
 #else
-	FsrEasuH(color, gl_GlobalInvocationID.xy, u_fsrConsts0, u_fsrConsts1, u_fsrConsts2, u_fsrConsts3);
+	FsrEasuH(color, uv, u_fsrConsts0, u_fsrConsts1, u_fsrConsts2, u_fsrConsts3);
 #endif
 
+#if defined(ANKI_COMPUTE_SHADER)
 	imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), Vec4(color, 0.0));
+#else
+	out_color = Vec3(color);
+#endif
 }
-
-#pragma anki end

+ 8 - 0
AnKi/Shaders/FsrCompute.ankiprog

@@ -0,0 +1,8 @@
+// Copyright (C) 2009-2021, 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/Fsr.glsl>
+#pragma anki end

+ 12 - 0
AnKi/Shaders/FsrRaster.ankiprog

@@ -0,0 +1,12 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki start vert
+#include <AnKi/Shaders/QuadVert.glsl>
+#pragma anki end
+
+#pragma anki start frag
+#include <AnKi/Shaders/Fsr.glsl>
+#pragma anki end

+ 22 - 9
AnKi/Shaders/ShadowmapsResolve.ankiprog → AnKi/Shaders/ShadowmapsResolve.glsl

@@ -3,8 +3,6 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#pragma anki start comp
-
 ANKI_SPECIALIZATION_CONSTANT_UVEC2(FB_SIZE, 0u);
 ANKI_SPECIALIZATION_CONSTANT_UVEC2(TILE_COUNTS, 2u);
 ANKI_SPECIALIZATION_CONSTANT_U32(Z_SPLIT_COUNT, 4u);
@@ -16,29 +14,42 @@ ANKI_SPECIALIZATION_CONSTANT_U32(TILE_SIZE, 5u);
 #define CLUSTERED_SHADING_CLUSTERS_BINDING 4
 #include <AnKi/Shaders/ClusteredShadingCommon.glsl>
 
+layout(set = 0, binding = 5) uniform sampler u_linearAnyClampSampler;
+layout(set = 0, binding = 6) uniform texture2D u_depthRt;
+
+#if defined(ANKI_COMPUTE_SHADER)
 const UVec2 WORKGROUP_SIZE = UVec2(8, 8);
 layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 5, rgba8) writeonly uniform ANKI_RP image2D u_outImg;
-layout(set = 0, binding = 6) uniform sampler u_linearAnyClampSampler;
-layout(set = 0, binding = 7) uniform texture2D u_depthRt;
+layout(set = 0, binding = 7, rgba8) writeonly uniform ANKI_RP image2D u_outImg;
+#else
+layout(location = 0) in Vec2 in_uv;
+layout(location = 0) out Vec4 out_color;
+#endif
 
 void main()
 {
+#if defined(ANKI_COMPUTE_SHADER)
 	if(skipOutOfBoundsInvocations(WORKGROUP_SIZE, FB_SIZE))
 	{
 		return;
 	}
+	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(FB_SIZE);
+#else
+	const Vec2 uv = in_uv;
+#endif
 
 	// World position
-	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(FB_SIZE);
 	const Vec2 ndc = UV_TO_NDC(uv);
 	const F32 depth = textureLod(u_depthRt, u_linearAnyClampSampler, uv, 0.0).r;
 	const Vec4 worldPos4 = u_clusteredShading.m_matrices.m_invertedViewProjectionJitter * Vec4(ndc, depth, 1.0);
 	const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
 
 	// Cluster
+#if defined(ANKI_COMPUTE_SHADER)
 	const Vec2 fragCoord = uv * u_clusteredShading.m_renderingSize;
+#else
+	const Vec2 fragCoord = gl_FragCoord.xy;
+#endif
 	Cluster cluster = getClusterFragCoord(Vec3(fragCoord, depth), TILE_SIZE, TILE_COUNTS, Z_SPLIT_COUNT,
 										  u_clusteredShading.m_zSplitMagic.x, u_clusteredShading.m_zSplitMagic.y);
 
@@ -111,8 +122,10 @@ void main()
 	}
 
 	// Store
+#if defined(ANKI_COMPUTE_SHADER)
 	imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy),
 			   Vec4(shadowFactors[0], shadowFactors[1], shadowFactors[2], shadowFactors[3]));
+#else
+	out_color = Vec4(shadowFactors[0], shadowFactors[1], shadowFactors[2], shadowFactors[3]);
+#endif
 }
-
-#pragma anki end

+ 8 - 0
AnKi/Shaders/ShadowmapsResolveCompute.ankiprog

@@ -0,0 +1,8 @@
+// Copyright (C) 2009-2021, 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/ShadowmapsResolve.glsl>
+#pragma anki end

+ 12 - 0
AnKi/Shaders/ShadowmapsResolveRaster.ankiprog

@@ -0,0 +1,12 @@
+// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki start vert
+#include <AnKi/Shaders/QuadVert.glsl>
+#pragma anki end
+
+#pragma anki start frag
+#include <AnKi/Shaders/ShadowmapsResolve.glsl>
+#pragma anki end