Bläddra i källkod

Perform MSAA resolve after tonemapping

BearishSun 8 år sedan
förälder
incheckning
f886443836

+ 42 - 18
Data/Raw/Engine/Shaders/PPDownsample.bsl

@@ -9,30 +9,54 @@ technique PPDownsample
 		[internal]
 		[internal]
 		cbuffer Input
 		cbuffer Input
 		{
 		{
-			float2 gInvTexSize;
+			float2 gOffsets[4];
 		}		
 		}		
-	
-		SamplerState gInputSamp;
-		Texture2D gInputTex;
 
 
+		#if MSAA
+			Texture2DMS<float4> gInputTex;
+			
+			// position is expected to be at the center of 2x2 pixel tile, in pixels
+			float4 bilinearFilter(float2 position)
+			{
+				float4 sampleSum;
+
+				sampleSum = gInputTex.Load(trunc(position + float2(-0.5f, -0.5f)), 0);
+				sampleSum += gInputTex.Load(trunc(position + float2(0.5f, -0.5f)), 0);
+				sampleSum += gInputTex.Load(trunc(position + float2(-0.5f, 0.5f)), 0);
+				sampleSum += gInputTex.Load(trunc(position + float2(0.5f, 0.5f)), 0);
+				
+				return sampleSum * 0.25f;
+			}
+		#else
+			SamplerState gInputSamp;
+			Texture2D gInputTex;
+			
+			// position is expected to be at the center of 2x2 pixel tile, in UV
+			float4 bilinearFilter(float2 position)
+			{
+				return gInputTex.Sample(gInputSamp, position);
+			}			
+		#endif
+		
 		float4 fsmain(VStoFS input) : SV_Target0
 		float4 fsmain(VStoFS input) : SV_Target0
 		{
 		{
-			float2 UV[4];
-
-			// Blur using a 4x4 kernel. It's assumed current position is right in the middle of a 2x2 kernel (because the output
-			// texture should be 1/2 the size of the output texture), and moving by one in each direction will sample areas
-			// between a 2x2 kernel as well if bilinear filtering is enabled.
-			UV[0] = input.uv0 + gInvTexSize * float2(-1, -1);
-			UV[1] = input.uv0 + gInvTexSize * float2( 1, -1);
-			UV[2] = input.uv0 + gInvTexSize * float2(-1,  1);
-			UV[3] = input.uv0 + gInvTexSize * float2( 1,  1);
-
-			float4 samples[4];
+			// input.uv0 is in the center of 2x2 block of pixels. If MSAA is enabled the value is
+			// in pixels, otherwise normal UV range.
+			
+			#if QUALITY == 0 
+				// Single bilinearly filtered sample (2x2 block average)
+				return bilinearFilter(input.uv0);
+			#else // QUALITY == 1
+				// Four bilinearly filtered samples (4x4 block average)
+				float4 samples[4];
 
 
-			for(uint i = 0; i < 4; i++)
-				samples[i] = gInputTex.Sample(gInputSamp, UV[i]);
+				[unroll]
+				for(uint i = 0; i < 4; i++)
+					samples[i] = bilinearFilter(input.uv0 + gOffsets[i]);
 
 
-			return (samples[0] + samples[1] + samples[2] + samples[3]) * 0.25f;
+				return (samples[0] + samples[1] + samples[2] + samples[3]) * 0.25f;
+				
+			#endif // QUALITY
 		}	
 		}	
 	};
 	};
 };
 };

+ 30 - 10
Data/Raw/Engine/Shaders/PPTonemapping.bsl

@@ -38,8 +38,12 @@ technique PPTonemapping
 			return output;
 			return output;
 		}			
 		}			
 
 
-		SamplerState gInputSamp;
-		Texture2D gInputTex;
+		#if MSAA
+			Texture2DMS<float4> gInputTex;
+		#else
+			SamplerState gInputSamp;
+			Texture2D gInputTex;
+		#endif
 		
 		
 		SamplerState gColorLUTSamp;
 		SamplerState gColorLUTSamp;
 		Texture3D gColorLUT;
 		Texture3D gColorLUT;
@@ -48,6 +52,7 @@ technique PPTonemapping
 		{
 		{
 			float gRawGamma;
 			float gRawGamma;
 			float gManualExposureScale;
 			float gManualExposureScale;
+			uint gNumSamples;
 		}				
 		}				
 		
 		
 		float3 ColorLookupTable(float3 linearColor)
 		float3 ColorLookupTable(float3 linearColor)
@@ -58,22 +63,37 @@ technique PPTonemapping
 			float3 gradedColor = gColorLUT.Sample(gColorLUTSamp, UVW).rgb;
 			float3 gradedColor = gColorLUT.Sample(gColorLUTSamp, UVW).rgb;
 			return gradedColor;
 			return gradedColor;
 		}
 		}
-					
-		float4 fsmain(VStoFS input) : SV_Target0
+		
+		float3 tonemapSample(float3 samp, float exposureScale)
 		{
 		{
-			float4 sceneColor = gInputTex.Sample(gInputSamp, input.uv0);
-			
 			#if AUTO_EXPOSURE
 			#if AUTO_EXPOSURE
-				sceneColor.rgb = sceneColor.rgb * input.exposureScale;
+				samp = samp * exposureScale;
 			#else
 			#else
-				sceneColor.rgb = sceneColor.rgb * gManualExposureScale;
+				samp = samp * gManualExposureScale;
 			#endif
 			#endif
 			
 			
 			#if GAMMA_ONLY
 			#if GAMMA_ONLY
-				sceneColor.rgb = pow(sceneColor.rgb, gRawGamma);				
+				return pow(samp, gRawGamma);				
+			#else
+				return ColorLookupTable(samp);
+			#endif
+		}
+		
+		float4 fsmain(VStoFS input) : SV_Target0
+		{
+			float4 sceneColor = 0;
+			#if MSAA
+				for(uint i = 0; i < gNumSamples; ++i)
+					sceneColor.rgb += tonemapSample(gInputTex.Load(trunc(input.uv0), i).rgb, input.exposureScale);
+			
+				sceneColor.rgb /= gNumSamples;
 			#else
 			#else
-				sceneColor.rgb = ColorLookupTable(sceneColor.rgb);
+				sceneColor.rgb = tonemapSample(gInputTex.Sample(gInputSamp, input.uv0).rgb, input.exposureScale);
 			#endif
 			#endif
+						
+			// Output luma in gamma-space, for FXAA
+			// Note: This can be avoided if FXAA is not used
+			sceneColor.a = dot(sceneColor.rgb, float3(0.299, 0.587, 0.114));
 
 
 			return sceneColor;
 			return sceneColor;
 		}	
 		}	

+ 77 - 11
Source/RenderBeast/Include/BsPostProcessing.h

@@ -29,13 +29,20 @@ namespace bs { namespace ct
 	};
 	};
 
 
 	BS_PARAM_BLOCK_BEGIN(DownsampleParamDef)
 	BS_PARAM_BLOCK_BEGIN(DownsampleParamDef)
-		BS_PARAM_BLOCK_ENTRY(Vector2, gInvTexSize)
+		BS_PARAM_BLOCK_ENTRY_ARRAY(Vector2, gOffsets, 4)
 	BS_PARAM_BLOCK_END
 	BS_PARAM_BLOCK_END
 
 
 	extern DownsampleParamDef gDownsampleParamDef;
 	extern DownsampleParamDef gDownsampleParamDef;
 
 
-	/** Shader that downsamples a texture to half its size. */
-	class DownsampleMat : public RendererMaterial<DownsampleMat>
+	/** 
+	 * Shader that downsamples a texture to half its size. 
+	 * 
+	 * @tparam	Quality		0 for a 2x2 filtered sample, 1 or higher for 4x4 filtered sample
+	 * @tparam	MSAA		True if the input texture is multi-sampled. Only first sample will be used, the rest will be
+	 *						discarded.
+	 */
+	template<int Quality, bool MSAA>
+	class DownsampleMat : public RendererMaterial<DownsampleMat<Quality, MSAA>>
 	{
 	{
 		RMAT_DEF("PPDownsample.bsl");
 		RMAT_DEF("PPDownsample.bsl");
 
 
@@ -58,6 +65,35 @@ namespace bs { namespace ct
 		SPtr<RenderTexture> mOutput;
 		SPtr<RenderTexture> mOutput;
 	};
 	};
 
 
+	/** Contains all variations of the DownsampleMat material. */
+	class DownsampleMaterials
+	{
+	public:
+		/**
+		 * Executes the appropriate downsampling material.
+		 * 
+		 * @param[in]	quality		Determines quality of the downsampling filer. Specify 0 to use a 2x2 filter block, and
+		 *							1 or higher for a 4x4 filter block.
+		 * @param[in]	msaa		If true the input texture is assumed to have multiple samples. The downsampling shader
+		 *							will discard all samples except the first one.
+		 * @param[in]	target		Texture to downsample.
+		 * @param[in]	ppInfo		Information about the current post processing pass.
+		 */
+		void execute(UINT32 quality, bool msaa, const SPtr<Texture>& target, PostProcessInfo& ppInfo);
+
+		/**
+		 * Releases any resources allocated by execute(). Must be called using the same @p quality and @p msaa parameters as
+		 * the corresponding execute() call. @see execute().
+		 */
+		void release(UINT32 quality, bool msaa, PostProcessInfo& ppInfo);
+	private:
+		DownsampleMat<0, false> m0_NoMSAA;
+		DownsampleMat<0, true> m0_MSAA;
+		
+		DownsampleMat<1, false> m1_NoMSAA;
+		DownsampleMat<1, true> m1_MSAA;
+	};
+
 	BS_PARAM_BLOCK_BEGIN(EyeAdaptHistogramParamDef)
 	BS_PARAM_BLOCK_BEGIN(EyeAdaptHistogramParamDef)
 		BS_PARAM_BLOCK_ENTRY(Vector4I, gPixelOffsetAndSize)
 		BS_PARAM_BLOCK_ENTRY(Vector4I, gPixelOffsetAndSize)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gHistogramParams)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gHistogramParams)
@@ -209,13 +245,14 @@ namespace bs { namespace ct
 	BS_PARAM_BLOCK_BEGIN(TonemappingParamDef)
 	BS_PARAM_BLOCK_BEGIN(TonemappingParamDef)
 		BS_PARAM_BLOCK_ENTRY(float, gRawGamma)
 		BS_PARAM_BLOCK_ENTRY(float, gRawGamma)
 		BS_PARAM_BLOCK_ENTRY(float, gManualExposureScale)
 		BS_PARAM_BLOCK_ENTRY(float, gManualExposureScale)
+		BS_PARAM_BLOCK_ENTRY(int, gNumSamples)
 	BS_PARAM_BLOCK_END
 	BS_PARAM_BLOCK_END
 
 
 	extern TonemappingParamDef gTonemappingParamDef;
 	extern TonemappingParamDef gTonemappingParamDef;
 
 
 	/** Shader that applies tonemapping and converts a HDR image into a LDR image. */
 	/** Shader that applies tonemapping and converts a HDR image into a LDR image. */
-	template<bool GammaOnly, bool AutoExposure>
-	class TonemappingMat : public RendererMaterial<TonemappingMat<GammaOnly, AutoExposure>>
+	template<bool GammaOnly, bool AutoExposure, bool MSAA>
+	class TonemappingMat : public RendererMaterial<TonemappingMat<GammaOnly, AutoExposure, MSAA>>
 	{
 	{
 		RMAT_DEF("PPTonemapping.bsl");
 		RMAT_DEF("PPTonemapping.bsl");
 
 
@@ -234,6 +271,38 @@ namespace bs { namespace ct
 		GpuParamTexture mEyeAdaptationTex;
 		GpuParamTexture mEyeAdaptationTex;
 	};
 	};
 
 
+	/** Container for all variations of the TonemappingMat material. */
+	class TonemappingMaterials
+	{
+	public:
+		/** 
+		 * Finds a valid tonemapping material according to the requested parameters and executes it. 
+		 *
+		 * @param[in]	gammaOnly		If true no color correction, white balancing or curve tonemapping will take place. 
+		 *								Instead the image will only be scaled by the exposure value and gamma corrected.
+		 * @param[in]	autoExposure	If true, the automatically calculated eye-adapatation exposure value will be used
+		 *								as the exposure scale. If false, the user provided value will be used instead.
+		 * @param[in]	MSAA			True if the input texture has multiple samples. This will ensure that the samples
+		 *								are resolved properly into a non-MSAA output texture.
+		 * @param[in]	sceneColor		Texture to apply tonemapping to.
+		 * @param[in]	outputRT		Render target to write the results to.
+		 * @param[in]	outputRect		Normalized rectangle determining to which part of the output texture to write to.
+		 * @param[in]	ppInfo			Information about the current post processing pass.
+		 */
+		void execute(bool gammaOnly, bool autoExposure, bool MSAA, const SPtr<Texture>& sceneColor,
+			const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo);
+
+	private:
+		TonemappingMat<false, false, false> mFFF;
+		TonemappingMat<false, false, true> mFFT;
+		TonemappingMat<false, true, false> mFTF;
+		TonemappingMat<false, true, true> mFTT;
+		TonemappingMat<true, false, false> mTFF;
+		TonemappingMat<true, false, true> mTFT;
+		TonemappingMat<true, true, false> mTTF;
+		TonemappingMat<true, true, true> mTTT;
+	};
+
 	/**
 	/**
 	 * Renders post-processing effects for the provided render target.
 	 * Renders post-processing effects for the provided render target.
 	 *
 	 *
@@ -247,19 +316,16 @@ namespace bs { namespace ct
 		 * view's final output render target. Once the method exits, final render target is guaranteed to be currently
 		 * view's final output render target. Once the method exits, final render target is guaranteed to be currently
 		 * bound for rendering. 
 		 * bound for rendering. 
 		 */
 		 */
-		void postProcess(RendererView* viewInfo, const SPtr<Texture>& sceneColor, float frameDelta);
+		void postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta);
 		
 		
 	private:
 	private:
-		DownsampleMat mDownsample;
+		DownsampleMaterials mDownsample;
 		EyeAdaptHistogramMat mEyeAdaptHistogram;
 		EyeAdaptHistogramMat mEyeAdaptHistogram;
 		EyeAdaptHistogramReduceMat mEyeAdaptHistogramReduce;
 		EyeAdaptHistogramReduceMat mEyeAdaptHistogramReduce;
 		EyeAdaptationMat mEyeAdaptation;
 		EyeAdaptationMat mEyeAdaptation;
 
 
 		CreateTonemapLUTMat mCreateLUT;
 		CreateTonemapLUTMat mCreateLUT;
-		TonemappingMat<false, true> mTonemapping_AE;
-		TonemappingMat<true, true> mTonemapping_AE_GO;
-		TonemappingMat<false, false> mTonemapping;
-		TonemappingMat<true, false> mTonemapping_GO;
+		TonemappingMaterials mTonemapping;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 0 - 10
Source/RenderBeast/Include/BsRenderTargets.h

@@ -113,15 +113,6 @@ namespace bs { namespace ct
 		 */
 		 */
 		SPtr<GpuBuffer> getLightAccumulationBuffer() const;
 		SPtr<GpuBuffer> getLightAccumulationBuffer() const;
 
 
-		/** 
-		 * Returns a scene color texture with a single-sample per pixel. If no multisampling is used, this is the same as
-		 * getSceneColor().
-		 */
-		SPtr<Texture> getResolvedSceneColor() const;
-
-		/** Returns a render target that can be used for rendering to the texture returned by getResolvedSceneColor(). */
-		SPtr<RenderTexture> getResolvedSceneColorRT() const;
-
 		/**	Checks if the targets support HDR rendering. */
 		/**	Checks if the targets support HDR rendering. */
 		bool getHDR() const { return mHDR; }
 		bool getHDR() const { return mHDR; }
 
 
@@ -159,7 +150,6 @@ namespace bs { namespace ct
 		SPtr<PooledStorageBuffer> mFlattenedLightAccumulationBuffer;
 		SPtr<PooledStorageBuffer> mFlattenedLightAccumulationBuffer;
 
 
 		SPtr<PooledRenderTexture> mSceneColorTex;
 		SPtr<PooledRenderTexture> mSceneColorTex;
-		SPtr<PooledRenderTexture> mSceneColorNonMSAATex;
 		SPtr<PooledStorageBuffer> mFlattenedSceneColorBuffer;
 		SPtr<PooledStorageBuffer> mFlattenedSceneColorBuffer;
 
 
 		SPtr<RenderTexture> mGBufferRT;
 		SPtr<RenderTexture> mGBufferRT;

+ 162 - 34
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -8,33 +8,55 @@
 #include "BsCamera.h"
 #include "BsCamera.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
 #include "BsRendererView.h"
 #include "BsRendererView.h"
+#include "BsRenderTargets.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
 	DownsampleParamDef gDownsampleParamDef;
 	DownsampleParamDef gDownsampleParamDef;
 
 
-	DownsampleMat::DownsampleMat()
+	template<int Quality, bool MSAA>
+	DownsampleMat<Quality, MSAA>::DownsampleMat()
 	{
 	{
 		mParamBuffer = gDownsampleParamDef.createBuffer();
 		mParamBuffer = gDownsampleParamDef.createBuffer();
 
 
-		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
+		SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
+		if(gpuParams->hasParamBlock(GPT_FRAGMENT_PROGRAM, "Input"))
+			mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
+
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
 	}
 	}
 
 
-	void DownsampleMat::_initDefines(ShaderDefines& defines)
+	template<int Quality, bool MSAA>
+	void DownsampleMat<Quality, MSAA>::_initDefines(ShaderDefines& defines)
 	{
 	{
-		// Do nothing
+		defines.set("QUALITY", Quality);
+		defines.set("MSAA", MSAA ? 1 : 0);
 	}
 	}
 
 
-	void DownsampleMat::execute(const SPtr<Texture>& target, PostProcessInfo& ppInfo)
+	template<int Quality, bool MSAA>
+	void DownsampleMat<Quality, MSAA>::execute(const SPtr<Texture>& target, PostProcessInfo& ppInfo)
 	{
 	{
 		// Set parameters
 		// Set parameters
 		mInputTexture.set(target);
 		mInputTexture.set(target);
 
 
 		const TextureProperties& rtProps = target->getProperties();
 		const TextureProperties& rtProps = target->getProperties();
-		Vector2 invTextureSize(1.0f / rtProps.getWidth(), 1.0f / rtProps.getHeight());
 
 
-		gDownsampleParamDef.gInvTexSize.set(mParamBuffer, invTextureSize);
+		if(MSAA)
+		{
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(-1.0f, -1.0f));
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(1.0f, -1.0f));
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(-1.0f, 1.0f));
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, Vector2(1.0f, 1.0f));
+		}
+		else
+		{
+			Vector2 invTextureSize(1.0f / rtProps.getWidth(), 1.0f / rtProps.getHeight());
+
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(-1.0f, -1.0f));
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(1.0f, -1.0f));
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(-1.0f, 1.0f));
+			gDownsampleParamDef.gOffsets.set(mParamBuffer, invTextureSize * Vector2(1.0f, 1.0f));
+		}
 
 
 		// Set output
 		// Set output
 		UINT32 width = std::max(1, Math::ceilToInt(rtProps.getWidth() * 0.5f));
 		UINT32 width = std::max(1, Math::ceilToInt(rtProps.getWidth() * 0.5f));
@@ -50,19 +72,65 @@ namespace bs { namespace ct
 
 
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
-		gRendererUtility().drawScreenQuad();
+
+		if (MSAA)
+			gRendererUtility().drawScreenQuad(Rect2(0.0f, 0.0f, (float)rtProps.getWidth(), (float)rtProps.getHeight()));
+		else
+			gRendererUtility().drawScreenQuad();
 
 
 		rapi.setRenderTarget(nullptr);
 		rapi.setRenderTarget(nullptr);
 
 
 		mOutput = ppInfo.downsampledSceneTex->renderTexture;
 		mOutput = ppInfo.downsampledSceneTex->renderTexture;
 	}
 	}
 
 
-	void DownsampleMat::release(PostProcessInfo& ppInfo)
+	template<int Quality, bool MSAA>
+	void DownsampleMat<Quality, MSAA>::release(PostProcessInfo& ppInfo)
 	{
 	{
 		GpuResourcePool::instance().release(ppInfo.downsampledSceneTex);
 		GpuResourcePool::instance().release(ppInfo.downsampledSceneTex);
 		mOutput = nullptr;
 		mOutput = nullptr;
 	}
 	}
 
 
+	void DownsampleMaterials::execute(UINT32 quality, bool msaa, const SPtr<Texture>& target, PostProcessInfo& ppInfo)
+	{
+		if(quality == 0)
+		{
+			if(msaa)
+				m0_MSAA.execute(target, ppInfo);
+			else
+				m0_NoMSAA.execute(target, ppInfo);
+		}
+		else
+		{
+			if (msaa)
+				m1_MSAA.execute(target, ppInfo);
+			else
+				m1_NoMSAA.execute(target, ppInfo);
+		}
+	}
+
+	void DownsampleMaterials::release(UINT32 quality, bool msaa, PostProcessInfo& ppInfo)
+	{
+		if(quality == 0)
+		{
+			if(msaa)
+				m0_MSAA.release(ppInfo);
+			else
+				m0_NoMSAA.release(ppInfo);
+		}
+		else
+		{
+			if (msaa)
+				m1_MSAA.release(ppInfo);
+			else
+				m1_NoMSAA.release(ppInfo);
+		}
+	}
+
+	template class DownsampleMat<0, false>;
+	template class DownsampleMat<0, true>;
+	template class DownsampleMat<1, false>;
+	template class DownsampleMat<1, true>;
+
 	EyeAdaptHistogramParamDef gEyeAdaptHistogramParamDef;
 	EyeAdaptHistogramParamDef gEyeAdaptHistogramParamDef;
 
 
 	EyeAdaptHistogramMat::EyeAdaptHistogramMat()
 	EyeAdaptHistogramMat::EyeAdaptHistogramMat()
@@ -362,8 +430,8 @@ namespace bs { namespace ct
 
 
 	TonemappingParamDef gTonemappingParamDef;
 	TonemappingParamDef gTonemappingParamDef;
 
 
-	template<bool GammaOnly, bool AutoExposure>
-	TonemappingMat<GammaOnly, AutoExposure>::TonemappingMat()
+	template<bool GammaOnly, bool AutoExposure, bool MSAA>
+	TonemappingMat<GammaOnly, AutoExposure, MSAA>::TonemappingMat()
 	{
 	{
 		mParamBuffer = gTonemappingParamDef.createBuffer();
 		mParamBuffer = gTonemappingParamDef.createBuffer();
 		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
 		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
@@ -376,8 +444,8 @@ namespace bs { namespace ct
 			params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gColorLUT", mColorLUT);
 			params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gColorLUT", mColorLUT);
 	}
 	}
 
 
-	template<bool GammaOnly, bool AutoExposure>
-	void TonemappingMat<GammaOnly, AutoExposure>::_initDefines(ShaderDefines& defines)
+	template<bool GammaOnly, bool AutoExposure, bool MSAA>
+	void TonemappingMat<GammaOnly, AutoExposure, MSAA>::_initDefines(ShaderDefines& defines)
 	{
 	{
 		if(GammaOnly)
 		if(GammaOnly)
 			defines.set("GAMMA_ONLY", 1);
 			defines.set("GAMMA_ONLY", 1);
@@ -385,15 +453,19 @@ namespace bs { namespace ct
 		if (AutoExposure)
 		if (AutoExposure)
 			defines.set("AUTO_EXPOSURE", 1);
 			defines.set("AUTO_EXPOSURE", 1);
 
 
+		defines.set("MSAA", MSAA ? 1 : 0);
 		defines.set("LUT_SIZE", CreateTonemapLUTMat::LUT_SIZE);
 		defines.set("LUT_SIZE", CreateTonemapLUTMat::LUT_SIZE);
 	}
 	}
 
 
-	template<bool GammaOnly, bool AutoExposure>
-	void TonemappingMat<GammaOnly, AutoExposure>::execute(const SPtr<Texture>& sceneColor, 
+	template<bool GammaOnly, bool AutoExposure, bool MSAA>
+	void TonemappingMat<GammaOnly, AutoExposure, MSAA>::execute(const SPtr<Texture>& sceneColor, 
 		const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo)
 		const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo)
 	{
 	{
+		const TextureProperties& texProps = sceneColor->getProperties();
+
 		gTonemappingParamDef.gRawGamma.set(mParamBuffer, 1.0f / ppInfo.settings->gamma);
 		gTonemappingParamDef.gRawGamma.set(mParamBuffer, 1.0f / ppInfo.settings->gamma);
 		gTonemappingParamDef.gManualExposureScale.set(mParamBuffer, Math::pow(2.0f, ppInfo.settings->exposureScale));
 		gTonemappingParamDef.gManualExposureScale.set(mParamBuffer, Math::pow(2.0f, ppInfo.settings->exposureScale));
+		gTonemappingParamDef.gNumSamples.set(mParamBuffer, texProps.getNumSamples());
 
 
 		// Set parameters
 		// Set parameters
 		mInputTex.set(sceneColor);
 		mInputTex.set(sceneColor);
@@ -418,31 +490,79 @@ namespace bs { namespace ct
 
 
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
-		gRendererUtility().drawScreenQuad();
+
+		if (MSAA)
+			gRendererUtility().drawScreenQuad(Rect2(0.0f, 0.0f, (float)texProps.getWidth(), (float)texProps.getHeight()));
+		else
+			gRendererUtility().drawScreenQuad();
 	}
 	}
 
 
-	template class TonemappingMat<true, true>;
-	template class TonemappingMat<false, true>;
-	template class TonemappingMat<true, false>;
-	template class TonemappingMat<false, false>;
+	template class TonemappingMat<false, false, false>;
+	template class TonemappingMat<false, false, true>;
+	template class TonemappingMat<false, true, false>;
+	template class TonemappingMat<false, true, true>;
+	template class TonemappingMat<true, false, false>;
+	template class TonemappingMat<true, false, true>;
+	template class TonemappingMat<true, true, false>;
+	template class TonemappingMat<true, true, true>;
+
+	void TonemappingMaterials::execute(bool gammaOnly, bool autoExposure, bool MSAA, const SPtr<Texture>& sceneColor, 
+		const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo)
+	{
+		if (gammaOnly)
+		{
+			if (autoExposure)
+			{
+				if (MSAA)
+					mTTT.execute(sceneColor, outputRT, outputRect, ppInfo);
+				else
+					mTTF.execute(sceneColor, outputRT, outputRect, ppInfo);
+			}
+			else
+			{
+				if (MSAA)
+					mTFT.execute(sceneColor, outputRT, outputRect, ppInfo);
+				else
+					mTFF.execute(sceneColor, outputRT, outputRect, ppInfo);
+			}
+		}
+		else
+		{
+			if (autoExposure)
+			{
+				if (MSAA)
+					mFTT.execute(sceneColor, outputRT, outputRect, ppInfo);
+				else
+					mFTF.execute(sceneColor, outputRT, outputRect, ppInfo);
+			}
+			else
+			{
+				if (MSAA)
+					mFFT.execute(sceneColor, outputRT, outputRect, ppInfo);
+				else
+					mFFF.execute(sceneColor, outputRT, outputRect, ppInfo);
+			}
+		}
+	}
 
 
-	void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<Texture>& sceneColor, float frameDelta)
+	void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta)
 	{
 	{
 		auto& viewProps = viewInfo->getProperties();
 		auto& viewProps = viewInfo->getProperties();
 
 
 		PostProcessInfo& ppInfo = viewInfo->getPPInfo();
 		PostProcessInfo& ppInfo = viewInfo->getPPInfo();
 		const StandardPostProcessSettings& settings = *ppInfo.settings;
 		const StandardPostProcessSettings& settings = *ppInfo.settings;
 
 
-		SPtr<RenderTarget> finalRT = viewProps.target;
+		SPtr<Texture> sceneColor = renderTargets->getSceneColor();
 		Rect2 viewportRect = viewProps.nrmViewRect;
 		Rect2 viewportRect = viewProps.nrmViewRect;
 
 
 		bool hdr = viewProps.isHDR;
 		bool hdr = viewProps.isHDR;
+		bool msaa = viewProps.numSamples > 1;
 
 
 		if(hdr && settings.enableAutoExposure)
 		if(hdr && settings.enableAutoExposure)
 		{
 		{
-			mDownsample.execute(sceneColor, ppInfo);
+			mDownsample.execute(1, msaa, sceneColor, ppInfo);
 			mEyeAdaptHistogram.execute(ppInfo);
 			mEyeAdaptHistogram.execute(ppInfo);
-			mDownsample.release(ppInfo);
+			mDownsample.release(1, msaa, ppInfo);
 
 
 			mEyeAdaptHistogramReduce.execute(ppInfo);
 			mEyeAdaptHistogramReduce.execute(ppInfo);
 			mEyeAdaptHistogram.release(ppInfo);
 			mEyeAdaptHistogram.release(ppInfo);
@@ -451,24 +571,32 @@ namespace bs { namespace ct
 			mEyeAdaptHistogramReduce.release(ppInfo);
 			mEyeAdaptHistogramReduce.release(ppInfo);
 		}
 		}
 
 
-		if (hdr && settings.enableTonemapping)
+		SPtr<RenderTarget> resolveTarget = viewProps.target;
+
+		bool gammaOnly;
+		bool autoExposure;
+		if (hdr)
 		{
 		{
-			if (ppInfo.settingDirty) // Rebuild LUT if PP settings changed
-				mCreateLUT.execute(ppInfo);
+			if (settings.enableTonemapping)
+			{
+				if (ppInfo.settingDirty) // Rebuild LUT if PP settings changed
+					mCreateLUT.execute(ppInfo);
 
 
-			if (settings.enableAutoExposure)
-				mTonemapping_AE.execute(sceneColor, finalRT, viewportRect, ppInfo);
+				gammaOnly = false;
+			}
 			else
 			else
-				mTonemapping.execute(sceneColor, finalRT, viewportRect, ppInfo);
+				gammaOnly = true;
+
+			autoExposure = settings.enableAutoExposure;
 		}
 		}
 		else
 		else
 		{
 		{
-			if (hdr && settings.enableAutoExposure)
-				mTonemapping_AE_GO.execute(sceneColor, finalRT, viewportRect, ppInfo);
-			else
-				mTonemapping_GO.execute(sceneColor, finalRT, viewportRect, ppInfo);
+			gammaOnly = true;
+			autoExposure = false;
 		}
 		}
 
 
+		mTonemapping.execute(gammaOnly, autoExposure, msaa, sceneColor, resolveTarget, viewportRect, ppInfo);
+
 		if (ppInfo.settingDirty)
 		if (ppInfo.settingDirty)
 			ppInfo.settingDirty = false;
 			ppInfo.settingDirty = false;
 	}
 	}

+ 1 - 11
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -673,18 +673,8 @@ namespace bs { namespace ct
 
 
 		if (viewProps.runPostProcessing)
 		if (viewProps.runPostProcessing)
 		{
 		{
-			// If using MSAA, resolve into non-MSAA texture before post-processing
-			if(numSamples > 1)
-			{
-				rapi.setRenderTarget(renderTargets->getResolvedSceneColorRT());
-				rapi.setViewport(viewportArea);
-
-				SPtr<Texture> sceneColor = renderTargets->getSceneColor();
-				gRendererUtility().blit(sceneColor, Rect2I::EMPTY, viewProps.flipView);
-			}
-
 			// Post-processing code also takes care of writting to the final output target
 			// Post-processing code also takes care of writting to the final output target
-			PostProcessing::instance().postProcess(viewInfo, renderTargets->getResolvedSceneColor(), frameDelta);
+			PostProcessing::instance().postProcess(viewInfo, renderTargets, frameDelta);
 		}
 		}
 		else
 		else
 		{
 		{

+ 0 - 23
Source/RenderBeast/Source/BsRenderTargets.cpp

@@ -114,10 +114,6 @@ namespace bs { namespace ct
 			{
 			{
 				UINT32 bufferNumElements = width * height * mViewTarget.numSamples;
 				UINT32 bufferNumElements = width * height * mViewTarget.numSamples;
 				mFlattenedSceneColorBuffer = texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
 				mFlattenedSceneColorBuffer = texPool.get(POOLED_STORAGE_BUFFER_DESC::createStandard(BF_16X4F, bufferNumElements));
-
-				// Need a texture we'll resolve MSAA to before post-processing
-				mSceneColorNonMSAATex = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width,
-					height, TU_RENDERTARGET, 1, false));
 			}
 			}
 
 
 			bool rebuildRT = false;
 			bool rebuildRT = false;
@@ -232,9 +228,6 @@ namespace bs { namespace ct
 		{
 		{
 			texPool.release(mSceneColorTex);
 			texPool.release(mSceneColorTex);
 
 
-			if (mSceneColorNonMSAATex != nullptr)
-				texPool.release(mSceneColorNonMSAATex);
-
 			if (mFlattenedSceneColorBuffer != nullptr)
 			if (mFlattenedSceneColorBuffer != nullptr)
 				texPool.release(mFlattenedSceneColorBuffer);
 				texPool.release(mFlattenedSceneColorBuffer);
 		}
 		}
@@ -328,22 +321,6 @@ namespace bs { namespace ct
 		return mDepthTex->texture;
 		return mDepthTex->texture;
 	}
 	}
 
 
-	SPtr<Texture> RenderTargets::getResolvedSceneColor() const
-	{
-		if (mSceneColorNonMSAATex != nullptr)
-			return mSceneColorNonMSAATex->texture;
-
-		return getSceneColor();
-	}
-
-	SPtr<RenderTexture> RenderTargets::getResolvedSceneColorRT() const
-	{
-		if (mSceneColorNonMSAATex != nullptr)
-			return mSceneColorNonMSAATex->renderTexture;
-
-		return mSceneColorTex->renderTexture;
-	}
-
 	SPtr<GpuBuffer> RenderTargets::getSceneColorBuffer() const
 	SPtr<GpuBuffer> RenderTargets::getSceneColorBuffer() const
 	{
 	{
 		return mFlattenedSceneColorBuffer->buffer;
 		return mFlattenedSceneColorBuffer->buffer;