Browse Source

Merged resolve/blit shaders into one and unrolled loops
Added a resolved depth buffer to use as input to DOF
Modified the HiZ buffer generation so it starts with one lower mip level, and precisely samples 2x2 pixels from higher levels

BearishSun 8 years ago
parent
commit
d22aec38a6

+ 0 - 8
Data/Raw/Engine/DataList.json

@@ -76,10 +76,6 @@
             "Path": "ReflectionCubemapCommon.bslinc",
             "UUID": "eef92578-b8ed-45d6-8eed-d85697ade3c5"
         },
-        {
-            "Path": "ResolveCommon.bslinc",
-            "UUID": "1cde4f3c-534e-4128-8ee1-63e3bb620734"
-        },
         {
             "Path": "SkinnedVertexInput.bslinc",
             "UUID": "d6a2ea27-5f4c-41ad-88bc-cad7dd7adc8d"
@@ -194,10 +190,6 @@
             "Path": "PPTonemapping.bsl",
             "UUID": "a8aa01e7-7e72-4f84-89f8-a0097250b0d3"
         },
-        {
-            "Path": "Resolve.bsl",
-            "UUID": "9d5f5101-2d7e-432c-b8ad-1998de9ca5c7"
-        },
         {
             "Path": "Skybox.bsl",
             "UUID": "b1c191fa-0c24-4987-8d3b-72b17511621d"

+ 0 - 65
Data/Raw/Engine/Includes/ResolveCommon.bslinc

@@ -1,65 +0,0 @@
-technique Resolve
-{
-	depth
-	{
-		read = false;
-		write = false;
-	};
-
-	code
-	{
-		struct VStoFS
-		{
-			float4 position : SV_POSITION;
-			float2 uv0 : TEXCOORD0;
-		};
-
-		struct VertexInput
-		{
-			float2 screenPos : POSITION;
-			float2 uv0 : TEXCOORD0;
-		};
-		
-		VStoFS vsmain(VertexInput input)
-		{
-			VStoFS output;
-		
-			output.position = float4(input.screenPos, 0, 1);
-			output.uv0 = input.uv0;
-
-			return output;
-		}			
-
-		#ifdef ENABLE_MSAA
-		
-		cbuffer FragParams
-		{
-			int gNumSamples;
-		};
-		
-		Texture2DMS<float4> gSource;
-		
-		float4 fsmain(VStoFS input) : SV_Target0
-		{
-			int2 iUV = trunc(input.uv0);
-		
-			float4 sum = float4(0, 0, 0, 0);
-			for(int i = 0; i < gNumSamples; i++)
-				sum += gSource.Load(iUV, i);
-				
-			return sum / gNumSamples;
-		}
-		
-		#else
-		
-		Texture2D<float4> gSource;
-	
-		float4 fsmain(VStoFS input) : SV_Target0
-		{
-			int2 iUV = trunc(input.uv0);
-			return gSource.Load(int3(iUV.xy, 0));
-		}
-		
-		#endif
-	};
-};

+ 78 - 1
Data/Raw/Engine/Shaders/Blit.bsl

@@ -1 +1,78 @@
-#include "$ENGINE$\ResolveCommon.bslinc"
+technique Blit
+{
+	depth
+	{
+		read = false;
+		write = false;
+	};
+
+	code
+	{
+		struct VStoFS
+		{
+			noperspective float4 position : SV_POSITION;
+			noperspective float2 uv0 : TEXCOORD0;
+		};
+
+		struct VertexInput
+		{
+			float2 screenPos : POSITION;
+			float2 uv0 : TEXCOORD0;
+		};
+		
+		VStoFS vsmain(VertexInput input)
+		{
+			VStoFS output;
+		
+			output.position = float4(input.screenPos, 0, 1);
+			output.uv0 = input.uv0;
+
+			return output;
+		}			
+
+		#if MSAA_COUNT > 1
+		
+		#if COLOR
+		Texture2DMS<float4> gSource;
+		
+		float4 fsmain(VStoFS input) : SV_Target0
+		#else // Assuming depth
+		Texture2DMS<float> gSource;
+		
+		float fsmain(VStoFS input) : SV_Target0
+		#endif
+		{
+			int2 iUV = trunc(input.uv0);
+		
+			#if COLOR
+				float4 sum = float4(0, 0, 0, 0);
+				
+				[unroll]
+				for(int i = 0; i < MSAA_COUNT; i++)
+					sum += gSource.Load(iUV, i);
+					
+				return sum / MSAA_COUNT;
+			#else // Assuming depth
+				float minVal = gSource.Load(iUV, 0);
+				
+				[unroll]
+				for(int i = 1; i < MSAA_COUNT; i++)
+					minVal = min(minVal, gSource.Load(iUV, i));
+					
+				return minVal;
+			#endif
+		}
+		
+		#else
+		
+		Texture2D<float4> gSource;
+	
+		float4 fsmain(VStoFS input) : SV_Target0
+		{
+			int2 iUV = trunc(input.uv0);
+			return gSource.Load(int3(iUV.xy, 0));
+		}
+		
+		#endif
+	};
+};

+ 2 - 17
Data/Raw/Engine/Shaders/PPBuildHiZ.bsl

@@ -6,28 +6,13 @@ technique PPBuildHiZ
 
 	code
 	{	
-		#if MSAA_COUNT <= 1
 		SamplerState gDepthSamp;
 		Texture2D gDepthTex;
-		#else
-		Texture2DMS<float, MSAA_COUNT> gDepthTex;
-		#endif
 		
 		float fsmain(VStoFS input) : SV_Target0
 		{
-			// First pass, resolve MSAA (if needed)
-			#if MSAA_COUNT > 1
-				float depth = gDepthTex.Load(trunc(input.uv0), 0);
-				
-				[unroll]
-				for(int i = 1; i < MSAA_COUNT; ++i)
-					depth = min(depth, gDepthTex.Load(trunc(input.uv0), i));
-				
-				return depth;
-			#else
-				float4 depth = gDepthTex.Gather(gDepthSamp, input.uv0);
-				return min(min(depth.x, depth.y), min(depth.z, depth.w));
-			#endif
+			float4 depth = gDepthTex.Gather(gDepthSamp, input.uv0);
+			return min(min(depth.x, depth.y), min(depth.z, depth.w));
 		}	
 	};
 };

+ 0 - 2
Data/Raw/Engine/Shaders/Resolve.bsl

@@ -1,2 +0,0 @@
-#define ENABLE_MSAA
-#include "$ENGINE$\ResolveCommon.bslinc"

+ 37 - 35
Source/BansheeEngine/Include/BsRendererUtility.h

@@ -15,8 +15,29 @@ namespace bs { namespace ct
 	 *  @{
 	 */
 
-	class ResolveMat;
-	class BlitMat;
+	/** 
+	 * Shader that copies a source texture into a render target, and optionally resolves it. 
+	 * 
+	 * @tparam	MSAA_COUNT		Number of MSAA samples in the input texture. If larger than 1 the texture will be resolved
+	 *							before written to the destination.
+	 * @tparam	IS_COLOR		If true the input is assumed to be a 4-component color texture. If false it is assumed
+	 *							the input is a 1-component depth texture. This controls how is the texture resolve and is
+	 *							only relevant if MSAA_COUNT > 1. Color texture MSAA samples will be averaged, while for
+	 *							depth textures the minimum of all samples will be used.
+	 */
+	template<int MSAA_COUNT, bool IS_COLOR = true>
+	class BlitMat : public RendererMaterial<BlitMat<MSAA_COUNT, IS_COLOR>>
+	{
+		RMAT_DEF("Blit.bsl");
+
+	public:
+		BlitMat();
+
+		/** Updates the parameter buffers used by the material. */
+		void setParameters(const SPtr<Texture>& source);
+	private:
+		MaterialParamTexture mSource;
+	};
 
 	/**
 	 * Contains various utility methods that make various common operations in the renderer easier.
@@ -103,9 +124,13 @@ namespace bs { namespace ct
 		 * @param[in]	texture	Source texture to blit.
 		 * @param[in]	area	Area of the source texture to blit in pixels. If width or height is zero it is assumed
 		 *						the entire texture should be blitted.
-		 * @param[in]	flipUV If true, vertical UV coordinate will be flipped upside down.
+		 * @param[in]	flipUV	If true, vertical UV coordinate will be flipped upside down.
+		 * @param[in]	isDepth	If true, the input texture is assumed to be a depth texture (instead of a color one).
+		 *						Multisampled depth textures will be resolved by taking the minimum value of all samples,
+		 *						unlike color textures which wil be averaged.
 		 */
-		void blit(const SPtr<Texture>& texture, const Rect2I& area = Rect2I::EMPTY, bool flipUV = false);
+		void blit(const SPtr<Texture>& texture, const Rect2I& area = Rect2I::EMPTY, bool flipUV = false, 
+			bool isDepth = false);
 
 		/**
 		 * Draws a quad over the entire viewport in normalized device coordinates.
@@ -157,41 +182,18 @@ namespace bs { namespace ct
 		SPtr<Mesh> mPointLightStencilMesh;
 		SPtr<Mesh> mSpotLightStencilMesh;
 		SPtr<Mesh> mSkyBoxMesh;
-		SPtr<ResolveMat> mResolveMat;
-		SPtr<BlitMat> mBlitMat;
+
+		BlitMat<1, true> mBlitMat_Color_NoMSAA;
+		BlitMat<2, true> mBlitMat_Color_MSAA2x;
+		BlitMat<4, true> mBlitMat_Color_MSAA4x;
+		BlitMat<8, true> mBlitMat_Color_MSAA8x;
+		BlitMat<2, false> mBlitMat_Depth_MSAA2x;
+		BlitMat<4, false> mBlitMat_Depth_MSAA4x;
+		BlitMat<8, false> mBlitMat_Depth_MSAA8x;
 	};
 
 	/** Provides easy access to RendererUtility. */
 	BS_EXPORT RendererUtility& gRendererUtility();
 
-	/** Shader that resolves a MSAA surface into a non-MSAA render target. */
-	class ResolveMat : public RendererMaterial<ResolveMat>
-	{
-		RMAT_DEF("Resolve.bsl");
-
-	public:
-		ResolveMat();
-
-		/** Updates the parameter buffers used by the material. */
-		void setParameters(const SPtr<Texture>& source);
-	private:
-		MaterialParamInt mNumSamples;
-		MaterialParamTexture mSource;
-	};
-
-	/** Shader that copies a source texture into a render target. */
-	class BlitMat : public RendererMaterial<BlitMat>
-	{
-		RMAT_DEF("Blit.bsl");
-
-	public:
-		BlitMat();
-
-		/** Updates the parameter buffers used by the material. */
-		void setParameters(const SPtr<Texture>& source);
-	private:
-		MaterialParamTexture mSource;
-	};
-
 	/** @} */
 }}

+ 60 - 35
Source/BansheeEngine/Source/BsRendererUtility.cpp

@@ -123,10 +123,6 @@ namespace bs { namespace ct
 			mSkyBoxMesh = Mesh::create(meshData);
 		}
 
-		// TODO - When I add proper preprocessor support, merge these into a single material
-		mResolveMat = bs_shared_ptr_new<ResolveMat>();
-		mBlitMat = bs_shared_ptr_new<BlitMat>();
-
 		IBLUtility::startUp();
 	}
 
@@ -254,24 +250,62 @@ namespace bs { namespace ct
 		mesh->_notifyUsedOnGPU();
 	}
 
-	void RendererUtility::blit(const SPtr<Texture>& texture, const Rect2I& area, bool flipUV)
+	void RendererUtility::blit(const SPtr<Texture>& texture, const Rect2I& area, bool flipUV, bool isDepth)
 	{
 		auto& texProps = texture->getProperties();
 		SPtr<Material> mat;
 		SPtr<GpuParamsSet> params;
+
+#define PICK_MATERIAL(Type)									\
+			mat = mBlitMat_##Type.getMaterial();			\
+			params = mBlitMat_##Type.getParamsSet();		\
+			mBlitMat_##Type.setParameters(texture);
+
 		if (texProps.getNumSamples() > 1)
 		{
-			mat = mResolveMat->getMaterial();
-			params = mResolveMat->getParamsSet();
-			mResolveMat->setParameters(texture);
+			if(texProps.getNumSamples() > 8)
+				LOGWRN("Unsupported sample count in an MSAA texture");
+
+			if(isDepth)
+			{
+				switch(texProps.getNumSamples())
+				{
+				case 2:
+					PICK_MATERIAL(Depth_MSAA2x)
+					break;
+				case 4:
+					PICK_MATERIAL(Depth_MSAA4x)
+					break;
+				default:
+				case 8:
+					PICK_MATERIAL(Depth_MSAA8x)
+					break;
+				}
+			}
+			else
+			{
+				switch(texProps.getNumSamples())
+				{
+				case 2:
+					PICK_MATERIAL(Color_MSAA2x)
+					break;
+				case 4:
+					PICK_MATERIAL(Color_MSAA4x)
+					break;
+				default:
+				case 8:
+					PICK_MATERIAL(Color_MSAA8x)
+					break;
+				}
+			}
 		}
 		else
 		{
-			mat = mBlitMat->getMaterial();
-			params = mBlitMat->getParamsSet();
-			mBlitMat->setParameters(texture);
+			PICK_MATERIAL(Color_NoMSAA)
 		}
 
+#undef PICK_MATERIAL
+
 		setPass(mat);
 		setPassParams(params);
 
@@ -359,40 +393,31 @@ namespace bs { namespace ct
 		return RendererUtility::instance();
 	}
 
-	BlitMat::BlitMat()
+	template<int MSAA_COUNT, bool IS_COLOR>
+	BlitMat<MSAA_COUNT, IS_COLOR>::BlitMat()
 	{
 		mSource = mMaterial->getParamTexture("gSource");
 	}
 
-	void BlitMat::_initDefines(ShaderDefines& defines)
+	template<int MSAA_COUNT, bool IS_COLOR>
+	void BlitMat<MSAA_COUNT, IS_COLOR>::_initDefines(ShaderDefines& defines)
 	{
-		// Do nothing
+		defines.set("MSAA_COUNT", MSAA_COUNT);
+		defines.set("COLOR", IS_COLOR ? 1 : 0);
 	}
 
-	void BlitMat::setParameters(const SPtr<Texture>& source)
+	template<int MSAA_COUNT, bool IS_COLOR>
+	void BlitMat<MSAA_COUNT, IS_COLOR>::setParameters(const SPtr<Texture>& source)
 	{
 		mSource.set(source);
 		mMaterial->updateParamsSet(mParamsSet);
 	}
 
-	ResolveMat::ResolveMat()
-	{
-		mSource = mMaterial->getParamTexture("gSource");
-		mMaterial->getParam("gNumSamples", mNumSamples);
-	}
-
-	void ResolveMat::_initDefines(ShaderDefines& defines)
-	{
-		// Do nothing
-	}
-
-	void ResolveMat::setParameters(const SPtr<Texture>& source)
-	{
-		mSource.set(source);
-
-		UINT32 sampleCount = source->getProperties().getNumSamples();
-		mNumSamples.set(sampleCount);
-
-		mMaterial->updateParamsSet(mParamsSet);
-	}
+	template class BlitMat<1, true>;
+	template class BlitMat<2, true>;
+	template class BlitMat<4, true>;
+	template class BlitMat<8, true>;
+	template class BlitMat<2, false>;
+	template class BlitMat<4, false>;
+	template class BlitMat<8, false>;
 }}

+ 5 - 7
Source/RenderBeast/Include/BsPostProcessing.h

@@ -510,8 +510,7 @@ namespace bs { namespace ct
 	};
 
 	/** Shader that calculates a single level of the hierarchical Z mipmap chain. */
-	template<int MSAA_COUNT>
-	class BuildHiZMat : public RendererMaterial<BuildHiZMat<MSAA_COUNT>>
+	class BuildHiZMat : public RendererMaterial<BuildHiZMat>
 	{
 		RMAT_DEF("PPBuildHiZ.bsl");
 
@@ -525,9 +524,11 @@ namespace bs { namespace ct
 		 * @param[in]	srcMip		Mip level to read from the @p source texture.
 		 * @param[in]	srcRect		Rectangle in normalized coordinates, describing from which portion of the source
 		 *							texture to read the input.
+		 * @param[in]	dstRect		Destination rectangle to limit the writes to.
 		 * @param[in]	output		Output target to which to write to results.
 		 */
-		void execute(const SPtr<Texture>& source, UINT32 srcMip, const Rect2& srcRect, const SPtr<RenderTexture>& output);
+		void execute(const SPtr<Texture>& source, UINT32 srcMip, const Rect2& srcRect, const Rect2& dstRect,
+			const SPtr<RenderTexture>& output);
 	private:
 		GpuParamTexture mInputTexture;
 	};
@@ -550,10 +551,7 @@ namespace bs { namespace ct
 		static POOLED_RENDER_TEXTURE_DESC getHiZTextureDesc(UINT32 viewWidth, UINT32 viewHeight);
 
 	private:
-		BuildHiZMat<1> mHiZMatNoMSAA;
-		BuildHiZMat<2> mHiZMatMSAA2;
-		BuildHiZMat<4> mHiZMatMSAA4;
-		BuildHiZMat<8> mHiZMatMSAA8;
+		BuildHiZMat mHiZMat;
 	};
 
 	BS_PARAM_BLOCK_BEGIN(FXAAParamDef)

+ 42 - 20
Source/RenderBeast/Include/BsRenderTargets.h

@@ -35,7 +35,21 @@ namespace bs { namespace ct
 		 * Secondary resolved scene color texture that can be used for ping-ponging between primary and secondary scene
 		 * color textures. Primarily useful for post-processing effects.
 		 */
-		RTT_ResolvedSceneColorSecondary
+		RTT_ResolvedSceneColorSecondary,
+		/**
+		 * Buffer containing a hierarchical Z buffer. If passed to RenderTargets::generate() it will allocate and build
+		 * the hierarchical Z buffer from the current contents of the scene depth buffer. Generated buffer can be
+		 * accessed from getHiZ(). If using MSAA render targets, make sure to first generate the RTT_ResolvedDepth
+		 * target as HiZ can't be built from multisampled depth buffer.
+		 */
+		RTT_HiZ,
+		/**
+		 * Buffer containing the resolved (non-multisampled) depth buffer. If multisampling isn't used then this will be
+		 * the same buffer as the scene depth buffer. If passed to RenderTargets::generate() it will allocate and resolve
+		 * the scene depth buffer into the newly allocated buffer. Scene depth must be previously allocated and populated
+		 * with scene data.
+		 */
+		RTT_ResolvedDepth
 	};
 
 	/**
@@ -59,12 +73,11 @@ namespace bs { namespace ct
 		 */
 		void cleanup();
 
-		/**	Returns the depth buffer as a bindable texture. */
-		SPtr<Texture> getSceneDepth() const;
-
 		/**
 		 * Allocates the textures required for rendering. Allocations are pooled so this is generally a fast operation
 		 * unless the size or other render target options changed. This must be called before binding render targets.
+		 * Some render target types are also automatically populated with data, in which case calling generate() instead
+		 * of allocate is a better option - see individual target descriptions for more details.
 		 */
 		void allocate(RenderTargetType type);
 
@@ -75,18 +88,17 @@ namespace bs { namespace ct
 		 */
 		void release(RenderTargetType type);
 
+		/**
+		 * Generates contents for the specified render target type. Target must first be allocated by calling allocate().
+		 * Note that not all target types can have their contents automatically generated, most are meant to be populated
+		 * by external code. And those that can usually have prerequisites. See individual target descriptions for more
+		 * details.
+		 */
+		void generate(RenderTargetType type);
+
 		/**	Binds the GBuffer render target for rendering. */
 		void bindGBuffer();
 
-		/**	Returns the first color texture of the gbuffer as a bindable texture. */
-		SPtr<Texture> getGBufferA() const;
-
-		/**	Returns the second color texture of the gbuffer as a bindable texture. */
-		SPtr<Texture> getGBufferB() const;
-
-		/**	Returns the third color texture of the gbuffer as a bindable texture. */
-		SPtr<Texture> getGBufferC() const;
-
 		/**	
 		 * Binds the scene color render target for rendering. If using MSAA this texture will be allocated as a texture 
 		 * with multiple samples.
@@ -102,14 +114,17 @@ namespace bs { namespace ct
 		 */
 		void bindLightOcclusion();
 
-		/**
-		 * Generates the hierarchical Z buffer from the current contents of the scene depth buffer. Generated buffer can be
-		 * accessed from getHiZ(). When no longer required, buffer must be released by calling releaseHiZ().
-		 */
-		void generateHiZ();
+		/**	Returns the first color texture of the gbuffer as a bindable texture. */
+		SPtr<Texture> getGBufferA() const;
 
-		/** Releases the memory used by the hierarchical z-buffer texture generated by generateHiZ(). */
-		void releaseHiZ();
+		/**	Returns the second color texture of the gbuffer as a bindable texture. */
+		SPtr<Texture> getGBufferB() const;
+
+		/**	Returns the third color texture of the gbuffer as a bindable texture. */
+		SPtr<Texture> getGBufferC() const;
+
+		/**	Returns the depth buffer as a bindable texture. */
+		SPtr<Texture> getSceneDepth() const;
 
 		/** Returns the hierarchical Z buffer texture generated by calling generateHiZ(). */
 		SPtr<Texture> getHiZ() const;
@@ -141,6 +156,12 @@ namespace bs { namespace ct
 		 */
 		SPtr<RenderTarget> getResolvedSceneColorRT(bool secondary = false) const;
 
+		/**
+		 * Returns the non-MSAA version of the scene depth texture. If MSAA is not used this is equivalent to calling
+		 * getSceneDepth().
+		 */
+		SPtr<Texture> getResolvedDepth() const;
+
 		/** Returns the texture for storing of the intermediate lighting information. */
 		SPtr<Texture> getLightAccumulation() const;
 
@@ -195,6 +216,7 @@ namespace bs { namespace ct
 		SPtr<PooledRenderTexture> mResolvedSceneColorTex2;
 
 		SPtr<PooledRenderTexture> mHiZ;
+		SPtr<PooledRenderTexture> mResolvedDepthTex;
 
 		SPtr<RenderTexture> mGBufferRT;
 		SPtr<RenderTexture> mSceneColorRT;

+ 27 - 61
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -988,21 +988,18 @@ namespace bs { namespace ct
 		return settings.enabled && (near || far);
 	}
 	
-	template<int MSAA_COUNT>
-	BuildHiZMat<MSAA_COUNT>::BuildHiZMat()
+	BuildHiZMat::BuildHiZMat()
 	{
 		SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
 		gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mInputTexture);
 	}
 
-	template<int MSAA_COUNT>
-	void BuildHiZMat<MSAA_COUNT>::_initDefines(ShaderDefines& defines)
+	void BuildHiZMat::_initDefines(ShaderDefines& defines)
 	{
-		defines.set("MSAA_COUNT", MSAA_COUNT);
+		// Do nothing
 	}
 
-	template<int MSAA_COUNT>
-	void BuildHiZMat<MSAA_COUNT>::execute(const SPtr<Texture>& source, UINT32 srcMip, const Rect2& srcRect, 
+	void BuildHiZMat::execute(const SPtr<Texture>& source, UINT32 srcMip, const Rect2& srcRect, const Rect2& dstRect,
 		const SPtr<RenderTexture>& output)
 	{
 		RenderAPI& rapi = RenderAPI::instance();
@@ -1010,16 +1007,14 @@ namespace bs { namespace ct
 
 		mInputTexture.set(source, TextureSurface(srcMip));
 		rapi.setRenderTarget(output);
+		rapi.setViewport(dstRect);
 
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().drawScreenQuad(srcRect);
-	}
 
-	template class BuildHiZMat<1>;
-	template class BuildHiZMat<2>;
-	template class BuildHiZMat<4>;
-	template class BuildHiZMat<8>;
+		rapi.setViewport(Rect2(0, 0, 1, 1));
+	}
 
 	void BuildHiZ::execute(const RendererViewTargetData& viewInfo, const SPtr<Texture>& source, const SPtr<Texture>& output)
 	{
@@ -1027,64 +1022,33 @@ namespace bs { namespace ct
 
 		// First resolve if MSAA if required
 		SPtr<PooledRenderTexture> resolvedDepth;
-		SPtr<Texture> depthInput;
-		Rect2 srcRect;
-		if (viewInfo.numSamples > 1)
-		{
-			resolvedDepth = pool.get(
-				POOLED_RENDER_TEXTURE_DESC::create2D(
-					PF_FLOAT16_R,
-					viewInfo.viewRect.width,
-					viewInfo.viewRect.height,
-					TU_RENDERTARGET)
-			);
-
-			srcRect.x = (float)viewInfo.viewRect.x;
-			srcRect.y = (float)viewInfo.viewRect.y;
-			srcRect.width = (float)viewInfo.viewRect.width;
-			srcRect.height = (float)viewInfo.viewRect.height;
-
-			switch(viewInfo.numSamples)
-			{
-			case 2:
-				mHiZMatMSAA2.execute(source, 0, srcRect, resolvedDepth->renderTexture);
-				break;
-			case 4:
-				mHiZMatMSAA4.execute(source, 0, srcRect, resolvedDepth->renderTexture);
-				break;
-			case 8:
-				mHiZMatMSAA8.execute(source, 0, srcRect, resolvedDepth->renderTexture);
-				break;
-			default:
-				LOGERR("Invalid MSAA count: " + toString(viewInfo.numSamples));
-				break;
-			}
-
-			depthInput = resolvedDepth->texture;
-			srcRect = Rect2(0, 0, 1, 1);
-		}
-		else
-		{
-			depthInput = source;
-			srcRect = viewInfo.nrmViewRect;
-		}
+		Rect2 srcRect = viewInfo.nrmViewRect;
 
 		// Generate first mip
 		RENDER_TEXTURE_DESC rtDesc;
 		rtDesc.colorSurfaces[0].texture = output;
 		rtDesc.colorSurfaces[0].mipLevel = 0;
 
+		// Make sure that 1 pixel in HiZ maps to a 2x2 block in source
+		const TextureProperties& outProps = output->getProperties();
+		Rect2 destRect(0, 0,
+			Math::ceilToInt(viewInfo.viewRect.width / 2.0f) / (float)outProps.getWidth(),
+			Math::ceilToInt(viewInfo.viewRect.height / 2.0f) / (float)outProps.getHeight());
+
+		// If viewport size is odd, adjust UV
+		srcRect.width += (viewInfo.viewRect.width % 2) * (1.0f / viewInfo.viewRect.width);
+		srcRect.height += (viewInfo.viewRect.height % 2) * (1.0f / viewInfo.viewRect.height);
+
 		SPtr<RenderTexture> rt = RenderTexture::create(rtDesc);
-		mHiZMatNoMSAA.execute(depthInput, 0, srcRect, rt);
+		mHiZMat.execute(source, 0, srcRect, destRect, rt);
 
 		// Generate remaining mip levels
-		const TextureProperties& outProps = output->getProperties();
 		for(UINT32 i = 1; i <= outProps.getNumMipmaps(); i++)
 		{
 			rtDesc.colorSurfaces[0].mipLevel = i;
 
 			rt = RenderTexture::create(rtDesc);
-			mHiZMatNoMSAA.execute(output, i - 1, Rect2(0, 0, 1, 1), rt);
+			mHiZMat.execute(output, i - 1, destRect, destRect, rt);
 		}
 
 		if (resolvedDepth)
@@ -1094,9 +1058,13 @@ namespace bs { namespace ct
 	POOLED_RENDER_TEXTURE_DESC BuildHiZ::getHiZTextureDesc(UINT32 viewWidth, UINT32 viewHeight)
 	{
 		UINT32 size = Bitwise::nextPow2(std::max(viewWidth, viewHeight));
-		UINT32 numMips = PixelUtil::getMaxMipmaps(size, size, 1, PF_FLOAT16_R);
+		UINT32 numMips = std::max(1U, PixelUtil::getMaxMipmaps(size, size, 1, PF_FLOAT32_R) - 1);
+		size = 1 << numMips;
 
-		return POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_R, size, size, TU_RENDERTARGET, 1, false, 1, numMips);
+		// Note: Use the 32-bit buffer here as 16-bit causes too much banding (most of the scene gets assigned 4-5 different
+		// depth values). Perhaps if the depth was linealized before generation, or the far plane distance reduced, 16-bit
+		// would work, but for now sticking with 32-bit.
+		return POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT32_R, size, size, TU_RENDERTARGET, 1, false, 1, numMips);
 	}
 
 	FXAAParamDef gFXAAParamDef;
@@ -1331,9 +1299,7 @@ namespace bs { namespace ct
 			else
 				dofTarget = viewProps.target;
 
-			// Use the HiZ buffer instead of main scene depth since DOF shaders don't support MSAA, and HiZ is guaranteed to
-			// be resolved.
-			SPtr<Texture> sceneDepth = renderTargets->getHiZ();
+			SPtr<Texture> sceneDepth = renderTargets->getResolvedDepth();
 
 			mGaussianDOF.execute(renderTargets->getResolvedSceneColor(true), sceneDepth, dofTarget, *viewInfo, 
 				settings.depthOfField);

+ 13 - 3
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -537,8 +537,16 @@ namespace bs { namespace ct
 		}
 
 		// Build HiZ buffer
+		bool isMSAA = numSamples > 1;
 		// TODO - Avoid generating it unless it actually gets used in some system
-		renderTargets->generateHiZ();
+		if (isMSAA)
+		{
+			renderTargets->allocate(RTT_ResolvedDepth);
+			renderTargets->generate(RTT_ResolvedDepth);
+		}
+
+		renderTargets->allocate(RTT_HiZ);
+		renderTargets->generate(RTT_HiZ);
 
 		// Trigger post-base-pass callbacks
 		if (viewProps.triggerCallbacks)
@@ -569,7 +577,6 @@ namespace bs { namespace ct
 
 		// If we're using flattened accumulation buffer for MSAA we need to copy its contents to the MSAA texture before
 		// continuing
-		bool isMSAA = numSamples > 1;
 		if(isMSAA)
 		{
 			renderTargets->bindLightAccumulation();
@@ -692,9 +699,12 @@ namespace bs { namespace ct
 			gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewProps.flipView);
 		}
 
-		renderTargets->releaseHiZ();
+		renderTargets->release(RTT_HiZ);
 		renderTargets->release(RTT_SceneColor);
 
+		if (isMSAA)
+			renderTargets->release(RTT_ResolvedDepth);
+
 		// Trigger overlay callbacks
 		if (viewProps.triggerCallbacks)
 		{

+ 48 - 11
Source/RenderBeast/Source/BsRenderTargets.cpp

@@ -225,6 +225,23 @@ namespace bs { namespace ct
 			mResolvedSceneColorTex2 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, 
 				width, height, TU_RENDERTARGET, 1, false));
 		}
+		else if(type == RTT_HiZ)
+		{
+			mHiZ = GpuResourcePool::instance().get(
+				BuildHiZ::getHiZTextureDesc(
+					mViewTarget.viewRect.width, 
+					mViewTarget.viewRect.height)
+			);
+		}
+		else if(type == RTT_ResolvedDepth)
+		{
+			// If not using MSAA, this is equivalent to default depth texture
+			if(mViewTarget.numSamples > 1)
+			{
+				mResolvedDepthTex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32, width, height, TU_RENDERTARGET,
+					1, false));
+			}
+		}
 	}
 
 	void RenderTargets::release(RenderTargetType type)
@@ -268,6 +285,16 @@ namespace bs { namespace ct
 			if (mResolvedSceneColorTex2 != nullptr)
 				texPool.release(mResolvedSceneColorTex2);
 		}
+		else if(type == RTT_HiZ)
+		{
+			if (mHiZ != nullptr)
+				texPool.release(mHiZ);
+		}
+		else if(type == RTT_ResolvedDepth)
+		{
+			if (mResolvedDepthTex != nullptr)
+				texPool.release(mResolvedDepthTex);
+		}
 	}
 
 	void RenderTargets::bindGBuffer()
@@ -320,21 +347,31 @@ namespace bs { namespace ct
 		RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO);
 	}
 
-	void RenderTargets::generateHiZ()
+	void RenderTargets::generate(RenderTargetType type)
 	{
-		mHiZ = GpuResourcePool::instance().get(
-			BuildHiZ::getHiZTextureDesc(
-				mViewTarget.viewRect.width, 
-				mViewTarget.viewRect.height)
-		);
-
-		mBuildHiZ.execute(mViewTarget, mDepthTex->texture, mHiZ->texture);
+		switch(type)
+		{
+		case RTT_HiZ:
+			mBuildHiZ.execute(mViewTarget, getResolvedDepth(), mHiZ->texture);
+		break;
+		case RTT_ResolvedSceneColor:
+			if (mViewTarget.numSamples > 1)
+			{
+				RenderAPI::instance().setRenderTarget(mResolvedDepthTex->renderTexture);
+				gRendererUtility().blit(mDepthTex->texture);
+			}
+			break;
+		default:
+			break;
+		}
 	}
 
-	void RenderTargets::releaseHiZ()
+	SPtr<Texture> RenderTargets::getResolvedDepth() const
 	{
-		if (mHiZ)
-			GpuResourcePool::instance().release(mHiZ);
+		if (mViewTarget.numSamples > 1)
+			return mResolvedDepthTex->texture;
+
+		return mDepthTex->texture;
 	}
 
 	SPtr<Texture> RenderTargets::getHiZ() const