Browse Source

Add tonemapping to DLSS

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
1560a7cc69

+ 2 - 2
AnKi/Renderer/ConfigVars.defs.h

@@ -88,6 +88,6 @@ ANKI_CONFIG_VAR_BOOL(RRtShadowsSvgf, false, "Enable or not RT shadows SVGF")
 ANKI_CONFIG_VAR_U8(RRtShadowsSvgfAtrousPassCount, 3, 1, 20, "Number of atrous passes of SVGF")
 ANKI_CONFIG_VAR_U32(RRtShadowsRaysPerPixel, 1, 1, 8, "Number of shadow rays per pixel")
 
-ANKI_CONFIG_VAR_U8(RFsr, 1, 0, 2, "0: Use bilinear, 1: FSR low quality, 2: FSR high quality")
-ANKI_CONFIG_VAR_U8(RDlss, 2, 0, 3, "0: Disabled, 1: Performance, 2: Balanced, 3: Quality")
+ANKI_CONFIG_VAR_U8(RFsrQuality, 1, 0, 2, "0: Use bilinear, 1: FSR low quality, 2: FSR high quality")
+ANKI_CONFIG_VAR_U8(RDlssQuality, 2, 0, 3, "0: Disabled, 1: Performance, 2: Balanced, 3: Quality")
 ANKI_CONFIG_VAR_BOOL(RSharpen, true, "Sharpen the image")

+ 20 - 10
AnKi/Renderer/DownscaleBlur.cpp

@@ -89,6 +89,8 @@ void DownscaleBlur::populateRenderGraph(RenderingContext& ctx)
 	// Create passes
 	static const Array<CString, 8> passNames = {"DownBlur #0",  "Down/Blur #1", "Down/Blur #2", "Down/Blur #3",
 												"Down/Blur #4", "Down/Blur #5", "Down/Blur #6", "Down/Blur #7"};
+	const RenderTargetHandle inRt =
+		(m_r->getScale().hasUpscaledHdrRt()) ? m_r->getScale().getHdrRt() : m_r->getScale().getTonemappedRt();
 	if(getConfig().getRPreferCompute())
 	{
 		for(U32 i = 0; i < m_passCount; ++i)
@@ -106,15 +108,18 @@ void DownscaleBlur::populateRenderGraph(RenderingContext& ctx)
 				sampleSubresource.m_firstMipmap = i - 1;
 				renderSubresource.m_firstMipmap = i;
 
-				pass.newDependency({m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE, renderSubresource});
-				pass.newDependency({m_runCtx.m_rt, TextureUsageBit::SAMPLED_COMPUTE, sampleSubresource});
+				pass.newDependency(
+					RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE, renderSubresource));
+				pass.newDependency(
+					RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::SAMPLED_COMPUTE, sampleSubresource));
 			}
 			else
 			{
 				TextureSubresourceInfo renderSubresource;
 
-				pass.newDependency({m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE, renderSubresource});
-				pass.newDependency({m_r->getScale().getRt(), TextureUsageBit::SAMPLED_COMPUTE});
+				pass.newDependency(
+					RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::IMAGE_COMPUTE_WRITE, renderSubresource));
+				pass.newDependency(RenderPassDependency(inRt, TextureUsageBit::SAMPLED_COMPUTE));
 			}
 		}
 	}
@@ -136,15 +141,18 @@ void DownscaleBlur::populateRenderGraph(RenderingContext& ctx)
 				sampleSubresource.m_firstMipmap = i - 1;
 				renderSubresource.m_firstMipmap = i;
 
-				pass.newDependency({m_runCtx.m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, renderSubresource});
-				pass.newDependency({m_runCtx.m_rt, TextureUsageBit::SAMPLED_FRAGMENT, sampleSubresource});
+				pass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+														renderSubresource));
+				pass.newDependency(
+					RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::SAMPLED_FRAGMENT, sampleSubresource));
 			}
 			else
 			{
 				TextureSubresourceInfo renderSubresource;
 
-				pass.newDependency({m_runCtx.m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, renderSubresource});
-				pass.newDependency({m_r->getScale().getRt(), TextureUsageBit::SAMPLED_FRAGMENT});
+				pass.newDependency(RenderPassDependency(m_runCtx.m_rt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE,
+														renderSubresource));
+				pass.newDependency(RenderPassDependency(inRt, TextureUsageBit::SAMPLED_FRAGMENT));
 			}
 		}
 	}
@@ -169,12 +177,14 @@ void DownscaleBlur::run(U32 passIdx, RenderPassWorkContext& rgraphCtx)
 	}
 	else
 	{
-		rgraphCtx.bindColorTexture(0, 1, m_r->getScale().getRt());
+		const RenderTargetHandle inRt =
+			(m_r->getScale().hasUpscaledHdrRt()) ? m_r->getScale().getHdrRt() : m_r->getScale().getTonemappedRt();
+		rgraphCtx.bindColorTexture(0, 1, inRt);
 	}
 
 	rgraphCtx.bindImage(0, 2, m_r->getTonemapping().getRt());
 
-	const Bool revertTonemap = passIdx == 0;
+	const Bool revertTonemap = passIdx == 0 && !m_r->getScale().hasUpscaledHdrRt();
 	const UVec4 fbSize(vpWidth, vpHeight, revertTonemap, 0);
 	cmdb->setPushConstants(&fbSize, sizeof(fbSize));
 

+ 2 - 2
AnKi/Renderer/FinalComposite.cpp

@@ -107,7 +107,7 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		pass.newDependency(RenderPassDependency(m_r->getDbg().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
 	}
 
-	pass.newDependency(RenderPassDependency(m_r->getScale().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
+	pass.newDependency(RenderPassDependency(m_r->getScale().getTonemappedRt(), TextureUsageBit::SAMPLED_FRAGMENT));
 	pass.newDependency(RenderPassDependency(m_r->getBloom().getRt(), TextureUsageBit::SAMPLED_FRAGMENT));
 	pass.newDependency(
 		RenderPassDependency(m_r->getMotionVectors().getMotionVectorsRt(), TextureUsageBit::SAMPLED_FRAGMENT));
@@ -153,7 +153,7 @@ void FinalComposite::run(RenderingContext& ctx, RenderPassWorkContext& rgraphCtx
 		cmdb->bindSampler(0, 1, m_r->getSamplers().m_trilinearClamp);
 		cmdb->bindSampler(0, 2, m_r->getSamplers().m_trilinearRepeat);
 
-		rgraphCtx.bindColorTexture(0, 3, m_r->getScale().getRt());
+		rgraphCtx.bindColorTexture(0, 3, m_r->getScale().getTonemappedRt());
 
 		rgraphCtx.bindColorTexture(0, 4, m_r->getBloom().getRt());
 		cmdb->bindTexture(0, 5, m_lut->getTextureView());

+ 114 - 12
AnKi/Renderer/Scale.cpp

@@ -38,8 +38,6 @@ Scale::~Scale()
 
 Error Scale::init()
 {
-	ANKI_R_LOGV("Initializing scale");
-
 	const Bool needsScaling = m_r->getPostProcessResolution() != m_r->getInternalResolution();
 	const Bool needsSharpening = getConfig().getRSharpen();
 	if(!needsScaling && !needsSharpening)
@@ -48,8 +46,8 @@ Error Scale::init()
 	}
 
 	const Bool preferCompute = getConfig().getRPreferCompute();
-	const U32 dlssQuality = getConfig().getRDlss();
-	const U32 fsrQuality = getConfig().getRFsr();
+	const U32 dlssQuality = getConfig().getRDlssQuality();
+	const U32 fsrQuality = getConfig().getRFsrQuality();
 
 	if(needsScaling)
 	{
@@ -87,6 +85,15 @@ Error Scale::init()
 		m_sharpenMethod = SharpenMethod::NONE;
 	}
 
+	m_neeedsTonemapping = (m_upscalingMethod == UpscalingMethod::GR); // Because GR upscaling spits HDR
+
+	static const Array<const Char*, U32(UpscalingMethod::COUNT)> upscalingMethodNames = {"none", "bilinear", "FSR 1.0",
+																						 "DLSS 2"};
+	static const Array<const Char*, U32(SharpenMethod::COUNT)> sharpenMethodNames = {"none", "RCAS", "DLSS 2"};
+
+	ANKI_R_LOGV("Initializing upscaling. Upscaling method %s, sharpenning method %s",
+				upscalingMethodNames[U32(m_upscalingMethod)], sharpenMethodNames[U32(m_sharpenMethod)]);
+
 	// Scale programs
 	if(m_upscalingMethod == UpscalingMethod::BILINEAR)
 	{
@@ -138,6 +145,17 @@ Error Scale::init()
 		m_sharpenGrProg = variant->getProgram();
 	}
 
+	// Tonemapping programs
+	if(m_neeedsTonemapping)
+	{
+		ANKI_CHECK(getResourceManager().loadResource((preferCompute) ? "ShaderBinaries/TonemapCompute.ankiprogbin"
+																	 : "ShaderBinaries/TonemapRaster.ankiprogbin",
+													 m_tonemapProg));
+		const ShaderProgramResourceVariant* variant;
+		m_tonemapProg->getOrCreateVariant(variant);
+		m_tonemapGrProg = variant->getProgram();
+	}
+
 	// Descriptors
 	Format format;
 	if(m_upscalingMethod == UpscalingMethod::GR)
@@ -153,9 +171,19 @@ Error Scale::init()
 		format = Format::R8G8B8A8_UNORM;
 	}
 
-	m_rtDesc = m_r->create2DRenderTargetDescription(m_r->getPostProcessResolution().x(),
-													m_r->getPostProcessResolution().y(), format, "Scaling");
-	m_rtDesc.bake();
+	m_upscaleAndSharpenRtDescr = m_r->create2DRenderTargetDescription(
+		m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y(), format, "Scaling");
+	m_upscaleAndSharpenRtDescr.bake();
+
+	if(m_neeedsTonemapping)
+	{
+		const Format fmt = (getGrManager().getDeviceCapabilities().m_unalignedBbpTextureFormats)
+							   ? Format::R8G8B8_UNORM
+							   : Format::R8G8B8A8_UNORM;
+		m_tonemapedRtDescr = m_r->create2DRenderTargetDescription(
+			m_r->getPostProcessResolution().x(), m_r->getPostProcessResolution().y(), fmt, "Tonemapped");
+		m_tonemapedRtDescr.bake();
+	}
 
 	m_fbDescr.m_colorAttachmentCount = 1;
 	m_fbDescr.bake();
@@ -178,7 +206,7 @@ void Scale::populateRenderGraph(RenderingContext& ctx)
 	// Scaling
 	if(m_upscalingMethod == UpscalingMethod::GR)
 	{
-		m_runCtx.m_scaledRt = rgraph.newRenderTarget(m_rtDesc);
+		m_runCtx.m_scaledRt = rgraph.newRenderTarget(m_upscaleAndSharpenRtDescr);
 
 		ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("DLSS");
 
@@ -198,7 +226,7 @@ void Scale::populateRenderGraph(RenderingContext& ctx)
 	}
 	else if(m_upscalingMethod == UpscalingMethod::FSR || m_upscalingMethod == UpscalingMethod::BILINEAR)
 	{
-		m_runCtx.m_scaledRt = rgraph.newRenderTarget(m_rtDesc);
+		m_runCtx.m_scaledRt = rgraph.newRenderTarget(m_upscaleAndSharpenRtDescr);
 
 		if(preferCompute)
 		{
@@ -227,14 +255,15 @@ void Scale::populateRenderGraph(RenderingContext& ctx)
 	else
 	{
 		ANKI_ASSERT(m_upscalingMethod == UpscalingMethod::NONE);
+		// Pretend that it got scaled
+		m_runCtx.m_scaledRt = m_r->getTemporalAA().getRt();
 	}
 
 	// Sharpenning
 	if(m_sharpenMethod == SharpenMethod::RCAS)
 	{
-		m_runCtx.m_sharpenedRt = rgraph.newRenderTarget(m_rtDesc);
-		const RenderTargetHandle inRt =
-			(m_upscalingMethod == UpscalingMethod::NONE) ? m_r->getTemporalAA().getRt() : m_runCtx.m_scaledRt;
+		m_runCtx.m_sharpenedRt = rgraph.newRenderTarget(m_upscaleAndSharpenRtDescr);
+		const RenderTargetHandle inRt = m_runCtx.m_scaledRt;
 
 		if(preferCompute)
 		{
@@ -267,6 +296,44 @@ void Scale::populateRenderGraph(RenderingContext& ctx)
 	else
 	{
 		ANKI_ASSERT(m_sharpenMethod == SharpenMethod::NONE);
+		// Pretend that it's sharpened
+		m_runCtx.m_sharpenedRt = m_runCtx.m_scaledRt;
+	}
+
+	// Tonemapping
+	if(m_neeedsTonemapping)
+	{
+		m_runCtx.m_tonemappedRt = rgraph.newRenderTarget(m_tonemapedRtDescr);
+		m_runCtx.m_upscaledHdrRt = m_runCtx.m_sharpenedRt;
+
+		if(preferCompute)
+		{
+			ComputeRenderPassDescription& pass = ctx.m_renderGraphDescr.newComputeRenderPass("Tonemap");
+			pass.newDependency(RenderPassDependency(m_runCtx.m_sharpenedRt, TextureUsageBit::SAMPLED_COMPUTE));
+			pass.newDependency(RenderPassDependency(m_runCtx.m_tonemappedRt, TextureUsageBit::IMAGE_COMPUTE_WRITE));
+
+			pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+				runTonemapping(rgraphCtx);
+			});
+		}
+		else
+		{
+			GraphicsRenderPassDescription& pass = ctx.m_renderGraphDescr.newGraphicsRenderPass("Sharpen");
+			pass.setFramebufferInfo(m_fbDescr, {m_runCtx.m_tonemappedRt});
+
+			pass.newDependency(RenderPassDependency(m_runCtx.m_sharpenedRt, TextureUsageBit::SAMPLED_FRAGMENT));
+			pass.newDependency(
+				RenderPassDependency(m_runCtx.m_tonemappedRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE));
+
+			pass.setWork([this](RenderPassWorkContext& rgraphCtx) {
+				runTonemapping(rgraphCtx);
+			});
+		}
+	}
+	else
+	{
+		m_runCtx.m_tonemappedRt = m_runCtx.m_sharpenedRt;
+		m_runCtx.m_upscaledHdrRt = {}; // Doesn't exist
 	}
 }
 
@@ -396,4 +463,39 @@ void Scale::runGrUpscaling(RenderingContext& ctx, RenderPassWorkContext& rgraphC
 				  mvScale);
 }
 
+void Scale::runTonemapping(RenderPassWorkContext& rgraphCtx)
+{
+	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+	const Bool preferCompute = getConfig().getRPreferCompute();
+
+	cmdb->bindShaderProgram(m_tonemapGrProg);
+
+	cmdb->bindSampler(0, 0, m_r->getSamplers().m_nearestNearestClamp);
+	rgraphCtx.bindColorTexture(0, 1, m_runCtx.m_sharpenedRt);
+
+	rgraphCtx.bindImage(0, 2, m_r->getTonemapping().getRt());
+
+	class
+	{
+	public:
+		Vec2 m_viewportSizeOverOne;
+		UVec2 m_viewportSize;
+	} pc;
+	pc.m_viewportSizeOverOne = 1.0f / Vec2(m_r->getPostProcessResolution());
+	pc.m_viewportSize = m_r->getPostProcessResolution();
+	cmdb->setPushConstants(&pc, sizeof(pc));
+
+	if(preferCompute)
+	{
+		rgraphCtx.bindImage(0, 3, m_runCtx.m_tonemappedRt);
+
+		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

+ 28 - 5
AnKi/Renderer/Scale.h

@@ -27,9 +27,22 @@ public:
 
 	void populateRenderGraph(RenderingContext& ctx);
 
-	RenderTargetHandle getRt() const
+	/// This is the tonemapped, upscaled and sharpened RT.
+	RenderTargetHandle getTonemappedRt() const
 	{
-		return (m_sharpenMethod != SharpenMethod::NONE) ? m_runCtx.m_sharpenedRt : m_runCtx.m_scaledRt;
+		return m_runCtx.m_tonemappedRt;
+	}
+
+	/// This is the HDR, upscaled and sharpened RT. It's available if hasUscaledHdrRt() returns true.
+	RenderTargetHandle getHdrRt() const
+	{
+		ANKI_ASSERT(hasUpscaledHdrRt());
+		return m_runCtx.m_upscaledHdrRt;
+	}
+
+	Bool hasUpscaledHdrRt() const
+	{
+		return m_upscalingMethod == UpscalingMethod::GR;
 	}
 
 	Bool getUsingGrUpscaler() const
@@ -42,18 +55,22 @@ private:
 	ShaderProgramPtr m_scaleGrProg;
 	ShaderProgramResourcePtr m_sharpenProg;
 	ShaderProgramPtr m_sharpenGrProg;
+	ShaderProgramResourcePtr m_tonemapProg;
+	ShaderProgramPtr m_tonemapGrProg;
 
 	GrUpscalerPtr m_grUpscaler;
 
 	FramebufferDescription m_fbDescr;
-	RenderTargetDescription m_rtDesc;
+	RenderTargetDescription m_upscaleAndSharpenRtDescr;
+	RenderTargetDescription m_tonemapedRtDescr;
 
 	enum class UpscalingMethod : U8
 	{
 		NONE,
 		BILINEAR,
 		FSR,
-		GR
+		GR,
+		COUNT
 	};
 
 	UpscalingMethod m_upscalingMethod = UpscalingMethod::NONE;
@@ -62,21 +79,27 @@ private:
 	{
 		NONE,
 		RCAS,
-		GR
+		GR,
+		COUNT
 	};
 
 	SharpenMethod m_sharpenMethod = SharpenMethod::NONE;
 
+	Bool m_neeedsTonemapping = false;
+
 	class
 	{
 	public:
 		RenderTargetHandle m_scaledRt;
 		RenderTargetHandle m_sharpenedRt;
+		RenderTargetHandle m_tonemappedRt;
+		RenderTargetHandle m_upscaledHdrRt;
 	} m_runCtx;
 
 	void runFsrOrBilinearScaling(RenderPassWorkContext& rgraphCtx);
 	void runRcasSharpening(RenderPassWorkContext& rgraphCtx);
 	void runGrUpscaling(RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
+	void runTonemapping(RenderPassWorkContext& rgraphCtx);
 };
 /// @}
 

+ 55 - 0
AnKi/Shaders/Tonemap.glsl

@@ -0,0 +1,55 @@
+// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+// Does tonemapping
+
+#include <AnKi/Shaders/Functions.glsl>
+#include <AnKi/Shaders/TonemappingFunctions.glsl>
+
+layout(set = 0, binding = 0) uniform sampler u_nearestAnyClampSampler;
+layout(set = 0, binding = 1) uniform ANKI_RP texture2D u_inputRt;
+
+const U32 TONEMAPPING_SET = 0u;
+const U32 TONEMAPPING_BINDING = 2u;
+#include <AnKi/Shaders/TonemappingResources.glsl>
+
+#if defined(ANKI_COMPUTE_SHADER)
+layout(set = 0, binding = 3) writeonly uniform image2D u_outImg;
+
+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;
+#else
+layout(location = 0) in Vec2 in_uv;
+layout(location = 0) out Vec3 out_color;
+#endif
+
+layout(push_constant, std140) uniform b_pc
+{
+	Vec2 u_viewportSizeOverOne;
+	UVec2 u_viewportSize;
+};
+
+void main()
+{
+#if defined(ANKI_COMPUTE_SHADER)
+	if(skipOutOfBoundsInvocations(WORKGROUP_SIZE, u_viewportSize))
+	{
+		return;
+	}
+
+	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5f) * u_viewportSizeOverOne;
+#else
+	const Vec2 uv = in_uv;
+#endif
+
+	const ANKI_RP Vec3 hdr = textureLod(u_inputRt, u_nearestAnyClampSampler, uv, 0.0f).rgb;
+	const Vec3 tonemapped = linearToSRgb(tonemap(hdr, readExposureAndAverageLuminance().x));
+
+#if defined(ANKI_COMPUTE_SHADER)
+	imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), Vec4(tonemapped, 0.0));
+#else
+	out_color = tonemapped;
+#endif
+}

+ 8 - 0
AnKi/Shaders/TonemapCompute.ankiprog

@@ -0,0 +1,8 @@
+// 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/Tonemap.glsl>
+#pragma anki end

+ 12 - 0
AnKi/Shaders/TonemapRaster.ankiprog

@@ -0,0 +1,12 @@
+// 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 vert
+#include <AnKi/Shaders/QuadVert.glsl>
+#pragma anki end
+
+#pragma anki start frag
+#include <AnKi/Shaders/Tonemap.glsl>
+#pragma anki end