BearishSun 8 лет назад
Родитель
Сommit
1a1b8bc0d5

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

@@ -305,6 +305,10 @@
         {
             "Path": "PPGaussianDOFCombine.bsl",
             "UUID": "2743e8f1-97cf-4441-b9e4-aad280343901"
+        },
+        {
+            "Path": "PPBuildHiZ.bsl",
+            "UUID": "1b314248-1965-49c5-968b-ae923c2af717"
         }
     ],
     "Skin": [

+ 33 - 0
Data/Raw/Engine/Shaders/PPBuildHiZ.bsl

@@ -0,0 +1,33 @@
+#include "$ENGINE$\PPBase.bslinc"
+
+technique PPBuildHiZ
+{
+	mixin PPBase;
+
+	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
+		}	
+	};
+};

+ 8 - 4
Data/Raw/Engine/Shaders/PPGaussianDOFSeparate.bsl

@@ -11,9 +11,13 @@ technique PPGaussianDOFSeparate
 		SamplerState gColorSamp;
 		Texture2D gColorTex;
 		
+		#if MSAA
+		Texture2DMS<float> gDepthTex;
+		#else
 		SamplerState gDepthSamp;
 		Texture2D gDepthTex;
-
+		#endif
+		
 		void addSample(float2 uv, float2 offset, float depth, inout float4 nearColor, inout float4 farColor)
 		{
 			float4 smp;
@@ -36,7 +40,7 @@ technique PPGaussianDOFSeparate
 			#endif
 			)
 		{
-			float4 depth = convertFromDeviceZ(gDepthTex.Gather(gDepthSamp, input.uv0));
+			float4 depth = -convertFromDeviceZ(gDepthTex.Gather(gDepthSamp, input.uv0));
 			
 			float4 nearColor = 0;
 			float4 farColor = 0;
@@ -45,8 +49,8 @@ technique PPGaussianDOFSeparate
 			// depth Gather
 			addSample(input.uv0, float2(-1, 1), depth.x, nearColor, farColor);
 			addSample(input.uv0, float2(1, 1), depth.y, nearColor, farColor);
-			addSample(input.uv0, float2(1, -1), depth.x, nearColor, farColor);
-			addSample(input.uv0, float2(-1, -1), depth.x, nearColor, farColor);
+			addSample(input.uv0, float2(1, -1), depth.z, nearColor, farColor);
+			addSample(input.uv0, float2(-1, -1), depth.w, nearColor, farColor);
 			
 			nearColor *= 0.25f;
 			farColor *= 0.25f;

+ 23 - 23
Source/BansheeCore/Include/BsPixelUtil.h

@@ -76,9 +76,9 @@ namespace bs
 	};
 
 	/**	Utility methods for converting and managing pixel data and formats. */
-    class BS_CORE_EXPORT PixelUtil 
+	class BS_CORE_EXPORT PixelUtil 
 	{
-    public:
+	public:
 		/**	Filtering types to use when scaling images. */
 		enum Filter
 		{
@@ -87,10 +87,10 @@ namespace bs
 		};
 
 		/**	Returns the size of a single pixel of the provided pixel format, in bytes. */
-        static UINT32 getNumElemBytes(PixelFormat format);
+		static UINT32 getNumElemBytes(PixelFormat format);
 
 		/**	Returns the size of a single pixel of the provided pixel format, in bits. */
-        static UINT32 getNumElemBits( PixelFormat format );
+		static UINT32 getNumElemBits(PixelFormat format);
 
 		/**	Returns the size of the memory region required to hold pixels of the provided size ana format. */
 		static UINT32 getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format);
@@ -112,22 +112,22 @@ namespace bs
 		 *
 		 * @see		PixelFormatFlags
 		 */
-        static UINT32 getFlags(PixelFormat format);
+		static UINT32 getFlags(PixelFormat format);
 
 		/**	Checks if the provided pixel format has an alpha channel. */
-        static bool hasAlpha(PixelFormat format);
+		static bool hasAlpha(PixelFormat format);
 
 		/**	Checks is the provided pixel format a floating point format. */
-        static bool isFloatingPoint(PixelFormat format);
+		static bool isFloatingPoint(PixelFormat format);
 
 		/**	Checks is the provided pixel format compressed. */
-        static bool isCompressed(PixelFormat format);
+		static bool isCompressed(PixelFormat format);
 
 		/**	Checks is the provided pixel format a depth/stencil buffer format. */
-        static bool isDepth(PixelFormat format);
+		static bool isDepth(PixelFormat format);
 
 		/**	Checks is the provided format in native endian format. */
-        static bool isNativeEndian(PixelFormat format);
+		static bool isNativeEndian(PixelFormat format);
 		
 		/** 
 		 * Checks is the provided format valid for the texture type and usage. 
@@ -158,7 +158,7 @@ namespace bs
 		 * Returns the number of bits per each element in the provided pixel format. This will return all zero for 
 		 * compressed and depth/stencil formats.
 		 */
-        static void getBitDepths(PixelFormat format, int (&rgba)[4]);
+		static void getBitDepths(PixelFormat format, int(&rgba)[4]);
 
 		/**
 		 * Returns bit masks that determine in what bit range is each channel stored.
@@ -167,7 +167,7 @@ namespace bs
 		 * For example if your color is stored in an UINT32 and you want to extract the red channel you should AND the color
 		 * UINT32 with the bit-mask for the red channel and then right shift it by the red channel bit shift amount.
 		 */
-        static void getBitMasks(PixelFormat format, UINT32 (&rgba)[4]);
+		static void getBitMasks(PixelFormat format, UINT32(&rgba)[4]);
 
 		/**
 		 * Returns number of bits you need to shift a pixel element in order to move it to the start of the data type.
@@ -179,17 +179,17 @@ namespace bs
 		static void getBitShifts(PixelFormat format, UINT8 (&rgba)[4]);
 
 		/**	Returns the name of the pixel format. */
-        static String getFormatName(PixelFormat srcformat);
+		static String getFormatName(PixelFormat srcformat);
 
 		/**
 		 * Returns true if the pixel data in the format can be directly accessed and read. This is generally not true 
 		 * for compressed formats.
 		 */
-        static bool isAccessible(PixelFormat srcformat);
-        
+		static bool isAccessible(PixelFormat srcformat);
+
 		/**	Returns the type of an individual pixel element in the provided format. */
-        static PixelComponentType getElementType(PixelFormat format);
-        
+		static PixelComponentType getElementType(PixelFormat format);
+
 		/**	Returns the number of pixel elements in the provided format. */
 		static UINT32 getNumElements(PixelFormat format);
 
@@ -200,7 +200,7 @@ namespace bs
 		static UINT32 getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format);
 
 		/**	Writes the color to the provided memory location. */
-        static void packColor(const Color& color, PixelFormat format, void* dest);
+		static void packColor(const Color& color, PixelFormat format, void* dest);
 
 		/**
 		 * Writes the color to the provided memory location. If the destination	format is floating point, the byte values
@@ -227,19 +227,19 @@ namespace bs
 		 * Reads the color from the provided memory location and stores it into the provided color elements. If the format 
 		 * is not natively floating point a conversion is done in such a way that returned values range [0.0, 1.0].
 		 */
-        static void unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src); 
+		static void unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src);
 
 		/** Writes a depth value to the provided memory location. Depth should be in range [0, 1]. */
 		static void packDepth(float depth, const PixelFormat format, void* dest);
 
 		/** Reads the depth from the provided memory location. Value ranges in [0, 1]. */
 		static float unpackDepth(PixelFormat format, void* src);
-        
+
 		/**
 		 * Converts pixels from one format to another. Provided pixel data objects must have previously allocated buffers
 		 * of adequate size and their sizes must match.
 		 */
-        static void bulkPixelConversion(const PixelData& src, PixelData& dst);
+		static void bulkPixelConversion(const PixelData& src, PixelData& dst);
 
 		/** Flips the order of components in each individual pixel. For example RGBA -> ABGR. */
 		static void flipComponentOrder(PixelData& data);
@@ -282,8 +282,8 @@ namespace bs
 		 * @param[in]	size	Size of the buffer in bytes.
 		 * @param[in]	bpp		Number of bits per pixel of the pixels in the buffer.
 		 */
-        static void applyGamma(UINT8* buffer, float gamma, UINT32 size, UINT8 bpp);
-    };
+		static void applyGamma(UINT8* buffer, float gamma, UINT32 size, UINT8 bpp);
+	};
 
 	/** @} */
 }

+ 373 - 373
Source/BansheeCore/Source/BsPixelUtil.cpp

@@ -589,31 +589,31 @@ namespace bs
 		0, 0, 0, 0, 0, 0, 0, 0
 		},
 	//-----------------------------------------------------------------------
-        {"PF_FLOAT16_RGB",
-        /* Bytes per element */
-        6,
-        /* Flags */
-        PFF_FLOAT,
-        /* Component type and count */
-        PCT_FLOAT16, 3,
-        /* rbits, gbits, bbits, abits */
-        16, 16, 16, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
+		{ "PF_FLOAT16_RGB",
+		/* Bytes per element */
+		6,
+		/* Flags */
+		PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT16, 3,
+		/* rbits, gbits, bbits, abits */
+		16, 16, 16, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
 	//-----------------------------------------------------------------------
-        {"PF_FLOAT16_RGBA",
-        /* Bytes per element */
-        8,
-        /* Flags */
-        PFF_FLOAT | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_FLOAT16, 4,
-        /* rbits, gbits, bbits, abits */
-        16, 16, 16, 16,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
+		{ "PF_FLOAT16_RGBA",
+		/* Bytes per element */
+		8,
+		/* Flags */
+		PFF_FLOAT | PFF_HASALPHA,
+		/* Component type and count */
+		PCT_FLOAT16, 4,
+		/* rbits, gbits, bbits, abits */
+		16, 16, 16, 16,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
 	//-----------------------------------------------------------------------
 		{"PF_FLOAT32_R",
 		/* Bytes per element */
@@ -641,31 +641,31 @@ namespace bs
 		0, 0, 0, 0, 0, 0, 0, 0
 		},
 	//-----------------------------------------------------------------------
-        {"PF_FLOAT32_RGB",
-        /* Bytes per element */
-        12,
-        /* Flags */
-        PFF_FLOAT,
-        /* Component type and count */
-        PCT_FLOAT32, 3,
-        /* rbits, gbits, bbits, abits */
-        32, 32, 32, 0,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
+		{ "PF_FLOAT32_RGB",
+		/* Bytes per element */
+		12,
+		/* Flags */
+		PFF_FLOAT,
+		/* Component type and count */
+		PCT_FLOAT32, 3,
+		/* rbits, gbits, bbits, abits */
+		32, 32, 32, 0,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
 	//-----------------------------------------------------------------------
-        {"PF_FLOAT32_RGBA",
-        /* Bytes per element */
-        16,
-        /* Flags */
-        PFF_FLOAT | PFF_HASALPHA,
-        /* Component type and count */
-        PCT_FLOAT32, 4,
-        /* rbits, gbits, bbits, abits */
-        32, 32, 32, 32,
-        /* Masks and shifts */
-        0, 0, 0, 0, 0, 0, 0, 0
-        },
+		{ "PF_FLOAT32_RGBA",
+		/* Bytes per element */
+		16,
+		/* Flags */
+		PFF_FLOAT | PFF_HASALPHA,
+		/* Component type and count */
+		PCT_FLOAT32, 4,
+		/* rbits, gbits, bbits, abits */
+		32, 32, 32, 32,
+		/* Masks and shifts */
+		0, 0, 0, 0, 0, 0, 0, 0
+		},
 	//-----------------------------------------------------------------------
 		{"PF_D32_S8X24",
 		/* Bytes per element */
@@ -746,15 +746,15 @@ namespace bs
 		0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000,
 		0, 10, 20, 30
 		},
-    };
+	};
 
-    static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
-    {
-        const int ord = (int)fmt;
-        assert(ord>=0 && ord<PF_COUNT);
+	static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
+	{
+		const int ord = (int)fmt;
+		assert(ord >= 0 && ord < PF_COUNT);
 
-        return _pixelFormats[ord];
-    }
+		return _pixelFormats[ord];
+	}
 
 	/**	Handles compression output from NVTT library for a single image. */
 	struct NVTTCompressOutputHandler : public nvtt::OutputHandler
@@ -895,10 +895,10 @@ namespace bs
 		return nvtt::WrapMode_Mirror;
 	}
 
-    UINT32 PixelUtil::getNumElemBytes(PixelFormat format)
-    {
-        return getDescriptionFor(format).elemBytes;
-    }
+	UINT32 PixelUtil::getNumElemBytes(PixelFormat format)
+	{
+		return getDescriptionFor(format).elemBytes;
+	}
 
 	UINT32 PixelUtil::getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
 	{
@@ -974,40 +974,40 @@ namespace bs
 		}
 	}
 
-    UINT32 PixelUtil::getNumElemBits(PixelFormat format)
-    {
-        return getDescriptionFor(format).elemBytes * 8;
-    }
-
-    UINT32 PixelUtil::getFlags(PixelFormat format)
-    {
-        return getDescriptionFor(format).flags;
-    }
-
-    bool PixelUtil::hasAlpha(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
-    }
-
-    bool PixelUtil::isFloatingPoint(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
-    }
-
-    bool PixelUtil::isCompressed(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
-    }
-
-    bool PixelUtil::isDepth(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
-    }
-
-    bool PixelUtil::isNativeEndian(PixelFormat format)
-    {
-        return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
-    }
+	UINT32 PixelUtil::getNumElemBits(PixelFormat format)
+	{
+		return getDescriptionFor(format).elemBytes * 8;
+	}
+
+	UINT32 PixelUtil::getFlags(PixelFormat format)
+	{
+		return getDescriptionFor(format).flags;
+	}
+
+	bool PixelUtil::hasAlpha(PixelFormat format)
+	{
+		return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
+	}
+
+	bool PixelUtil::isFloatingPoint(PixelFormat format)
+	{
+		return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
+	}
+
+	bool PixelUtil::isCompressed(PixelFormat format)
+	{
+		return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
+	}
+
+	bool PixelUtil::isDepth(PixelFormat format)
+	{
+		return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
+	}
+
+	bool PixelUtil::isNativeEndian(PixelFormat format)
+	{
+		return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
+	}
 
 	bool PixelUtil::checkFormat(PixelFormat& format, TextureType texType, int usage)
 	{
@@ -1101,25 +1101,25 @@ namespace bs
 		}
 	}
 
-    void PixelUtil::getBitDepths(PixelFormat format, int (&rgba)[4])
-    {
-        const PixelFormatDescription& des = getDescriptionFor(format);
-        rgba[0] = des.rbits;
-        rgba[1] = des.gbits;
-        rgba[2] = des.bbits;
-        rgba[3] = des.abits;
-    }
-
-	void PixelUtil::getBitMasks(PixelFormat format, UINT32 (&rgba)[4])
-    {
-        const PixelFormatDescription& des = getDescriptionFor(format);
-        rgba[0] = des.rmask;
-        rgba[1] = des.gmask;
-        rgba[2] = des.bmask;
-        rgba[3] = des.amask;
-    }
-
-	void PixelUtil::getBitShifts(PixelFormat format, UINT8 (&rgba)[4])
+	void PixelUtil::getBitDepths(PixelFormat format, int(&rgba)[4])
+	{
+		const PixelFormatDescription& des = getDescriptionFor(format);
+		rgba[0] = des.rbits;
+		rgba[1] = des.gbits;
+		rgba[2] = des.bbits;
+		rgba[3] = des.abits;
+	}
+
+	void PixelUtil::getBitMasks(PixelFormat format, UINT32(&rgba)[4])
+	{
+		const PixelFormatDescription& des = getDescriptionFor(format);
+		rgba[0] = des.rmask;
+		rgba[1] = des.gmask;
+		rgba[2] = des.bmask;
+		rgba[3] = des.amask;
+	}
+
+	void PixelUtil::getBitShifts(PixelFormat format, UINT8(&rgba)[4])
 	{
 		const PixelFormatDescription& des = getDescriptionFor(format);
 		rgba[0] = des.rshift;
@@ -1128,262 +1128,262 @@ namespace bs
 		rgba[3] = des.ashift;
 	}
 
-    String PixelUtil::getFormatName(PixelFormat srcformat)
-    {
-        return getDescriptionFor(srcformat).name;
-    }
+	String PixelUtil::getFormatName(PixelFormat srcformat)
+	{
+		return getDescriptionFor(srcformat).name;
+	}
 
-    bool PixelUtil::isAccessible(PixelFormat srcformat)
-    {
-        if (srcformat == PF_UNKNOWN)
-            return false;
+	bool PixelUtil::isAccessible(PixelFormat srcformat)
+	{
+		if (srcformat == PF_UNKNOWN)
+			return false;
 
-        UINT32 flags = getFlags(srcformat);
-        return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
-    }
+		UINT32 flags = getFlags(srcformat);
+		return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
+	}
 
-    PixelComponentType PixelUtil::getElementType(PixelFormat format)
-    {
+	PixelComponentType PixelUtil::getElementType(PixelFormat format)
+	{
 		const PixelFormatDescription& des = getDescriptionFor(format);
-        return des.componentType;
-    }
+		return des.componentType;
+	}
 
 	UINT32 PixelUtil::getNumElements(PixelFormat format)
-    {
+	{
 		const PixelFormatDescription& des = getDescriptionFor(format);
-        return des.componentCount;
-    }
+		return des.componentCount;
+	}
 
 	UINT32 PixelUtil::getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
 	{
 		UINT32 count = 0;
-        if((width > 0) && (height > 0))
-        {
+		if ((width > 0) && (height > 0))
+		{
 			while (!(width == 1 && height == 1 && depth == 1))
-            { 
-                if(width>1)		width = width/2;
-                if(height>1)	height = height/2;
-                if(depth>1)		depth = depth/2;
-                    
-                count ++;
-            } 
-        }
+			{
+				if (width > 1)		width = width / 2;
+				if (height > 1)	height = height / 2;
+				if (depth > 1)		depth = depth / 2;
+
+				count++;
+			}
+		}
 
 		return count;
 	}
 
-    void PixelUtil::packColor(const Color& color, PixelFormat format, void* dest)
-    {
-        packColor(color.r, color.g, color.b, color.a, format, dest);
-    }
+	void PixelUtil::packColor(const Color& color, PixelFormat format, void* dest)
+	{
+		packColor(color.r, color.g, color.b, color.a, format, dest);
+	}
 
-    void PixelUtil::packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format,  void* dest)
-    {
-        const PixelFormatDescription &des = getDescriptionFor(format);
+	void PixelUtil::packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format, void* dest)
+	{
+		const PixelFormatDescription &des = getDescriptionFor(format);
 
-        if(des.flags & PFF_NATIVEENDIAN) 
+		if (des.flags & PFF_NATIVEENDIAN)
 		{
-            // Shortcut for integer formats packing
-            UINT32 value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
-                ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
-                ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
-                ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
-
-            // And write to memory
-            Bitwise::intWrite(dest, des.elemBytes, value);
-        } 
-		else 
+			// Shortcut for integer formats packing
+			UINT32 value = ((Bitwise::fixedToFixed(r, 8, des.rbits) << des.rshift) & des.rmask) |
+				((Bitwise::fixedToFixed(g, 8, des.gbits) << des.gshift) & des.gmask) |
+				((Bitwise::fixedToFixed(b, 8, des.bbits) << des.bshift) & des.bmask) |
+				((Bitwise::fixedToFixed(a, 8, des.abits) << des.ashift) & des.amask);
+
+			// And write to memory
+			Bitwise::intWrite(dest, des.elemBytes, value);
+		}
+		else
 		{
-            // Convert to float
-            packColor((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, format, dest);
-        }
-    }
+			// Convert to float
+			packColor((float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f, format, dest);
+		}
+	}
 
-    void PixelUtil::packColor(float r, float g, float b, float a, const PixelFormat format, void* dest)
-    {
-        const PixelFormatDescription& des = getDescriptionFor(format);
+	void PixelUtil::packColor(float r, float g, float b, float a, const PixelFormat format, void* dest)
+	{
+		const PixelFormatDescription& des = getDescriptionFor(format);
 
-        if(des.flags & PFF_NATIVEENDIAN) 
+		if (des.flags & PFF_NATIVEENDIAN)
 		{
-            // Do the packing
-            const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
-                ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
-                ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
-                ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
-
-            // And write to memory
-            Bitwise::intWrite(dest, des.elemBytes, value);
-        }
-		else 
+			// Do the packing
+			const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits) << des.rshift) & des.rmask) |
+				((Bitwise::floatToFixed(g, des.gbits) << des.gshift) & des.gmask) |
+				((Bitwise::floatToFixed(b, des.bbits) << des.bshift) & des.bmask) |
+				((Bitwise::floatToFixed(a, des.abits) << des.ashift) & des.amask);
+
+			// And write to memory
+			Bitwise::intWrite(dest, des.elemBytes, value);
+		}
+		else
 		{
-            switch(format)
-            {
-            case PF_FLOAT32_R:
-                ((float*)dest)[0] = r;
-                break;
+			switch (format)
+			{
+			case PF_FLOAT32_R:
+				((float*)dest)[0] = r;
+				break;
 			case PF_FLOAT32_RG:
 				((float*)dest)[0] = r;
 				((float*)dest)[1] = g;
 				break;
-            case PF_FLOAT32_RGB:
-                ((float*)dest)[0] = r;
-                ((float*)dest)[1] = g;
-                ((float*)dest)[2] = b;
-                break;
-            case PF_FLOAT32_RGBA:
-                ((float*)dest)[0] = r;
-                ((float*)dest)[1] = g;
-                ((float*)dest)[2] = b;
-                ((float*)dest)[3] = a;
-                break;
-            case PF_FLOAT16_R:
-                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
-                break;
+			case PF_FLOAT32_RGB:
+				((float*)dest)[0] = r;
+				((float*)dest)[1] = g;
+				((float*)dest)[2] = b;
+				break;
+			case PF_FLOAT32_RGBA:
+				((float*)dest)[0] = r;
+				((float*)dest)[1] = g;
+				((float*)dest)[2] = b;
+				((float*)dest)[3] = a;
+				break;
+			case PF_FLOAT16_R:
+				((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
+				break;
 			case PF_FLOAT16_RG:
 				((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
 				((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
 				break;
-            case PF_FLOAT16_RGB:
-                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
-                ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
-                ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
-                break;
-            case PF_FLOAT16_RGBA:
-                ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
-                ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
-                ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
-                ((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
-                break;
+			case PF_FLOAT16_RGB:
+				((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
+				((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
+				((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
+				break;
+			case PF_FLOAT16_RGBA:
+				((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
+				((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
+				((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
+				((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
+				break;
 			case PF_R8G8:
 				((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
-                ((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
+				((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
 				break;
 			case PF_R8:
 				((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
 				break;
 			case PF_FLOAT_R11G11B10:
-				{
-					UINT32 value;
-					value = Bitwise::floatToFloat11(r);
-					value |= Bitwise::floatToFloat11(g) << 11;
-					value |= Bitwise::floatToFloat10(b) << 22;
+			{
+				UINT32 value;
+				value = Bitwise::floatToFloat11(r);
+				value |= Bitwise::floatToFloat11(g) << 11;
+				value |= Bitwise::floatToFloat10(b) << 22;
 
-					((UINT32*)dest)[0] = value;
-				}
+				((UINT32*)dest)[0] = value;
+			}
+			break;
+			default:
+				LOGERR("Pack to " + getFormatName(format) + " not implemented");
 				break;
-            default:
-                LOGERR("Pack to " + getFormatName(format) + " not implemented");
-                break;
-            }
-        }
-    }
-    void PixelUtil::unpackColor(Color* color, PixelFormat format, const void* src)
-    {
+			}
+		}
+	}
+	void PixelUtil::unpackColor(Color* color, PixelFormat format, const void* src)
+	{
 		unpackColor(&color->r, &color->g, &color->b, &color->a, format, src);
-    }
+	}
 
-    void PixelUtil::unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src)
-    {
-        const PixelFormatDescription &des = getDescriptionFor(format);
+	void PixelUtil::unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src)
+	{
+		const PixelFormatDescription &des = getDescriptionFor(format);
 
-        if(des.flags & PFF_NATIVEENDIAN) 
+		if (des.flags & PFF_NATIVEENDIAN)
 		{
-            // Shortcut for integer formats unpacking
-            const UINT32 value = Bitwise::intRead(src, des.elemBytes);
-
-            *r = (UINT8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
-            *g = (UINT8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
-            *b = (UINT8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
-
-            if(des.flags & PFF_HASALPHA)
-            {
-                *a = (UINT8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
-            }
-            else
-            {
-                *a = 255; // No alpha, default a component to full
-            }
-        } 
-		else 
+			// Shortcut for integer formats unpacking
+			const UINT32 value = Bitwise::intRead(src, des.elemBytes);
+
+			*r = (UINT8)Bitwise::fixedToFixed((value & des.rmask) >> des.rshift, des.rbits, 8);
+			*g = (UINT8)Bitwise::fixedToFixed((value & des.gmask) >> des.gshift, des.gbits, 8);
+			*b = (UINT8)Bitwise::fixedToFixed((value & des.bmask) >> des.bshift, des.bbits, 8);
+
+			if (des.flags & PFF_HASALPHA)
+			{
+				*a = (UINT8)Bitwise::fixedToFixed((value & des.amask) >> des.ashift, des.abits, 8);
+			}
+			else
+			{
+				*a = 255; // No alpha, default a component to full
+			}
+		}
+		else
 		{
-            // Do the operation with the more generic floating point
-            float rr, gg, bb, aa;
-            unpackColor(&rr,&gg,&bb,&aa, format, src);
-
-            *r = (UINT8)Bitwise::floatToFixed(rr, 8);
-            *g = (UINT8)Bitwise::floatToFixed(gg, 8);
-            *b = (UINT8)Bitwise::floatToFixed(bb, 8);
-            *a = (UINT8)Bitwise::floatToFixed(aa, 8);
-        }
-    }
-
-    void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
-    {
-        const PixelFormatDescription &des = getDescriptionFor(format);
-        if(des.flags & PFF_NATIVEENDIAN) 
+			// Do the operation with the more generic floating point
+			float rr, gg, bb, aa;
+			unpackColor(&rr, &gg, &bb, &aa, format, src);
+
+			*r = (UINT8)Bitwise::floatToFixed(rr, 8);
+			*g = (UINT8)Bitwise::floatToFixed(gg, 8);
+			*b = (UINT8)Bitwise::floatToFixed(bb, 8);
+			*a = (UINT8)Bitwise::floatToFixed(aa, 8);
+		}
+	}
+
+	void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
+	{
+		const PixelFormatDescription &des = getDescriptionFor(format);
+		if (des.flags & PFF_NATIVEENDIAN)
 		{
-            // Shortcut for integer formats unpacking
-            const unsigned int value = Bitwise::intRead(src, des.elemBytes);
-
-			*r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
-			*g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
-			*b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
-
-            if(des.flags & PFF_HASALPHA)
-            {
-                *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
-            }
-            else
-            {
-                *a = 1.0f; // No alpha, default a component to full
-            }
-        } 
-		else 
+			// Shortcut for integer formats unpacking
+			const unsigned int value = Bitwise::intRead(src, des.elemBytes);
+
+			*r = Bitwise::fixedToFloat((value & des.rmask) >> des.rshift, des.rbits);
+			*g = Bitwise::fixedToFloat((value & des.gmask) >> des.gshift, des.gbits);
+			*b = Bitwise::fixedToFloat((value & des.bmask) >> des.bshift, des.bbits);
+
+			if (des.flags & PFF_HASALPHA)
+			{
+				*a = Bitwise::fixedToFloat((value & des.amask) >> des.ashift, des.abits);
+			}
+			else
+			{
+				*a = 1.0f; // No alpha, default a component to full
+			}
+		}
+		else
 		{
-            switch(format)
-            {
-            case PF_FLOAT32_R:
-                *r = *g = *b = ((float*)src)[0];
-                *a = 1.0f;
-                break;
+			switch (format)
+			{
+			case PF_FLOAT32_R:
+				*r = *g = *b = ((float*)src)[0];
+				*a = 1.0f;
+				break;
 			case PF_FLOAT32_RG:
 				*r = ((float*)src)[0];
 				*g = *b = ((float*)src)[1];
 				*a = 1.0f;
 				break;
-            case PF_FLOAT32_RGB:
-                *r = ((float*)src)[0];
-                *g = ((float*)src)[1];
-                *b = ((float*)src)[2];
-                *a = 1.0f;
-                break;
-            case PF_FLOAT32_RGBA:
-                *r = ((float*)src)[0];
-                *g = ((float*)src)[1];
-                *b = ((float*)src)[2];
-                *a = ((float*)src)[3];
-                break;
-            case PF_FLOAT16_R:
-                *r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
-                *a = 1.0f;
-                break;
+			case PF_FLOAT32_RGB:
+				*r = ((float*)src)[0];
+				*g = ((float*)src)[1];
+				*b = ((float*)src)[2];
+				*a = 1.0f;
+				break;
+			case PF_FLOAT32_RGBA:
+				*r = ((float*)src)[0];
+				*g = ((float*)src)[1];
+				*b = ((float*)src)[2];
+				*a = ((float*)src)[3];
+				break;
+			case PF_FLOAT16_R:
+				*r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
+				*a = 1.0f;
+				break;
 			case PF_FLOAT16_RG:
 				*r = Bitwise::halfToFloat(((UINT16*)src)[0]);
 				*g = *b = Bitwise::halfToFloat(((UINT16*)src)[1]);
 				*a = 1.0f;
 				break;
-            case PF_FLOAT16_RGB:
-                *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
-                *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
-                *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
-                *a = 1.0f;
-                break;
-            case PF_FLOAT16_RGBA:
-                *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
-                *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
-                *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
-                *a = Bitwise::halfToFloat(((UINT16*)src)[3]);
-                break;
+			case PF_FLOAT16_RGB:
+				*r = Bitwise::halfToFloat(((UINT16*)src)[0]);
+				*g = Bitwise::halfToFloat(((UINT16*)src)[1]);
+				*b = Bitwise::halfToFloat(((UINT16*)src)[2]);
+				*a = 1.0f;
+				break;
+			case PF_FLOAT16_RGBA:
+				*r = Bitwise::halfToFloat(((UINT16*)src)[0]);
+				*g = Bitwise::halfToFloat(((UINT16*)src)[1]);
+				*b = Bitwise::halfToFloat(((UINT16*)src)[2]);
+				*a = Bitwise::halfToFloat(((UINT16*)src)[3]);
+				break;
 			case PF_R8G8:
 				*r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
 				*g = Bitwise::fixedToFloat(((UINT8*)src)[1], 8);
@@ -1404,12 +1404,12 @@ namespace bs
 				*b = Bitwise::float10ToFloat(value >> 22);
 			}
 			break;
-            default:
-                LOGERR("Unpack from " + getFormatName(format) + " not implemented");
-                break;
-            }
-        }
-    }
+			default:
+				LOGERR("Unpack from " + getFormatName(format) + " not implemented");
+				break;
+			}
+		}
+	}
 
 	void PixelUtil::packDepth(float depth, const PixelFormat format, void* dest)
 	{
@@ -1455,16 +1455,16 @@ namespace bs
 		}
 	}
 
-    void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
-    {
-        assert(src.getWidth() == dst.getWidth() &&
-			   src.getHeight() == dst.getHeight() &&
-			   src.getDepth() == dst.getDepth());
+	void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
+	{
+		assert(src.getWidth() == dst.getWidth() &&
+			src.getHeight() == dst.getHeight() &&
+			src.getDepth() == dst.getDepth());
 
 		// Check for compressed formats, we don't support decompression
-		if(PixelUtil::isCompressed(src.getFormat()))
+		if (PixelUtil::isCompressed(src.getFormat()))
 		{
-			if(src.getFormat() == dst.getFormat())
+			if (src.getFormat() == dst.getFormat())
 			{
 				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
 				return;
@@ -1494,85 +1494,85 @@ namespace bs
 			}
 		}
 
-        // The easy case
-        if(src.getFormat() == dst.getFormat()) 
+		// The easy case
+		if (src.getFormat() == dst.getFormat())
 		{
-            // Everything consecutive?
-            if(src.isConsecutive() && dst.isConsecutive())
-            {
+			// Everything consecutive?
+			if (src.isConsecutive() && dst.isConsecutive())
+			{
 				memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
-                return;
-            }
+				return;
+			}
 
 			const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
 			const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
-            UINT8 *srcptr = static_cast<UINT8*>(src.getData())
-                + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
-            UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
+			UINT8 *srcptr = static_cast<UINT8*>(src.getData())
+				+ (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
+			UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
 				+ (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
 
-            // Calculate pitches+skips in bytes
+			// Calculate pitches+skips in bytes
 			const UINT32 srcRowPitchBytes = src.getRowPitch()*srcPixelSize;
 			const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
 
 			const UINT32 dstRowPitchBytes = dst.getRowPitch()*dstPixelSize;
 			const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
 
-            // Otherwise, copy per row
+			// Otherwise, copy per row
 			const UINT32 rowSize = src.getWidth()*srcPixelSize;
 			for (UINT32 z = src.getFront(); z < src.getBack(); z++)
-            {
-                for(UINT32 y = src.getTop(); y < src.getBottom(); y++)
-                {
+			{
+				for (UINT32 y = src.getTop(); y < src.getBottom(); y++)
+				{
 					memcpy(dstptr, srcptr, rowSize);
 
-                    srcptr += srcRowPitchBytes;
-                    dstptr += dstRowPitchBytes;
-                }
+					srcptr += srcRowPitchBytes;
+					dstptr += dstRowPitchBytes;
+				}
 
-                srcptr += srcSliceSkipBytes;
-                dstptr += dstSliceSkipBytes;
-            }
+				srcptr += srcSliceSkipBytes;
+				dstptr += dstSliceSkipBytes;
+			}
 
-            return;
-        }
+			return;
+		}
 
 		UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
 		UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
-        UINT8 *srcptr = static_cast<UINT8*>(src.getData())
-            + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
-        UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
-            + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
-		
-        // Calculate pitches+skips in bytes
+		UINT8 *srcptr = static_cast<UINT8*>(src.getData())
+			+ (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
+		UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
+			+ (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
+
+		// Calculate pitches+skips in bytes
 		UINT32 srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
 		UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
 		UINT32 dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
 		UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
 
-        // The brute force fallback
-        float r,g,b,a;
-		for (UINT32 z = src.getFront(); z<src.getBack(); z++)
+		// The brute force fallback
+		float r, g, b, a;
+		for (UINT32 z = src.getFront(); z < src.getBack(); z++)
 		{
 			for (UINT32 y = src.getTop(); y < src.getBottom(); y++)
-            {
-				for (UINT32 x = src.getLeft(); x<src.getRight(); x++)
-                {
-                    unpackColor(&r, &g, &b, &a, src.getFormat(), srcptr);
-                    packColor(r, g, b, a, dst.getFormat(), dstptr);
-
-                    srcptr += srcPixelSize;
-                    dstptr += dstPixelSize;
-                }
-
-                srcptr += srcRowSkipBytes;
-                dstptr += dstRowSkipBytes;
-            }
-
-            srcptr += srcSliceSkipBytes;
-            dstptr += dstSliceSkipBytes;
-        }
-    }
+			{
+				for (UINT32 x = src.getLeft(); x < src.getRight(); x++)
+				{
+					unpackColor(&r, &g, &b, &a, src.getFormat(), srcptr);
+					packColor(r, g, b, a, dst.getFormat(), dstptr);
+
+					srcptr += srcPixelSize;
+					dstptr += dstPixelSize;
+				}
+
+				srcptr += srcRowSkipBytes;
+				dstptr += dstRowSkipBytes;
+			}
+
+			srcptr += srcSliceSkipBytes;
+			dstptr += dstSliceSkipBytes;
+		}
+	}
 
 	void PixelUtil::flipComponentOrder(PixelData& data)
 	{

+ 3 - 1
Source/RenderBeast/Include/BsGpuResourcePool.h

@@ -145,10 +145,11 @@ namespace bs { namespace ct
 		 * @param[in]	samples		If higher than 1, texture containing multiple samples per pixel is created.
 		 * @param[in]	hwGamma		Should the written pixels be gamma corrected.
 		 * @param[in]	arraySize	Number of textures in a texture array. Specify 1 for no array.
+		 * @param[in]	mipCount	Number of mip levels, excluding the root mip level.
 		 * @return					Descriptor that is accepted by RenderTexturePool.
 		 */
 		static POOLED_RENDER_TEXTURE_DESC create2D(PixelFormat format, UINT32 width, UINT32 height, 
-			INT32 usage = TU_STATIC, UINT32 samples = 0, bool hwGamma = false, UINT32 arraySize = 1);
+			INT32 usage = TU_STATIC, UINT32 samples = 0, bool hwGamma = false, UINT32 arraySize = 1, UINT32 mipCount = 0);
 
 		/**
 		 * Creates a descriptor for a three dimensional render texture.
@@ -188,6 +189,7 @@ namespace bs { namespace ct
 		TextureType type;
 		bool hwGamma;
 		UINT32 arraySize;
+		UINT32 numMipLevels;
 	};
 
 	/** Structure used for describing a pooled storage buffer. */

+ 49 - 0
Source/RenderBeast/Include/BsPostProcessing.h

@@ -10,6 +10,8 @@
 
 namespace bs { namespace ct
 {
+	struct RendererViewTargetData;
+
 	/** @addtogroup RenderBeast
 	 *  @{
 	 */
@@ -507,6 +509,53 @@ namespace bs { namespace ct
 		GaussianBlurMat mBlur;
 	};
 
+	/** Shader that calculates a single level of the hierarchical Z mipmap chain. */
+	template<int MSAA_COUNT>
+	class BuildHiZMat : public RendererMaterial<BuildHiZMat<MSAA_COUNT>>
+	{
+		RMAT_DEF("PPBuildHiZ.bsl");
+
+	public:
+		BuildHiZMat();
+
+		/** 
+		 * Renders the post-process effect with the provided parameters. 
+		 * 
+		 * @param[in]	source		Input depth texture to use as the source.
+		 * @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]	output		Output target to which to write to results.
+		 */
+		void execute(const SPtr<Texture>& source, UINT32 srcMip, const Rect2& srcRect, const SPtr<RenderTexture>& output);
+	private:
+		GpuParamTexture mInputTexture;
+	};
+
+	/** Builds a hierarchical Z mipmap chain from the source depth texture. */
+	class BuildHiZ
+	{
+	public:
+		/** 
+		 * Renders the post-process effect with the provided parameters. 
+		 * 
+		 * @param[in]	viewInfo	Information about the view we're rendering from.
+		 * @param[in]	source		Input depth texture to use as the source.
+		 * @param[in]	output		Output target to which to write to results. This texture should be created using the
+		 *							descriptor returned by getHiZTextureDesc().
+		 */
+		void execute(const RendererViewTargetData& viewInfo, const SPtr<Texture>& source, const SPtr<Texture>& output);
+
+		/** Generates a descriptor that can be used for creating a texture to contain the HiZ mipmap chain. */
+		static POOLED_RENDER_TEXTURE_DESC getHiZTextureDesc(UINT32 viewWidth, UINT32 viewHeight);
+
+	private:
+		BuildHiZMat<1> mHiZMatNoMSAA;
+		BuildHiZMat<2> mHiZMatMSAA2;
+		BuildHiZMat<4> mHiZMatMSAA4;
+		BuildHiZMat<8> mHiZMatMSAA8;
+	};
+
 	/**
 	 * Renders post-processing effects for the provided render target.
 	 *

+ 17 - 11
Source/RenderBeast/Include/BsRenderTargets.h

@@ -93,15 +93,6 @@ namespace bs { namespace ct
 		 */
 		void bindSceneColor(bool readOnlyDepthStencil);
 
-		/**
-		 * Binds the non-MSAA version of the scene color texture for rendering. If not using MSAA this is equivalent to
-		 * calling bindSceneColor() (as long as @p secondary is false).
-		 * 
-		 * @param[in]	secondary	If true, a seconday scene color texture will be bound. This texture can be used
-		 *							for ping-pong operations between it and the primary scene color.
-		 */
-		void bindResolvedSceneColor(bool secondary = false);
-
 		/** Binds the light accumulation render target for rendering. */
 		void bindLightAccumulation();
 
@@ -111,6 +102,18 @@ 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();
+
+		/** Releases the memory used by the hierarchical z-buffer texture generated by generateHiZ(). */
+		void releaseHiZ();
+
+		/** Returns the hierarchical Z buffer texture generated by calling generateHiZ(). */
+		SPtr<Texture> getHiZ() const;
+
 		/** Returns the texture containing (potentially multisampled) scene color. */
 		SPtr<Texture> getSceneColor() const;
 
@@ -191,10 +194,10 @@ namespace bs { namespace ct
 		SPtr<PooledRenderTexture> mResolvedSceneColorTex1;
 		SPtr<PooledRenderTexture> mResolvedSceneColorTex2;
 
+		SPtr<PooledRenderTexture> mHiZ;
+
 		SPtr<RenderTexture> mGBufferRT;
 		SPtr<RenderTexture> mSceneColorRT;
-		SPtr<RenderTexture> mResolvedSceneColorRT1;
-		SPtr<RenderTexture> mResolvedSceneColorRT2;
 		SPtr<RenderTexture> mLightAccumulationRT;
 		SPtr<RenderTexture> mLightOcclusionRT;
 
@@ -205,6 +208,9 @@ namespace bs { namespace ct
 
 		UINT32 mWidth;
 		UINT32 mHeight;
+
+		// Note: Only a single instance of this is needed, move it to a Module eventually
+		BuildHiZ mBuildHiZ;
 	};
 
 	/** @} */

+ 6 - 1
Source/RenderBeast/Source/BsGpuResourcePool.cpp

@@ -68,6 +68,7 @@ namespace bs { namespace ct
 		texDesc.usage = desc.flag;
 		texDesc.hwGamma = desc.hwGamma;
 		texDesc.numSamples = desc.numSamples;
+		texDesc.numMips = desc.numMipLevels;
 
 		if (desc.type != TEX_TYPE_3D)
 			texDesc.numArraySlices = desc.arraySize;
@@ -164,6 +165,7 @@ namespace bs { namespace ct
 				|| (desc.type == TEX_TYPE_CUBE_MAP)
 				)
 			&& texProps.getNumArraySlices() == desc.arraySize
+			&& texProps.getNumMipmaps() == desc.numMipLevels
 			;
 
 		return match;
@@ -206,7 +208,7 @@ namespace bs { namespace ct
 	}
 
 	POOLED_RENDER_TEXTURE_DESC POOLED_RENDER_TEXTURE_DESC::create2D(PixelFormat format, UINT32 width, UINT32 height,
-		INT32 usage, UINT32 samples, bool hwGamma, UINT32 arraySize)
+		INT32 usage, UINT32 samples, bool hwGamma, UINT32 arraySize, UINT32 mipCount)
 	{
 		POOLED_RENDER_TEXTURE_DESC desc;
 		desc.width = width;
@@ -218,6 +220,7 @@ namespace bs { namespace ct
 		desc.hwGamma = hwGamma;
 		desc.type = TEX_TYPE_2D;
 		desc.arraySize = arraySize;
+		desc.numMipLevels = mipCount;
 
 		return desc;
 	}
@@ -235,6 +238,7 @@ namespace bs { namespace ct
 		desc.hwGamma = false;
 		desc.type = TEX_TYPE_3D;
 		desc.arraySize = 1;
+		desc.numMipLevels = 0;
 
 		return desc;
 	}
@@ -252,6 +256,7 @@ namespace bs { namespace ct
 		desc.hwGamma = false;
 		desc.type = TEX_TYPE_CUBE_MAP;
 		desc.arraySize = arraySize;
+		desc.numMipLevels = 0;
 
 		return desc;
 	}

+ 126 - 6
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -9,6 +9,8 @@
 #include "BsGpuParamsSet.h"
 #include "BsRendererView.h"
 #include "BsRenderTargets.h"
+#include "BsPixelUtil.h"
+#include "BsBitwise.h"
 
 namespace bs { namespace ct
 {
@@ -549,7 +551,7 @@ namespace bs { namespace ct
 
 	GaussianBlurMat::GaussianBlurMat()
 	{
-		mParamBuffer = gDownsampleParamDef.createBuffer();
+		mParamBuffer = gGaussianBlurParamDef.createBuffer();
 
 		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gInputTex", mInputTexture);
@@ -717,7 +719,7 @@ namespace bs { namespace ct
 	template<bool Near, bool Far>
 	GaussianDOFSeparateMat<Near, Far>::GaussianDOFSeparateMat()
 	{
-		mParamBuffer = gDownsampleParamDef.createBuffer();
+		mParamBuffer = gGaussianDOFParamDef.createBuffer();
 
 		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
 		mParamsSet->getGpuParams()->getTextureParam(GPT_FRAGMENT_PROGRAM, "gColorTex", mColorTexture);
@@ -752,8 +754,11 @@ namespace bs { namespace ct
 	{
 		const TextureProperties& srcProps = color->getProperties();
 
+		UINT32 outputWidth = std::max(1U, srcProps.getWidth() / 2);
+		UINT32 outputHeight = std::max(1U, srcProps.getHeight() / 2);
+
 		POOLED_RENDER_TEXTURE_DESC outputTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(srcProps.getFormat(), 
-			srcProps.getWidth(), srcProps.getHeight(), TU_RENDERTARGET);
+			outputWidth, outputHeight, TU_RENDERTARGET);
 		mOutput0 = GpuResourcePool::instance().get(outputTexDesc);
 
 		SPtr<RenderTexture> rt;
@@ -820,7 +825,7 @@ namespace bs { namespace ct
 	template<bool Near, bool Far>
 	GaussianDOFCombineMat<Near, Far>::GaussianDOFCombineMat()
 	{
-		mParamBuffer = gDownsampleParamDef.createBuffer();
+		mParamBuffer = gGaussianDOFParamDef.createBuffer();
 
 		mParamsSet->setParamBlockBuffer("Input", mParamBuffer);
 
@@ -910,6 +915,10 @@ namespace bs { namespace ct
 		}
 
 		separateMat->execute(sceneColor, sceneDepth, view, settings);
+		separateMat->release();
+
+		// DEBUG ONLY
+		return;
 
 		SPtr<PooledRenderTexture> nearTex, farTex;
 		if(near && far)
@@ -927,7 +936,7 @@ namespace bs { namespace ct
 
 		// Blur the out of focus pixels
 		// Note: Perhaps set up stencil so I can avoid performing blur on unused parts of the textures?
-		const TextureProperties& texProps = sceneColor->getProperties();
+		const TextureProperties& texProps = nearTex ? nearTex->texture->getProperties() : farTex->texture->getProperties();
 		POOLED_RENDER_TEXTURE_DESC tempTexDesc = POOLED_RENDER_TEXTURE_DESC::create2D(texProps.getFormat(), 
 			texProps.getWidth(), texProps.getHeight(), TU_RENDERTARGET);
 		SPtr<PooledRenderTexture> tempTexture = GpuResourcePool::instance().get(tempTexDesc);
@@ -969,6 +978,117 @@ namespace bs { namespace ct
 		return settings.enabled && (near || far);
 	}
 	
+	template<int MSAA_COUNT>
+	BuildHiZMat<MSAA_COUNT>::BuildHiZMat()
+	{
+		SPtr<GpuParams> gpuParams = mParamsSet->getGpuParams();
+		gpuParams->getTextureParam(GPT_FRAGMENT_PROGRAM, "gDepthTex", mInputTexture);
+	}
+
+	template<int MSAA_COUNT>
+	void BuildHiZMat<MSAA_COUNT>::_initDefines(ShaderDefines& defines)
+	{
+		defines.set("MSAA_COUNT", MSAA_COUNT);
+	}
+
+	template<int MSAA_COUNT>
+	void BuildHiZMat<MSAA_COUNT>::execute(const SPtr<Texture>& source, UINT32 srcMip, const Rect2& srcRect, 
+		const SPtr<RenderTexture>& output)
+	{
+		RenderAPI& rapi = RenderAPI::instance();
+		const TextureProperties& srcProps = source->getProperties();
+
+		mInputTexture.set(source, TextureSurface(srcMip));
+		rapi.setRenderTarget(output);
+
+		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>;
+
+	void BuildHiZ::execute(const RendererViewTargetData& viewInfo, const SPtr<Texture>& source, const SPtr<Texture>& output)
+	{
+		GpuResourcePool& pool = GpuResourcePool::instance();
+
+		// 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;
+		}
+
+		// Generate first mip
+		RENDER_TEXTURE_DESC rtDesc;
+		rtDesc.colorSurfaces[0].texture = output;
+		rtDesc.colorSurfaces[0].mipLevel = 0;
+
+		SPtr<RenderTexture> rt = RenderTexture::create(rtDesc);
+		mHiZMatNoMSAA.execute(depthInput, 0, srcRect, 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);
+		}
+
+		if (resolvedDepth)
+			pool.release(resolvedDepth);
+	}
+
+	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);
+
+		return POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_R, size, size, TU_RENDERTARGET, 1, false, 1, numMips);
+	}
+
 	void PostProcessing::postProcess(RendererView* viewInfo, const SPtr<RenderTargets>& renderTargets, float frameDelta)
 	{
 		auto& viewProps = viewInfo->getProperties();
@@ -1044,4 +1164,4 @@ namespace bs { namespace ct
 		if (ppInfo.settingDirty)
 			ppInfo.settingDirty = false;
 	}
-}}
+}}

+ 24 - 69
Source/RenderBeast/Source/BsRenderTargets.cpp

@@ -218,66 +218,12 @@ namespace bs { namespace ct
 			{
 				mResolvedSceneColorTex1 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, width, height,
 					TU_RENDERTARGET, 1, false));
-
-				bool rebuildRT = false;
-				if (mResolvedSceneColorRT1 != nullptr)
-				{
-					rebuildRT |= mResolvedSceneColorRT1->getColorTexture(0) != mResolvedSceneColorTex1->texture;
-					rebuildRT |= mResolvedSceneColorRT1->getDepthStencilTexture() != mDepthTex->texture;
-				}
-				else
-					rebuildRT = true;
-
-				if (rebuildRT)
-				{
-					RENDER_TEXTURE_DESC sceneColorDesc;
-					sceneColorDesc.colorSurfaces[0].texture = mResolvedSceneColorTex1->texture;
-					sceneColorDesc.colorSurfaces[0].face = 0;
-					sceneColorDesc.colorSurfaces[0].numFaces = 1;
-					sceneColorDesc.colorSurfaces[0].mipLevel = 0;
-
-					sceneColorDesc.depthStencilSurface.texture = mDepthTex->texture;
-					sceneColorDesc.depthStencilSurface.face = 0;
-					sceneColorDesc.depthStencilSurface.numFaces = 1;
-					sceneColorDesc.depthStencilSurface.mipLevel = 0;
-
-					mResolvedSceneColorRT1 = TextureManager::instance().createRenderTexture(sceneColorDesc);
-				}
 			}
 		}
 		else if(type == RTT_ResolvedSceneColorSecondary)
 		{
-			// If not using MSAA, this is equivalent to default scene color texture
-			if(mViewTarget.numSamples > 1)
-			{
-				mResolvedSceneColorTex2 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, 
-					width, height, TU_RENDERTARGET, 1, false));
-
-				bool rebuildRT = false;
-				if (mResolvedSceneColorRT2 != nullptr)
-				{
-					rebuildRT |= mResolvedSceneColorRT2->getColorTexture(0) != mResolvedSceneColorTex2->texture;
-					rebuildRT |= mResolvedSceneColorRT2->getDepthStencilTexture() != mDepthTex->texture;
-				}
-				else
-					rebuildRT = true;
-
-				if (rebuildRT)
-				{
-					RENDER_TEXTURE_DESC sceneColorDesc;
-					sceneColorDesc.colorSurfaces[0].texture = mResolvedSceneColorTex2->texture;
-					sceneColorDesc.colorSurfaces[0].face = 0;
-					sceneColorDesc.colorSurfaces[0].numFaces = 1;
-					sceneColorDesc.colorSurfaces[0].mipLevel = 0;
-
-					sceneColorDesc.depthStencilSurface.texture = mDepthTex->texture;
-					sceneColorDesc.depthStencilSurface.face = 0;
-					sceneColorDesc.depthStencilSurface.numFaces = 1;
-					sceneColorDesc.depthStencilSurface.mipLevel = 0;
-
-					mResolvedSceneColorRT2 = TextureManager::instance().createRenderTexture(sceneColorDesc);
-				}
-			}
+			mResolvedSceneColorTex2 = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mSceneColorFormat, 
+				width, height, TU_RENDERTARGET, 1, false));
 		}
 	}
 
@@ -374,21 +320,30 @@ namespace bs { namespace ct
 		RenderAPI::instance().clearViewport(FBT_COLOR, Color::ZERO);
 	}
 
-	void RenderTargets::bindResolvedSceneColor(bool secondary)
+	void RenderTargets::generateHiZ()
 	{
-		RenderAPI& rapi = RenderAPI::instance();
+		mHiZ = GpuResourcePool::instance().get(
+			BuildHiZ::getHiZTextureDesc(
+				mViewTarget.viewRect.width, 
+				mViewTarget.viewRect.height)
+		);
 
-		if(secondary)
-			rapi.setRenderTarget(mResolvedSceneColorRT2, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
-		else
-		{
-			if(mViewTarget.numSamples > 1)
-				rapi.setRenderTarget(mResolvedSceneColorRT1, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
-			else
-				rapi.setRenderTarget(mSceneColorRT, FBT_DEPTH | FBT_STENCIL, RT_DEPTH_STENCIL);
-		}
+		mBuildHiZ.execute(mViewTarget, mDepthTex->texture, mHiZ->texture);
+	}
+
+	void RenderTargets::releaseHiZ()
+	{
+		if (mHiZ)
+			GpuResourcePool::instance().release(mHiZ);
 	}
 
+	SPtr<Texture> RenderTargets::getHiZ() const
+	{
+		if (mHiZ)
+			return mHiZ->texture;
+
+		return nullptr;
+	}
 
 	SPtr<Texture> RenderTargets::getSceneColor() const
 	{
@@ -451,11 +406,11 @@ namespace bs { namespace ct
 	SPtr<RenderTarget> RenderTargets::getResolvedSceneColorRT(bool secondary) const
 	{
 		if (secondary)
-			return mResolvedSceneColorRT2;
+			return mResolvedSceneColorTex2->renderTexture;
 		else
 		{
 			if (mViewTarget.numSamples > 1)
-				return mResolvedSceneColorRT1;
+				return mResolvedSceneColorTex1->renderTexture;
 			else
 				return mSceneColorRT;
 		}