From 536e38ad51b89808f26d8e3cd107fe093862d22a Mon Sep 17 00:00:00 2001
From: David Parks <davep@lindenlab.com>
Date: Tue, 22 Sep 2009 11:11:45 +0000
Subject: [PATCH] Merging render-pipeline-6-qa-2 into viewer-2

Self reviewed.
---
 doc/contributions.txt                         |    4 +
 .../llui_libtest/CMakeLists.txt               |    3 +
 indra/llmath/llcamera.cpp                     |   28 +-
 indra/llmath/llcamera.h                       |   16 +-
 indra/llmath/llrect.h                         |    1 +
 indra/llmath/llvolume.cpp                     |   11 +-
 indra/llprimitive/llprimitive.cpp             |   77 +
 indra/llprimitive/llprimitive.h               |   25 +-
 indra/llrender/llgl.cpp                       |   27 +-
 indra/llrender/llgl.h                         |   32 +
 indra/llrender/llimagegl.cpp                  |  214 +-
 indra/llrender/llimagegl.h                    |   44 +-
 indra/llrender/llrender.cpp                   |   10 +-
 indra/llrender/llrender.h                     |    1 +
 indra/llrender/llrendertarget.cpp             |   59 +-
 indra/llrender/llrendertarget.h               |    4 +
 indra/llui/llfloater.cpp                      |   22 +-
 indra/llui/llmenugl.cpp                       |    8 +
 indra/llui/lltabcontainer.cpp                 |    9 +-
 indra/llui/llui.cpp                           |   17 +-
 indra/llui/llui.h                             |    4 +
 indra/llui/llview.cpp                         |   27 +-
 indra/llui/llview.h                           |    1 +
 indra/newview/CMakeLists.txt                  |    4 +
 indra/newview/app_settings/settings.xml       |  750 +++-
 .../shaders/class1/deferred/alphaF.glsl       |   57 +-
 .../shaders/class1/deferred/alphaV.glsl       |    8 +-
 .../shaders/class1/deferred/avatarAlphaF.glsl |    2 +-
 .../shaders/class1/deferred/avatarF.glsl      |   13 +-
 .../class1/deferred/avatarShadowF.glsl        |    3 +-
 .../class1/deferred/avatarShadowV.glsl        |    3 +-
 .../shaders/class1/deferred/avatarV.glsl      |    2 -
 .../shaders/class1/deferred/blurLightF.glsl   |   42 +-
 .../shaders/class1/deferred/bumpF.glsl        |    8 +-
 .../shaders/class1/deferred/bumpV.glsl        |    3 -
 .../shaders/class1/deferred/diffuseF.glsl     |    6 +-
 .../shaders/class1/deferred/diffuseV.glsl     |    5 +-
 .../shaders/class1/deferred/fullbrightF.glsl  |   28 +-
 .../shaders/class1/deferred/fullbrightV.glsl  |    2 +-
 .../shaders/class1/deferred/giF.glsl          |  165 +
 .../shaders/class1/deferred/giV.glsl          |   22 +
 .../shaders/class1/deferred/impostorF.glsl    |    5 +-
 .../shaders/class1/deferred/impostorV.glsl    |    4 -
 .../shaders/class1/deferred/luminanceF.glsl   |   15 +
 .../shaders/class1/deferred/luminanceV.glsl   |   20 +
 .../class1/deferred/multiPointLightF.glsl     |   64 +-
 .../class1/deferred/multiSpotLightF.glsl      |  178 +
 .../shaders/class1/deferred/pointLightF.glsl  |   66 +-
 .../shaders/class1/deferred/pointLightV.glsl  |    6 +-
 .../class1/deferred/postDeferredF.glsl        |   57 +
 .../class1/deferred/postDeferredV.glsl        |   17 +
 .../shaders/class1/deferred/postgiF.glsl      |   79 +
 .../shaders/class1/deferred/postgiV.glsl      |   17 +
 .../shaders/class1/deferred/shadowF.glsl      |    3 +
 .../shaders/class1/deferred/shadowV.glsl      |   10 +-
 .../shaders/class1/deferred/softenLightF.glsl |   69 +-
 .../shaders/class1/deferred/spotLightF.glsl   |  177 +
 .../shaders/class1/deferred/sunLightF.glsl    |  111 +-
 .../shaders/class1/deferred/terrainF.glsl     |    6 +-
 .../shaders/class1/deferred/terrainV.glsl     |    2 -
 .../shaders/class1/deferred/treeF.glsl        |    6 +-
 .../shaders/class1/deferred/treeV.glsl        |    3 -
 .../shaders/class1/deferred/waterF.glsl       |   72 +-
 .../shaders/class2/deferred/alphaF.glsl       |  132 +
 .../shaders/class2/deferred/alphaV.glsl       |   76 +
 .../shaders/class2/deferred/avatarAlphaF.glsl |   98 +
 .../shaders/class2/deferred/avatarAlphaV.glsl |   84 +
 .../shaders/class2/deferred/blurLightF.glsl   |   96 +
 .../shaders/class2/deferred/blurLightV.glsl   |   17 +
 .../shaders/class2/deferred/edgeF.glsl        |   58 +
 .../shaders/class2/deferred/edgeV.glsl        |   17 +
 .../class2/deferred/multiSpotLightF.glsl      |  188 +
 .../class2/deferred/postDeferredF.glsl        |   59 +
 .../class2/deferred/postDeferredV.glsl        |   17 +
 .../shaders/class2/deferred/softenLightF.glsl |  294 ++
 .../shaders/class2/deferred/softenLightV.glsl |   24 +
 .../shaders/class2/deferred/spotLightF.glsl   |  199 +
 .../shaders/class2/deferred/sunLightF.glsl    |  235 ++
 .../shaders/class2/deferred/sunLightV.glsl    |   25 +
 .../class3/deferred/giDownsampleF.glsl        |   84 +
 .../class3/deferred/giDownsampleV.glsl        |   17 +
 .../shaders/class3/deferred/giF.glsl          |  190 +
 .../shaders/class3/deferred/giFinalF.glsl     |   25 +
 .../shaders/class3/deferred/giFinalV.glsl     |   17 +
 .../shaders/class3/deferred/giV.glsl          |   22 +
 .../shaders/class3/deferred/luminanceF.glsl   |   19 +
 .../shaders/class3/deferred/luminanceV.glsl   |   20 +
 .../class3/deferred/postDeferredF.glsl        |   80 +
 .../class3/deferred/postDeferredV.glsl        |   17 +
 .../shaders/class3/deferred/postgiF.glsl      |   69 +
 .../shaders/class3/deferred/postgiV.glsl      |   17 +
 .../shaders/class3/deferred/softenLightF.glsl |  297 ++
 .../shaders/class3/deferred/softenLightV.glsl |   24 +
 .../shaders/class3/deferred/treeF.glsl        |   18 +
 indra/newview/gpu_table.txt                   |    5 +-
 indra/newview/llappviewer.cpp                 |   61 +-
 indra/newview/llappviewerwin32.cpp            |    2 +
 indra/newview/lldebugview.cpp                 |   12 +
 indra/newview/lldrawable.cpp                  |   58 +-
 indra/newview/lldrawable.h                    |    5 +-
 indra/newview/lldrawpool.cpp                  |    9 +-
 indra/newview/lldrawpool.h                    |    7 +-
 indra/newview/lldrawpoolalpha.cpp             |   60 +-
 indra/newview/lldrawpoolavatar.cpp            |    8 +-
 indra/newview/lldrawpoolbump.cpp              |   14 +-
 indra/newview/lldrawpoolsimple.cpp            |   13 +-
 indra/newview/lldrawpoolterrain.cpp           |    6 +-
 indra/newview/lldrawpooltree.cpp              |   14 +-
 indra/newview/lldrawpoolwater.cpp             |   52 +-
 indra/newview/lldrawpoolwater.h               |    4 +-
 indra/newview/llface.cpp                      |  287 +-
 indra/newview/llface.h                        |   23 +-
 indra/newview/llfloaterpostcard.cpp           |    4 +-
 indra/newview/llfloatersettingsdebug.cpp      |    5 +
 indra/newview/llfloaterwindlight.cpp          |    7 +
 indra/newview/llhudtext.cpp                   |    2 +
 indra/newview/llmanip.cpp                     |    1 +
 indra/newview/llpanelvolume.cpp               |  125 +
 indra/newview/llpanelvolume.h                 |    5 +
 indra/newview/llspatialpartition.cpp          |  730 +++-
 indra/newview/llspatialpartition.h            |  112 +-
 indra/newview/llstartup.cpp                   |    4 +-
 indra/newview/llsurface.cpp                   |   32 +-
 indra/newview/llsurfacepatch.cpp              |   34 +-
 indra/newview/llsurfacepatch.h                |    1 +
 indra/newview/lltexlayer.h                    |    2 +-
 indra/newview/lltexlayerparams.cpp            |    2 +-
 indra/newview/lltextureatlas.cpp              |  422 ++
 indra/newview/lltextureatlas.h                |   95 +
 indra/newview/lltextureatlasmanager.cpp       |  273 ++
 indra/newview/lltextureatlasmanager.h         |  111 +
 indra/newview/lltextureview.cpp               |  229 +-
 indra/newview/lltextureview.h                 |   20 +
 indra/newview/lltoolpie.h                     |    4 +-
 indra/newview/llviewercamera.cpp              |    2 +
 indra/newview/llviewercamera.h                |   18 +
 indra/newview/llviewercontrol.cpp             |    4 +
 indra/newview/llviewerdisplay.cpp             |   99 +-
 indra/newview/llviewerjointmesh.cpp           |    3 +-
 indra/newview/llviewermenu.cpp                |   71 +-
 indra/newview/llviewermessage.cpp             |    3 -
 indra/newview/llviewerobject.cpp              |   21 +-
 indra/newview/llviewerobject.h                |    9 +-
 indra/newview/llviewerparceloverlay.cpp       |   20 +-
 indra/newview/llviewerparceloverlay.h         |    4 +-
 indra/newview/llviewerpartsource.cpp          |    2 +-
 indra/newview/llviewershadermgr.cpp           |  149 +-
 indra/newview/llviewershadermgr.h             |   30 +
 indra/newview/llviewertexture.cpp             |  237 +-
 indra/newview/llviewertexture.h               |   13 +-
 indra/newview/llviewerwindow.cpp              |   21 +-
 indra/newview/llvlcomposition.cpp             |    4 +
 indra/newview/llvoavatar.cpp                  |   72 +-
 indra/newview/llvoavatar.h                    |    5 +-
 indra/newview/llvoavatarself.cpp              |    4 +-
 indra/newview/llvoclouds.cpp                  |    5 +-
 indra/newview/llvopartgroup.cpp               |   12 +-
 indra/newview/llvosurfacepatch.cpp            |   14 +-
 indra/newview/llvosurfacepatch.h              |    1 +
 indra/newview/llvotree.cpp                    |    7 +-
 indra/newview/llvovolume.cpp                  |  253 +-
 indra/newview/llvovolume.h                    |   13 +
 indra/newview/llvowater.cpp                   |    3 +-
 indra/newview/llwaterparammanager.cpp         |    7 +-
 indra/newview/llwlparammanager.cpp            |    5 +-
 indra/newview/llworldmap.cpp                  |    1 -
 indra/newview/llworldmapview.cpp              |    6 +-
 indra/newview/pipeline.cpp                    | 3733 +++++++++++++----
 indra/newview/pipeline.h                      |  134 +-
 .../skins/default/xui/en/floater_tools.xml    |   39 +-
 .../skins/default/xui/en/menu_viewer.xml      |  193 +-
 171 files changed, 11743 insertions(+), 1623 deletions(-)
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/giF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/giV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/giV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
 create mode 100644 indra/newview/lltextureatlas.cpp
 create mode 100644 indra/newview/lltextureatlas.h
 create mode 100644 indra/newview/lltextureatlasmanager.cpp
 create mode 100644 indra/newview/lltextureatlasmanager.h

diff --git a/doc/contributions.txt b/doc/contributions.txt
index c18d3eb1710..9b3087a0ac0 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -38,6 +38,7 @@ Aimee Trescothick
 	VWR-11100
 	VWR-11111
  	VWR-11844
+	VWR-14087
 Alejandro Rosenthal
 	VWR-1184
 Aleric Inglewood
@@ -551,6 +552,8 @@ Strife Onizuka
 	VWR-183
 	VWR-2265
 	VWR-4111
+Tayra Dagostino
+	VWR-13947
 TBBle Kurosawa
 	VWR-938
 	VWR-941
@@ -567,6 +570,7 @@ Tharax Ferraris
 	VWR-605
 Thickbrick Sleaford
 	VWR-7109
+	VWR-13947
 Thraxis Epsilon
 	SVC-371
 	VWR-383
diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt
index 84e3477ce62..452d37d3be7 100644
--- a/indra/integration_tests/llui_libtest/CMakeLists.txt
+++ b/indra/integration_tests/llui_libtest/CMakeLists.txt
@@ -57,6 +57,8 @@ if (DARWIN)
   find_library(COCOA_LIBRARY Cocoa)
   set(OS_LIBRARIES ${COCOA_LIBRARY})
 elseif (WINDOWS)
+  #ll_stack_trace needs this now...
+  list(APPEND WINDOWS_LIBRARIES dbghelp)
   set(OS_LIBRARIES ${WINDOWS_LIBRARIES})
 elseif (LINUX)
   set(OS_LIBRARIES)
@@ -95,6 +97,7 @@ if (WINDOWS)
         COMMAND ${CMAKE_COMMAND} -E copy_if_different 
             ${OPENJPEG_DEBUG} ${CMAKE_CURRENT_BINARY_DIR}
         )
+  
 endif (WINDOWS)
 
 # Ensure people working on the viewer don't break this library
diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index 0f343bcefee..21ea4b2e7c5 100644
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -178,7 +178,7 @@ S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
 	U8 mask = 0;
 	S32 result = 2;
 
-	if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
+	/*if (mFrustumCornerDist > 0.f && radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
 	{ //box is larger than frustum, check frustum quads against box planes
 
 		static const LLVector3 dir[] = 
@@ -241,11 +241,15 @@ S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
 			result = 1;
 		}
 	}
-	else
+	else*/
 	{
 		for (U32 i = 0; i < mPlaneCount; i++)
 		{
 			mask = mAgentPlanes[i].mask;
+			if (mask == 0xff)
+			{
+				continue;
+			}
 			LLPlane p = mAgentPlanes[i].p;
 			LLVector3 n = LLVector3(p);
 			float d = p.mV[3];
@@ -294,6 +298,10 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& r
 		}
 
 		mask = mAgentPlanes[i].mask;
+		if (mask == 0xff)
+		{
+			continue;
+		}
 		LLPlane p = mAgentPlanes[i].p;
 		LLVector3 n = LLVector3(p);
 		float d = p.mV[3];
@@ -437,6 +445,11 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius)
 	int res = 2;
 	for (int i = 0; i < 6; i++)
 	{
+		if (mAgentPlanes[i].mask == 0xff)
+		{
+			continue;
+		}
+
 		float d = mAgentPlanes[i].p.dist(sphere_center);
 
 		if (d > radius) 
@@ -622,6 +635,17 @@ U8 LLCamera::calcPlaneMask(const LLPlane& plane)
 	return mask;
 }
 
+void LLCamera::ignoreAgentFrustumPlane(S32 idx)
+{
+	if (idx < 0 || idx > (S32) mPlaneCount)
+	{
+		return;
+	}
+
+	mAgentPlanes[idx].mask = 0xff;
+	mAgentPlanes[idx].p.clearVec();
+}
+
 void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
 {
 
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 23ee1157f9c..0c81067919a 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -93,6 +93,17 @@ class LLCamera
 		PLANE_TOP_MASK = (1<<PLANE_TOP),
 		PLANE_ALL_MASK = 0xf
 	};
+
+	enum
+	{
+		AGENT_PLANE_LEFT = 0,
+		AGENT_PLANE_RIGHT,
+		AGENT_PLANE_NEAR,
+		AGENT_PLANE_BOTTOM,
+		AGENT_PLANE_TOP,
+		AGENT_PLANE_FAR,
+	};
+
 	enum {
 		HORIZ_PLANE_LEFT = 0,
 		HORIZ_PLANE_RIGHT = 1,
@@ -132,7 +143,8 @@ class LLCamera
 public:
 	LLVector3 mAgentFrustum[8];  //8 corners of 6-plane frustum
 	F32	mFrustumCornerDist;		//distance to corner of frustum against far clip plane
-	
+	LLPlane getAgentPlane(U32 idx) { return mAgentPlanes[idx].p; }
+
 public:
 	LLCamera();
 	LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);
@@ -179,6 +191,8 @@ class LLCamera
 	// Return number of bytes copied.
 	size_t readFrustumFromBuffer(const char *buffer);
 	void calcAgentFrustumPlanes(LLVector3* frust);
+	void ignoreAgentFrustumPlane(S32 idx);
+
 	// Returns 1 if partly in, 2 if fully in.
 	// NOTE: 'center' is in absolute frame.
 	S32 sphereInFrustumOld(const LLVector3 &center, const F32 radius) const;
diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h
index c03a331aff0..2fa8cb3f161 100644
--- a/indra/llmath/llrect.h
+++ b/indra/llmath/llrect.h
@@ -42,6 +42,7 @@
 template <class Type> class LLRectBase
 {
 public:
+	typedef	Type tCoordType;
 	Type		mLeft;
 	Type		mTop;
 	Type		mRight;
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index a0357a32cc4..5cc0a596fdb 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -84,6 +84,7 @@ const F32 SKEW_MIN	= -0.95f;
 const F32 SKEW_MAX	=  0.95f;
 
 const F32 SCULPT_MIN_AREA = 0.002f;
+const S32 SCULPT_MIN_AREA_DETAIL = 1;
 
 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
 {    
@@ -2230,10 +2231,14 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
 	if (!data_is_empty)
 	{
 		sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type);
-		
-		if (sculptGetSurfaceArea() < SCULPT_MIN_AREA)
+
+		// don't test lowest LOD to support legacy content DEV-33670
+		if (mDetail > SCULPT_MIN_AREA_DETAIL)
 		{
-			data_is_empty = TRUE;
+			if (sculptGetSurfaceArea() < SCULPT_MIN_AREA)
+			{
+				data_is_empty = TRUE;
+			}
 		}
 	}
 
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 33807e7545f..b925d97b5c9 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -1314,6 +1314,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size)
 		return (size == 16);
 	case PARAMS_SCULPT:
 		return (size == 17);
+	case PARAMS_LIGHT_IMAGE:
+		return (size == 28);
 	}
 	
 	return FALSE;
@@ -1646,3 +1648,78 @@ bool LLSculptParams::fromLLSD(LLSD& sd)
 	return false;
 }
 
+//============================================================================
+
+LLLightImageParams::LLLightImageParams()
+{
+	mType = PARAMS_LIGHT_IMAGE;
+	mParams.setVec(F_PI*0.5f, 0.f, 0.f);
+}
+
+BOOL LLLightImageParams::pack(LLDataPacker &dp) const
+{
+	dp.packUUID(mLightTexture, "texture");
+	dp.packVector3(mParams, "params");
+
+	return TRUE;
+}
+
+BOOL LLLightImageParams::unpack(LLDataPacker &dp)
+{
+	dp.unpackUUID(mLightTexture, "texture");
+	dp.unpackVector3(mParams, "params");
+	
+	return TRUE;
+}
+
+bool LLLightImageParams::operator==(const LLNetworkData& data) const
+{
+	if (data.mType != PARAMS_LIGHT_IMAGE)
+	{
+		return false;
+	}
+	
+	const LLLightImageParams *param = (const LLLightImageParams*)&data;
+	if ( (param->mLightTexture != mLightTexture) )
+	{
+		return false;
+	}
+
+	if ( (param->mParams != mParams ) )
+	{
+		return false;
+	}
+	
+	return true;
+}
+
+void LLLightImageParams::copy(const LLNetworkData& data)
+{
+	const LLLightImageParams *param = (LLLightImageParams*)&data;
+	mLightTexture = param->mLightTexture;
+	mParams = param->mParams;
+}
+
+
+
+LLSD LLLightImageParams::asLLSD() const
+{
+	LLSD sd;
+	
+	sd["texture"] = mLightTexture;
+	sd["params"] = mParams.getValue();
+		
+	return sd;
+}
+
+bool LLLightImageParams::fromLLSD(LLSD& sd)
+{
+	if (sd.has("texture") && sd.has("params") && sd["params"].size() == 3)
+	{
+		setLightTexture( sd["texture"] );
+		setParams( LLVector3(sd["params"][0].asReal(), sd["params"][1].asReal(), sd["params"][2].asReal()) );
+		return true;
+	} 
+	
+	return false;
+}
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index b3a337ce5da..53095cc925c 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -107,7 +107,8 @@ class LLNetworkData
 	{
 		PARAMS_FLEXIBLE = 0x10,
 		PARAMS_LIGHT    = 0x20,
-		PARAMS_SCULPT   = 0x30
+		PARAMS_SCULPT   = 0x30,
+		PARAMS_LIGHT_IMAGE = 0x40,
 	};
 	
 public:
@@ -267,6 +268,28 @@ class LLSculptParams : public LLNetworkData
 	U8 getSculptType()                      { return mSculptType; }
 };
 
+class LLLightImageParams : public LLNetworkData
+{
+protected:
+	LLUUID mLightTexture;
+	LLVector3 mParams;
+	
+public:
+	LLLightImageParams();
+	/*virtual*/ BOOL pack(LLDataPacker &dp) const;
+	/*virtual*/ BOOL unpack(LLDataPacker &dp);
+	/*virtual*/ bool operator==(const LLNetworkData& data) const;
+	/*virtual*/ void copy(const LLNetworkData& data);
+	LLSD asLLSD() const;
+	operator LLSD() const { return asLLSD(); }
+	bool fromLLSD(LLSD& sd);
+
+	void setLightTexture(const LLUUID& id) { mLightTexture = id; }
+	LLUUID getLightTexture() const         { return mLightTexture; }
+	void setParams(const LLVector3& params) { mParams = params; }
+	LLVector3 getParams() const			   { return mParams; }
+	
+};
 
 
 class LLPrimitive : public LLXform
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 7e1df0e5652..e29688bf247 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -64,6 +64,8 @@ BOOL gDebugSession = FALSE;
 BOOL gDebugGL = FALSE;
 BOOL gClothRipple = FALSE;
 BOOL gNoRender = FALSE;
+BOOL gGLActive = FALSE;
+
 
 std::ofstream gFailLog;
 
@@ -107,6 +109,7 @@ LLMatrix4 gGLObliqueProjectionInverse;
 #define LL_GL_NAME_POOLING 0
 
 LLGLNamePool::pool_list_t LLGLNamePool::sInstances;
+std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
 
 #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS)  && !LL_MESA_HEADLESS
 // ATI prototypes
@@ -1013,6 +1016,16 @@ void flush_glerror()
 
 void assert_glerror()
 {
+	if (!gGLActive)
+	{
+		//llwarns << "GL used while not active!" << llendl;
+
+		if (gDebugSession)
+		{
+			ll_fail("GL used while not active");
+		}
+	}
+
 	if (gNoRender || !gDebugGL) 
 	{
 		return;
@@ -1258,8 +1271,10 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 	};
 
 	GLint stackDepth = 0;
-	LLMatrix4 identity;
-	LLMatrix4 matrix;
+
+	glh::matrix4f mat;
+	glh::matrix4f identity;
+	identity.identity();
 
 	for (GLint i = 1; i < maxTextureUnits; i++)
 	{
@@ -1280,10 +1295,10 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 			}
 		}
 
-		glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix);
+		glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) mat.m);
 		stop_glerror();
 
-		if (matrix != identity)
+		if (mat != identity)
 		{
 			error = TRUE;
 			LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL;
@@ -1309,10 +1324,6 @@ void LLGLState::checkTextureChannels(const std::string& msg)
 			stop_glerror();
 		}
 
-		glh::matrix4f mat;
-		glh::matrix4f identity;
-		identity.identity();
-
 		glGetFloatv(GL_TEXTURE_MATRIX, mat.m);
 		stop_glerror();
 
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 34dd982259c..91421f3c954 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -37,6 +37,7 @@
 
 #include <string>
 #include <map>
+#include <list>
 
 #include "llerror.h"
 #include "v4color.h"
@@ -367,6 +368,35 @@ class LLGLNamePool
 	virtual void releaseName(GLuint name) = 0;
 };
 
+/*
+	Interface for objects that need periodic GL updates applied to them.
+	Used to synchronize GL updates with GL thread.
+*/
+class LLGLUpdate
+{
+public:
+
+	static std::list<LLGLUpdate*> sGLQ;
+
+	BOOL mInQ;
+	LLGLUpdate()
+		: mInQ(FALSE)
+	{
+	}
+	virtual ~LLGLUpdate()
+	{
+		if (mInQ)
+		{
+			std::list<LLGLUpdate*>::iterator iter = std::find(sGLQ.begin(), sGLQ.end(), this);
+			if (iter != sGLQ.end())
+			{
+				sGLQ.erase(iter);
+			}
+		}
+	}
+	virtual void updateGL() = 0;
+};
+
 extern LLMatrix4 gGLObliqueProjectionInverse;
 
 #include "llglstates.h"
@@ -385,4 +415,6 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
 
 extern BOOL gClothRipple;
 extern BOOL gNoRender;
+extern BOOL gGLActive;
+
 #endif // LL_LLGL_H
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 9d2cd4867a1..dd64d753c74 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -44,7 +44,6 @@
 #include "llgl.h"
 #include "llrender.h"
 
-
 //----------------------------------------------------------------------------
 const F32 MIN_TEXTURE_LIFETIME = 10.f;
 
@@ -57,12 +56,25 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes		= 0;
 S32 LLImageGL::sBoundTextureMemoryInBytes		= 0;
 S32 LLImageGL::sCurBoundTextureMemory	= 0;
 S32 LLImageGL::sCount					= 0;
+std::list<U32> LLImageGL::sDeadTextureList;
 
 BOOL LLImageGL::sGlobalUseAnisotropic	= FALSE;
 F32 LLImageGL::sLastFrameTime			= 0.f;
 LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
 std::set<LLImageGL*> LLImageGL::sImageList;
 
+#if !LL_RELEASE_FOR_DOWNLOAD
+//-----------------------
+//debug use
+#define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048
+std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
+std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
+std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
+S32 LLImageGL::sCurTexSizeBar = -1 ;
+S32 LLImageGL::sCurTexPickSize = -1 ;
+LLPointer<LLImageGL> LLImageGL::sDefaultTexturep = NULL;
+//------------------------
+#endif
 //**************************************************************************************
 //below are functions for debug use
 //do not delete them even though they are not currently being used.
@@ -198,6 +210,14 @@ void LLImageGL::updateStats(F32 current_time)
 	sLastFrameTime = current_time;
 	sBoundTextureMemoryInBytes = sCurBoundTextureMemory;
 	sCurBoundTextureMemory = 0;
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+	for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
+	{
+		sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
+		sTextureCurBoundCounter[i] = 0 ;
+	}
+#endif
 }
 
 //static
@@ -363,6 +383,10 @@ void LLImageGL::init(BOOL usemipmaps)
 	mGLTextureCreated = FALSE ;
 	mIsMask = FALSE;
 	mNeedsAlphaAndPickMask = TRUE ;
+
+	mDiscardLevelInAtlas = -1 ;
+	mTexelsInAtlas = 0 ;
+	mTexelsInGLTexture = 0 ;
 }
 
 void LLImageGL::cleanup()
@@ -523,7 +547,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		is_compressed = true;
 	}
 
-	gGL.getTexUnit(0)->bind(this);
+	llverify(gGL.getTexUnit(0)->bind(this));
 	
 	if (mUseMipMaps)
 	{
@@ -728,6 +752,92 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 	llpushcallstacks ;
 }
 
+BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
+{
+	if (gGLManager.mIsDisabled)
+	{
+		llwarns << "Trying to create a texture while GL is disabled!" << llendl;
+		return FALSE;
+	}
+	llassert(gGLManager.mInited);
+	stop_glerror();
+
+	if (discard_level < 0)
+	{
+		llassert(mCurrentDiscardLevel >= 0);
+		discard_level = mCurrentDiscardLevel;
+	}
+	discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
+
+	// Actual image width/height = raw image width/height * 2^discard_level
+	S32 w = raw_image->getWidth() << discard_level;
+	S32 h = raw_image->getHeight() << discard_level;
+
+	// setSize may call destroyGLTexture if the size does not match
+	setSize(w, h, raw_image->getComponents());
+
+	if( !mHasExplicitFormat )
+	{
+		switch (mComponents)
+		{
+		  case 1:
+			// Use luminance alpha (for fonts)
+			mFormatInternal = GL_LUMINANCE8;
+			mFormatPrimary = GL_LUMINANCE;
+			mFormatType = GL_UNSIGNED_BYTE;
+			break;
+		  case 2:
+			// Use luminance alpha (for fonts)
+			mFormatInternal = GL_LUMINANCE8_ALPHA8;
+			mFormatPrimary = GL_LUMINANCE_ALPHA;
+			mFormatType = GL_UNSIGNED_BYTE;
+			break;
+		  case 3:
+			mFormatInternal = GL_RGB8;
+			mFormatPrimary = GL_RGB;
+			mFormatType = GL_UNSIGNED_BYTE;
+			break;
+		  case 4:
+			mFormatInternal = GL_RGBA8;
+			mFormatPrimary = GL_RGBA;
+			mFormatType = GL_UNSIGNED_BYTE;
+			break;
+		  default:
+			llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
+		}
+	}
+
+	mCurrentDiscardLevel = discard_level;	
+	mDiscardLevelInAtlas = discard_level;
+	mTexelsInAtlas = raw_image->getWidth() * raw_image->getHeight() ;
+	mLastBindTime = sLastFrameTime;
+	mGLTextureCreated = false ;
+	
+	glPixelStorei(GL_UNPACK_ROW_LENGTH, raw_image->getWidth());
+	stop_glerror();
+
+	if(mFormatSwapBytes)
+	{
+		glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+		stop_glerror();
+	}
+
+	return TRUE ;
+}
+
+void LLImageGL::postAddToAtlas()
+{
+	if(mFormatSwapBytes)
+	{
+		glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
+		stop_glerror();
+	}
+
+	glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+	gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);	
+	stop_glerror();	
+}
+
 BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update)
 {
 	llpushcallstacks ;
@@ -832,7 +942,7 @@ BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S3
 // Copy sub image from frame buffer
 BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
 {
-	if (gGL.getTexUnit(0)->bind(this, true))
+	if (gGL.getTexUnit(0)->bind(this))
 	{
 		glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
 		mGLTextureCreated = true;
@@ -854,13 +964,17 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
 // static
 void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
 {
-	glDeleteTextures(numTextures, (GLuint*)textures);
+	for (S32 i = 0; i < numTextures; i++)
+	{
+		sDeadTextureList.push_back(textures[i]);
+	}
 }
 
 // static
 void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
 {
 	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
+	stop_glerror();
 }
 
 //create an empty GL texture: just create a texture name
@@ -895,12 +1009,12 @@ BOOL LLImageGL::createGLTexture()
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/)
 {
-	llpushcallstacks ;
 	if (gGLManager.mIsDisabled)
 	{
 		llwarns << "Trying to create a texture while GL is disabled!" << llendl;
 		return FALSE;
 	}
+
 	mGLTextureCreated = false ;
 	llassert(gGLManager.mInited);
 	stop_glerror();
@@ -1023,12 +1137,21 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	if (old_name != 0)
 	{
 		sGlobalTextureMemoryInBytes -= mTextureMemory;
+#if !LL_RELEASE_FOR_DOWNLOAD
+		decTextureCounter(mTextureMemory / mComponents) ;
+#endif
+
 		LLImageGL::deleteTextures(1, &old_name);
 		stop_glerror();
 	}
 
 	mTextureMemory = getMipBytes(discard_level);
 	sGlobalTextureMemoryInBytes += mTextureMemory;
+	mTexelsInGLTexture = getWidth() * getHeight() ;
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+	incTextureCounter(mTextureMemory / mComponents) ;
+#endif
 
 	// mark this as bound at this point, so we don't throw it out immediately
 	mLastBindTime = sLastFrameTime;
@@ -1208,32 +1331,48 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 	return TRUE ;
 }
 
-void LLImageGL::destroyGLTexture()
+void LLImageGL::deleteDeadTextures()
 {
-	if (mTexName != 0)
+	while (!sDeadTextureList.empty())
 	{
-		stop_glerror();
-
+		GLuint tex = sDeadTextureList.front();
+		sDeadTextureList.pop_front();
 		for (int i = 0; i < gGLManager.mNumTextureUnits; i++)
 		{
-			if (sCurrentBoundTextures[i] == mTexName)
+			if (sCurrentBoundTextures[i] == tex)
 			{
 				gGL.getTexUnit(i)->unbind(LLTexUnit::TT_TEXTURE);
 				stop_glerror();
 			}
 		}
 
-		sGlobalTextureMemoryInBytes -= mTextureMemory;
-		mTextureMemory = 0;
+		glDeleteTextures(1, &tex);
+		stop_glerror();
+	}
+}
+
+void LLImageGL::destroyGLTexture()
+{
+	if (mTexName != 0)
+	{
+		if(mTextureMemory)
+		{
+#if !LL_RELEASE_FOR_DOWNLOAD
+			decTextureCounter(mTextureMemory / mComponents) ;
+#endif
+			sGlobalTextureMemoryInBytes -= mTextureMemory;
+			mTextureMemory = 0;
+		}
 
 		LLImageGL::deleteTextures(1, &mTexName);			
 		mTexName = 0;
 		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
 		mGLTextureCreated = FALSE ;
-		stop_glerror();
 	}
 }
 
+
+
 //----------------------------------------------------------------------------
 
 void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode)
@@ -1259,12 +1398,12 @@ void LLImageGL::setFilteringOption(LLTexUnit::eTextureFilterOptions option)
 		mFilterOption = option;
 	}
 
-	if (gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName)
+	if (mTexName != 0 && gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->getCurrTexture() == mTexName)
 	{
 		gGL.getTexUnit(gGL.getCurrentTexUnitIndex())->setTextureFilteringOption(option);
 		mTexOptionsDirty = false;
+		stop_glerror();
 	}
-	stop_glerror();
 }
 
 BOOL LLImageGL::getIsResident(BOOL test_now)
@@ -1500,7 +1639,50 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
 }
 
 //----------------------------------------------------------------------------
-
+#if !LL_RELEASE_FOR_DOWNLOAD
+//for debug use 
+//val is a "power of two" number
+S32 LLImageGL::getTextureCounterIndex(U32 val) 
+{
+	//index range is [0, MAX_TEXTURE_LOG_SIZE].
+	if(val < 2)
+	{
+		return 0 ;
+	}
+	else if(val >= (1 << MAX_TEXTURE_LOG_SIZE))
+	{
+		return MAX_TEXTURE_LOG_SIZE ;
+	}
+	else
+	{
+		S32 ret = 0 ;
+		while(val >>= 1)
+		{
+			++ret;
+		}
+		return ret ;
+	}
+}
+void LLImageGL::incTextureCounter(U32 val) 
+{
+	sTextureLoadedCounter[getTextureCounterIndex(val)]++ ;
+}
+void LLImageGL::decTextureCounter(U32 val) 
+{
+	sTextureLoadedCounter[getTextureCounterIndex(val)]-- ;
+}
+void LLImageGL::setCurTexSizebar(S32 index)
+{
+	sCurTexSizeBar = index ;
+	sCurTexPickSize = (1 << index) ;
+}
+void LLImageGL::resetCurTexSizebar()
+{
+	sCurTexSizeBar = -1 ;
+	sCurTexPickSize = -1 ;
+}
+//----------------------------------------------------------------------------
+#endif
 
 // Manual Mip Generation
 /*
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 987a1dc538f..a094605607c 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -42,7 +42,7 @@
 #include "v2math.h"
 
 #include "llrender.h"
-
+class LLTextureAtlas ;
 #define BYTES_TO_MEGA_BYTES(x) ((x) >> 20)
 #define MEGA_BYTES_TO_BYTES(x) ((x) << 20)
 
@@ -52,6 +52,10 @@ class LLImageGL : public LLRefCount
 {
 	friend class LLTexUnit;
 public:
+	static std::list<U32> sDeadTextureList;
+
+	static void deleteDeadTextures();
+
 	// Size calculation
 	static S32 dataFormatBits(S32 dataformat);
 	static S32 dataFormatBytes(S32 dataformat, S32 width, S32 height);
@@ -69,7 +73,6 @@ class LLImageGL : public LLRefCount
 
 	// Sometimes called externally for textures not using LLImageGL (should go away...)
 	static S32 updateBoundTexMem(const S32 delta);
-
 	static bool checkSize(S32 width, S32 height);
 
 	//for server side use only.
@@ -115,6 +118,7 @@ class LLImageGL : public LLRefCount
 	void destroyGLTexture();
 
 	void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
+	void setComponents(S8 ncomponents) { mComponents = ncomponents; }
 
 	S32	 getDiscardLevel() const		{ return mCurrentDiscardLevel; }
 	S32	 getMaxDiscardLevel() const		{ return mMaxDiscardLevel; }
@@ -128,6 +132,7 @@ class LLImageGL : public LLRefCount
 	S32  getMipBytes(S32 discard_level = -1) const;
 	BOOL getBoundRecently() const;
 	LLGLenum getPrimaryFormat() const { return mFormatPrimary; }
+	LLGLenum getFormatType() const { return mFormatType; }
 
 	BOOL getHasGLTexture() const { return mTexName != 0; }
 	LLGLuint getTexName() const { return mTexName; }
@@ -164,10 +169,20 @@ class LLImageGL : public LLRefCount
 	void setFilteringOption(LLTexUnit::eTextureFilterOptions option);
 	LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; }
 
+	LLGLenum getTexTarget()const { return mTarget ;}
+	S8       getDiscardLevelInAtlas()const {return mDiscardLevelInAtlas;}
+	U32      getTexelsInAtlas()const { return mTexelsInAtlas ;}
+	U32      getTexelsInGLTexture()const {return mTexelsInGLTexture;}
+
+	
 	void init(BOOL usemipmaps);
 	virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized.  Be careful when using this in derived class destructors
 
 	void setNeedsAlphaAndPickMask(BOOL need_mask) {mNeedsAlphaAndPickMask = need_mask;}
+
+	BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
+	void postAddToAtlas() ;	
+
 public:
 	// Various GL/Rendering options
 	S32 mTextureMemory;
@@ -189,6 +204,10 @@ class LLImageGL : public LLRefCount
 	U16      mHeight;	
 	S8       mCurrentDiscardLevel;
 
+	S8       mDiscardLevelInAtlas;
+	U32      mTexelsInAtlas ;
+	U32      mTexelsInGLTexture;
+
 protected:
 	LLGLenum mTarget;		// Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
 	LLTexUnit::eTextureType mBindTarget;	// Normally TT_TEXTURE, sometimes something else (ex. cube maps)
@@ -224,7 +243,26 @@ class LLImageGL : public LLRefCount
 	static U32 sBindCount;					// Tracks number of texture binds for current frame
 	static U32 sUniqueCount;				// Tracks number of unique texture binds for current frame
 	static BOOL sGlobalUseAnisotropic;
-	static LLImageGL* sDefaultGLTexture ;
+	static LLImageGL* sDefaultGLTexture ;	
+	static BOOL sAutomatedTest;
+
+#if !LL_RELEASE_FOR_DOWNLOAD
+	//for debug use: show texture size distribution 
+	//----------------------------------------
+	static LLPointer<LLImageGL> sDefaultTexturep; //default texture to replace normal textures
+	static std::vector<S32> sTextureLoadedCounter ;
+	static std::vector<S32> sTextureBoundCounter ;
+	static std::vector<S32> sTextureCurBoundCounter ;
+	static S32 sCurTexSizeBar ;
+	static S32 sCurTexPickSize ;
+	
+	static S32 getTextureCounterIndex(U32 val) ;
+	static void incTextureCounter(U32 val) ;
+	static void decTextureCounter(U32 val) ;
+	static void setCurTexSizebar(S32 index) ;
+	static void resetCurTexSizebar();
+	//----------------------------------------
+#endif
 
 #if DEBUG_MISS
 	BOOL mMissed; // Missed on last bind?
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index d577daf3f41..b74d824c9e4 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -45,10 +45,11 @@ LLRender gGL;
 // Handy copies of last good GL matrices
 F64	gGLModelView[16];
 F64	gGLLastModelView[16];
+F64 gGLLastProjection[16];
 F64 gGLProjection[16];
 S32	gGLViewport[4];
 
-static const U32 LL_NUM_TEXTURE_LAYERS = 8; 
+static const U32 LL_NUM_TEXTURE_LAYERS = 16; 
 
 static GLenum sGLTextureType[] =
 {
@@ -311,6 +312,11 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
 
 	if (bindDepth)
 	{
+		if (renderTarget->hasStencil())
+		{
+			llerrs << "Cannot bind a render buffer for sampling.  Allocate render target without a stencil buffer if sampling of depth buffer is required." << llendl;
+		}
+
 		bindManual(renderTarget->getUsage(), renderTarget->getDepth());
 	}
 	else
@@ -328,7 +334,7 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips)
 	{
 		return false;
 	}
-
+	
 	if(mCurrTexture != texture)
 	{
 		gGL.flush();
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 74f87f6d409..cb2a4d44507 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -355,6 +355,7 @@ class LLRender
 
 extern F64 gGLModelView[16];
 extern F64 gGLLastModelView[16];
+extern F64 gGLLastProjection[16];
 extern F64 gGLProjection[16];
 extern S32 gGLViewport[4];
 
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index dc052851ca8..567e3a6c3ea 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -204,7 +204,7 @@ void LLRenderTarget::allocateDepth()
 		gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
 		U32 internal_type = LLTexUnit::getInternalType(mUsage);
 		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
-		LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8_EXT, mResX, mResY, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL);
+		LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT32_ARB, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
 	}
 }
 
@@ -382,7 +382,7 @@ void LLRenderTarget::flush(BOOL fetch_depth)
 				allocateDepth();
 			}
 
-			gGL.getTexUnit(0)->bind(this, true);
+			gGL.getTexUnit(0)->bind(this);
 			glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8_EXT, 0, 0, mResX, mResY, 0);
 		}
 
@@ -392,7 +392,11 @@ void LLRenderTarget::flush(BOOL fetch_depth)
 	{
 #if !LL_DARWIN
 
+		stop_glerror();
+
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+		stop_glerror();
 	
 		if (mSampleBuffer)
 		{
@@ -434,7 +438,6 @@ void LLRenderTarget::flush(BOOL fetch_depth)
 #endif
 
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-		glFlush();
 	}
 }
 
@@ -442,6 +445,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
 						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
 {
 #if !LL_DARWIN
+	gGL.flush();
 	if (!source.mFBO || !mFBO)
 	{
 		llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
@@ -453,12 +457,55 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
 	}
 	else
 	{
-		glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO);
-		glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO);
+		if (mask == GL_DEPTH_BUFFER_BIT && source.mStencil != mStencil)
+		{
+			stop_glerror();
+		
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, source.mFBO);
+			gGL.getTexUnit(0)->bind(this, true);
+			stop_glerror();
+			glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, srcX0, srcY0, dstX0, dstY0, dstX1, dstY1);
+			stop_glerror();
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+			stop_glerror();
+		}
+		else
+		{
+			glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO);
+			stop_glerror();
+			glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFBO);
+			stop_glerror();
+			check_framebuffer_status();
+			stop_glerror();
+			glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+			stop_glerror();
+			glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+			stop_glerror();
+		}
+	}
+#endif
+}
 
+//static
+void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
+						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
+{
+#if !LL_DARWIN
+	if (!source.mFBO)
+	{
+		llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+	}
+	{
+		glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, source.mFBO);
+		stop_glerror();
+		glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+		stop_glerror();
+		check_framebuffer_status();
+		stop_glerror();
 		glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
-
+		stop_glerror();
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+		stop_glerror();
 	}
 #endif
 }
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 98b608f8347..b7ebfc8f7f6 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -121,6 +121,7 @@ class LLRenderTarget
 	U32 getTexture(U32 attachment = 0) const;
 
 	U32 getDepth(void) const { return mDepth; }
+	BOOL hasStencil() const { return mStencil; }
 
 	void bindTexture(U32 index, S32 channel);
 
@@ -135,6 +136,9 @@ class LLRenderTarget
 	void copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
 						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter);
 
+	static void copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
+						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter);
+
 	//Returns TRUE if target is ready to be rendered into.
 	//That is, if the target has been allocated with at least
 	//one renderable attachment (i.e. color buffer, depth buffer).
diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp
index 228e23b67eb..81915731c38 100644
--- a/indra/llui/llfloater.cpp
+++ b/indra/llui/llfloater.cpp
@@ -602,6 +602,8 @@ void LLFloater::openFloater(const LLSD& key)
 
 	mOpenSignal(this, key);
 	onOpen(key);
+
+	dirtyRect();
 }
 
 void LLFloater::closeFloater(bool app_quitting)
@@ -667,7 +669,9 @@ void LLFloater::closeFloater(bool app_quitting)
 				}
 			}
 		}
-		
+
+		dirtyRect();
+
 		// Close callback
 		mCloseSignal(this, LLSD(app_quitting));
 		
@@ -1933,8 +1937,8 @@ void LLFloaterView::restoreAll()
 LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor )
 {
 	LLRect base_rect = reference_floater->getRect();
-	S32 width = neighbor->getRect().getWidth();
-	S32 height = neighbor->getRect().getHeight();
+	LLRect::tCoordType width = neighbor->getRect().getWidth();
+	LLRect::tCoordType height = neighbor->getRect().getHeight();
 	LLRect new_rect = neighbor->getRect();
 
 	LLRect expanded_base_rect = base_rect;
@@ -1953,10 +1957,10 @@ LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLF
 		}
 	}
 
-	S32 left_margin = llmax(0, base_rect.mLeft);
-	S32 right_margin = llmax(0, getRect().getWidth() - base_rect.mRight);
-	S32 top_margin = llmax(0, getRect().getHeight() - base_rect.mTop);
-	S32 bottom_margin = llmax(0, base_rect.mBottom);
+	LLRect::tCoordType left_margin = llmax(0, base_rect.mLeft);
+	LLRect::tCoordType right_margin = llmax(0, getRect().getWidth() - base_rect.mRight);
+	LLRect::tCoordType top_margin = llmax(0, getRect().getHeight() - base_rect.mTop);
+	LLRect::tCoordType bottom_margin = llmax(0, base_rect.mBottom);
 
 	// find position for floater in following order
 	// right->left->bottom->top
@@ -2262,8 +2266,8 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out
 		// floater is hosted elsewhere, so ignore
 		return;
 	}
-	S32 screen_width = getSnapRect().getWidth();
-	S32 screen_height = getSnapRect().getHeight();
+	LLRect::tCoordType screen_width = getSnapRect().getWidth();
+	LLRect::tCoordType screen_height = getSnapRect().getHeight();
 	// convert to local coordinate frame
 	LLRect snap_rect_local = getLocalSnapRect();
 
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index e0bb6bd5d3a..03374b856b2 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -408,6 +408,12 @@ void LLMenuItemGL::onCommit( void )
 	{
 		getMenu()->clearHoverItem();
 	}
+
+	if (mHighlight != highlight)
+	{
+		dirtyRect();
+	}
+
 	mHighlight = highlight;
 }
 
@@ -1233,6 +1239,8 @@ void LLMenuItemBranchGL::openMenu()
 		branch->translate( delta_x, delta_y );
 		branch->setVisible( TRUE );
 		branch->getParent()->sendChildToFront(branch);
+
+		dirtyRect();
 	}
 }
 
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index 720ca692f77..b6eed3ef185 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -329,10 +329,13 @@ void LLTabContainer::draw()
 	}
 	
 	// Hide all the buttons
-	for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
+	if (getTabsHidden())
 	{
-		LLTabTuple* tuple = *iter;
-		tuple->mButton->setVisible( FALSE );
+		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
+		{
+			LLTabTuple* tuple = *iter;
+			tuple->mButton->setVisible( FALSE );
+		}
 	}
 
 	LLPanel::draw();
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 950eaf2ea77..000e85f78c4 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -81,7 +81,8 @@ std::list<std::string> gUntranslated;
 /*static*/ LLWindow*		LLUI::sWindow = NULL;
 /*static*/ LLHtmlHelp*		LLUI::sHtmlHelp = NULL;
 /*static*/ LLView*			LLUI::sRootView = NULL;
-
+/*static*/ BOOL				LLUI::sDirty = FALSE;
+/*static*/ LLRect			LLUI::sDirtyRect;
 /*static*/ std::vector<std::string> LLUI::sXUIPaths;
 /*static*/ LLFrameTimer		LLUI::sMouseIdleTimer;
 
@@ -1603,6 +1604,20 @@ void LLUI::cleanupClass()
 	sImageProvider->cleanUp();
 }
 
+//static
+void LLUI::dirtyRect(LLRect rect)
+{
+	if (!sDirty)
+	{
+		sDirtyRect = rect;
+		sDirty = TRUE;
+	}
+	else
+	{
+		sDirtyRect.unionWith(rect);
+	}		
+}
+ 
 
 //static
 void LLUI::translate(F32 x, F32 y, F32 z)
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 33338f30f9d..fddf8192ade 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -174,6 +174,10 @@ class LLUI
 	static void loadIdentity();
 	static void translate(F32 x, F32 y, F32 z = 0.0f);
 
+	static LLRect	sDirtyRect;
+	static BOOL		sDirty;
+	static void		dirtyRect(LLRect rect);
+
 	// Return the ISO639 language name ("en", "ko", etc.) for the viewer UI.
 	// http://www.loc.gov/standards/iso639-2/php/code_list.php
 	static std::string getLanguage();
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index 46510804f87..8d723877d62 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -143,6 +143,7 @@ LLView::LLView(const LLView::Params& p)
 
 LLView::~LLView()
 {
+	dirtyRect();
 	//llinfos << "Deleting view " << mName << ":" << (void*) this << llendl;
 // 	llassert(LLView::sIsDrawing == FALSE);
 	
@@ -602,6 +603,7 @@ void LLView::setVisible(BOOL visible)
 		if (!getParent() || getParent()->isInVisibleChain())
 		{
 			// tell all children of this view that the visibility may have changed
+			dirtyRect();
 			handleVisibilityChange( visible );
 		}
 		updateBoundingRect();
@@ -1297,7 +1299,7 @@ void LLView::drawChildren()
 			{
 				// Only draw views that are within the root view
 				localRectToScreen(viewp->getRect(),&screenRect);
-				if ( rootRect.overlaps(screenRect) )
+				if ( rootRect.overlaps(screenRect)  && LLUI::sDirtyRect.overlaps(screenRect))
 				{
 					glMatrixMode(GL_MODELVIEW);
 					LLUI::pushMatrix();
@@ -1316,6 +1318,21 @@ void LLView::drawChildren()
 	gGL.getTexUnit(0)->disable();
 }
 
+void LLView::dirtyRect()
+{
+	LLView* child = getParent();
+	LLView* parent = child ? child->getParent() : NULL;
+	LLView* cur = this;
+	while (child && parent && parent->getParent())
+	{ //find third to top-most view
+		cur = child;
+		child = parent;
+		parent = parent->getParent();
+	}
+
+	LLUI::dirtyRect(cur->calcScreenRect());
+}
+
 //Draw a box for debugging.
 void LLView::drawDebugRect()
 {
@@ -1529,6 +1546,8 @@ void LLView::updateBoundingRect()
 {
 	if (isDead()) return;
 
+	LLRect cur_rect = mBoundingRect;
+
 	if (mUseBoundingRect)
 	{
 		mBoundingRect = calcBoundingRect();
@@ -1543,6 +1562,12 @@ void LLView::updateBoundingRect()
 	{
 		getParent()->updateBoundingRect();
 	}
+
+	if (mBoundingRect != cur_rect)
+	{
+		dirtyRect();
+	}
+
 }
 
 LLRect LLView::calcScreenRect() const
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 1f7e5afaaec..bf3b5d0614e 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -519,6 +519,7 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	virtual BOOL	handleUnicodeCharHere(llwchar uni_char);
 
 	virtual void	handleReshape(const LLRect& rect, bool by_user);
+	virtual void	dirtyRect();
 
 	virtual void	notifyParent(const LLSD& info);
 	virtual void	notifyChildren(const LLSD& info);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 96aace9e2d1..8a59b34332f 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -372,6 +372,8 @@ set(viewer_SOURCE_FILES
     lltexglobalcolor.cpp
     lltexlayer.cpp
     lltexlayerparams.cpp
+    lltextureatlas.cpp
+    lltextureatlasmanager.cpp
     lltexturecache.cpp
     lltexturectrl.cpp
     lltexturefetch.cpp
@@ -830,6 +832,8 @@ set(viewer_HEADER_FILES
     lltexglobalcolor.h
     lltexlayer.h
     lltexlayerparams.h
+    lltextureatlas.h
+    lltextureatlasmanager.h
     lltexturecache.h
     lltexturectrl.h
     lltexturefetch.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index bbe69531b42..c794d7d319b 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2597,6 +2597,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>EnableTextureAtlas</key>
+    <map>
+      <key>Comment</key>
+      <string>Whether to use texture atlas or not</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>EnableVoiceChat</key>
     <map>
       <key>Comment</key>
@@ -5513,42 +5524,56 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-
-  <key>RenderShadowGaussian</key>
+  
+  <key>RenderShadowNearDist</key>
   <map>
     <key>Comment</key>
-    <string>Gaussian coefficients for the two shadow/SSAO blurring passes (z component unused).</string>
+    <string>Near clip plane of shadow camera (affects precision of depth shadows).</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
     <string>Vector3</string>
     <key>Value</key>
     <array>
-      <real>2.0</real>
-      <real>2.0</real>
-      <real>0.0</real>
+      <real>256</real>
+      <real>256</real>
+      <real>256</real>
     </array>
   </map>
-
-  <key>RenderShadowNearDist</key>
+  <key>RenderShadowClipPlanes</key>
   <map>
     <key>Comment</key>
-    <string>Near clip plane of shadow camera (affects precision of depth shadows).</string>
+    <string>Near clip plane split distances for shadow map frusta.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
     <string>Vector3</string>
     <key>Value</key>
     <array>
-      <real>256</real>
-      <real>256</real>
-      <real>256</real>
+      <real>1.0</real>
+      <real>12.0</real>
+      <real>32.0</real>
     </array>
   </map>
-  <key>RenderShadowClipPlanes</key>
+  <key>RenderShadowSplitExponent</key>
   <map>
     <key>Comment</key>
-    <string>Near clip plane split distances for shadow map frusta.</string>
+    <string>Near clip plane split distances for shadow map frusta (x=perspective, y=ortho, z=transition rate).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Vector3</string>
+    <key>Value</key>
+    <array>
+      <real>3.0</real>
+      <real>3.0</real>
+      <real>2.0</real>
+    </array>
+  </map>
+  <key>RenderShadowOrthoClipPlanes</key>
+  <map>
+    <key>Comment</key>
+    <string>Near clip plane split distances for orthographic shadow map frusta.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -5560,6 +5585,39 @@
       <real>24.0</real>
     </array>
   </map>
+  <key>RenderShadowProjOffset</key>
+  <map>
+    <key>Comment</key>
+    <string>Amount to scale distance to virtual origin of shadow perspective projection.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>2.0</real>
+  </map>
+  <key>RenderShadowSlopeThreshold</key>
+  <map>
+    <key>Comment</key>
+    <string>Cutoff slope value for points to affect perspective shadow generation</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.0</real>
+  </map>
+  <key>RenderShadowProjExponent</key>
+  <map>
+    <key>Comment</key>
+    <string>Exponent applied to transition between ortho and perspective shadow projections based on viewing angle and light vector.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.5</real>
+  </map>
   <key>RenderSSAOScale</key>
   <map>
     <key>Comment</key>
@@ -5628,7 +5686,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>128</real>
+    <real>64</real>
   </map>
     <key>RenderCubeMap</key>
     <map>
@@ -5707,7 +5765,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
-
+  
   <key>RenderAnimateTrees</key>
   <map>
     <key>Comment</key>
@@ -5719,6 +5777,174 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
+
+  <key>RenderGIRange</key>
+  <map>
+    <key>Comment</key>
+    <string>Distance to cut off GI effect.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>96</real>
+  </map>
+
+  <key>RenderGILuminance</key>
+  <map>
+    <key>Comment</key>
+    <string>Luminance factor of global illumination contribution.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.075</real>
+  </map>
+  
+  <key>RenderGIBrightness</key>
+  <map>
+    <key>Comment</key>
+    <string>Brightness factor of global illumination contribution.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.3</real>
+  </map>
+
+  <key>RenderGINoise</key>
+  <map>
+    <key>Comment</key>
+    <string>Noise of position sampling for GI photon mapping.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.7</real>
+  </map>
+
+  <key>RenderGIAttenuation</key>
+  <map>
+    <key>Comment</key>
+    <string>Distance attenuation factor for indirect lighting.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.1</real>
+  </map>
+
+  <key>RenderGIBlurBrightness</key>
+  <map>
+    <key>Comment</key>
+    <string>Brightness factor of global illumination blur effect.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1.025</real>
+  </map>
+
+  <key>RenderGIBlurEdgeWeight</key>
+  <map>
+    <key>Comment</key>
+    <string>Edge weight for GI soften filter (sharpness).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.8</real>
+  </map>
+
+  <key>RenderGIBlurIncrement</key>
+  <map>
+    <key>Comment</key>
+    <string>Increment of scale for each pass of global illumination blur effect.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.8</real>
+  </map>
+
+  <key>RenderLuminanceScale</key>
+  <map>
+    <key>Comment</key>
+    <string>Luminance value scalar for darkening effect.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1.0</real>
+  </map>
+
+  <key>RenderSunLuminanceScale</key>
+  <map>
+    <key>Comment</key>
+    <string>Sun Luminance value scalar for darkening effect.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1.0</real>
+  </map>
+
+  <key>RenderSunLuminanceOffset</key>
+  <map>
+    <key>Comment</key>
+    <string>Sun Luminance value offset for darkening effect.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0</real>
+  </map>
+
+  <key>RenderLuminanceDetail</key>
+  <map>
+    <key>Comment</key>
+    <string>Mipmap level to use for luminance</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>16.0</real>
+   </map>
+
+  <key>RenderEdgeDepthCutoff</key>
+  <map>
+    <key>Comment</key>
+    <string>Cutoff for depth difference that amounts to an edge.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.01</real>
+  </map>
+  <key>RenderEdgeNormCutoff</key>
+  <map>
+    <key>Comment</key>
+    <string>Cutoff for normal difference that amounts to an edge.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.25</real>
+  </map>
+
   <key>RenderDeferredAlphaSoften</key>
   <map>
     <key>Comment</key>
@@ -5741,94 +5967,489 @@
     <key>Value</key>
     <real>4</real>
   </map>
-  <key>RenderDeferred</key>
+  <key>RenderDeferredSpotShadowBias</key>
   <map>
     <key>Comment</key>
-    <string>Use deferred rendering pipeline.</string>
+    <string>Bias value for spot shadows (prevent shadow acne).</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
-    <string>Boolean</string>
+    <string>F32</string>
     <key>Value</key>
-    <integer>0</integer>
+    <real>-64.0</real>
   </map>
-  <key>RenderDeferredSunShadow</key>
+  <key>RenderDeferredSpotShadowOffset</key>
   <map>
     <key>Comment</key>
-    <string>Generate shadows from the sun.</string>
+    <string>Offset value for spot shadows (prevent shadow acne).</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
-    <string>Boolean</string>
+    <string>F32</string>
     <key>Value</key>
+    <real>0.8</real>
+  </map>
+
+  <key>RenderShadowBias</key>
+  <map>
+    <key>Comment</key>
+    <string>Bias value for shadows (prevent shadow acne).</string>
+    <key>Persist</key>
     <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>-0.008</real>
   </map>
-  <key>RenderDeferredSunWash</key>
+  <key>RenderShadowOffset</key>
   <map>
     <key>Comment</key>
-    <string>Amount local lights are washed out by sun.</string>
+    <string>Offset value for shadows (prevent shadow acne).</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>0.5</real>
+    <real>0.01</real>
   </map>
-  <key>RenderShadowNoise</key>
+
+  <key>RenderShadowResolutionScale</key>
   <map>
     <key>Comment</key>
-    <string>Magnitude of noise on shadow samples.</string>
+    <string>Scale of shadow map resolution vs. screen resolution</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>-0.0001</real>
+    <real>1.0</real>
   </map>
-  <key>RenderShadowBlurSize</key>
+
+
+
+  <key>RenderDeferredTreeShadowBias</key>
   <map>
     <key>Comment</key>
-    <string>Scale of shadow softening kernel.</string>
+    <string>Bias value for tree shadows (prevent shadow acne).</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>0.7</real>
+    <real>1.0</real>
   </map>
-  <key>RenderShadowBlurSamples</key>
+  <key>RenderDeferredTreeShadowOffset</key>
   <map>
     <key>Comment</key>
-    <string>Number of samples to take for each pass of shadow blur (value range 1-16).  Actual number of samples is value * 2 - 1.</string>
+    <string>Offset value for tree shadows (prevent shadow acne).</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
-    <string>U32</string>
+    <string>F32</string>
     <key>Value</key>
-    <real>5</real>
+    <real>1.0</real>
   </map>
-  <key>RenderDynamicLOD</key>
-    <map>
-      <key>Comment</key>
-      <string>Dynamically adjust level of detail.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
-    <key>RenderFSAASamples</key>
-    <map>
-      <key>Comment</key>
-      <string>Number of samples to use for FSAA (0 = no AA).</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>U32</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
+
+  <key>RenderHighlightFadeTime</key>
+  <map>
+    <key>Comment</key>
+    <string>Transition time for mouseover highlights.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.1</real>
+  </map>
+  
+  <key>RenderHighlightBrightness</key>
+  <map>
+    <key>Comment</key>
+    <string>Brightness of mouseover highlights.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>4.0</real>
+  </map>
+
+  <key>RenderHighlightThickness</key>
+  <map>
+    <key>Comment</key>
+    <string>Thickness of mouseover highlights.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.6</real>
+  </map>
+  
+  <key>RenderHighlightColor</key>
+  <map>
+    <key>Comment</key>
+    <string>Brightness of mouseover highlights.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Color4</string>
+    <key>Value</key>
+    <array>
+      <real>0.4</real>
+      <real>0.98</real>
+      <real>0.93</real>
+      <real>1.0</real>
+    </array>
+  </map>
+
+  <key>RenderSpecularResX</key>
+  <map>
+    <key>Comment</key>
+    <string>Spec map resolution.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>128</real>
+  </map>
+
+  <key>RenderSpecularResY</key>
+  <map>
+    <key>Comment</key>
+    <string>Spec map resolution.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>128</real>
+  </map>
+
+  <key>RenderSpecularExponent</key>
+  <map>
+    <key>Comment</key>
+    <string>Specular exponent for generating spec map</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1</real>
+  </map>
+
+  <key>RenderDeferred</key>
+  <map>
+    <key>Comment</key>
+    <string>Use deferred rendering pipeline.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+
+  <key>RenderDeferredShadow</key>
+  <map>
+    <key>Comment</key>
+    <string>Enable shadows in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
+  <key>RenderDeferredGI</key>
+  <map>
+    <key>Comment</key>
+    <string>Enable GI in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+
+  <key>RenderDeferredSunShadow</key>
+  <map>
+    <key>Comment</key>
+    <string>Generate shadows from the sun.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
+  <key>RenderDeferredSun</key>
+  <map>
+    <key>Comment</key>
+    <string>Execute sunlight shader in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
+  <key>RenderDeferredAtmospheric</key>
+  <map>
+    <key>Comment</key>
+    <string>Execute atmospheric shader in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
+  <key>RenderDeferredBlurLight</key>
+  <map>
+    <key>Comment</key>
+    <string>Execute shadow softening shader in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
+  <key>RenderDeferredLocalLights</key>
+  <map>
+    <key>Comment</key>
+    <string>Execute local lighting shader in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
+  <key>RenderDeferredFullscreenLights</key>
+  <map>
+    <key>Comment</key>
+    <string>Execute local lighting shader in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
+  <key>RenderDeferredSunWash</key>
+  <map>
+    <key>Comment</key>
+    <string>Amount local lights are washed out by sun.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.5</real>
+  </map>
+  <key>RenderShadowNoise</key>
+  <map>
+    <key>Comment</key>
+    <string>Magnitude of noise on shadow samples.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>-0.0001</real>
+  </map>
+  <key>RenderShadowErrorCutoff</key>
+  <map>
+    <key>Comment</key>
+    <string>Cutoff error value to use ortho instead of perspective projection.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>5.0</real>
+  </map>
+  <key>RenderShadowFOVCutoff</key>
+  <map>
+    <key>Comment</key>
+    <string>Cutoff FOV to use ortho instead of perspective projection.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1.1</real>
+  </map>
+
+  <key>RenderShadowGaussian</key>
+  <map>
+    <key>Comment</key>
+    <string>Gaussian coefficients for the two shadow/SSAO blurring passes (z component unused).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Vector3</string>
+    <key>Value</key>
+    <array>
+      <real>3.0</real>
+      <real>2.0</real>
+      <real>0.0</real>
+    </array>
+  </map>
+
+  <key>RenderShadowBlurSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Scale of shadow softening kernel.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>1.4</real>
+  </map>
+  <key>RenderShadowBlurSamples</key>
+  <map>
+    <key>Comment</key>
+    <string>Number of samples to take for each pass of shadow blur (value range 1-16).  Actual number of samples is value * 2 - 1.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>4</real>
+  </map>
+  <key>RenderShadowBlurDistFactor</key>
+  <map>
+    <key>Comment</key>
+    <string>Distance scaler for shadow blur.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.1</real>
+  </map>
+
+  <key>RenderGIAmbiance</key>
+  <map>
+    <key>Comment</key>
+    <string>Ambiance factor of global illumination contribution.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.5</real>
+  </map>
+
+  <key>RenderGIMinRenderSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Minimum size of objects to put into GI source map.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.5</real>
+  </map>
+
+  <key>RenderGIBlurColorCurve</key>
+  <map>
+    <key>Comment</key>
+    <string>Color curve for GI softening kernel</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Vector3</string>
+    <key>Value</key>
+    <array>
+      <real>1.0</real>
+      <real>0.6</real>
+      <real>0.02</real>
+    </array>
+  </map>
+
+  <key>RenderGIBlurPasses</key>
+  <map>
+    <key>Comment</key>
+    <string>Scale of GI softening kernel.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>4</real>
+  </map>
+
+  <key>RenderGIBlurSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Scale of GI softening kernel.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>4.0</real>
+  </map>
+  <key>RenderGIBlurSamples</key>
+  <map>
+    <key>Comment</key>
+    <string>Number of samples to take for each pass of GI blur (value range 1-16).  Actual number of samples is value * 2 - 1.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>16</real>
+  </map>
+  <key>RenderGIBlurDistFactor</key>
+  <map>
+    <key>Comment</key>
+    <string>Distance scaler for GI blur.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.0</real>
+  </map>
+
+  <key>RenderDynamicLOD</key>
+    <map>
+      <key>Comment</key>
+      <string>Dynamically adjust level of detail.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+    <key>RenderFSAASamples</key>
+    <map>
+      <key>Comment</key>
+      <string>Number of samples to use for FSAA (0 = no AA).</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RenderFarClip</key>
     <map>
       <key>Comment</key>
@@ -6143,7 +6764,7 @@
     <key>Type</key>
     <string>S32</string>
     <key>Value</key>
-    <integer>4096</integer>
+    <integer>8192</integer>
   </map>
     <key>RenderMaxVBOSize</key>
     <map>
@@ -6354,6 +6975,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>RenderUIBuffer</key>
+    <map>
+      <key>Comment</key>
+      <string>Cache ui render in a screen aligned buffer.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RenderUnloadedAvatar</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index a91e9fa15b7..4fb109d6870 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -8,14 +8,10 @@
 #extension GL_ARB_texture_rectangle : enable
 
 uniform sampler2D diffuseMap;
-uniform sampler2DShadow shadowMap0;
-uniform sampler2DShadow shadowMap1;
-uniform sampler2DShadow shadowMap2;
-uniform sampler2DShadow shadowMap3;
 uniform sampler2D noiseMap;
-uniform sampler2DRect positionMap;
+uniform sampler2DRect depthMap;
 
-uniform mat4 shadow_matrix[4];
+uniform mat4 shadow_matrix[6];
 uniform vec4 shadow_clip;
 uniform vec2 screen_res;
 
@@ -26,52 +22,42 @@ varying vec3 vary_ambient;
 varying vec3 vary_directional;
 varying vec3 vary_fragcoord;
 varying vec3 vary_position;
+varying vec3 vary_light;
 
 uniform float alpha_soften;
 
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
 void main() 
 {
 	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
 	frag *= screen_res;
 	
-	vec3 samp_pos = texture2DRect(positionMap, frag).xyz;
+	vec3 samp_pos = getPosition(frag).xyz;
 	
-	float shadow = 1.0;
 	vec4 pos = vec4(vary_position, 1.0);
 	
-	if (pos.z > -shadow_clip.w)
-	{	
-		if (pos.z < -shadow_clip.z)
-		{
-			vec4 lpos = shadow_matrix[3]*pos;
-			shadow = shadow2DProj(shadowMap3, lpos).x;
-			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
-		}
-		else if (pos.z < -shadow_clip.y)
-		{
-			vec4 lpos = shadow_matrix[2]*pos;
-			shadow = shadow2DProj(shadowMap2, lpos).x;
-		}
-		else if (pos.z < -shadow_clip.x)
-		{
-			vec4 lpos = shadow_matrix[1]*pos;
-			shadow = shadow2DProj(shadowMap1, lpos).x;
-		}
-		else
-		{
-			vec4 lpos = shadow_matrix[0]*pos;
-			shadow = shadow2DProj(shadowMap0, lpos).x;
-		}
-	}
-	
-	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, gl_Color.a);
+	vec4 col = vec4(vary_ambient + vary_directional.rgb, gl_Color.a);
 	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
 	
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
 
-	if (samp_pos.z != 0.0)
+	if (samp_pos.z != 0.0 && gl_Color.a < 1.0)
 	{
 		float dist_factor = alpha_soften;
 		float a = gl_Color.a;
@@ -83,6 +69,7 @@ void main()
 	//gl_FragColor = gl_Color;
 	gl_FragColor = color;
 	//gl_FragColor = vec4(1,0,1,1);
+	//gl_FragColor = vec4(1,0,1,1)*shadow;
 	
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index b496bd674fa..1a7d58b07ba 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -20,8 +20,11 @@ varying vec3 vary_ambient;
 varying vec3 vary_directional;
 varying vec3 vary_fragcoord;
 varying vec3 vary_position;
+varying vec3 vary_light;
 
 uniform float near_clip;
+uniform float shadow_offset;
+uniform float shadow_bias;
 
 void main()
 {
@@ -32,8 +35,9 @@ void main()
 	
 	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
-	vary_position = pos.xyz;
 	
+	vary_position = pos.xyz + norm.xyz * (-pos.z/64.0*shadow_offset+shadow_bias);
+		
 	calcAtmospherics(pos.xyz);
 
 	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
@@ -54,6 +58,8 @@ void main()
 	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
 	col.rgb = scaleDownLight(col.rgb);
 	
+	vary_light = gl_LightSource[0].position.xyz;
+	
 	vary_ambient = col.rgb*gl_Color.rgb;
 	vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
 	
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
index 6c94f5c5a7a..ff64a6b0c33 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaF.glsl
@@ -12,7 +12,7 @@ uniform sampler2DShadow shadowMap2;
 uniform sampler2DShadow shadowMap3;
 uniform sampler2D noiseMap;
 
-uniform mat4 shadow_matrix[4];
+uniform mat4 shadow_matrix[6];
 uniform vec4 shadow_clip;
 
 vec3 atmosLighting(vec3 light);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
index 58aa5a9cb5d..75df3889418 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
@@ -8,13 +8,18 @@
 uniform sampler2D diffuseMap;
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 void main() 
 {
-	gl_FragData[0] = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 diff = gl_Color*texture2D(diffuseMap, gl_TexCoord[0].xy);
+	
+	if (diff.a < 0.2)
+	{
+		discard;
+	}
+	
+	gl_FragData[0] = vec4(diff.rgb, 0.0);
 	gl_FragData[1] = vec4(0,0,0,0);
-	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
-	gl_FragData[3] = vary_position;
+	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
index 27c09db9220..00083eb6b39 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
@@ -10,6 +10,7 @@ uniform sampler2D diffuseMap;
 
 void main() 
 {
-	gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy));
+	gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy).a);
+	//gl_FragColor = vec4(1,1,1,1);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
index 14da6b1ad45..8c8489d087f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
@@ -28,8 +28,7 @@ void main()
 	norm = normalize(norm);
 	
 	pos = gl_ProjectionMatrix * pos;
-	//smash geometry against near clip plane
-	pos.z = max(pos.z, -1.0);
+	pos.z = max(pos.z, -pos.w+0.01);
 	gl_Position = pos;
 	
 	gl_FrontColor = gl_Color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
index 12a7ff7f297..471a1f04071 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarV.glsl
@@ -10,7 +10,6 @@ mat4 getSkinnedTransform();
 attribute vec4 weight;
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 void main()
 {
@@ -30,7 +29,6 @@ void main()
 	norm.z = dot(trans[2].xyz, gl_Normal);
 	norm = normalize(norm);
 	
-	vary_position = pos;
 	vary_normal = norm;
 	
 	gl_Position = gl_ProjectionMatrix * pos;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index 3c6700a871f..bd5e9dd7580 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -7,10 +7,12 @@
 
 #extension GL_ARB_texture_rectangle : enable
 
-uniform sampler2DRect positionMap;
+uniform sampler2DRect depthMap;
 uniform sampler2DRect normalMap;
 uniform sampler2DRect lightMap;
+uniform sampler2DRect giLightMap;
 
+uniform float dist_factor;
 uniform float blur_size;
 uniform vec2 delta;
 uniform vec3 kern[32];
@@ -19,30 +21,52 @@ uniform float kern_scale;
 
 varying vec2 vary_fragcoord;
 
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
 void main() 
 {
-	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
-	vec3 pos = texture2DRect(positionMap, vary_fragcoord.xy).xyz;
-	vec2 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 pos = getPosition(vary_fragcoord.xy).xyz;
+	vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba;
 	
 	vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy);
 	
+	dlt /= max(-pos.z*dist_factor, 1.0);
+	
 	vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
-	vec2 col = defined_weight * ccol;
+	vec4 col = defined_weight.xyxx * ccol;
 	
 	for (int i = 1; i < kern_length; i++)
 	{
 		vec2 tc = vary_fragcoord.xy + kern[i].z*dlt;
-	        vec3 samppos = texture2DRect(positionMap, tc).xyz;
+	        vec3 samppos = getPosition(tc).xyz; 
 		float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
 		if (d*d <= 0.003)
 		{
-			col += texture2DRect(lightMap, tc).rg*kern[i].xy;
+			col += texture2DRect(lightMap, tc)*kern[i].xyxx;
 			defined_weight += kern[i].xy;
 		}
 	}
 
-	col /= defined_weight;
 
-	gl_FragColor = vec4(col.r, col.g, 0.0, 1.0);
+
+	col /= defined_weight.xyxx;
+	
+	gl_FragColor = col;
+	
+	//gl_FragColor = ccol;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index a8712bc8cc7..1c29dae5f7c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -11,7 +11,6 @@ uniform sampler2D bumpMap;
 varying vec3 vary_mat0;
 varying vec3 vary_mat1;
 varying vec3 vary_mat2;
-varying vec4 vary_position;
 
 void main() 
 {
@@ -22,8 +21,7 @@ void main()
 					  dot(norm,vary_mat1),
 					  dot(norm,vary_mat2));
 						
-	gl_FragData[0].rgb = gl_Color.rgb*col;
-	gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a);
-	gl_FragData[2] = vec4(normalize(tnorm), 0.0);
-	gl_FragData[3] = vary_position;
+	gl_FragData[0] = vec4(gl_Color.rgb*col, 0.0);
+	gl_FragData[1] = vec4(col*gl_Color.a, gl_Color.a);
+	gl_FragData[2] = vec4(normalize(tnorm)*0.5+0.5, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
index ba180922cc1..9589912c6ce 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
@@ -8,7 +8,6 @@
 varying vec3 vary_mat0;
 varying vec3 vary_mat1;
 varying vec3 vary_mat2;
-varying vec4 vary_position;
 
 void main()
 {
@@ -16,8 +15,6 @@ void main()
 	gl_Position = ftransform(); 
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vary_position = gl_ModelViewMatrix * gl_Vertex;
-	
 	vec3 n = normalize(gl_NormalMatrix * gl_Normal);
 	vec3 b = normalize(gl_NormalMatrix * gl_MultiTexCoord2.xyz);
 	vec3 t = cross(b, n);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
index f2ba2df69a0..5895ebda84c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
@@ -8,13 +8,11 @@
 uniform sampler2D diffuseMap;
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 void main() 
 {
 	vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
-	gl_FragData[0] = vec4(gl_Color.rgb*col, 1.0);
+	gl_FragData[0] = vec4(gl_Color.rgb*col, 0.0);
 	gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a);
-	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
-	gl_FragData[3] = vary_position;
+	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 3413a7f9d6e..44468cdfa29 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -6,16 +6,13 @@
  */
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 void main()
 {
 	//transform vertex
-	gl_Position = ftransform(); 
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vary_position = gl_ModelViewMatrix * gl_Vertex;
-	
 	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
 
 	gl_FrontColor = gl_Color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index 2a811c58971..e518bddb984 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -8,14 +8,9 @@
 #extension GL_ARB_texture_rectangle : enable
 
 uniform sampler2D diffuseMap;
-uniform sampler2DShadow shadowMap0;
-uniform sampler2DShadow shadowMap1;
-uniform sampler2DShadow shadowMap2;
-uniform sampler2DShadow shadowMap3;
+uniform sampler2DRect depthMap;
 uniform sampler2D noiseMap;
-uniform sampler2DRect positionMap;
 
-uniform mat4 shadow_matrix[4];
 uniform vec4 shadow_clip;
 uniform vec2 screen_res;
 
@@ -30,12 +25,27 @@ varying vec3 vary_fragcoord;
 
 uniform float alpha_soften;
 
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
 void main() 
 {
 	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
 	frag *= screen_res;
 	
-	vec3 samp_pos = texture2DRect(positionMap, frag).xyz;
+	vec3 samp_pos = getPosition(frag).xyz; 
 	
 	float shadow = 1.0;
 	vec4 pos = vary_position;
@@ -46,10 +56,10 @@ void main()
 
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
-	if (samp_pos.z != 0.0)
+	if (samp_pos.z != 0.0 && color.a < 1.0)
 	{
 		float dist_factor = alpha_soften;
-		float a = gl_Color.a;
+		float a = color.a;
 		a *= a;
 		dist_factor *= 1.0/(1.0-a);
 		color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index 6381a1ced8c..aff51178b05 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -12,12 +12,12 @@ vec3 atmosAffectDirectionalLight(float lightIntensity);
 vec3 scaleDownLight(vec3 light);
 vec3 scaleUpLight(vec3 light);
 
-varying vec4 vary_position;
 varying vec3 vary_ambient;
 varying vec3 vary_directional;
 varying vec3 vary_normal;
 varying vec3 vary_fragcoord;
 uniform float near_clip;
+varying vec4 vary_position;
 
 void main()
 {
diff --git a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
new file mode 100644
index 00000000000..b351eec6e54
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
@@ -0,0 +1,165 @@
+/** 
+ * @file giF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2D noiseMap;
+
+uniform sampler2D		diffuseGIMap;
+uniform sampler2D		normalGIMap;
+uniform sampler2D		depthGIMap;
+
+uniform sampler2D		lightFunc;
+
+// Inputs
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+uniform mat4 gi_mat;  //gPipeline.mGIMatrix - eye space to sun space
+uniform mat4 gi_mat_proj; //gPipeline.mGIMatrixProj - eye space to projected sun space
+uniform mat4 gi_norm_mat; //gPipeline.mGINormalMatrix - eye space normal to sun space normal matrix
+uniform mat4 gi_inv_proj; //gPipeline.mGIInvProj - projected sun space to sun space
+uniform float gi_radius;
+uniform float gi_intensity;
+uniform int gi_samples;
+uniform vec2 gi_kern[25];
+uniform vec2 gi_scale;
+uniform vec3 gi_quad;
+uniform vec3 gi_spec;
+uniform float gi_direction_weight;
+uniform float gi_light_offset;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec4 getGIPosition(vec2 gi_tc)
+{
+	float depth = texture2D(depthGIMap, gi_tc).a;
+	vec2 sc = gi_tc*2.0;
+	sc -= vec2(1.0, 1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = gi_inv_proj*ndc;
+	pos.xyz /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec3 giAmbient(vec3 pos, vec3 norm)
+{
+	vec4 gi_c = gi_mat_proj * vec4(pos, 1.0);
+	gi_c.xyz /= gi_c.w;
+
+	vec4 gi_pos = gi_mat*vec4(pos,1.0);
+	vec3 gi_norm = (gi_norm_mat*vec4(norm,1.0)).xyz;
+	gi_norm = normalize(gi_norm);
+	
+	vec2 tcx = gi_norm.xy;
+	vec2 tcy = gi_norm.yx;
+	
+	vec4 eye_pos = gi_mat*vec4(0,0,0,1.0);
+	
+	vec3 eye_dir = normalize(gi_pos.xyz-eye_pos.xyz/eye_pos.w);
+	
+	//vec3 eye_dir = vec3(0,0,-1);
+	//eye_dir = (gi_norm_mat*vec4(eye_dir, 1.0)).xyz;
+	//eye_dir = normalize(eye_dir);
+	
+	//float round_x = gi_scale.x;
+	//float round_y = gi_scale.y;
+	
+	vec3 debug = texture2D(normalGIMap, gi_c.xy).rgb*0.5+0.5;
+	debug.xz = vec2(0.0,0.0);
+	//debug = fract(debug);
+	
+	float round_x = 1.0/64.0;
+	float round_y = 1.0/64.0;
+	
+	//gi_c.x = floor(gi_c.x/round_x+0.5)*round_x;
+	//gi_c.y = floor(gi_c.y/round_y+0.5)*round_y;
+	
+	float fda = 0.0;
+	vec3 fdiff = vec3(0,0,0);
+	
+	vec3 rcol = vec3(0,0,0);
+	
+	float fsa = 0.0;
+	
+	for (int i = -1; i < 2; i+=2 )
+	{
+		for (int j = -1; j < 2; j+=2)
+		{
+			vec2 tc = vec2(i, j)*0.75;
+			vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0+tc*0.5).xyz;
+			//tc += gi_norm.xy*nz.z;
+			tc += nz.xy*2.0;
+			tc /= gi_samples;
+			tc += gi_c.xy;
+			
+			vec3 lnorm = -normalize(texture2D(normalGIMap, tc.xy).xyz*2.0-1.0);
+			vec3 lpos = getGIPosition(tc.xy).xyz;
+							
+			vec3 at = lpos-gi_pos.xyz;
+			float dist = dot(at,at);
+			float da = clamp(1.0/(gi_spec.x*dist), 0.0, 1.0);
+			
+			if (da > 0.0)
+			{
+				//add angular attenuation
+				vec3 ldir = at;
+				float ang_atten = clamp(dot(ldir, gi_norm), 0.0, 1.0);
+			
+				float ld = -dot(ldir, lnorm);
+				
+				if (ang_atten > 0.0 && ld < 0.0)
+				{
+					vec3 diff = texture2D(diffuseGIMap, tc.xy).xyz;
+					da = da*ang_atten;
+					fda += da;
+					fdiff += diff*da;
+				}
+			}
+		}
+	}
+
+	fdiff /= max(gi_spec.y*fda, gi_quad.z);
+	fdiff = clamp(fdiff, vec3(0), vec3(1));
+	
+	vec3 ret = fda*fdiff;
+	//ret = ret*ret*gi_quad.x+ret*gi_quad.y+gi_quad.z;			
+
+	//fda *= nz.z;
+	
+	//rcol.rgb *= gi_intensity;
+	//return rcol.rgb+vary_AmblitColor.rgb*0.25;
+	//return vec4(debug, 0.0);
+	//return vec4(fda*fdiff, 0.0);
+	return clamp(ret,vec3(0.0), vec3(1.0));
+	//return debug.xyz;
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	vec4 pos = getPosition(pos_screen);
+	vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+	
+	gl_FragData[0].xyz = giAmbient(pos, norm);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/giV.glsl b/indra/newview/app_settings/shaders/class1/deferred/giV.glsl
new file mode 100644
index 00000000000..71dcea9628e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/giV.glsl
@@ -0,0 +1,22 @@
+/** 
+ * @file giV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res;	
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
index 20a3f3df5b5..8c140a7b4f0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
@@ -9,12 +9,9 @@ uniform sampler2D diffuseMap;
 uniform sampler2D normalMap;
 uniform sampler2D specularMap;
 
-varying vec4 vary_position;
-
 void main() 
 {
 	gl_FragData[0] = texture2D(diffuseMap, gl_TexCoord[0].xy);
 	gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy);
-	gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, vary_position.z);
-	gl_FragData[3] = vary_position;
+	gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
index 9c5ae315415..57532a30b33 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorV.glsl
@@ -5,15 +5,11 @@
  * $License$
  */
 
-varying vec4 vary_position;
-
 void main()
 {
 	//transform vertex
 	gl_Position = ftransform(); 
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vary_position = gl_ModelViewMatrix * gl_Vertex;
-
 	gl_FrontColor = gl_Color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
new file mode 100644
index 00000000000..e8b53b02937
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
@@ -0,0 +1,15 @@
+/** 
+ * @file luminanceF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect diffuseMap;
+
+varying vec2 vary_fragcoord;
+
+void main() 
+{
+	gl_FragColor = texture2DRect(diffuseMap, vary_fragcoord.xy);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl
new file mode 100644
index 00000000000..db8775f024b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceV.glsl
@@ -0,0 +1,20 @@
+/** 
+ * @file giV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res;	
+
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 3689d12840a..797b9e9f3bf 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -7,13 +7,14 @@
 
 #extension GL_ARB_texture_rectangle : enable
 
+uniform sampler2DRect depthMap;
 uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
-uniform sampler2DRect positionMap;
 uniform sampler2DRect normalMap;
 uniform samplerCube environmentMap;
-uniform sampler2DRect lightMap;
 uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+
 
 uniform vec3 env_mat[3];
 uniform float sun_wash;
@@ -23,24 +24,48 @@ uniform int light_count;
 uniform vec4 light[16];
 uniform vec4 light_col[16];
 
-varying vec3 vary_fragcoord;
+varying vec4 vary_fragcoord;
 uniform vec2 screen_res;
 
+uniform float far_z;
+
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
 void main() 
 {
 	vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res;
-	vec3 pos = texture2DRect(positionMap, frag.xy).xyz;
-	vec3 norm = normalize(texture2DRect(normalMap, frag.xy).xyz);
+	vec3 pos = getPosition(frag.xy).xyz;
+	if (pos.z < far_z)
+	{
+		discard;
+	}
+	
+	vec3 norm = normalize(texture2DRect(normalMap, frag.xy).xyz*2.0-1.0);
 	vec4 spec = texture2DRect(specularRect, frag.xy);
 	vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb;
 	float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	vec3 out_col = vec3(0,0,0);
+	vec3 npos = normalize(-pos);
 	
 	for (int i = 0; i < light_count; ++i)
 	{
 		vec3 lv = light[i].xyz-pos;
 		float dist2 = dot(lv,lv);
-		if (dist2 > light[i].w)
+		dist2 /= light[i].w;
+		if (dist2 > 1.0)
 		{
 			continue;
 		}
@@ -55,29 +80,38 @@ void main()
 		da = dot(norm, lv);
 				
 		float fa = light_col[i].a+1.0;
-		float dist_atten = clamp(1.0-(dist2-light[i].w*(1.0-fa))/(light[i].w*fa), 0.0, 1.0);
+		float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
 		dist_atten *= noise;
 
 		float lit = da * dist_atten;
 		
 		vec3 col = light_col[i].rgb*lit*diff;
+		//vec3 col = vec3(dist2, light_col[i].a, lit);
 		
 		if (spec.a > 0.0)
 		{
-			vec3 ref = reflect(normalize(pos), norm);
-			float sa = dot(ref,lv);
-			sa = max(sa, 0.0);
-			sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
-			sa *= noise;
-			col += da*sa*light_col[i].rgb*spec.rgb;
+			//vec3 ref = dot(pos+lv, norm);
+			
+			float sa = dot(normalize(lv+npos),norm);
+			
+			if (sa > 0.0)
+			{
+				sa = texture2D(lightFunc,vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
+				sa *= noise;
+				col += da*sa*light_col[i].rgb*spec.rgb;
+			}
 		}
 		
 		out_col += col;	
 	}
 	
-	//attenuate point light contribution by SSAO component
-	out_col *= texture2DRect(lightMap, frag.xy).g;
+	if (dot(out_col, out_col) <= 0.0)
+	{
+		discard;
+	}
 	
 	gl_FragColor.rgb = out_col;
 	gl_FragColor.a = 0.0;
+	
+	//gl_FragColor = vec4(0.1, 0.025, 0.025/4.0, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
new file mode 100644
index 00000000000..28bcd720c0a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
@@ -0,0 +1,178 @@
+/** 
+ * @file multiSpotLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+void main() 
+{
+	vec4 frag = vary_fragcoord;
+	frag.xyz /= frag.w;
+	frag.xyz = frag.xyz*0.5+0.5;
+	frag.xy *= screen_res;
+	
+	vec3 pos = getPosition(frag.xy).xyz;
+	vec3 lv = vary_light.xyz-pos.xyz;
+	float dist2 = dot(lv,lv);
+	dist2 /= vary_light.w;
+	if (dist2 > 1.0)
+	{
+		discard;
+	}
+	
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	
+	norm = normalize(norm);
+	float l_dist = -dot(lv, proj_n);
+	
+	vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+	if (proj_tc.z < 0.0)
+	{
+		discard;
+	}
+	
+	proj_tc.xyz /= proj_tc.w;
+	
+	float fa = gl_Color.a+1.0;
+	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+	
+	lv = proj_origin-pos.xyz;
+	lv = normalize(lv);
+	float da = dot(norm, lv);
+		
+	vec3 col = vec3(0,0,0);
+		
+	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
+		
+	float noise = texture2D(noiseMap, frag.xy/128.0).b;
+	if (proj_tc.z > 0.0 &&
+		proj_tc.x < 1.0 &&
+		proj_tc.y < 1.0 &&
+		proj_tc.x > 0.0 &&
+		proj_tc.y > 0.0)
+	{
+		float lit = 0.0;
+		if (da > 0.0)
+		{
+			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+			float lod = diff * proj_lod;
+			
+			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+		
+			vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+			lit = da * dist_atten * noise;
+			
+			col = lcol*lit*diff_tex;
+		}
+		
+		float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+		float lod = diff * proj_lod;
+		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+		//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
+		float amb_da = proj_ambiance;
+		
+		amb_da += (da*da*0.5+0.5)*proj_ambiance;
+			
+		amb_da *= dist_atten * noise;
+		
+		amb_da = min(amb_da, 1.0-lit);
+		
+		col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+	}
+	
+	
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+	if (spec.a > 0.0)
+	{
+		vec3 ref = reflect(normalize(pos), norm);
+		
+		//project from point pos in direction ref to plane proj_p, proj_n
+		vec3 pdelta = proj_p-pos;
+		float ds = dot(ref, proj_n);
+		
+		if (ds < 0.0)
+		{
+			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+			vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
+
+			if (stc.z > 0.0)
+			{
+				stc.xy /= stc.z+proj_near;
+					
+				if (stc.x < 1.0 &&
+					stc.y < 1.0 &&
+					stc.x > 0.0 &&
+					stc.y > 0.0)
+				{
+					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb;
+				}
+			}
+		}
+	}
+	
+	/*if (spec.a > 0.0)
+	{
+		//vec3 ref = reflect(normalize(pos), norm);
+		float sa = dot(normalize(lv-normalize(pos)),norm);;
+		//sa = max(sa, 0.0);
+		//sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
+		sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
+		sa *= noise;
+		col += da*sa*lcol*spec.rgb;
+	}*/
+	
+	gl_FragColor.rgb = col;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index 52bad1f34cc..78256e20cc6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -9,33 +9,53 @@
 
 uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
-uniform sampler2DRect positionMap;
 uniform sampler2DRect normalMap;
 uniform samplerCube environmentMap;
-uniform sampler2DRect lightMap;
 uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2DRect depthMap;
 
 uniform vec3 env_mat[3];
 uniform float sun_wash;
 
 varying vec4 vary_light;
 
-varying vec3 vary_fragcoord;
+varying vec4 vary_fragcoord;
 uniform vec2 screen_res;
 
+uniform mat4 inv_proj;
+uniform vec4 viewport;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = (pos_screen.xy-viewport.xy)*2.0;
+	sc /= viewport.zw;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
 void main() 
 {
-	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
-	frag *= screen_res;	
-	vec3 pos = texture2DRect(positionMap, frag).xyz;
+	vec4 frag = vary_fragcoord;
+	frag.xyz /= frag.w;
+	frag.xyz = frag.xyz*0.5+0.5;
+	frag.xy *= screen_res;
+	
+	vec3 pos = getPosition(frag.xy).xyz;
 	vec3 lv = vary_light.xyz-pos;
 	float dist2 = dot(lv,lv);
-	if (dist2 > vary_light.w)
+	dist2 /= vary_light.w;
+	if (dist2 > 1.0)
 	{
 		discard;
 	}
 	
-	vec3 norm = texture2DRect(normalMap, frag).xyz;
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
 	float da = dot(norm, lv);
 	if (da < 0.0)
 	{
@@ -46,30 +66,32 @@ void main()
 	lv = normalize(lv);
 	da = dot(norm, lv);
 	
-	float noise = texture2D(noiseMap, frag/128.0).b;
+	float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	
-	vec3 col = texture2DRect(diffuseRect, frag).rgb;
+	vec3 col = texture2DRect(diffuseRect, frag.xy).rgb;
 	float fa = gl_Color.a+1.0;
-	float dist_atten = clamp(1.0-(dist2-vary_light.w*(1.0-fa))/(vary_light.w*fa), 0.0, 1.0);
+	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
 	float lit = da * dist_atten * noise;
 	
 	col = gl_Color.rgb*lit*col;
 
-	vec4 spec = texture2DRect(specularRect, frag);
+	vec4 spec = texture2DRect(specularRect, frag.xy);
 	if (spec.a > 0.0)
 	{
-		vec3 ref = reflect(normalize(pos), norm);
-		float sa = dot(ref,lv);
-		sa = max(sa, 0.0);
-		sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
-		sa *= noise;
-		col += da*sa*gl_Color.rgb*spec.rgb;
+		float sa = dot(normalize(lv-normalize(pos)),norm);
+		if (sa > 0.0)
+		{
+			sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
+			sa *= noise;
+			col += da*sa*gl_Color.rgb*spec.rgb;
+		}
 	}
 	
-	//attenuate point light contribution by SSAO component
-	col *= texture2DRect(lightMap, frag.xy).g;
-	
-
+	if (dot(col, col) <= 0.0)
+	{
+		discard;
+	}
+		
 	gl_FragColor.rgb = col;	
 	gl_FragColor.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
index a4edb88259f..e815ca260fd 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
@@ -6,7 +6,7 @@
  */
 
 varying vec4 vary_light;
-varying vec3 vary_fragcoord;
+varying vec4 vary_fragcoord;
 
 uniform vec2 screen_res;
 uniform float near_clip;
@@ -14,10 +14,10 @@ uniform float near_clip;
 void main()
 {
 	//transform vertex
-	gl_Position = ftransform(); 
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
 
 	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
-	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
+	vary_fragcoord = pos;
 		
 	vec4 tex = gl_MultiTexCoord0;
 	tex.w = 1.0;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
new file mode 100644
index 00000000000..71de03663c0
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
@@ -0,0 +1,57 @@
+/** 
+ * @file postDeferredF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect localLightMap;
+uniform sampler2DRect sunLightMap;
+uniform sampler2DRect giLightMap;
+uniform sampler2D	  luminanceMap;
+uniform sampler2DRect lightMap;
+
+uniform vec3 lum_quad;
+uniform float lum_lod;
+uniform vec4 ambient;
+
+uniform vec3 gi_quad;
+
+uniform vec2 screen_res;
+varying vec2 vary_fragcoord;
+
+void main() 
+{
+	vec2 tc = vary_fragcoord.xy;
+	vec3 lum = texture2DLod(luminanceMap, tc/screen_res, lum_lod).rgb;
+	float luminance = lum.r;
+	luminance = luminance*lum_quad.y+lum_quad.z;
+
+	vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
+
+	float ambocc = texture2DRect(lightMap, vary_fragcoord.xy).g;
+			
+	vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
+	gi_col = gi_col*gi_col*gi_quad.x + gi_col*gi_quad.y+gi_quad.z*ambocc*ambient.rgb;
+	gi_col *= diff;
+	
+	vec4 sun_col =	texture2DRect(sunLightMap, vary_fragcoord.xy);
+	
+	vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb;
+		
+		
+	sun_col *= 1.0/min(luminance, 1.0);
+	gi_col *= 1.0/luminance;
+		
+	vec3 col = sun_col.rgb+gi_col+local_col;
+	
+	gl_FragColor.rgb = col.rgb;
+	col.rgb = max(col.rgb-vec3(1.0,1.0,1.0), vec3(0.0, 0.0, 0.0)); 
+	
+	gl_FragColor.a = 0.0; // max(dot(col.rgb,col.rgb)*lum_quad.x, sun_col.a);
+	
+	//gl_FragColor.rgb = vec3(lum_lod);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl
new file mode 100644
index 00000000000..9819232fd5d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file postDeferredV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
new file mode 100644
index 00000000000..9612aee4059
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
@@ -0,0 +1,79 @@
+/** 
+ * @file postgiF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect giLightMap;
+uniform sampler2D	noiseMap;
+
+uniform vec2 kern[32];
+uniform float dist_factor;
+uniform float blur_size;
+uniform vec2 delta;
+uniform int kern_length;
+uniform float kern_scale;
+uniform vec3 blur_quad;
+
+varying vec2 vary_fragcoord;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+void main() 
+{
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 pos = getPosition(vary_fragcoord.xy).xyz;
+	
+	
+	vec3 ccol = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
+	vec2 dlt = kern_scale * delta/(1.0+norm.xy*norm.xy);
+	dlt /= max(-pos.z*dist_factor, 1.0);
+	float defined_weight = kern[0].x;
+	vec3 col = vec3(0.0);
+	
+	for (int i = 0; i < kern_length; i++)
+	{
+		vec2 tc = vary_fragcoord.xy + kern[i].y*dlt;
+	    vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz*2.0-1.0;
+	    
+	    float d = dot(norm.xyz, sampNorm);
+		
+		if (d > 0.8)
+		{
+			vec3 samppos = getPosition(tc.xy).xyz;
+			samppos -= pos;
+			if (dot(samppos,samppos) < -0.05*pos.z)
+			{
+	    		col += texture2DRect(giLightMap, tc).rgb*kern[i].x;
+				defined_weight += kern[i].x;
+			}
+		}
+	}
+
+	col /= defined_weight;
+	
+	//col = ccol;
+	
+	col = col*col*blur_quad.x + col*blur_quad.y + blur_quad.z;
+	
+	gl_FragData[0].xyz = col;
+	
+	//gl_FragColor = ccol;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl
new file mode 100644
index 00000000000..6adcda82a30
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/postgiV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file postgiV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
index b3758c3638e..b0b31fd4baa 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
@@ -7,8 +7,11 @@
 
 uniform sampler2D diffuseMap;
 
+varying vec4 post_pos;
 
 void main() 
 {
 	gl_FragColor = vec4(1,1,1,texture2D(diffuseMap, gl_TexCoord[0].xy).a * gl_Color.a);
+	
+	gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
index aae1beeae35..7214d246a4e 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
@@ -5,13 +5,17 @@
  * $License$
  */
 
+varying vec4 post_pos;
+
 void main()
 {
 	//transform vertex
 	vec4 pos = gl_ModelViewProjectionMatrix*gl_Vertex;
-	//smash geometry against the near clip plane (great for ortho projections)
-	pos.z = max(pos.z, -1.0);
-	gl_Position = pos;
+	
+	post_pos = pos;
+	
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+	
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	gl_FrontColor = gl_Color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index d5671a6ce44..b4b0d0ce9de 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -12,9 +12,9 @@ uniform sampler2DRect specularRect;
 uniform sampler2DRect positionMap;
 uniform sampler2DRect normalMap;
 uniform sampler2DRect depthMap;
-uniform sampler2DRect lightMap;
 uniform sampler2D	  noiseMap;
 uniform samplerCube environmentMap;
+uniform sampler2D	  lightFunc;
 
 uniform float blur_size;
 uniform float blur_fidelity;
@@ -38,9 +38,9 @@ uniform vec4 max_y;
 uniform vec4 glow;
 uniform float scene_light_strength;
 uniform vec3 env_mat[3];
-uniform mat4 shadow_matrix[3];
-uniform vec4 shadow_clip;
-uniform mat3 ssao_effect_mat;
+//uniform mat4 shadow_matrix[3];
+//uniform vec4 shadow_clip;
+//uniform mat3 ssao_effect_mat;
 
 varying vec4 vary_light;
 varying vec2 vary_fragcoord;
@@ -52,6 +52,22 @@ vec3 vary_AmblitColor;
 vec3 vary_AdditiveColor;
 vec3 vary_AtmosAttenuation;
 
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+vec4 getPosition(vec2 pos_screen)
+{ //get position in screen space (world units) given window coordinate and depth map
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
 vec3 getPositionEye()
 {
 	return vary_PositionEye;
@@ -162,17 +178,7 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 	temp2.x += .25;
 	
 	//increase ambient when there are more clouds
-	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;
-	
-	/*  decrease value and saturation (that in HSV, not HSL) for occluded areas
-	 * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html
-	 * // The following line of code performs the equivalent of:
-	 * float ambAlpha = tmpAmbient.a;
-	 * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis
-	 * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue);
-	 * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha);
-	 */
-	tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a);
+	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;	
 
 	//haze color
 	setAdditiveColor(
@@ -235,36 +241,27 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	vec3 pos = texture2DRect(positionMap, tc).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz;
-	vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
+	vec3 pos = getPosition(tc).xyz;
+	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
+	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
 	
 	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
 	
-	vec4 diffuse = vec4(texture2DRect(diffuseRect, tc).rgb, 1.0);
+	vec4 diffuse = texture2DRect(diffuseRect, tc);
 	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
 	
-	vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
-	float scol = scol_ambocc.r; 
-	float ambocc = scol_ambocc.g;
-	
-	calcAtmospherics(pos.xyz, ambocc);
+	calcAtmospherics(pos.xyz, 0.0);
 	
 	vec3 col = atmosAmbient(vec3(0));
-	col += atmosAffectDirectionalLight(min(da, scol));
+	col += atmosAffectDirectionalLight(clamp(da, diffuse.a, 1.0));
 	
 	col *= diffuse.rgb;
 	
-	if (spec.a > 0.2)
+	if (spec.a > 0.0)
 	{
-		vec3 ref = reflect(pos.xyz, norm.xyz);
-		vec3 rc;
-		rc.x = dot(ref, env_mat[0]);
-		rc.y = dot(ref, env_mat[1]);
-		rc.z = dot(ref, env_mat[2]);
-		
-		vec3 refcol = textureCube(environmentMap, rc).rgb;
-		col.rgb += refcol * spec.rgb; 
+		vec3 ref = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(ref, vary_light.xyz);
+		col.rgb += vary_SunlitColor*spec.rgb*texture2D(lightFunc, vec2(sa, spec.a)).a;
 	}
 	
 	col = atmosLighting(col);
@@ -272,8 +269,4 @@ void main()
 	
 	gl_FragColor.rgb = col;
 	gl_FragColor.a = 0.0;
-	//gl_FragColor.rg = scol_ambocc.rg;
-	//gl_FragColor.rgb = norm.rgb*0.5+0.5;
-	//gl_FragColor.rgb = vec3(ambocc);
-	//gl_FragColor.rgb = vec3(scol);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
new file mode 100644
index 00000000000..2a7234fd83b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -0,0 +1,177 @@
+/** 
+ * @file spotLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+void main() 
+{
+	vec4 frag = vary_fragcoord;
+	frag.xyz /= frag.w;
+	frag.xyz = frag.xyz*0.5+0.5;
+	frag.xy *= screen_res;
+	
+	vec3 pos = getPosition(frag.xy).xyz;
+	vec3 lv = vary_light.xyz-pos.xyz;
+	float dist2 = dot(lv,lv);
+	dist2 /= vary_light.w;
+	if (dist2 > 1.0)
+	{
+		discard;
+	}
+	
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	
+	norm = normalize(norm);
+	float l_dist = -dot(lv, proj_n);
+	
+	vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+	if (proj_tc.z < 0.0)
+	{
+		discard;
+	}
+	
+	proj_tc.xyz /= proj_tc.w;
+	
+	float fa = gl_Color.a+1.0;
+	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+	
+	lv = proj_origin-pos.xyz;
+	lv = normalize(lv);
+	float da = dot(norm, lv);
+		
+	vec3 col = vec3(0,0,0);
+		
+	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
+		
+	float noise = texture2D(noiseMap, frag.xy/128.0).b;
+	if (proj_tc.z > 0.0 &&
+		proj_tc.x < 1.0 &&
+		proj_tc.y < 1.0 &&
+		proj_tc.x > 0.0 &&
+		proj_tc.y > 0.0)
+	{
+		float lit = 0.0;
+		if (da > 0.0)
+		{
+			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+			float lod = diff * proj_lod;
+			
+			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+		
+			vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+			lit = da * dist_atten * noise;
+			
+			col = lcol*lit*diff_tex;
+		}
+		
+		float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+		float lod = diff * proj_lod;
+		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+		//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
+		float amb_da = proj_ambiance;
+		
+		amb_da += (da*da*0.5+0.5)*proj_ambiance;
+			
+		amb_da *= dist_atten * noise;
+		
+		amb_da = min(amb_da, 1.0-lit);
+		
+		col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+	}
+	
+	
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+	if (spec.a > 0.0)
+	{
+		vec3 ref = reflect(normalize(pos), norm);
+		
+		//project from point pos in direction ref to plane proj_p, proj_n
+		vec3 pdelta = proj_p-pos;
+		float ds = dot(ref, proj_n);
+		
+		if (ds < 0.0)
+		{
+			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+			vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
+
+			if (stc.z > 0.0)
+			{
+				stc.xy /= stc.z+proj_near;
+					
+				if (stc.x < 1.0 &&
+					stc.y < 1.0 &&
+					stc.x > 0.0 &&
+					stc.y > 0.0)
+				{
+					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb;
+				}
+			}
+		}
+	}
+	
+	/*if (spec.a > 0.0)
+	{
+		//vec3 ref = reflect(normalize(pos), norm);
+		float sa = dot(normalize(lv-normalize(pos)),norm);;
+		//sa = max(sa, 0.0);
+		//sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
+		sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
+		sa *= noise;
+		col += da*sa*lcol*spec.rgb;
+	}*/
+	
+	gl_FragColor.rgb = col;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
index d43fe6ca95e..22bdd2c7f34 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
@@ -7,17 +7,21 @@
 
 #extension GL_ARB_texture_rectangle : enable
 
-uniform sampler2DRect positionMap;
-uniform sampler2DRect normalMap;
 uniform sampler2DRect depthMap;
-uniform sampler2DShadow shadowMap0;
-uniform sampler2DShadow shadowMap1;
-uniform sampler2DShadow shadowMap2;
-uniform sampler2DShadow shadowMap3;
+uniform sampler2DRect normalMap;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
+uniform sampler2DRectShadow shadowMap4;
+uniform sampler2DRectShadow shadowMap5;
 uniform sampler2D noiseMap;
 
+uniform sampler2D		lightFunc;
+
+
 // Inputs
-uniform mat4 shadow_matrix[4];
+uniform mat4 shadow_matrix[6];
 uniform vec4 shadow_clip;
 uniform float ssao_radius;
 uniform float ssao_max_radius;
@@ -27,6 +31,25 @@ uniform float ssao_factor_inv;
 varying vec2 vary_fragcoord;
 varying vec4 vary_light;
 
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+uniform float shadow_bias;
+uniform float shadow_offset;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
 //calculate decreases in ambient lighting when crowded out (SSAO)
 float calcAmbientOcclusion(vec4 pos, vec3 norm)
 {
@@ -54,7 +77,7 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm)
 	for (int i = 0; i < 8; i++)
 	{
 		vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
-		vec3 samppos_world = texture2DRect(positionMap, samppos_screen).xyz;
+		vec3 samppos_world = getPosition(samppos_screen).xyz; 
 		
 		vec3 diff = pos_world - samppos_world;
 		float dist2 = dot(diff, diff);
@@ -74,14 +97,18 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm)
 	
 	angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
 	
-	return 1.0 - (float(points != 0) * angle_hidden);
+	return (1.0 - (float(points != 0) * angle_hidden));
 }
 
 void main() 
 {
 	vec2 pos_screen = vary_fragcoord.xy;
-	vec4 pos = vec4(texture2DRect(positionMap, pos_screen).xyz, 1.0);
-        vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
+	
+	//try doing an unproject here
+	
+	vec4 pos = getPosition(pos_screen);
+	
+    vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
 	
 	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
 	{
@@ -90,35 +117,45 @@ void main()
 	}*/
 	
 	float shadow = 1.0;
-        float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
+    float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
 
+	vec4 spos = vec4(pos.xyz + norm.xyz * (-pos.z/64.0*shadow_offset+shadow_bias), 1.0);
+	
+	//vec3 debug = vec3(0,0,0);
+	
 	if (dp_directional_light == 0.0)
 	{
 		// if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup
 		shadow = 0.0;
 	}
-	else if (pos.z > -shadow_clip.w)
+	else if (spos.z > -shadow_clip.w)
 	{	
-		if (pos.z < -shadow_clip.z)
+		vec4 lpos;
+		
+		if (spos.z < -shadow_clip.z)
 		{
-			vec4 lpos = shadow_matrix[3]*pos;
-			shadow = shadow2DProj(shadowMap3, lpos).x;
+			lpos = shadow_matrix[3]*spos;
+			lpos.xy *= screen_res;
+			shadow = shadow2DRectProj(shadowMap3, lpos).x;
 			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
 		}
-		else if (pos.z < -shadow_clip.y)
+		else if (spos.z < -shadow_clip.y)
 		{
-			vec4 lpos = shadow_matrix[2]*pos;
-			shadow = shadow2DProj(shadowMap2, lpos).x;
+			lpos = shadow_matrix[2]*spos;
+			lpos.xy *= screen_res;
+			shadow = shadow2DRectProj(shadowMap2, lpos).x;
 		}
-		else if (pos.z < -shadow_clip.x)
+		else if (spos.z < -shadow_clip.x)
 		{
-			vec4 lpos = shadow_matrix[1]*pos;
-			shadow = shadow2DProj(shadowMap1, lpos).x;
+			lpos = shadow_matrix[1]*spos;
+			lpos.xy *= screen_res;
+			shadow = shadow2DRectProj(shadowMap1, lpos).x;
 		}
 		else
 		{
-			vec4 lpos = shadow_matrix[0]*pos;
-			shadow = shadow2DProj(shadowMap0, lpos).x;
+			lpos = shadow_matrix[0]*spos;
+			lpos.xy *= screen_res;
+			shadow = shadow2DRectProj(shadowMap0, lpos).x;
 		}
 
 		// take the most-shadowed value out of these two:
@@ -126,6 +163,17 @@ void main()
 		//  * an unblurred dot product between the sun and this norm
 		// the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting
 		shadow = min(shadow, dp_directional_light);
+		
+		/*debug.r = lpos.y / (lpos.w*screen_res.y);
+		
+		lpos.xy /= lpos.w*32.0;
+		if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1)
+		{
+			debug.gb = vec2(0.5, 0.5);
+		}
+		
+		debug += (1.0-shadow)*0.5;*/
+		
 	}
 	else
 	{
@@ -135,5 +183,18 @@ void main()
 	
 	gl_FragColor[0] = shadow;
 	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
-	//gl_FragColor[2] is unused as of August 2008, may be used for debugging
+	
+	//spotlight shadow 1
+	vec4 lpos = shadow_matrix[4]*spos;
+	lpos.xy *= screen_res;
+	gl_FragColor[2] = shadow2DRectProj(shadowMap4, lpos).x; 
+	
+	//spotlight shadow 2
+	lpos = shadow_matrix[5]*spos;
+	lpos.xy *= screen_res;
+	gl_FragColor[3] = shadow2DRectProj(shadowMap5, lpos).x; 
+
+	//gl_FragColor.rgb = pos.xyz;
+	//gl_FragColor.b = shadow;
+	//gl_FragColor.rgb = debug;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
index 211b2e03970..3cccfb72020 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
@@ -12,7 +12,6 @@ uniform sampler2D detail_3;
 uniform sampler2D alpha_ramp;
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 void main()
 {
@@ -28,9 +27,8 @@ void main()
 	float alphaFinal = texture2D(alpha_ramp, gl_TexCoord[1].zw).a;
 	vec4 outColor = mix( mix(color3, color2, alpha2), mix(color1, color0, alpha1), alphaFinal );
 	
-	gl_FragData[0] = vec4(outColor.rgb, 1.0);
+	gl_FragData[0] = vec4(outColor.rgb, 0.0);
 	gl_FragData[1] = vec4(outColor.rgb*0.2, 0.2);
-	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
-	gl_FragData[3] = vary_position;
+	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
index e9d6dcabff8..3038b147723 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainV.glsl
@@ -6,7 +6,6 @@
  */
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 vec4 texgen_object(vec4  vpos, vec4 tc, mat4 mat, vec4 tp0, vec4 tp1)
 {
@@ -27,7 +26,6 @@ void main()
 	//transform vertex
 	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
 			
-	vary_position = gl_ModelViewMatrix * gl_Vertex;
 	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
 	
 	// Transform and pass tex coords
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
index bc2c9816dc4..258acee08c1 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
@@ -8,13 +8,11 @@
 uniform sampler2D diffuseMap;
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 void main() 
 {
 	vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
-	gl_FragData[0] = gl_Color*col;
+	gl_FragData[0] = vec4(gl_Color.rgb*col.rgb, col.a <= 0.5 ? 0.0 : 0.005);
 	gl_FragData[1] = vec4(0,0,0,0);
-	gl_FragData[2] = vec4(normalize(vary_normal), 0.0);
-	gl_FragData[3] = vary_position;
+	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
index 9131d7c2b32..6b9dc2defbf 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeV.glsl
@@ -6,7 +6,6 @@
  */
 
 varying vec3 vary_normal;
-varying vec4 vary_position;
 
 void main()
 {
@@ -14,8 +13,6 @@ void main()
 	gl_Position = ftransform(); 
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vary_position = gl_ModelViewMatrix * gl_Vertex;
-	
 	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
 
 	gl_FrontColor = gl_Color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
index 0a1f019e3d9..d21575119dd 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -5,19 +5,21 @@
  * $License$
  */
 
+#extension GL_ARB_texture_rectangle : enable
+
 vec3 scaleSoftClip(vec3 inColor);
 vec3 atmosTransport(vec3 inColor);
 
 uniform sampler2D bumpMap;   
 uniform sampler2D screenTex;
 uniform sampler2D refTex;
-uniform sampler2DShadow shadowMap0;
-uniform sampler2DShadow shadowMap1;
-uniform sampler2DShadow shadowMap2;
-uniform sampler2DShadow shadowMap3;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
 uniform sampler2D noiseMap;
 
-uniform mat4 shadow_matrix[4];
+uniform mat4 shadow_matrix[6];
 uniform vec4 shadow_clip;
 
 uniform float sunAngle;
@@ -32,7 +34,8 @@ uniform vec3 normScale;
 uniform float fresnelScale;
 uniform float fresnelOffset;
 uniform float blurMultiplier;
-
+uniform vec2 screen_res;
+uniform mat4 norm_mat; //region space to screen space
 
 //bigWave is (refCoord.w, view.w);
 varying vec4 refCoord;
@@ -88,7 +91,7 @@ void main()
 	refcol *= df1 * 0.333;
 	
 	vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5;
-	wavef.z *= max(-viewVec.z, 0.1);
+	//wavef.z *= max(-viewVec.z, 0.1);
 	wavef = normalize(wavef);
 	
 	float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset;
@@ -101,10 +104,10 @@ void main()
 	refcol = mix(baseCol*df2, refcol, dweight);
 
 	//get specular component
-	float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
+	//float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
 		
 	//harden specular
-	spec = pow(spec, 128.0);
+	//spec = pow(spec, 128.0);
 
 	//figure out distortion vector (ripply)   
 	vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0);
@@ -118,40 +121,21 @@ void main()
 	float shadow = 1.0;
 	vec4 pos = vary_position;
 	
-	vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
-
-	if (pos.z > -shadow_clip.w)
-	{	
-		vec4 spos = pos;
-			
-		if (pos.z < -shadow_clip.z)
-		{
-			vec4 lpos = (shadow_matrix[3]*spos);
-			shadow = shadow2DProj(shadowMap3, lpos).x;
-		}
-		else if (pos.z < -shadow_clip.y)
-		{
-			vec4 lpos = (shadow_matrix[2]*spos);
-			shadow = shadow2DProj(shadowMap2, lpos).x;
-		}
-		else if (pos.z < -shadow_clip.x)
-		{
-			vec4 lpos = (shadow_matrix[1]*spos);
-			shadow = shadow2DProj(shadowMap1, lpos).x;
-		}
-		else
-		{
-			vec4 lpos = (shadow_matrix[0]*spos);
-			shadow = shadow2DProj(shadowMap0, lpos).x;
-		}
-	}
-	
-	spec *= shadow;
-	color.rgb += spec * specular;
-	
-	color.rgb = atmosTransport(color.rgb);
-	color.rgb = scaleSoftClip(color.rgb);
-	color.a = spec * sunAngle2;
+	//vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+	vec4 spos = pos;
+		
+	//spec *= shadow;
+	//color.rgb += spec * specular;
+	
+	//color.rgb = atmosTransport(color.rgb);
+	//color.rgb = scaleSoftClip(color.rgb);
+	//color.a = spec * sunAngle2;
 
-	gl_FragColor = color;
+	//wavef.z = -0.25f;
+	wavef = normalize(wavef);
+	wavef = (norm_mat*vec4(wavef, 1.0)).xyz;
+	
+	gl_FragData[0] = vec4(color.rgb, 0.75);
+	gl_FragData[1] = vec4(1,1,1, 0.8);
+	gl_FragData[2] = vec4(wavef*0.5+0.5, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
new file mode 100644
index 00000000000..ad16de6d816
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -0,0 +1,132 @@
+/** 
+ * @file alphaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2D diffuseMap;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
+uniform sampler2D noiseMap;
+uniform sampler2DRect depthMap;
+
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform vec2 screen_res;
+uniform vec2 shadow_res;
+
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_fragcoord;
+varying vec3 vary_position;
+varying vec3 vary_light;
+
+uniform float alpha_soften;
+
+uniform float shadow_bias;
+
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos.xyz /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias;
+	
+	float cs = shadow2DRect(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs);
+			
+	return shadow/5.0;
+}
+
+
+void main() 
+{
+	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
+	frag *= screen_res;
+	
+	vec3 samp_pos = getPosition(frag).xyz;
+	
+	float shadow = 1.0;
+	vec4 pos = vec4(vary_position, 1.0);
+	
+	vec4 spos = pos;
+		
+	if (spos.z > -shadow_clip.w)
+	{	
+		vec4 lpos;
+		
+		if (spos.z < -shadow_clip.z)
+		{
+			lpos = shadow_matrix[3]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap3, lpos, 1.5);
+			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+		}
+		else if (spos.z < -shadow_clip.y)
+		{
+			lpos = shadow_matrix[2]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap2, lpos, 1.5);
+		}
+		else if (spos.z < -shadow_clip.x)
+		{
+			lpos = shadow_matrix[1]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap1, lpos, 1.5);
+		}
+		else
+		{
+			lpos = shadow_matrix[0]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap0, lpos, 1.5);
+		}
+	}
+	
+	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, gl_Color.a);
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+	
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+
+	if (samp_pos.z != 0.0 && gl_Color.a < 1.0)
+	{
+		float dist_factor = alpha_soften;
+		float a = gl_Color.a;
+		a *= a;
+		dist_factor *= 1.0/(1.0-a);
+		color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0);
+	}
+	
+	//gl_FragColor = gl_Color;
+	gl_FragColor = color;
+	//gl_FragColor = vec4(1,0,1,1)*shadow;
+	
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
new file mode 100644
index 00000000000..5991e1f3b5e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
@@ -0,0 +1,76 @@
+/** 
+ * @file alphaV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_fragcoord;
+varying vec3 vary_position;
+varying vec3 vary_light;
+
+uniform float near_clip;
+uniform float shadow_offset;
+uniform float shadow_bias;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	
+	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
+	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
+	
+	float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz));
+	vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset;
+		
+	calcAtmospherics(pos.xyz);
+
+	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+	vec4 col;
+	col.a = gl_Color.a;
+	
+	// Add windlight lights
+	col.rgb = atmosAmbient(vec3(0.));
+	col.rgb = scaleUpLight(col.rgb);
+
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
+ 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
+ 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+	
+	vary_light = gl_LightSource[0].position.xyz;
+	
+	vary_ambient = col.rgb*gl_Color.rgb;
+	vary_directional.rgb = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+	
+	col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+	
+	gl_FrontColor = col;
+
+	gl_FogFragCoord = pos.z;
+	
+	pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
+	
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl
new file mode 100644
index 00000000000..a81e4caf4ce
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaF.glsl
@@ -0,0 +1,98 @@
+/** 
+ * @file avatarAlphaF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2D diffuseMap;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
+uniform sampler2D noiseMap;
+
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform vec2 screen_res;
+uniform vec2 shadow_res;
+
+vec3 atmosLighting(vec3 light);
+vec3 scaleSoftClip(vec3 light);
+
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_position;
+varying vec3 vary_normal;
+
+uniform float shadow_bias;
+
+float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias;
+	
+	float cs = shadow2DRect(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, scl, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(scl, -scl, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, scl, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-scl, -scl, 0.0)).x, cs);
+			
+	return shadow/5.0;
+}
+
+void main() 
+{
+	float shadow = 1.0;
+	vec4 pos = vec4(vary_position, 1.0);
+	vec3 norm = normalize(vary_normal);
+	
+	//vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
+
+	vec4 spos = pos;
+	
+	if (spos.z > -shadow_clip.w)
+	{	
+		vec4 lpos;
+		
+		if (spos.z < -shadow_clip.z)
+		{
+			lpos = shadow_matrix[3]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap3, lpos, 1.5);
+			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+		}
+		else if (spos.z < -shadow_clip.y)
+		{
+			lpos = shadow_matrix[2]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap2, lpos, 1.5);
+		}
+		else if (spos.z < -shadow_clip.x)
+		{
+			lpos = shadow_matrix[1]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap1, lpos, 1.5);
+		}
+		else
+		{
+			lpos = shadow_matrix[0]*spos;
+			lpos.xy *= shadow_res;
+			shadow = pcfShadow(shadowMap0, lpos, 1.5);
+		}
+	}
+	
+	
+	vec4 col = vec4(vary_ambient + vary_directional*shadow, gl_Color.a);	
+	vec4 color = texture2D(diffuseMap, gl_TexCoord[0].xy) * col;
+	
+	color.rgb = atmosLighting(color.rgb);
+
+	color.rgb = scaleSoftClip(color.rgb);
+
+	gl_FragColor = color;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
new file mode 100644
index 00000000000..a939499b171
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
@@ -0,0 +1,84 @@
+/** 
+ * @file avatarAlphaV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
+mat4 getSkinnedTransform();
+void calcAtmospherics(vec3 inPositionEye);
+
+float calcDirectionalLight(vec3 n, vec3 l);
+float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+
+vec3 atmosAmbient(vec3 light);
+vec3 atmosAffectDirectionalLight(float lightIntensity);
+vec3 scaleDownLight(vec3 light);
+vec3 scaleUpLight(vec3 light);
+
+varying vec3 vary_position;
+varying vec3 vary_ambient;
+varying vec3 vary_directional;
+varying vec3 vary_normal;
+
+uniform float near_clip;
+uniform float shadow_offset;
+uniform float shadow_bias;
+
+void main()
+{
+	gl_TexCoord[0] = gl_MultiTexCoord0;
+				
+	vec4 pos;
+	vec3 norm;
+	
+	mat4 trans = getSkinnedTransform();
+	pos.x = dot(trans[0], gl_Vertex);
+	pos.y = dot(trans[1], gl_Vertex);
+	pos.z = dot(trans[2], gl_Vertex);
+	pos.w = 1.0;
+	
+	norm.x = dot(trans[0].xyz, gl_Normal);
+	norm.y = dot(trans[1].xyz, gl_Normal);
+	norm.z = dot(trans[2].xyz, gl_Normal);
+	norm = normalize(norm);
+		
+	gl_Position = gl_ProjectionMatrix * pos;
+	
+	float dp_directional_light = max(0.0, dot(norm, gl_LightSource[0].position.xyz));
+	vary_position = pos.xyz + gl_LightSource[0].position.xyz * (1.0-dp_directional_light)*shadow_offset;
+	vary_normal = norm;	
+	
+	calcAtmospherics(pos.xyz);
+
+	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
+	vec4 col;
+	col.a = gl_Color.a;
+	
+	// Add windlight lights
+	col.rgb = atmosAmbient(vec3(0.));
+	col.rgb = scaleUpLight(col.rgb);
+
+	// Collect normal lights (need to be divided by two, as we later multiply by 2)
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
+ 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
+ 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
+	col.rgb = scaleDownLight(col.rgb);
+	
+	vary_ambient = col.rgb*gl_Color.rgb;
+	vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
+	
+	col.rgb = min(col.rgb*gl_Color.rgb, 1.0);
+	
+	gl_FrontColor = col;
+
+	gl_FogFragCoord = pos.z;
+
+}
+
+
diff --git a/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
new file mode 100644
index 00000000000..8bd702a8da9
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
@@ -0,0 +1,96 @@
+/** 
+ * @file blurLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect lightMap;
+uniform sampler2DRect edgeMap;
+
+uniform float dist_factor;
+uniform float blur_size;
+uniform vec2 delta;
+uniform vec3 kern[4];
+uniform float kern_scale;
+
+varying vec2 vary_fragcoord;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+void main() 
+{
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 pos = getPosition(vary_fragcoord.xy).xyz;
+	vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba;
+	
+	vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy);
+	
+	dlt /= max(-pos.z*dist_factor, 1.0);
+	
+	vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
+	vec4 col = defined_weight.xyxx * ccol;
+	
+	float e = 1.0;
+	for (int i = 0; i < 4; i++)
+	{
+		vec2 tc = vary_fragcoord.xy + kern[i].z*dlt;
+		
+		e = max(e, 0.0);
+		
+		vec2 wght = kern[i].xy*e;
+		
+		col += texture2DRect(lightMap, tc)*wght.xyxx;
+		defined_weight += wght;
+		
+		e *= e;
+		e -= texture2DRect(edgeMap, tc.xy).a+
+			texture2DRect(edgeMap, tc.xy+dlt*0.333).a+
+			texture2DRect(edgeMap, tc.xy-dlt*0.333).a;
+	}
+
+
+	e = 1.0;
+	
+	for (int i = 0; i < 4; i++)
+	{
+		vec2 tc = vary_fragcoord.xy - kern[i].z*dlt;
+		
+		e = max(e, 0.0);
+		
+		vec2 wght = kern[i].xy*e;
+		
+		col += texture2DRect(lightMap, tc)*wght.xyxx;
+		defined_weight += wght;
+		
+		e *= e;
+		e -= texture2DRect(edgeMap, tc.xy).a+
+			texture2DRect(edgeMap, tc.xy+dlt*0.333).a+
+			texture2DRect(edgeMap, tc.xy-dlt*0.333).a;
+	}
+
+
+	col /= defined_weight.xyxx;
+	
+	gl_FragColor = col;
+	
+	//gl_FragColor = ccol;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl
new file mode 100644
index 00000000000..b7f07e57020
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/blurLightV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file blurLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
new file mode 100644
index 00000000000..02beddd43b3
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
@@ -0,0 +1,58 @@
+/** 
+ * @file edgeF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+
+uniform float gi_dist_cutoff;
+
+varying vec2 vary_fragcoord;
+
+uniform float depth_cutoff;
+uniform float norm_cutoff;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+float getDepth(vec2 pos_screen)
+{
+	float z = texture2DRect(depthMap, pos_screen.xy).a;
+	z = z*2.0-1.0;
+	vec4 ndc = vec4(0.0, 0.0, z, 1.0);
+	vec4 p = inv_proj*ndc;
+	return p.z/p.w;
+}
+
+void main() 
+{
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	float depth = getDepth(vary_fragcoord.xy);
+	
+	vec2 tc = vary_fragcoord.xy;
+	
+	float sc = 0.75;
+	
+	vec2 de;
+	de.x = (depth-getDepth(tc+vec2(sc, sc))) + (depth-getDepth(tc+vec2(-sc, -sc)));
+	de.y = (depth-getDepth(tc+vec2(-sc, sc))) + (depth-getDepth(tc+vec2(sc, -sc)));
+	de /= depth;
+	de *= de;
+	de = step(depth_cutoff, de);
+	
+	vec2 ne;
+	ne.x = dot(texture2DRect(normalMap, tc+vec2(-sc,-sc)).rgb*2.0-1.0, norm);
+	ne.y = dot(texture2DRect(normalMap, tc+vec2(sc,sc)).rgb*2.0-1.0, norm);
+	
+	ne = 1.0-ne;
+	
+	ne = step(norm_cutoff, ne);
+	
+	gl_FragColor.a = dot(de,de)+dot(ne,ne);
+	//gl_FragColor.a = dot(de,de);
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl
new file mode 100644
index 00000000000..f1938c92b86
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/edgeV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file edgeV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
new file mode 100644
index 00000000000..651959413cd
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -0,0 +1,188 @@
+/** 
+ * @file multiSpotLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
+uniform sampler2DRect lightMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+uniform int proj_shadow_idx;
+uniform float shadow_fade;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+void main() 
+{
+	vec4 frag = vary_fragcoord;
+	frag.xyz /= frag.w;
+	frag.xyz = frag.xyz*0.5+0.5;
+	frag.xy *= screen_res;
+	
+	vec3 pos = getPosition(frag.xy).xyz;
+	vec3 lv = vary_light.xyz-pos.xyz;
+	float dist2 = dot(lv,lv);
+	dist2 /= vary_light.w;
+	if (dist2 > 1.0)
+	{
+		discard;
+	}
+	
+	float shadow = 1.0;
+	
+	if (proj_shadow_idx >= 0)
+	{
+		vec4 shd = texture2DRect(lightMap, frag.xy);
+		float sh[2];
+		sh[0] = shd.b;
+		sh[1] = shd.a;
+		shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0);
+	}
+	
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	
+	norm = normalize(norm);
+	float l_dist = -dot(lv, proj_n);
+	
+	vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+	if (proj_tc.z < 0.0)
+	{
+		discard;
+	}
+	
+	proj_tc.xyz /= proj_tc.w;
+	
+	float fa = gl_Color.a+1.0;
+	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	if (dist_atten <= 0.0)
+	{
+		discard;
+	}
+	
+	lv = proj_origin-pos.xyz;
+	lv = normalize(lv);
+	float da = dot(norm, lv);
+		
+	vec3 col = vec3(0,0,0);
+		
+	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
+		
+	float noise = texture2D(noiseMap, frag.xy/128.0).b;
+	if (proj_tc.z > 0.0 &&
+		proj_tc.x < 1.0 &&
+		proj_tc.y < 1.0 &&
+		proj_tc.x > 0.0 &&
+		proj_tc.y > 0.0)
+	{
+		float lit = 0.0;
+		float amb_da = proj_ambiance;
+		
+		if (da > 0.0)
+		{
+			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+			float lod = diff * proj_lod;
+			
+			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+		
+			vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+			lit = da * dist_atten * noise;
+			
+			col = lcol*lit*diff_tex*shadow;
+			amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
+		}
+		
+		//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, proj_ambient_lod);
+							
+		amb_da += (da*da*0.5+0.5)*proj_ambiance;
+				
+		amb_da *= dist_atten * noise;
+			
+		amb_da = min(amb_da, 1.0-lit);
+			
+		col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+	}
+	
+	
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+	if (spec.a > 0.0)
+	{
+		vec3 ref = reflect(normalize(pos), norm);
+		
+		//project from point pos in direction ref to plane proj_p, proj_n
+		vec3 pdelta = proj_p-pos;
+		float ds = dot(ref, proj_n);
+		
+		if (ds < 0.0)
+		{
+			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+			vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+
+			if (stc.z > 0.0)
+			{
+				stc.xy /= stc.w;
+					
+				if (stc.x < 1.0 &&
+					stc.y < 1.0 &&
+					stc.x > 0.0 &&
+					stc.y > 0.0)
+				{
+					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb*shadow;
+				}
+			}
+		}
+	}
+	
+	//attenuate point light contribution by SSAO component
+	col *= texture2DRect(lightMap, frag.xy).g;
+	
+	gl_FragColor.rgb = col;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl
new file mode 100644
index 00000000000..ee0e9d6367b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/postDeferredF.glsl
@@ -0,0 +1,59 @@
+/** 
+ * @file postDeferredF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect localLightMap;
+uniform sampler2DRect sunLightMap;
+uniform sampler2DRect giLightMap;
+uniform sampler2D	  luminanceMap;
+uniform sampler2DRect lightMap;
+
+uniform vec3 gi_lum_quad;
+uniform vec3 sun_lum_quad;
+uniform vec3 lum_quad;
+uniform float lum_lod;
+uniform vec4 ambient;
+
+uniform vec3 gi_quad;
+
+uniform vec2 screen_res;
+varying vec2 vary_fragcoord;
+
+void main() 
+{
+	vec2 tc = vary_fragcoord.xy;
+	vec3 lcol = texture2DLod(luminanceMap, tc/screen_res, lum_lod).rgb;
+
+	float lum = sqrt(lcol.r)*lum_quad.x+lcol.r*lcol.r*lum_quad.y+lcol.r*lum_quad.z;
+	
+	vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
+
+	float ambocc = texture2DRect(lightMap, vary_fragcoord.xy).g;
+			
+	vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
+	gi_col = gi_col*gi_col*gi_quad.x + gi_col*gi_quad.y+gi_quad.z*ambocc*ambient.rgb;
+	gi_col *= diff;
+	
+	vec4 sun_col =	texture2DRect(sunLightMap, vary_fragcoord.xy);
+	
+	vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb;
+		
+
+	float sun_lum = 1.0-lum;
+	sun_lum = sun_lum*sun_lum*sun_lum_quad.x + sun_lum*sun_lum_quad.y+sun_lum_quad.z;
+		
+	float gi_lum = lum;
+	gi_lum = gi_lum*gi_lum*gi_lum_quad.x+gi_lum*gi_lum_quad.y+gi_lum_quad.z;
+	gi_col *= 1.0/gi_lum;
+		
+	vec3 col = sun_col.rgb*(1.0+max(sun_lum,0.0))+gi_col+local_col;
+	
+	gl_FragColor.rgb = col.rgb;
+	gl_FragColor.a = max(sun_lum*min(sun_col.r+sun_col.g+sun_col.b, 1.0), sun_col.a);
+	
+	//gl_FragColor.rgb = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl
new file mode 100644
index 00000000000..9819232fd5d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/postDeferredV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file postDeferredV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
new file mode 100644
index 00000000000..531f7376a37
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -0,0 +1,294 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect lightMap;
+uniform sampler2D	  noiseMap;
+uniform samplerCube environmentMap;
+uniform sampler2D	  lightFunc;
+uniform vec3 gi_quad;
+
+uniform float blur_size;
+uniform float blur_fidelity;
+
+// Inputs
+uniform vec4 morphFactor;
+uniform vec3 camPosLocal;
+//uniform vec4 camPosWorld;
+uniform vec4 gamma;
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform vec4 haze_horizon;
+uniform vec4 haze_density;
+uniform vec4 cloud_shadow;
+uniform vec4 density_multiplier;
+uniform vec4 distance_multiplier;
+uniform vec4 max_y;
+uniform vec4 glow;
+uniform float scene_light_strength;
+uniform vec3 env_mat[3];
+uniform vec4 shadow_clip;
+uniform mat3 ssao_effect_mat;
+
+uniform sampler2DRect depthMap;
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+
+vec3 vary_PositionEye;
+
+vec3 vary_SunlitColor;
+vec3 vary_AmblitColor;
+vec3 vary_AdditiveColor;
+vec3 vary_AtmosAttenuation;
+
+vec4 getPosition(vec2 pos_screen)
+{ //get position in screen space (world units) given window coordinate and depth map
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
+
+
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
+
+void setSunlitColor(vec3 v)
+{
+	vary_SunlitColor = v;
+}
+
+void setAmblitColor(vec3 v)
+{
+	vary_AmblitColor = v;
+}
+
+void setAdditiveColor(vec3 v)
+{
+	vary_AdditiveColor = v;
+}
+
+void setAtmosAttenuation(vec3 v)
+{
+	vary_AtmosAttenuation = v;
+}
+
+void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
+
+	vec3 P = inPositionEye;
+	setPositionEye(P);
+	
+	//(TERRAIN) limit altitude
+	if (P.y > max_y.x) P *= (max_y.x / P.y);
+	if (P.y < -max_y.x) P *= (-max_y.x / P.y);
+
+	vec3 tmpLightnorm = lightnorm.xyz;
+
+	vec3 Pn = normalize(P);
+	float Plen = length(P);
+
+	vec4 temp1 = vec4(0);
+	vec3 temp2 = vec3(0);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+	//sunlight attenuation effect (hue and brightness) due to atmosphere
+	//this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density * 1.0 + vec4(haze_density.r) * 0.25) * (density_multiplier.x * max_y.x);
+		//I had thought blue_density and haze_density should have equal weighting,
+		//but attenuation due to haze_density tends to seem too strong
+
+	temp1 = blue_density + vec4(haze_density.r);
+	blue_weight = blue_density / temp1;
+	haze_weight = vec4(haze_density.r) / temp1;
+
+	//(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain)
+	temp2.y = max(0.0, tmpLightnorm.y);
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// main atmospheric scattering line integral
+	temp2.z = Plen * density_multiplier.x;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier.x in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z * distance_multiplier.x);
+
+	//final atmosphere attenuation factor
+	setAtmosAttenuation(temp1.rgb);
+	
+	//compute haze glow
+	//(can use temp2.x as temp because we haven't used it yet)
+	temp2.x = dot(Pn, tmpLightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		//temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .03);	//was glow.y
+		//set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		//higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		//glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	//add "minimum anti-solar illumination"
+	temp2.x += .25;
+	
+	//increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;
+	
+	/*  decrease value and saturation (that in HSV, not HSL) for occluded areas
+	 * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html
+	 * // The following line of code performs the equivalent of:
+	 * float ambAlpha = tmpAmbient.a;
+	 * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis
+	 * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue);
+	 * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha);
+	 */
+	tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a);
+
+	//haze color
+	setAdditiveColor(
+		vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow.x) + tmpAmbient)
+	  + (haze_horizon.r * haze_weight) * (sunlight*(1.-cloud_shadow.x) * temp2.x
+		  + tmpAmbient)));
+
+	//brightness of surface both sunlight and ambient
+	setSunlitColor(vec3(sunlight * .5));
+	setAmblitColor(vec3(tmpAmbient * .25));
+	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
+}
+
+vec3 atmosLighting(vec3 light)
+{
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor();
+	return (2.0 * light);
+}
+
+vec3 atmosTransport(vec3 light) {
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor() * 2.0;
+	return light;
+}
+vec3 atmosGetDiffuseSunlightColor()
+{
+	return getSunlitColor();
+}
+
+vec3 scaleDownLight(vec3 light)
+{
+	return (light / scene_light_strength );
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	return (light * scene_light_strength);
+}
+
+vec3 atmosAmbient(vec3 light)
+{
+	return getAmblitColor() + light / 2.0;
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return getSunlitColor() * lightIntensity;
+}
+
+vec3 scaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+void main() 
+{
+	vec2 tc = vary_fragcoord.xy;
+	vec3 pos = getPosition(tc).xyz;
+	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
+	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
+	
+	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
+	
+	vec4 diffuse = texture2DRect(diffuseRect, tc);
+	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
+	
+	vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+	float scol = max(scol_ambocc.r, diffuse.a); 
+	float ambocc = scol_ambocc.g;
+	
+	calcAtmospherics(pos.xyz, ambocc);
+	
+	vec3 col = atmosAmbient(vec3(0));
+	col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
+	
+	col *= diffuse.rgb;
+	
+	if (spec.a > 0.0)
+	{
+		vec3 ref = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(ref, vary_light.xyz);
+		col.rgb += vary_SunlitColor*scol*spec.rgb*texture2D(lightFunc, vec2(sa, spec.a)).a;
+	}
+	
+	col = atmosLighting(col);
+	col = scaleSoftClip(col);
+		
+	gl_FragColor.rgb = col;
+	
+	//gl_FragColor.rgb = gi_col.rgb;
+	gl_FragColor.a = 0.0;
+	
+	//gl_FragColor.rg = scol_ambocc.rg;
+	//gl_FragColor.rgb = texture2DRect(lightMap, vary_fragcoord.xy).rgb;
+	//gl_FragColor.rgb = norm.rgb*0.5+0.5;
+	//gl_FragColor.rgb = vec3(ambocc);
+	//gl_FragColor.rgb = vec3(scol);
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl
new file mode 100644
index 00000000000..ad8af4780d4
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightV.glsl
@@ -0,0 +1,24 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec2 screen_res;
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+		
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
new file mode 100644
index 00000000000..d6534083cfe
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -0,0 +1,199 @@
+/** 
+ * @file spotLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
+uniform sampler2DRect lightMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+uniform int proj_shadow_idx;
+uniform float shadow_fade;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+void main() 
+{
+	vec4 frag = vary_fragcoord;
+	frag.xyz /= frag.w;
+	frag.xyz = frag.xyz*0.5+0.5;
+	frag.xy *= screen_res;
+	
+	float shadow = 1.0;
+	
+	if (proj_shadow_idx >= 0)
+	{
+		vec4 shd = texture2DRect(lightMap, frag.xy);
+		float sh[2];
+		sh[0] = shd.b;
+		sh[1] = shd.a;
+		shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0);
+	}
+	
+	vec3 pos = getPosition(frag.xy).xyz;
+	vec3 lv = vary_light.xyz-pos.xyz;
+	float dist2 = dot(lv,lv);
+	dist2 /= vary_light.w;
+	if (dist2 > 1.0)
+	{
+		discard;
+	}
+	
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	
+	norm = normalize(norm);
+	float l_dist = -dot(lv, proj_n);
+	
+	vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+	if (proj_tc.z < 0.0)
+	{
+		discard;
+	}
+	
+	proj_tc.xyz /= proj_tc.w;
+	
+	float fa = gl_Color.a+1.0;
+	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+	
+	lv = proj_origin-pos.xyz;
+	lv = normalize(lv);
+	float da = dot(norm, lv);
+		
+	vec3 col = vec3(0,0,0);
+		
+	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
+		
+	float noise = texture2D(noiseMap, frag.xy/128.0).b;
+	if (proj_tc.z > 0.0 &&
+		proj_tc.x < 1.0 &&
+		proj_tc.y < 1.0 &&
+		proj_tc.x > 0.0 &&
+		proj_tc.y > 0.0)
+	{
+		float lit = 0.0;
+		if (da > 0.0)
+		{
+			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+			float lod = diff * proj_lod;
+			
+			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+		
+			vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+			lit = da * dist_atten * noise;
+			
+			col = lcol*lit*diff_tex*shadow;
+		}
+		
+		float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+		float lod = diff * proj_lod;
+		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+		//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
+		float amb_da = proj_ambiance;
+		if (da > 0.0)
+		{
+			amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
+		}
+		
+		amb_da += (da*da*0.5+0.5)*proj_ambiance;
+			
+		amb_da *= dist_atten * noise;
+		
+		amb_da = min(amb_da, 1.0-lit);
+		
+		col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+	}
+	
+	
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+	if (spec.a > 0.0)
+	{
+		vec3 ref = reflect(normalize(pos), norm);
+		
+		//project from point pos in direction ref to plane proj_p, proj_n
+		vec3 pdelta = proj_p-pos;
+		float ds = dot(ref, proj_n);
+		
+		if (ds < 0.0)
+		{
+			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+			vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
+
+			if (stc.z > 0.0)
+			{
+				stc.xy /= stc.z+proj_near;
+					
+				if (stc.x < 1.0 &&
+					stc.y < 1.0 &&
+					stc.x > 0.0 &&
+					stc.y > 0.0)
+				{
+					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb*shadow;
+				}
+			}
+		}
+	}
+	
+	/*if (spec.a > 0.0)
+	{
+		//vec3 ref = reflect(normalize(pos), norm);
+		float sa = dot(normalize(lv-normalize(pos)),norm);;
+		//sa = max(sa, 0.0);
+		//sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
+		sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
+		sa *= noise;
+		col += da*sa*lcol*spec.rgb;
+	}*/
+	
+	//attenuate point light contribution by SSAO component
+	col *= texture2DRect(lightMap, frag.xy).g;
+	
+
+	gl_FragColor.rgb = col;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
new file mode 100644
index 00000000000..a0026edcd21
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -0,0 +1,235 @@
+/** 
+ * @file sunLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
+uniform sampler2DShadow shadowMap4;
+uniform sampler2DShadow shadowMap5;
+uniform sampler2D noiseMap;
+
+uniform sampler2D		lightFunc;
+
+
+// Inputs
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform float ssao_radius;
+uniform float ssao_max_radius;
+uniform float ssao_factor;
+uniform float ssao_factor_inv;
+
+varying vec2 vary_fragcoord;
+varying vec4 vary_light;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+uniform vec2 shadow_res;
+uniform vec2 proj_shadow_res;
+
+uniform float shadow_bias;
+uniform float shadow_offset;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+//calculate decreases in ambient lighting when crowded out (SSAO)
+float calcAmbientOcclusion(vec4 pos, vec3 norm)
+{
+	vec2 kern[8];
+	// exponentially (^2) distant occlusion samples spread around origin
+	kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+	kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+	kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+	kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+	kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+	kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+	kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+	kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+
+	vec2 pos_screen = vary_fragcoord.xy;
+	vec3 pos_world = pos.xyz;
+	vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
+	
+	float angle_hidden = 0.0;
+	int points = 0;
+	
+	float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+	
+	// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+	for (int i = 0; i < 8; i++)
+	{
+		vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
+		vec3 samppos_world = getPosition(samppos_screen).xyz; 
+		
+		vec3 diff = pos_world - samppos_world;
+		float dist2 = dot(diff, diff);
+		
+		// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+		// --> solid angle shrinking by the square of distance
+		//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+		//(k should vary inversely with # of samples, but this is taken care of later)
+		
+		//if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0)  // -0.05*norm to shift sample point back slightly for flat surfaces
+		//	angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional.  max of 1.0 (= ssao_factor_inv * ssao_factor)
+		angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
+		
+		// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
+		points = points + int(diff.z > -1.0);
+	}
+	
+	angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
+	
+	return (1.0 - (float(points != 0) * angle_hidden));
+}
+
+float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias*scl;
+	
+	float cs = shadow2DRect(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs);
+			
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias*scl;
+	
+	float cs = shadow2D(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	vec2 off = 1.5/proj_shadow_res;
+	
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs);
+	
+			
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	
+	//try doing an unproject here
+	
+	vec4 pos = getPosition(pos_screen);
+	
+    vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+	
+	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
+	{
+		gl_FragColor = vec4(0.0); // doesn't matter
+		return;
+	}*/
+	
+	float shadow = 1.0;
+    float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
+
+	vec4 spos = vec4(pos.xyz + vary_light.xyz * (1.0-dp_directional_light)*shadow_offset, 1.0);
+	
+	if (spos.z > -shadow_clip.w)
+	{	
+		if (dp_directional_light == 0.0)
+		{
+			// if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup
+			shadow = 0.0;
+		}
+		else
+		{
+			vec4 lpos;
+			
+			if (spos.z < -shadow_clip.z)
+			{
+				lpos = shadow_matrix[3]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap3, lpos, 0.25);
+				shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+			}
+			else if (spos.z < -shadow_clip.y)
+			{
+				lpos = shadow_matrix[2]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap2, lpos, 0.5);
+			}
+			else if (spos.z < -shadow_clip.x)
+			{
+				lpos = shadow_matrix[1]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap1, lpos, 0.75);
+			}
+			else
+			{
+				lpos = shadow_matrix[0]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap0, lpos, 1.0);
+			}
+		
+			// take the most-shadowed value out of these two:
+			//  * the blurred sun shadow in the light (shadow) map
+			//  * an unblurred dot product between the sun and this norm
+			// the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting
+			shadow = min(shadow, dp_directional_light);
+			
+			//lpos.xy /= lpos.w*32.0;
+			//if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1)
+			//{
+			//	shadow = 0.0;
+			//}
+			
+		}
+	}
+	else
+	{
+		// more distant than the shadow map covers
+		shadow = 1.0;
+	}
+	
+	gl_FragColor[0] = shadow;
+	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
+	
+	//spotlight shadow 1
+	vec4 lpos = shadow_matrix[4]*spos;
+	gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.1).x; 
+	
+	//spotlight shadow 2
+	lpos = shadow_matrix[5]*spos;
+	gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.1).x; 
+
+	//gl_FragColor.rgb = pos.xyz;
+	//gl_FragColor.b = shadow;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl
new file mode 100644
index 00000000000..5081485c4be
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightV.glsl
@@ -0,0 +1,25 @@
+/** 
+ * @file sunLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res;	
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+		
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
new file mode 100644
index 00000000000..7325825d6d4
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
@@ -0,0 +1,84 @@
+/** 
+ * @file giDownsampleF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2DRect giLightMap;
+
+uniform vec2 kern[32];
+uniform float dist_factor;
+uniform float blur_size;
+uniform vec2 delta;
+uniform int kern_length;
+uniform float kern_scale;
+uniform vec3 blur_quad;
+
+varying vec2 vary_fragcoord;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+float getDepth(vec2 pos_screen)
+{
+	float z = texture2DRect(depthMap, pos_screen.xy).a;
+	z = z*2.0-1.0;
+	vec4 ndc = vec4(0.0, 0.0, z, 1.0);
+	vec4 p = inv_proj*ndc;
+	return p.z/p.w;
+}
+
+void main() 
+{
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	float depth = getDepth(vary_fragcoord.xy);
+		
+	vec3 ccol = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
+	vec2 dlt = kern_scale * delta/(vec2(1.0,1.0)+norm.xy*norm.xy);
+	dlt /= clamp(-depth*blur_quad.x, 1.0, 3.0);
+	float defined_weight = kern[0].x;
+	vec3 col = ccol*kern[0].x;
+	
+	for (int i = 0; i < kern_length; i++)
+	{
+		vec2 tc = vary_fragcoord.xy + kern[i].y*dlt;
+	    vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz*2.0-1.0;
+	    
+	   float d = dot(norm.xyz, sampNorm);
+		
+		if (d > 0.5)
+		{
+			float sampdepth = getDepth(tc.xy);
+			sampdepth -= depth;
+			if (sampdepth*sampdepth < blur_quad.z)
+			{
+	    		col += texture2DRect(giLightMap, tc).rgb*kern[i].x;
+				defined_weight += kern[i].x;
+			}
+		}
+	}
+
+	col /= defined_weight;
+	
+	//col = ccol;
+	
+	col = col*blur_quad.y;
+	
+	gl_FragData[0].xyz = col;
+	
+	//gl_FragColor = ccol;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl
new file mode 100644
index 00000000000..6adcda82a30
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file postgiV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
new file mode 100644
index 00000000000..939710cb563
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
@@ -0,0 +1,190 @@
+/** 
+ * @file giF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect lightMap;
+uniform sampler2DRect specularRect;
+
+uniform sampler2D noiseMap;
+
+uniform sampler2D		diffuseGIMap;
+uniform sampler2D		specularGIMap;
+uniform sampler2D		normalGIMap;
+uniform sampler2D		depthGIMap;
+
+uniform sampler2D		lightFunc;
+
+// Inputs
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+uniform vec4 sunlight_color;
+
+uniform mat4 inv_proj;
+uniform mat4 gi_mat;  //gPipeline.mGIMatrix - eye space to sun space
+uniform mat4 gi_mat_proj; //gPipeline.mGIMatrixProj - eye space to projected sun space
+uniform mat4 gi_norm_mat; //gPipeline.mGINormalMatrix - eye space normal to sun space normal matrix
+uniform mat4 gi_inv_proj; //gPipeline.mGIInvProj - projected sun space to sun space
+uniform float gi_sample_width;
+uniform float gi_noise;
+uniform float gi_attenuation;
+uniform float gi_range;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec4 getGIPosition(vec2 gi_tc)
+{
+	float depth = texture2D(depthGIMap, gi_tc).a;
+	vec2 sc = gi_tc*2.0;
+	sc -= vec2(1.0, 1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = gi_inv_proj*ndc;
+	pos.xyz /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec3 giAmbient(vec3 pos, vec3 norm)
+{
+	vec4 gi_c = gi_mat_proj * vec4(pos, 1.0);
+	gi_c.xyz /= gi_c.w;
+
+	vec4 gi_pos = gi_mat*vec4(pos,1.0);
+	vec3 gi_norm = (gi_norm_mat*vec4(norm,1.0)).xyz;
+	gi_norm = normalize(gi_norm);
+	
+	vec4 c_spec = texture2DRect(specularRect, vary_fragcoord.xy);
+	vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).rgb;
+	gi_pos.xyz += nz.x*gi_noise*gi_norm.xyz;
+	vec2 tcx = gi_norm.xy;
+	vec2 tcy = gi_norm.yx;
+	
+	vec4 eye_pos = gi_mat*vec4(0,0,0,1.0);
+	
+	vec3 eye_dir = normalize(gi_pos.xyz-eye_pos.xyz);
+	vec3 eye_ref = reflect(eye_dir, gi_norm);
+	
+	float da = 0.0; //texture2DRect(lightMap, vary_fragcoord.xy).r*0.5;
+	vec3 fdiff = vec3(da);
+	float fda = da;
+	
+	vec3 rcol = vec3(0,0,0);
+	
+	float fsa = 0.0;
+	
+
+	for (int i = -1; i <= 1; i += 2 )
+	{
+		for (int j = -1; j <= 1; j+= 2)
+		{
+			vec2 tc = vec2(i, j)*0.75+gi_norm.xy*nz.z;
+			tc += nz.xy*2.0;
+			tc *= gi_sample_width*0.25;
+			tc += gi_c.xy;
+			
+			vec3 lnorm = -(texture2D(normalGIMap, tc.xy).xyz*2.0-1.0);
+			vec3 lpos = getGIPosition(tc.xy).xyz;
+							
+			vec3 at = lpos-gi_pos.xyz;
+			float dist = length(at);
+			float dist_atten = clamp(1.0/(gi_attenuation*dist), 0.0, 1.0);
+			
+						
+			if (dist_atten > 0.01)
+			{ //possible contribution of indirect light to this surface
+				vec3 ldir = at;
+				
+				float ld = -dot(ldir, lnorm);
+				
+				if (ld < 0.0)
+				{  					
+					float ang_atten = dot(ldir, gi_norm);
+				
+					if (ang_atten > 0.0)
+					{  
+						vec4 spec = texture2D(specularGIMap, tc.xy);
+						at = normalize(at);
+						vec3 diff;		
+						
+						float da = 0.0;
+												
+						//contribution from indirect source to visible pixel
+						vec3 ha = at;
+						ha.z -= 1.0;
+						ha = normalize(ha);
+						if (spec.a > 0.0)
+						{
+							float sa = dot(ha,lnorm);
+							da = texture2D(lightFunc, vec2(sa, spec.a)).a;
+						}
+						else
+						{
+							da = -lnorm.z;
+						}
+						
+						diff = texture2D(diffuseGIMap, tc.xy).rgb+spec.rgb*spec.a*2.0;
+												
+						if (da > 0.0)
+						{ //contribution from visible pixel to eye
+							vec3 ha = normalize(at-eye_dir);
+							if (c_spec.a > 0.0)
+							{
+								float sa = dot(ha, gi_norm);
+								da = dist_atten*texture2D(lightFunc, vec2(sa, c_spec.a)).a;
+							}
+							else
+							{
+								da = dist_atten*dot(gi_norm, normalize(ldir));
+							}
+							fda += da;
+							fdiff += da*(c_spec.rgb*c_spec.a*2.0+vec3(1,1,1))*diff.rgb;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	fdiff *= sunlight_color.rgb;
+	
+	vec3 ret = fda*fdiff;
+	
+	return clamp(ret,vec3(0.0), vec3(1.0));
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	vec4 pos = getPosition(pos_screen);
+	
+	float rad = gi_range*0.5;
+	
+	vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+	float dist = max(length(pos.xyz)-rad, 0.0);
+	
+	float da = clamp(1.0-dist/rad, 0.0, 1.0);
+	
+	vec3 ambient = da > 0.0 ? giAmbient(pos.xyz, norm) : vec3(0);
+	
+		
+	gl_FragData[0].xyz = mix(vec3(0), ambient, da);
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl
new file mode 100644
index 00000000000..e0eeebf8b65
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/giFinalF.glsl
@@ -0,0 +1,25 @@
+/** 
+ * @file giFinalF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2D	  bloomMap;
+uniform sampler2DRect edgeMap;
+
+uniform vec2 screen_res;
+varying vec2 vary_fragcoord;
+
+
+void main() 
+{
+	vec4 bloom = texture2D(bloomMap, vary_fragcoord.xy/screen_res);
+	vec4 diff = texture2DRect(diffuseRect, vary_fragcoord.xy);
+	
+	gl_FragColor = bloom + diff;
+	//gl_FragColor.rgb = vec3(texture2DRect(edgeMap, vary_fragcoord.xy).a);
+}
\ No newline at end of file
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl
new file mode 100644
index 00000000000..41a29c31bd2
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/giFinalV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file giFinalV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giV.glsl b/indra/newview/app_settings/shaders/class3/deferred/giV.glsl
new file mode 100644
index 00000000000..71dcea9628e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/giV.glsl
@@ -0,0 +1,22 @@
+/** 
+ * @file giV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res;	
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl
new file mode 100644
index 00000000000..406a7e07cf4
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/luminanceF.glsl
@@ -0,0 +1,19 @@
+/** 
+ * @file luminanceF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect lightMap;
+uniform sampler2DRect diffuseRect;
+
+varying vec2 vary_fragcoord;
+void main() 
+{
+	float i = texture2DRect(lightMap, vary_fragcoord.xy).r;
+	gl_FragColor.rgb = vec3(i);
+	gl_FragColor.a = 1.0;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl b/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl
new file mode 100644
index 00000000000..db8775f024b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/luminanceV.glsl
@@ -0,0 +1,20 @@
+/** 
+ * @file giV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy * 0.5 + 0.5)*screen_res;	
+
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl
new file mode 100644
index 00000000000..5e69bf36d9f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/postDeferredF.glsl
@@ -0,0 +1,80 @@
+/** 
+ * @file postDeferredF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+ 
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+
+uniform sampler2DRect localLightMap;
+uniform sampler2DRect sunLightMap;
+uniform sampler2DRect giLightMap;
+uniform sampler2DRect edgeMap;
+
+uniform sampler2D	  luminanceMap;
+
+uniform sampler2DRect lightMap;
+
+uniform sampler2D	  lightFunc;
+uniform sampler2D	  noiseMap;
+
+uniform float sun_lum_scale;
+uniform float sun_lum_offset;
+uniform float lum_scale;
+uniform float lum_lod;
+uniform vec4 ambient;
+uniform float gi_brightness;
+uniform float gi_luminance;
+
+uniform vec4 sunlight_color;
+
+uniform vec2 screen_res;
+varying vec2 vary_fragcoord;
+
+void main() 
+{
+	vec2 tc = vary_fragcoord.xy;
+	vec4 lcol = texture2DLod(luminanceMap, vec2(0.5, 0.5), lum_lod);
+	
+	vec3 gi_col = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
+	vec4 sun_col =	texture2DRect(sunLightMap, vary_fragcoord.xy);
+	vec3 local_col = texture2DRect(localLightMap, vary_fragcoord.xy).rgb;
+	
+	float scol = texture2DRect(lightMap, vary_fragcoord.xy).r;
+			
+	vec3 diff = texture2DRect(diffuseRect, vary_fragcoord.xy).rgb;
+	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
+	
+	gi_col = gi_col*(diff.rgb+spec.rgb*spec.a);
+
+	float lum = 1.0-clamp(pow(lcol.r, gi_brightness)+sun_lum_offset, 0.0, 1.0);
+	
+	lum *= sun_lum_scale;
+	
+	sun_col *= 1.0+(lum*lum_scale*scol);
+					  
+	vec4 col;
+	col.rgb = gi_col+sun_col.rgb+local_col;
+	
+	col.a = sun_col.a;
+	
+	vec3 bcol = vec3(0,0,0);
+	float tweight = 0.0;
+	for (int i = 0; i < 16; i++)
+	{
+		float weight = (float(i)+1.0)/2.0;
+		bcol += texture2DLod(luminanceMap, vary_fragcoord.xy/screen_res, weight).rgb*weight*weight*weight;
+		tweight += weight*weight;
+	}
+	
+	bcol /= tweight;
+	bcol *= gi_luminance;
+	col.rgb += bcol*lum;
+	
+	gl_FragColor = col;
+	//gl_FragColor.rgb = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl b/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl
new file mode 100644
index 00000000000..9819232fd5d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/postDeferredV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file postDeferredV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl
new file mode 100644
index 00000000000..901b60af597
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/postgiF.glsl
@@ -0,0 +1,69 @@
+/** 
+ * @file postgiF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect giLightMap;
+uniform sampler2D	noiseMap;
+uniform sampler2D	giMip;
+uniform sampler2DRect edgeMap;
+
+
+uniform vec2 delta;
+uniform float kern_scale;
+uniform float gi_edge_weight;
+uniform float gi_blur_brightness;
+
+varying vec2 vary_fragcoord;
+
+void main() 
+{
+	vec2 dlt = kern_scale*delta;
+	float defined_weight = 0.0; 
+	vec3 col = vec3(0.0); 
+	
+	float e = 1.0;
+	
+	for (int i = 1; i < 8; i++)
+	{
+		vec2 tc = vary_fragcoord.xy + float(i) * dlt;
+		
+		e = max(e, 0.0);
+		float wght = e;
+		
+	   	col += texture2DRect(giLightMap, tc).rgb*wght;
+		defined_weight += wght;
+				
+		e *= e;
+		e -=(texture2DRect(edgeMap, tc.xy-dlt*0.25).a+
+			texture2DRect(edgeMap, tc.xy+dlt*0.25).a)*gi_edge_weight;
+	}
+
+	e = 1.0;
+	
+	for (int i = 1; i < 8; i++)
+	{
+		vec2 tc = vary_fragcoord.xy - float(i) * dlt;
+		
+		e = max(e,0.0);
+		float wght = e;
+		
+	   	col += texture2DRect(giLightMap, tc).rgb*wght;
+		defined_weight += wght;
+	
+		e *= e;
+		e -= (texture2DRect(edgeMap, tc.xy-dlt*0.25).a+
+			texture2DRect(edgeMap, tc.xy+dlt*0.25).a)*gi_edge_weight;
+		
+	}
+	
+	col /= max(defined_weight, 0.01);
+
+	gl_FragColor.rgb = col * gi_blur_brightness;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl b/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl
new file mode 100644
index 00000000000..6adcda82a30
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/postgiV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file postgiV.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+varying vec2 vary_fragcoord;
+uniform vec2 screen_res;
+
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
new file mode 100644
index 00000000000..96a083b5221
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -0,0 +1,297 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+uniform sampler2DRect diffuseRect;
+uniform sampler2DRect specularRect;
+uniform sampler2DRect normalMap;
+uniform sampler2DRect lightMap;
+uniform sampler2D	  noiseMap;
+uniform samplerCube environmentMap;
+uniform sampler2D	  lightFunc;
+uniform vec3 gi_quad;
+
+uniform float blur_size;
+uniform float blur_fidelity;
+
+// Inputs
+uniform vec4 morphFactor;
+uniform vec3 camPosLocal;
+//uniform vec4 camPosWorld;
+uniform vec4 gamma;
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform vec4 haze_horizon;
+uniform vec4 haze_density;
+uniform vec4 cloud_shadow;
+uniform vec4 density_multiplier;
+uniform vec4 distance_multiplier;
+uniform vec4 max_y;
+uniform vec4 glow;
+uniform float scene_light_strength;
+uniform vec3 env_mat[3];
+uniform vec4 shadow_clip;
+uniform mat3 ssao_effect_mat;
+
+uniform sampler2DRect depthMap;
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+
+vec3 vary_PositionEye;
+
+vec3 vary_SunlitColor;
+vec3 vary_AmblitColor;
+vec3 vary_AdditiveColor;
+vec3 vary_AtmosAttenuation;
+uniform float gi_ambiance;
+
+vec4 getPosition(vec2 pos_screen)
+{ //get position in screen space (world units) given window coordinate and depth map
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
+
+
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
+
+void setSunlitColor(vec3 v)
+{
+	vary_SunlitColor = v;
+}
+
+void setAmblitColor(vec3 v)
+{
+	vary_AmblitColor = v;
+}
+
+void setAdditiveColor(vec3 v)
+{
+	vary_AdditiveColor = v;
+}
+
+void setAtmosAttenuation(vec3 v)
+{
+	vary_AtmosAttenuation = v;
+}
+
+void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
+
+	vec3 P = inPositionEye;
+	setPositionEye(P);
+	
+	//(TERRAIN) limit altitude
+	if (P.y > max_y.x) P *= (max_y.x / P.y);
+	if (P.y < -max_y.x) P *= (-max_y.x / P.y);
+
+	vec3 tmpLightnorm = lightnorm.xyz;
+
+	vec3 Pn = normalize(P);
+	float Plen = length(P);
+
+	vec4 temp1 = vec4(0);
+	vec3 temp2 = vec3(0);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+	//sunlight attenuation effect (hue and brightness) due to atmosphere
+	//this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density * 1.0 + vec4(haze_density.r) * 0.25) * (density_multiplier.x * max_y.x);
+		//I had thought blue_density and haze_density should have equal weighting,
+		//but attenuation due to haze_density tends to seem too strong
+
+	temp1 = blue_density + vec4(haze_density.r);
+	blue_weight = blue_density / temp1;
+	haze_weight = vec4(haze_density.r) / temp1;
+
+	//(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain)
+	temp2.y = max(0.0, tmpLightnorm.y);
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// main atmospheric scattering line integral
+	temp2.z = Plen * density_multiplier.x;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier.x in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z * distance_multiplier.x);
+
+	//final atmosphere attenuation factor
+	setAtmosAttenuation(temp1.rgb);
+	
+	//compute haze glow
+	//(can use temp2.x as temp because we haven't used it yet)
+	temp2.x = dot(Pn, tmpLightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		//temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .03);	//was glow.y
+		//set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		//higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		//glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	//add "minimum anti-solar illumination"
+	temp2.x += .25;
+	
+	//increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient*gi_ambiance + (vec4(1.) - ambient*gi_ambiance) * cloud_shadow.x * 0.5;
+	
+	/*  decrease value and saturation (that in HSV, not HSL) for occluded areas
+	 * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html
+	 * // The following line of code performs the equivalent of:
+	 * float ambAlpha = tmpAmbient.a;
+	 * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis
+	 * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue);
+	 * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha);
+	 */
+	tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a);
+
+	//haze color
+	setAdditiveColor(
+		vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow.x) + tmpAmbient)
+	  + (haze_horizon.r * haze_weight) * (sunlight*(1.-cloud_shadow.x) * temp2.x
+		  + tmpAmbient)));
+
+	//brightness of surface both sunlight and ambient
+	setSunlitColor(vec3(sunlight * .5));
+	setAmblitColor(vec3(tmpAmbient * .25));
+	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
+}
+
+vec3 atmosLighting(vec3 light)
+{
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor();
+	return (2.0 * light);
+}
+
+vec3 atmosTransport(vec3 light) {
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor() * 2.0;
+	return light;
+}
+vec3 atmosGetDiffuseSunlightColor()
+{
+	return getSunlitColor();
+}
+
+vec3 scaleDownLight(vec3 light)
+{
+	return (light / scene_light_strength );
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	return (light * scene_light_strength);
+}
+
+vec3 atmosAmbient(vec3 light)
+{
+	return getAmblitColor() + light / 2.0;
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return getSunlitColor() * lightIntensity;
+}
+
+vec3 scaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	light = 1. - clamp(light, vec3(0.), vec3(1.));
+	light = 1. - pow(light, gamma.xxx);
+
+	return light;
+}
+
+void main() 
+{
+	vec2 tc = vary_fragcoord.xy;
+	vec3 pos = getPosition(tc).xyz;
+	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
+	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
+	
+	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
+	
+	vec4 diffuse = texture2DRect(diffuseRect, tc);
+	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
+	
+	da = texture2D(lightFunc, vec2(da, 0.0)).a;
+		
+	vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+	float scol = max(scol_ambocc.r, diffuse.a); 
+	float ambocc = scol_ambocc.g;
+	
+	calcAtmospherics(pos.xyz, ambocc);
+	
+	vec3 col = atmosAmbient(vec3(0));
+	col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
+	
+	col *= diffuse.rgb;
+	
+	if (spec.a > 0.0)
+	{
+		vec3 ref = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(ref, vary_light.xyz);
+		col.rgb += vary_SunlitColor*scol*spec.rgb*texture2D(lightFunc, vec2(sa, spec.a)).a;
+	}
+	
+	col = atmosLighting(col);
+	col = scaleSoftClip(col);
+		
+	gl_FragColor.rgb = col;
+	
+	//gl_FragColor.rgb = gi_col.rgb;
+	gl_FragColor.a = 0.0;
+	
+	//gl_FragColor.rg = scol_ambocc.rg;
+	//gl_FragColor.rgb = texture2DRect(lightMap, vary_fragcoord.xy).rgb;
+	//gl_FragColor.rgb = norm.rgb*0.5+0.5;
+	//gl_FragColor.rgb = vec3(ambocc);
+	//gl_FragColor.rgb = vec3(scol);
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl
new file mode 100644
index 00000000000..ad8af4780d4
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightV.glsl
@@ -0,0 +1,24 @@
+/** 
+ * @file softenLightF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform vec2 screen_res;
+
+varying vec4 vary_light;
+varying vec2 vary_fragcoord;
+void main()
+{
+	//transform vertex
+	gl_Position = ftransform(); 
+	
+	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
+	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
+		
+	vec4 tex = gl_MultiTexCoord0;
+	tex.w = 1.0;
+	
+	vary_light = gl_MultiTexCoord0;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
new file mode 100644
index 00000000000..258acee08c1
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
@@ -0,0 +1,18 @@
+/** 
+ * @file treeF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+uniform sampler2D diffuseMap;
+
+varying vec3 vary_normal;
+
+void main() 
+{
+	vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[0] = vec4(gl_Color.rgb*col.rgb, col.a <= 0.5 ? 0.0 : 0.005);
+	gl_FragData[1] = vec4(0,0,0,0);
+	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
+}
diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt
index 733670f3117..5c5c4e5b3c8 100644
--- a/indra/newview/gpu_table.txt
+++ b/indra/newview/gpu_table.txt
@@ -162,8 +162,9 @@ Intel Montara					.*Intel.*Montara.*					0		0
 Intel Springdale				.*Intel.*Springdale.*				0		0
 Matrox							.*Matrox.*							0		0
 Mesa							.*Mesa.*							0		0
-NVIDIA GT 120                   .*NVIDIA.*GeForce.*GT.*12.*		    3		1
-NVIDIA GT 130                   .*NVIDIA.*GeForce.*GT.*13.*		    3		1
+NVIDIA GT 120					.*NVIDIA.*GeForce.*GT.*12.*			2		1
+NVIDIA GT 130					.*NVIDIA.*GeForce.*GT.*13.*			3		1
+NVIDIA GTS 250					.*NVIDIA.*GeForce.*GTS.*25.*		3		1
 NVIDIA GTX 260					.*NVIDIA.*GeForce.*GTX.*26.*		3		1
 NVIDIA GTX 270					.*NVIDIA.*GeForce.*GTX.*27.*		3		1
 NVIDIA GTX 280					.*NVIDIA.*GeForce.*GTX.*28.*		3		1
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 19e1273dc67..355660faa5a 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -74,6 +74,7 @@
 #include "llrender.h"
 #include "lllocationhistory.h"
 #include "llfasttimerview.h"
+
 #include "llweb.h"
 #include "llsecondlifeurls.h"
 
@@ -765,6 +766,7 @@ bool LLAppViewer::init()
 	//
 	// Initialize the window
 	//
+	gGLActive = TRUE;
 	initWindow();
 
 	// call all self-registered classes
@@ -869,12 +871,16 @@ bool LLAppViewer::init()
 	gSimFrames = (F32)gFrameCount;
 
 	LLViewerJoystick::getInstance()->init(false);
-
+	gGLActive = FALSE;
 	return true;
 }
 
 static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
 static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep");
+static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache");
+static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode");
+static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread");
+static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads");
 static LLFastTimer::DeclareTimer FTM_IDLE("Idle");
 static LLFastTimer::DeclareTimer FTM_PUMP("Pump");
 
@@ -914,6 +920,7 @@ bool LLAppViewer::mainLoop()
 	while (!LLApp::isExiting())
 	{
 		LLFastTimer::nextFrame(); // Should be outside of any timer instances
+
 		try
 		{
 			pingMainloopTimeout("Main:MiscNativeWindowEvents");
@@ -923,7 +930,7 @@ bool LLAppViewer::mainLoop()
 				LLFastTimer t2(FTM_MESSAGES);
 				gViewerWindow->mWindow->processMiscNativeEvents();
 			}
-			
+		
 			pingMainloopTimeout("Main:GatherInput");
 			
 			if (gViewerWindow)
@@ -1007,10 +1014,11 @@ bool LLAppViewer::mainLoop()
 				if (!LLApp::isExiting())
 				{
 					pingMainloopTimeout("Main:Display");
+					gGLActive = TRUE;
 					display();
-
 					pingMainloopTimeout("Main:Snapshot");
 					LLFloaterSnapshot::update(); // take snapshots
+					gGLActive = FALSE;
 				}
 
 			}
@@ -1070,11 +1078,24 @@ bool LLAppViewer::mainLoop()
 				{
 					S32 work_pending = 0;
 					S32 io_pending = 0;
- 					work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
- 					work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
- 					work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
-					io_pending += LLVFSThread::updateClass(1);
-					io_pending += LLLFSThread::updateClass(1);
+					{
+						LLFastTimer ftm(FTM_TEXTURE_CACHE);
+ 						work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
+					}
+					{
+						LLFastTimer ftm(FTM_DECODE);
+	 					work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
+					}
+					{
+						LLFastTimer ftm(FTM_DECODE);
+	 					work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
+					}
+
+					{
+						LLFastTimer ftm(FTM_VFS);
+	 					io_pending += LLVFSThread::updateClass(1);
+					}
+
 					if (io_pending > 1000)
 					{
 						ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
@@ -1100,6 +1121,8 @@ bool LLAppViewer::mainLoop()
 				// if (LLThread::processorCount()==1) //pause() should only be required when on a single processor client...
 				if (run_multiple_threads == FALSE)
 				{
+					LLFastTimer ftm(FTM_PAUSE_THREADS);
+	 					
 					LLAppViewer::getTextureCache()->pause();
 					LLAppViewer::getImageDecodeThread()->pause();
 					// LLAppViewer::getTextureFetch()->pause(); // Don't pause the fetch (IO) thread
@@ -3317,10 +3340,13 @@ void LLAppViewer::idle()
 	if (LLStartUp::getStartupState() < STATE_STARTED)
 	{
 		// Skip rest if idle startup returns false (essentially, no world yet)
+		gGLActive = TRUE;
 		if (!idle_startup())
 		{
+			gGLActive = FALSE;
 			return;
 		}
+		gGLActive = FALSE;
 	}
 
 	
@@ -3419,10 +3445,8 @@ void LLAppViewer::idle()
 	    // floating throughout the various object lists.
 	    //
     
-		stop_glerror();
 		idleNetwork();
-	    stop_glerror();
-	        
+	    	        
 
 		// Check for away from keyboard, kick idle agents.
 		idle_afk_check();
@@ -3512,8 +3536,6 @@ void LLAppViewer::idle()
 		LLHUDManager::getInstance()->sendEffects();
 	}
 
-	stop_glerror();
-
 	////////////////////////////////////////
 	//
 	// Unpack layer data that we've received
@@ -3569,7 +3591,6 @@ void LLAppViewer::idle()
 			gWindVec.setVec(0.0f, 0.0f, 0.0f);
 		}
 	}
-	stop_glerror();
 	
 	//////////////////////////////////////
 	//
@@ -3584,7 +3605,6 @@ void LLAppViewer::idle()
 
 		LLWorld::getInstance()->updateParticles();
 	}
-	stop_glerror();
 
 	if (LLViewerJoystick::getInstance()->getOverrideCamera())
 	{
@@ -3629,10 +3649,9 @@ void LLAppViewer::idle()
 	// forcibly quit if it has taken too long
 	if (mQuitRequested)
 	{
+		gGLActive = TRUE;
 		idleShutdown();
 	}
-
-	stop_glerror();
 }
 
 void LLAppViewer::idleShutdown()
@@ -3771,7 +3790,6 @@ void LLAppViewer::idleNetwork()
 		llpushcallstacks ;
 		LLTimer check_message_timer;
 		//  Read all available packets from network 
-		stop_glerror();
 		const S64 frame_count = gFrameCount;  // U32->S64
 		F32 total_time = 0.0f;
 
@@ -3784,8 +3802,7 @@ void LLAppViewer::idleNetwork()
 				// server going down, so this is OK.
 				break;
 			}
-			stop_glerror();
-
+			
 			total_decoded++;
 			gPacketsIn++;
 
@@ -3825,9 +3842,7 @@ void LLAppViewer::idleNetwork()
 
 		// we want to clear the control after sending out all necessary agent updates
 		gAgent.resetControlFlags();
-		stop_glerror();
-
-		
+				
 		// Decode enqueued messages...
 		S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
 
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 98d7ab712b7..12cff327803 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -245,6 +245,8 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,
 	}
 #endif
 	
+	gGLActive = TRUE;
+
 	viewer_app_ptr->cleanup();
 	
 #if WINDOWS_CRT_MEM_CHECKS
diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp
index bd5b9c30a21..24a57cb0c1b 100644
--- a/indra/newview/lldebugview.cpp
+++ b/indra/newview/lldebugview.cpp
@@ -102,6 +102,17 @@ LLDebugView::LLDebugView(const LLDebugView::Params& p)
 	gTextureView = LLUICtrlFactory::create<LLTextureView>(tvp);
 	addChild(gTextureView);
 	//gTextureView->reshape(r.getWidth(), r.getHeight(), TRUE);
+#if !LL_RELEASE_FOR_DOWNLOAD
+	r.set(150, rect.getHeight() - 50, 900 + LLImageGL::sTextureLoadedCounter.size() * 30, 100);
+	LLTextureSizeView::Params tsvp;
+	tsvp.name("gTextureSizeView");
+	tsvp.rect(r);
+	tsvp.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT);
+	tsvp.visible(false);
+	gTextureSizeView = LLUICtrlFactory::create<LLTextureSizeView>(tsvp);
+	addChild(gTextureSizeView);
+#endif
+
 }
 
 
@@ -110,5 +121,6 @@ LLDebugView::~LLDebugView()
 	// These have already been deleted.  Fix the globals appropriately.
 	gDebugView = NULL;
 	gTextureView = NULL;
+	gTextureSizeView = NULL;
 }
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 7cc78aff928..4cf12a1533d 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -678,6 +678,11 @@ BOOL LLDrawable::updateMoveDamped()
 
 void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 {
+	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
+	{
+		llerrs << "WTF?" << llendl;
+	}
+
 	//switch LOD with the spatial group to avoid artifacts
 	//LLSpatialGroup* sg = getSpatialGroup();
 
@@ -695,19 +700,22 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 				pos += volume->getRegion()->getOriginAgent();
 			}
 
-			for (S32 i = 0; i < getNumFaces(); i++)
+			if (isState(LLDrawable::HAS_ALPHA))
 			{
-				LLFace* facep = getFace(i);
-				if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)
+				for (S32 i = 0; i < getNumFaces(); i++)
 				{
-					LLVector3 box = (facep->mExtents[1] - facep->mExtents[0]) * 0.25f;
-					LLVector3 v = (facep->mCenterLocal-camera.getOrigin());
-					LLVector3 at = camera.getAtAxis();
-					for (U32 j = 0; j < 3; j++)
+					LLFace* facep = getFace(i);
+					if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)
 					{
-						v.mV[j] -= box.mV[j] * at.mV[j];
+						LLVector3 box = (facep->mExtents[1] - facep->mExtents[0]) * 0.25f;
+						LLVector3 v = (facep->mCenterLocal-camera.getOrigin());
+						const LLVector3& at = camera.getAtAxis();
+						for (U32 j = 0; j < 3; j++)
+						{
+							v.mV[j] -= box.mV[j] * at.mV[j];
+						}
+						facep->mDistance = v * camera.getAtAxis();
 					}
-					facep->mDistance = v * camera.getAtAxis();
 				}
 			}
 		}
@@ -1002,8 +1010,8 @@ BOOL LLDrawable::isVisible() const
 // Spatial Partition Bridging Drawable
 //=======================================
 
-LLSpatialBridge::LLSpatialBridge(LLDrawable* root, U32 data_mask)
-: LLSpatialPartition(data_mask, FALSE)
+LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask)
+: LLSpatialPartition(data_mask, render_by_group, FALSE)
 {
 	mDrawable = root;
 	root->setSpatialBridge(this);
@@ -1241,7 +1249,9 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 		(camera_in.AABBInFrustumNoFarClip(center, size) && 
 		AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))
 	{
-		if (!LLPipeline::sImpostorRender && LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA)
+		if (!LLPipeline::sImpostorRender &&
+			!LLPipeline::sShadowRender && 
+			LLPipeline::calcPixelArea(center, size, camera_in) < FORCE_INVISIBLE_AREA)
 		{
 			return;
 		}
@@ -1280,12 +1290,25 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
 		return;
 	}
 
-	LLCamera camera = transformCamera(camera_in);
-	
-	mDrawable->updateDistance(camera, force_update);
-	
 	if (mDrawable->getVObj())
 	{
+		if (mDrawable->getVObj()->isAttachment())
+		{
+			LLDrawable* parent = mDrawable->getParent();
+			if (parent && parent->getVObj())
+			{
+				LLVOAvatar* av = parent->getVObj()->asAvatar();
+				if (av && av->isImpostor())
+				{
+					return;
+				}
+			}
+		}
+
+		LLCamera camera = transformCamera(camera_in);
+	
+		mDrawable->updateDistance(camera, force_update);
+	
 		LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
 		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
 			 iter != child_list.end(); iter++)
@@ -1427,9 +1450,8 @@ void LLDrawable::updateFaceSize(S32 idx)
 }
 
 LLBridgePartition::LLBridgePartition()
-: LLSpatialPartition(0, TRUE) 
+: LLSpatialPartition(0, FALSE, 0) 
 { 
-	mRenderByGroup = FALSE; 
 	mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; 
 	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
 	mLODPeriod = 16;
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index c765980c30c..986440397b6 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -264,7 +264,8 @@ class LLDrawable : public LLRefCount
 		BUILT			= 0x08000000,
 		FORCE_INVISIBLE = 0x10000000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
 		CLEAR_INVISIBLE = 0x20000000, // clear FORCE_INVISIBLE next draw frame
-		REBUILD_SHADOW =  0x40000000
+		REBUILD_SHADOW =  0x40000000,
+		HAS_ALPHA		= 0x80000000,
 	} EDrawableFlags;
 
 	LLXformMatrix       mXform;
@@ -299,7 +300,7 @@ class LLDrawable : public LLRefCount
 	LLVector3d		mPositionGroup;
 	F64				mBinRadius;
 	S32				mGeneration;
-
+	
 	LLVector3		mCurrentScale;
 	
 	static U32 sCurVisible; // Counter for what value of mVisible means currently visible
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 3a064a4e7d8..976f02eeb7f 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -279,7 +279,7 @@ S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage)
 			 iter != face_list.end(); iter++)
 		{
 			LLFace *facep = *iter;
-			gGL.getTexUnit(stage)->bind(facep->getTexture()) ;
+			gGL.getTexUnit(stage)->bind(facep->getTexture());
 			gGL.getTexUnit(0)->activate();
 			res += facep->renderIndexed();
 		}
@@ -474,14 +474,17 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 	{
 		if (params.mTexture.notNull())
 		{
-			gGL.getTexUnit(0)->bind(params.mTexture) ;
+			gGL.getTexUnit(0)->bind(params.mTexture.get());
 			if (params.mTextureMatrix)
 			{
 				glMatrixMode(GL_TEXTURE);
 				glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
 				gPipeline.mTextureMatrixOps++;
 			}
-			params.mTexture->addTextureStats(params.mVSize);
+			if(params.mTexture.notNull())//will be removed.
+			{
+				params.mTexture->addTextureStats(params.mVSize);
+			}
 		}
 		else
 		{
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 966de41df3c..67870c10e93 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -61,12 +61,17 @@ class LLDrawPool
 		POOL_GRASS,
 		POOL_FULLBRIGHT,
 		POOL_BUMP,
-		POOL_INVISIBLE,
+		POOL_INVISIBLE, // see below *
 		POOL_AVATAR,
 		POOL_WATER,
 		POOL_GLOW,
 		POOL_ALPHA,
 		NUM_POOL_TYPES,
+		// * invisiprims work by rendering to the depth buffer but not the color buffer, occluding anything rendered after them
+		// - and the LLDrawPool types enum controls what order things are rendered in
+		// - so, it has absolute control over what invisprims block
+		// ...invisiprims being rendered in pool_invisible
+		// ...shiny/bump mapped objects in rendered in POOL_BUMP
 	};
 	
 	LLDrawPool(const U32 type);
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 88f79fc1b95..a5a29dea7b2 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -87,22 +87,23 @@ void LLDrawPoolAlpha::beginDeferredPass(S32 pass)
 
 void LLDrawPoolAlpha::endDeferredPass(S32 pass)
 {
-	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.4f);
+	
+}
+
+void LLDrawPoolAlpha::renderDeferred(S32 pass)
+{
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
 	{
 		LLFastTimer t(FTM_RENDER_GRASS);
 		gDeferredTreeProgram.bind();
 		LLGLEnable test(GL_ALPHA_TEST);
 		//render alpha masked objects
 		LLRenderPass::renderTexture(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());
+		gDeferredTreeProgram.unbind();
 	}			
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 }
 
-void LLDrawPoolAlpha::renderDeferred(S32 pass)
-{
-	
-}
-
 
 S32 LLDrawPoolAlpha::getNumPostDeferredPasses() 
 { 
@@ -260,6 +261,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 {
 	BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
+	S32 diffuse_channel = 0;
+
 	//BOOL is_particle = FALSE;
 	BOOL use_shaders = (LLPipeline::sUnderWaterRender && gPipeline.canUseVertexShaders())
 		|| gPipeline.canUseWindLightShadersOnObjects();
@@ -290,19 +293,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 
 				LLRenderPass::applyModelMatrix(params);
 
-				if (params.mTexture.notNull())
-				{
-					gGL.getTexUnit(0)->activate();
-					gGL.getTexUnit(0)->bind(params.mTexture) ;
-					params.mTexture->addTextureStats(params.mVSize);
-					if (params.mTextureMatrix)
-					{
-						glMatrixMode(GL_TEXTURE);
-						glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
-						gPipeline.mTextureMatrixOps++;
-					}
-				}
-
 				if (params.mFullbright)
 				{
 					// Turn off lighting if it hasn't already been so.
@@ -343,11 +333,13 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					if (deferred_render && current_shader != NULL)
 					{
 						gPipeline.unbindDeferredShader(*current_shader);
+						diffuse_channel = 0;
 					}
 					current_shader = target_shader;
 					if (deferred_render)
 					{
 						gPipeline.bindDeferredShader(*current_shader);
+						diffuse_channel = current_shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 					}
 					else
 					{
@@ -356,11 +348,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 				}
 				else if (!use_shaders && current_shader != NULL)
 				{
-					LLGLSLShader::bindNoShader();
 					if (deferred_render)
 					{
 						gPipeline.unbindDeferredShader(*current_shader);
+						diffuse_channel = 0;
 					}
+					LLGLSLShader::bindNoShader();
 					current_shader = NULL;
 				}
 
@@ -368,6 +361,24 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 				{
 					params.mGroup->rebuildMesh();
 				}
+
+				
+				if (params.mTexture.notNull())
+				{
+					gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get());
+					if(params.mTexture.notNull())
+					{
+						params.mTexture->addTextureStats(params.mVSize);
+					}
+					if (params.mTextureMatrix)
+					{
+						gGL.getTexUnit(0)->activate();
+						glMatrixMode(GL_TEXTURE);
+						glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+						gPipeline.mTextureMatrixOps++;
+					}
+				}
+
 				params.mVertexBuffer->setBuffer(mask);
 				params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 				gPipeline.addTrianglesDrawn(params.mCount/3);
@@ -382,6 +393,15 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 		}
 	}
 
+	if (deferred_render && current_shader != NULL)
+	{
+		gPipeline.unbindDeferredShader(*current_shader);
+		LLVertexBuffer::unbind();	
+		LLGLState::checkStates();
+		LLGLState::checkTextureChannels();
+		LLGLState::checkClientArrays();
+	}
+	
 	if (!light_enabled)
 	{
 		gPipeline.enableLightsDynamic();
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 565f906a3b9..546b60f2867 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -92,6 +92,7 @@ BOOL gAvatarEmbossBumpMap = FALSE;
 static BOOL sRenderingSkinned = FALSE;
 S32 normal_channel = -1;
 S32 specular_channel = -1;
+S32 diffuse_channel = -1;
 
 static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow");
 
@@ -388,6 +389,7 @@ void LLDrawPoolAvatar::beginFootShadow()
 	}
 
 	gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+	diffuse_channel = 0;
 }
 
 void LLDrawPoolAvatar::endFootShadow()
@@ -440,7 +442,8 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 
 	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-				
+	diffuse_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+
 	sVertexProgram->bind();
 }
 
@@ -449,6 +452,7 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 	sShaderLevel = mVertexShaderLevel;
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	sVertexProgram->unbind();
 	gGL.getTexUnit(0)->activate();
 }
@@ -685,7 +689,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 					avatarp->mImpostor.bindTexture(1, specular_channel);
 				}
 			}
-			avatarp->renderImpostor();
+			avatarp->renderImpostor(LLColor4U(255,255,255,255), diffuse_channel);
 		}
 		else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS) && !LLPipeline::sRenderDeferred)
 		{
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 331ba67d36c..f581f2c4022 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -572,6 +572,8 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 	LLViewerTexture* bump = NULL;
 
 	U8 bump_code = params.mBump;
+
+	//Note: texture atlas does not support bump texture now.
 	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params.mTexture) ;
 	if(!tex)
 	{
@@ -831,7 +833,7 @@ void LLBumpImageList::updateImages()
 		if( image )
 		{
 			BOOL destroy = TRUE;
-			if( image->hasValidGLTexture())
+			if( image->hasGLTexture())
 			{
 				if( image->getBoundRecently() )
 				{
@@ -858,7 +860,7 @@ void LLBumpImageList::updateImages()
 		if( image )
 		{
 			BOOL destroy = TRUE;
-			if( image->hasValidGLTexture())
+			if( image->hasGLTexture())
 			{
 				if( image->getBoundRecently() )
 				{
@@ -963,7 +965,7 @@ void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTextu
 		LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
 		generateNormalMapFromAlpha(src, nrm_image);
 		src_vi->setExplicitFormat(GL_RGBA, GL_RGBA);
-		src_vi->createGLTexture(0, nrm_image);
+		src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image);
 	}
 }
 
@@ -1147,14 +1149,14 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			if (!LLPipeline::sRenderDeferred)
 			{
 				bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
-				bump->createGLTexture(0, dst_image);
+				bump->createGLTexture(bump->getDiscardLevel(), dst_image);
 			}
 			else
 			{
 				LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
 				generateNormalMapFromAlpha(src, nrm_image);
 				bump->setExplicitFormat(GL_RGBA, GL_RGBA);
-				bump->createGLTexture(0, nrm_image);
+				bump->createGLTexture(bump->getDiscardLevel(), nrm_image);
 			}
 
 			
@@ -1216,7 +1218,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 		if (params.mTexture.notNull())
 		{
 			gGL.getTexUnit(diffuse_channel)->bind(params.mTexture) ;
-			params.mTexture->addTextureStats(params.mVSize);
+			params.mTexture->addTextureStats(params.mVSize);		
 		}
 		else
 		{
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 331536fdca7..ca7a1b47c2c 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -47,6 +47,9 @@
 static LLGLSLShader* simple_shader = NULL;
 static LLGLSLShader* fullbright_shader = NULL;
 
+static LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple");
+static LLFastTimer::DeclareTimer FTM_RENDER_GRASS_DEFERRED("Deferred Grass");
+
 void LLDrawPoolGlow::render(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_GLOW);
@@ -156,13 +159,13 @@ void LLDrawPoolSimple::render(S32 pass)
 
 void LLDrawPoolSimple::beginDeferredPass(S32 pass)
 {
-	LLFastTimer t(FTM_RENDER_SIMPLE);
+	LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED);
 	gDeferredDiffuseProgram.bind();
 }
 
 void LLDrawPoolSimple::endDeferredPass(S32 pass)
 {
-	LLFastTimer t(FTM_RENDER_SIMPLE);
+	LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED);
 	LLRenderPass::endRenderPass(pass);
 
 	gDeferredDiffuseProgram.unbind();
@@ -174,7 +177,7 @@ void LLDrawPoolSimple::renderDeferred(S32 pass)
 	LLGLDisable alpha_test(GL_ALPHA_TEST);
 
 	{ //render simple
-		LLFastTimer t(FTM_RENDER_SIMPLE);
+		LLFastTimer t(FTM_RENDER_SIMPLE_DEFERRED);
 		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
 	}
 }
@@ -258,10 +261,10 @@ void LLDrawPoolGrass::endDeferredPass(S32 pass)
 
 void LLDrawPoolGrass::renderDeferred(S32 pass)
 {
-	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
 
 	{
-		LLFastTimer t(FTM_RENDER_GRASS);
+		LLFastTimer t(FTM_RENDER_GRASS_DEFERRED);
 		gDeferredTreeProgram.bind();
 		LLGLEnable test(GL_ALPHA_TEST);
 		//render grass
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 345dd6bb844..790e75cfaae 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -77,7 +77,7 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) :
 													GL_ALPHA8, GL_ALPHA,
 													LLUUID("e97cf410-8e61-7005-ec06-629eba4cd1fb"));
 
-	gGL.getTexUnit(0)->bind(mAlphaRampImagep);
+	//gGL.getTexUnit(0)->bind(mAlphaRampImagep.get());
 	mAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
 	m2DAlphaRampImagep = LLViewerTextureManager::getFetchedTextureFromFile("alpha_gradient_2d.j2c", 
@@ -86,12 +86,12 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) :
 													GL_ALPHA8, GL_ALPHA,
 													LLUUID("38b86f85-2575-52a9-a531-23108d8da837"));
 
-	gGL.getTexUnit(0)->bind(m2DAlphaRampImagep);
+	//gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get());
 	m2DAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	
 	mTexturep->setBoostLevel(LLViewerTexture::BOOST_TERRAIN);
 	
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 }
 
 LLDrawPoolTerrain::~LLDrawPoolTerrain()
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 5cb1fcb635b..8d2cbc583c1 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -52,7 +52,6 @@ LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) :
 	LLFacePool(POOL_TREE),
 	mTexturep(texturep)
 {
-	gGL.getTexUnit(0)->bind(mTexturep);
 	mTexturep->setAddressMode(LLTexUnit::TAM_WRAP);
 }
 
@@ -138,7 +137,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass)
 void LLDrawPoolTree::beginDeferredPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_TREES);
-	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
 		
 	shader = &gDeferredTreeProgram;
 	shader->bind();
@@ -164,6 +163,9 @@ void LLDrawPoolTree::beginShadowPass(S32 pass)
 {
 	LLFastTimer t(FTM_SHADOW_TREE);
 	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
+	glPolygonOffset(gSavedSettings.getF32("RenderDeferredTreeShadowOffset"),
+					gSavedSettings.getF32("RenderDeferredTreeShadowBias"));
+
 	gDeferredShadowProgram.bind();
 }
 
@@ -176,7 +178,11 @@ void LLDrawPoolTree::endShadowPass(S32 pass)
 {
 	LLFastTimer t(FTM_SHADOW_TREE);
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
-	gDeferredShadowProgram.unbind();
+
+	glPolygonOffset(gSavedSettings.getF32("RenderDeferredSpotShadowOffset"),
+						gSavedSettings.getF32("RenderDeferredSpotShadowBias"));
+
+	//gDeferredShadowProgram.unbind();
 }
 
 
@@ -247,7 +253,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
 	LLGLState normalize(GL_NORMALIZE, TRUE);
 	
 	// Bind the texture for this tree.
-	gGL.getTexUnit(sDiffTex)->bind(mTexturep);
+	gGL.getTexUnit(sDiffTex)->bind(mTexturep.get());
 		
 	U32 indices_drawn = 0;
 
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index fd4dc123d5f..f56359afc36 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -136,6 +136,19 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass)
 	deferred_render = FALSE;
 }
 
+//===============================
+//DEFERRED IMPLEMENTATION
+//===============================
+void LLDrawPoolWater::renderDeferred(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_WATER);
+	deferred_render = TRUE;
+	shade();
+	deferred_render = FALSE;
+}
+
+//=========================================
+
 void LLDrawPoolWater::render(S32 pass)
 {
 	LLFastTimer ftm(FTM_RENDER_WATER);
@@ -337,7 +350,10 @@ void LLDrawPoolWater::renderReflection(LLFace* face)
 
 void LLDrawPoolWater::shade()
 {
-	gGL.setColorMask(true, true);
+	if (!deferred_render)
+	{
+		gGL.setColorMask(true, true);
+	}
 
 	LLVOSky *voskyp = gSky.mVOSkyp;
 
@@ -400,6 +416,15 @@ void LLDrawPoolWater::shade()
 		shader = &gWaterProgram;
 	}
 
+	if (deferred_render)
+	{
+		gPipeline.bindDeferredShader(*shader);
+	}
+	else
+	{
+		shader->bind();
+	}
+
 	sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f;
 	
 	S32 reftex = shader->enableTexture(LLViewerShaderMgr::WATER_REFTEX);
@@ -435,15 +460,6 @@ void LLDrawPoolWater::shade()
 	
 	S32 screentex = shader->enableTexture(LLViewerShaderMgr::WATER_SCREENTEX);	
 		
-	if (deferred_render)
-	{
-		gPipeline.bindDeferredShader(*shader);
-	}
-	else
-	{
-		shader->bind();
-	}
-	
 	if (screentex > -1)
 	{
 		shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
@@ -547,8 +563,15 @@ void LLDrawPoolWater::shade()
 			{ //smash background faces to far clip plane
 				if (water->getIsEdgePatch())
 				{
-					LLGLClampToFarClip far_clip(glh_get_current_projection());
-					face->renderIndexed();
+					if (deferred_render)
+					{
+						face->renderIndexed();
+					}
+					else
+					{
+						LLGLClampToFarClip far_clip(glh_get_current_projection());
+						face->renderIndexed();
+					}
 				}
 				else
 				{
@@ -577,7 +600,10 @@ void LLDrawPoolWater::shade()
 
 	gGL.getTexUnit(0)->activate();
 	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-	gGL.setColorMask(true, false);
+	if (!deferred_render)
+	{
+		gGL.setColorMask(true, false);
+	}
 
 }
 
diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h
index e28ac1cfaba..68a8172dd04 100644
--- a/indra/newview/lldrawpoolwater.h
+++ b/indra/newview/lldrawpoolwater.h
@@ -71,10 +71,12 @@ class LLDrawPoolWater: public LLFacePool
 	/*virtual*/ LLDrawPool *instancePool();
 	static void restoreGL();
 	
-	/*virtual*/ S32 getNumPostDeferredPasses() { return getNumPasses(); }
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 0; } //getNumPasses(); }
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass) { render(pass); }
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void renderDeferred(S32 pass = 0);
 
 	/*virtual*/ S32 getNumPasses();
 	/*virtual*/ void render(S32 pass = 0);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index bef9e40c494..8aea7422fc3 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -174,6 +174,9 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mLastGeomIndex = mGeomIndex;
 	mLastIndicesCount = mIndicesCount;
 	mLastIndicesIndex = mIndicesIndex;
+
+	mAtlasInfop = NULL ;
+	mUsingAtlas  = FALSE ;
 }
 
 
@@ -200,12 +203,14 @@ void LLFace::destroy()
 			if (group)
 			{
 				group->dirtyGeom();
+				gPipeline.markRebuild(group, TRUE);
 			}
 		}
 	}
 
 	setDrawInfo(NULL);
 	
+	removeAtlas();
 	mDrawablep = NULL;
 	mVObjp = NULL;
 }
@@ -264,6 +269,7 @@ void LLFace::setTexture(LLViewerTexture* tex)
 	if(mTexture.notNull())
 	{
 		mTexture->removeFace(this) ;
+		removeAtlas() ;
 	}
 	
 	mTexture = tex ;
@@ -447,8 +453,15 @@ void LLFace::renderForSelect(U32 data_mask)
 
 void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 {
-	if(mDrawablep.isNull() || mVertexBuffer.isNull() || mDrawablep->getSpatialGroup() == NULL ||
-		mDrawablep->getSpatialGroup()->isState(LLSpatialGroup::GEOM_DIRTY))
+	if (mDrawablep->getSpatialGroup() == NULL)
+	{
+		return;
+	}
+
+	mDrawablep->getSpatialGroup()->rebuildGeom();
+	mDrawablep->getSpatialGroup()->rebuildMesh();
+		
+	if(mDrawablep.isNull() || mVertexBuffer.isNull())
 	{
 		return;
 	}
@@ -467,17 +480,10 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 			glMultMatrixf((GLfloat*)mDrawablep->getRegion()->mRenderMatrix.mMatrix);
 		}
 
-		setFaceColor(color);
-		renderSetColor();
-
+		glColor4fv(color.mV);
 		mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
-#if !LL_RELEASE_FOR_DOWNLOAD
-		LLGLState::checkClientArrays("", LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
-#endif
 		mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
 
-		unsetFaceColor();
-		unsetFaceColor();
 		gGL.popMatrix();
 	}
 }
@@ -888,6 +894,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	{
 		mVertexBuffer->getBinormalStrider(binormals, mGeomIndex);
 	}
+
+	F32 tcoord_xoffset = 0.f ;
+	F32 tcoord_yoffset = 0.f ;
+	F32 tcoord_xscale = 1.f ;
+	F32 tcoord_yscale = 1.f ;
+	BOOL in_atlas = FALSE ;
+
 	if (rebuild_tcoord)
 	{
 		mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex);
@@ -895,6 +908,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		{
 			mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex);
 		}
+
+		in_atlas = isAtlasInUse() ;
+		if(in_atlas)
+		{
+			const LLVector2* tmp = getTexCoordOffset() ;
+			tcoord_xoffset = tmp->mV[0] ; 
+			tcoord_yoffset = tmp->mV[1] ;
+
+			tmp = getTexCoordScale() ;
+			tcoord_xscale = tmp->mV[0] ; 
+			tcoord_yscale = tmp->mV[1] ;	
+		}
 	}
 	if (rebuild_color)
 	{	
@@ -1021,7 +1046,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			break;
 			case BE_BRIGHTNESS:
 			case BE_DARKNESS:
-			if( mTexture.notNull() && mTexture->hasValidGLTexture())
+			if( mTexture.notNull() && mTexture->hasGLTexture())
 			{
 				// Offset by approximately one texel
 				S32 cur_discard = mTexture->getDiscardLevel();
@@ -1104,6 +1129,93 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
 			}
 
+			if(in_atlas)
+			{
+				//
+				//manually calculate tex-coord per vertex for varying address modes.
+				//should be removed if shader can handle this.
+				//
+
+				S32 int_part = 0 ;
+				switch(mTexture->getAddressMode())
+				{
+				case LLTexUnit::TAM_CLAMP:
+					if(tc.mV[0] < 0.f)
+					{
+						tc.mV[0] = 0.f ;
+					}
+					else if(tc.mV[0] > 1.f)
+					{
+						tc.mV[0] = 1.f;
+					}
+
+					if(tc.mV[1] < 0.f)
+					{
+						tc.mV[1] = 0.f ;
+					}
+					else if(tc.mV[1] > 1.f)
+					{
+						tc.mV[1] = 1.f;
+					}
+					break;
+				case LLTexUnit::TAM_MIRROR:
+					if(tc.mV[0] < 0.f)
+					{
+						tc.mV[0] = -tc.mV[0] ;
+					}
+					int_part = (S32)tc.mV[0] ;
+					if(int_part & 1) //odd number
+					{
+						tc.mV[0] = int_part + 1 - tc.mV[0] ;
+					}
+					else //even number
+					{
+						tc.mV[0] -= int_part ;
+					}
+
+					if(tc.mV[1] < 0.f)
+					{
+						tc.mV[1] = -tc.mV[1] ;
+					}
+					int_part = (S32)tc.mV[1] ;
+					if(int_part & 1) //odd number
+					{
+						tc.mV[1] = int_part + 1 - tc.mV[1] ;
+					}
+					else //even number
+					{
+						tc.mV[1] -= int_part ;
+					}
+					break;
+				case LLTexUnit::TAM_WRAP:
+					if(tc.mV[0] > 1.f)
+						tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
+					else if(tc.mV[0] < -1.f)
+						tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
+
+					if(tc.mV[1] > 1.f)
+						tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
+					else if(tc.mV[1] < -1.f)
+						tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
+
+					if(tc.mV[0] < 0.f)
+					{
+						tc.mV[0] = 1.0f + tc.mV[0] ;
+					}
+					if(tc.mV[1] < 0.f)
+					{
+						tc.mV[1] = 1.0f + tc.mV[1] ;
+					}
+					break;
+				default:
+					break;
+				}
+			
+				tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
+				tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
+			}
+			
+
 			*tex_coords++ = tc;
 		
 			if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
@@ -1358,3 +1470,156 @@ LLVector3 LLFace::getPositionAgent() const
 		return mCenterLocal * getRenderMatrix();
 	}
 }
+
+//
+//atlas
+//
+void LLFace::removeAtlas()
+{
+	setAtlasInUse(FALSE) ;
+	mAtlasInfop = NULL ;	
+}
+
+const LLTextureAtlas* LLFace::getAtlas()const 
+{
+	if(mAtlasInfop)
+	{
+		return mAtlasInfop->getAtlas() ;
+	}
+	return NULL ;
+}
+
+const LLVector2* LLFace::getTexCoordOffset()const 
+{
+	if(isAtlasInUse())
+	{
+		return mAtlasInfop->getTexCoordOffset() ;
+	}
+	return NULL ;
+}
+const LLVector2* LLFace::getTexCoordScale() const 
+{
+	if(isAtlasInUse())
+	{
+		return mAtlasInfop->getTexCoordScale() ;
+	}
+	return NULL ;
+}
+
+BOOL LLFace::isAtlasInUse()const
+{
+	return mUsingAtlas ;
+}
+
+BOOL LLFace::canUseAtlas()const
+{
+	//no drawable or no spatial group, do not use atlas
+	if(!mDrawablep || !mDrawablep->getSpatialGroup())
+	{
+		return FALSE ;
+	}
+
+	//if bump face, do not use atlas
+	if(getTextureEntry() && getTextureEntry()->getBumpmap())
+	{
+		return FALSE ;
+	}
+
+	//if animated texture, do not use atlas
+	if(isState(TEXTURE_ANIM))
+	{
+		return FALSE ;
+	}
+
+	return TRUE ;
+}
+
+void LLFace::setAtlasInUse(BOOL flag)
+{
+	//no valid atlas to use.
+	if(flag && (!mAtlasInfop || !mAtlasInfop->isValid()))
+	{
+		flag = FALSE ;
+	}
+
+	if(!flag && !mUsingAtlas)
+	{
+		return ;
+	}
+
+	//
+	//at this stage (flag || mUsingAtlas) is always true.
+	//
+
+	//rebuild the tex coords
+	if(mDrawablep)
+	{
+		gPipeline.markRebuild(mDrawablep, LLDrawable::REBUILD_TCOORD);
+		mUsingAtlas = flag ;
+	}
+	else
+	{
+		mUsingAtlas = FALSE ;
+	}
+}
+
+LLTextureAtlasSlot* LLFace::getAtlasInfo()
+{
+	return mAtlasInfop ;
+}
+
+void LLFace::setAtlasInfo(LLTextureAtlasSlot* atlasp)
+{	
+	if(mAtlasInfop != atlasp)
+	{
+		if(mAtlasInfop)
+		{
+			//llerrs << "Atlas slot changed!" << llendl ;
+		}
+		mAtlasInfop = atlasp ;
+	}
+}
+
+LLViewerTexture* LLFace::getTexture() const
+{
+	if(isAtlasInUse())
+	{
+		return (LLViewerTexture*)mAtlasInfop->getAtlas() ;
+	}
+
+	return mTexture ;
+}
+
+//switch to atlas or switch back to gl texture 
+//return TRUE if using atlas.
+BOOL LLFace::switchTexture()
+{
+	//no valid atlas or texture
+	if(!mAtlasInfop || !mAtlasInfop->isValid() || !mTexture)
+	{
+		return FALSE ;
+	}
+	
+	if(mTexture->getTexelsInAtlas() >= (U32)mVSize || 
+		mTexture->getTexelsInAtlas() >= mTexture->getTexelsInGLTexture())
+	{
+		//switch to use atlas
+		//atlas resolution is qualified, use it.		
+		if(!mUsingAtlas)
+		{
+			setAtlasInUse(TRUE) ;
+		}
+	}
+	else //if atlas not qualified.
+	{
+		//switch back to GL texture
+		if(mUsingAtlas && mTexture->isGLTextureCreated() && 
+			mTexture->getDiscardLevel() < mTexture->getDiscardLevelInAtlas())
+		{
+			setAtlasInUse(FALSE) ;
+		}
+	}
+
+	return mUsingAtlas ;
+}
+
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index e0728fe15e3..cafad5706c8 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -47,6 +47,7 @@
 #include "llvertexbuffer.h"
 #include "llviewertexture.h"
 #include "lldrawable.h"
+#include "lltextureatlasmanager.h"
 
 class LLFacePool;
 class LLVolume;
@@ -55,6 +56,7 @@ class LLTextureEntry;
 class LLVertexProgram;
 class LLViewerTexture;
 class LLGeometryManager;
+class LLTextureAtlasSlot;
 
 const F32 MIN_ALPHA_SIZE = 1024.f;
 const F32 MIN_TEX_ANIM_SIZE = 512.f;
@@ -86,7 +88,6 @@ class LLFace
 	U16				getGeomCount()		const	{ return mGeomCount; }		// vertex count for this face
 	U16				getGeomIndex()		const	{ return mGeomIndex; }		// index into draw pool
 	U16				getGeomStart()		const	{ return mGeomIndex; }		// index into draw pool
-	LLViewerTexture*	getTexture()		const	{ return mTexture; }
 	void			setTexture(LLViewerTexture* tex) ;
 	LLXformMatrix*	getXform()			const	{ return mXform; }
 	BOOL			hasGeometry()		const	{ return mGeomCount > 0; }
@@ -119,7 +120,7 @@ class LLFace
 	LLVertexBuffer* getVertexBuffer()	const	{ return mVertexBuffer; }
 	void			setPoolType(U32 type)		{ mPoolType = type; }
 	S32				getTEOffset()				{ return mTEOffset; }
-	LLViewerTexture*	getTexture()				{ return mTexture; }
+	LLViewerTexture*	getTexture() const;
 
 	void			setViewerObject(LLViewerObject* object);
 	void			setPool(LLFacePool *pool, LLViewerTexture *texturep);
@@ -185,7 +186,17 @@ class LLFace
 	void		setIndicesIndex(S32 idx) { mIndicesIndex = idx; }
 	void		setDrawInfo(LLDrawInfo* draw_info);
 
-protected:
+	//for atlas
+	LLTextureAtlasSlot*   getAtlasInfo() ;
+	void                  setAtlasInUse(BOOL flag);
+	void                  setAtlasInfo(LLTextureAtlasSlot* atlasp);
+	BOOL                  isAtlasInUse()const;
+	BOOL                  canUseAtlas() const;
+	const LLVector2*      getTexCoordScale() const ;
+	const LLVector2*      getTexCoordOffset()const;
+	const LLTextureAtlas* getAtlas()const ;
+	void                  removeAtlas() ;
+	BOOL                  switchTexture() ;
 
 public:
 	
@@ -230,6 +241,10 @@ class LLFace
 	S32			mReferenceIndex;
 	F32			mVSize;
 	F32			mPixelArea;
+
+	//atlas
+	LLPointer<LLTextureAtlasSlot> mAtlasInfop ;
+	BOOL                              mUsingAtlas ;
 	
 protected:
 	static BOOL	sSafeRenderSelect;
@@ -258,7 +273,7 @@ class LLFace
 			const LLTextureEntry* lte = lhs->getTextureEntry();
 			const LLTextureEntry* rte = rhs->getTextureEntry();
 
-			if (lhs->getTexture() != rhs->getTexture())
+			if(lhs->getTexture() != rhs->getTexture())
 			{
 				return lhs->getTexture() < rhs->getTexture();
 			}
diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp
index a27070de393..fbc0ff3cf57 100644
--- a/indra/newview/llfloaterpostcard.cpp
+++ b/indra/newview/llfloaterpostcard.cpp
@@ -148,11 +148,11 @@ void LLFloaterPostcard::draw()
 		F32 ratio = (F32)mJPEGImage->getWidth() / (F32)mJPEGImage->getHeight();
 		if ((F32)rect.getWidth() / (F32)rect.getHeight() >= ratio)
 		{
-			rect.mRight = (S32)((F32)rect.mLeft + ((F32)rect.getHeight() * ratio));
+			rect.mRight = LLRect::tCoordType((F32)rect.mLeft + ((F32)rect.getHeight() * ratio));
 		}
 		else
 		{
-			rect.mBottom = (S32)((F32)rect.mTop - ((F32)rect.getWidth() / ratio));
+			rect.mBottom = LLRect::tCoordType((F32)rect.mTop - ((F32)rect.getWidth() / ratio));
 		}
 		{
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp
index 616e9bac358..8979575ef79 100644
--- a/indra/newview/llfloatersettingsdebug.cpp
+++ b/indra/newview/llfloatersettingsdebug.cpp
@@ -111,6 +111,11 @@ void LLFloaterSettingsDebug::onCommitSettings()
 	LLComboBox* settings_combo = getChild<LLComboBox>("settings_combo");
 	LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata();
 
+	if (!controlp)
+	{
+		return;
+	}
+
 	LLVector3 vector;
 	LLVector3d vectord;
 	LLRect rect;
diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp
index 18745284cbc..02979acdd72 100644
--- a/indra/newview/llfloaterwindlight.cpp
+++ b/indra/newview/llfloaterwindlight.cpp
@@ -59,6 +59,8 @@
 #include "llwlparamset.h"
 #include "llwlparammanager.h"
 #include "llpostprocess.h"
+#include "lltabcontainer.h"
+
 
 #undef max
 
@@ -434,6 +436,11 @@ void LLFloaterWindLight::syncMenu()
 	childSetValue("WLGamma", param_mgr->mWLGamma.x);
 
 	childSetValue("WLStarAlpha", param_mgr->mCurParams.getStarBrightness());
+
+	LLTabContainer* tab = getChild<LLTabContainer>("WindLight Tabs");
+	LLPanel* panel = getChild<LLPanel>("Scattering");
+
+	tab->enableTabButton(tab->getIndexForPanel(panel), gSavedSettings.getBOOL("RenderDeferredGI"));
 }
 
 
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 8086400493c..55019f91f89 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -1063,6 +1063,8 @@ void LLHUDText::renderAllHUD()
 	
 	LLVertexBuffer::unbind();
 
+    LLVertexBuffer::unbind();
+
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
 	LLGLState::checkClientArrays();
diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp
index 3d1d6cad743..f62d7229a31 100644
--- a/indra/newview/llmanip.cpp
+++ b/indra/newview/llmanip.cpp
@@ -85,6 +85,7 @@ void LLManip::rebuild(LLViewerObject* vobj)
 		if (group)
 		{
 			group->dirtyGeom();
+			gPipeline.markRebuild(group, TRUE);
 		}
 	}
 }
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index ce16b95bc05..4ac109bf3d2 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -52,6 +52,7 @@
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
 #include "llcolorswatch.h"
+#include "lltexturectrl.h"
 #include "llcombobox.h"
 #include "llfirstuse.h"
 #include "llfocusmgr.h"
@@ -72,6 +73,7 @@
 #include "llvovolume.h"
 #include "llworld.h"
 #include "pipeline.h"
+#include "llviewershadermgr.h"
 
 #include "lldrawpool.h"
 #include "lluictrlfactory.h"
@@ -110,12 +112,28 @@ BOOL	LLPanelVolume::postBuild()
 			LightColorSwatch->setOnSelectCallback(boost::bind(&LLPanelVolume::onLightSelectColor, this, _2));
 			childSetCommitCallback("colorswatch",onCommitLight,this);
 		}
+
+		LLTextureCtrl* LightTexPicker = getChild<LLTextureCtrl>("light texture control");
+		if (LightTexPicker)
+		{
+			LightTexPicker->setOnCancelCallback(boost::bind(&LLPanelVolume::onLightCancelTexture, this, _2));
+			LightTexPicker->setOnSelectCallback(boost::bind(&LLPanelVolume::onLightSelectTexture, this, _2));
+			childSetCommitCallback("light texture control", onCommitLight, this);
+		}
+
 		childSetCommitCallback("Light Intensity",onCommitLight,this);
 		childSetValidate("Light Intensity",precommitValidate);
 		childSetCommitCallback("Light Radius",onCommitLight,this);
 		childSetValidate("Light Radius",precommitValidate);
 		childSetCommitCallback("Light Falloff",onCommitLight,this);
 		childSetValidate("Light Falloff",precommitValidate);
+		
+		childSetCommitCallback("Light FOV", onCommitLight, this);
+		childSetValidate("Light FOV", precommitValidate);
+		childSetCommitCallback("Light Focus", onCommitLight, this);
+		childSetValidate("Light Focus", precommitValidate);
+		childSetCommitCallback("Light Ambiance", onCommitLight, this);
+		childSetValidate("Light Ambiance", precommitValidate);
 	}
 	
 	// Start with everyone disabled
@@ -220,14 +238,32 @@ void LLPanelVolume::getState( )
 			LightColorSwatch->setValid( TRUE );
 			LightColorSwatch->set(volobjp->getLightBaseColor());
 		}
+
+		LLTextureCtrl* LightTextureCtrl = getChild<LLTextureCtrl>("light texture control");
+		if (LightTextureCtrl)
+		{
+			LightTextureCtrl->setEnabled(TRUE);
+			LightTextureCtrl->setValid(TRUE);
+			LightTextureCtrl->setImageAssetID(volobjp->getLightTextureID());
+		}
+
 		childSetEnabled("Light Intensity",true);
 		childSetEnabled("Light Radius",true);
 		childSetEnabled("Light Falloff",true);
 
+		childSetEnabled("Light FOV", true);
+		childSetEnabled("Light Focus", true);
+		childSetEnabled("Light Ambiance", true);
+		
 		childSetValue("Light Intensity",volobjp->getLightIntensity());
 		childSetValue("Light Radius",volobjp->getLightRadius());
 		childSetValue("Light Falloff",volobjp->getLightFalloff());
 
+		LLVector3 params = volobjp->getSpotLightParams();
+		childSetValue("Light FOV", params.mV[0]);
+		childSetValue("Light Focus", params.mV[1]);
+		childSetValue("Light Ambiance", params.mV[2]);
+
 		mLightSavedColor = volobjp->getLightColor();
 	}
 	else
@@ -243,9 +279,20 @@ void LLPanelVolume::getState( )
 			LightColorSwatch->setEnabled( FALSE );
 			LightColorSwatch->setValid( FALSE );
 		}
+		LLTextureCtrl* LightTextureCtrl = getChild<LLTextureCtrl>("light texture control");
+		if (LightTextureCtrl)
+		{
+			LightTextureCtrl->setEnabled(FALSE);
+			LightTextureCtrl->setValid(FALSE);
+		}
+
 		childSetEnabled("Light Intensity",false);
 		childSetEnabled("Light Radius",false);
 		childSetEnabled("Light Falloff",false);
+
+		childSetEnabled("Light FOV",false);
+		childSetEnabled("Light Focus",false);
+		childSetEnabled("Light Ambiance",false);
 	}
 	
 	// Flexible properties
@@ -335,6 +382,15 @@ void LLPanelVolume::refresh()
 	{
 		mRootObject = NULL;
 	}
+
+	BOOL visible = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 0 ? TRUE : FALSE;
+
+	childSetVisible("label texture", visible);
+	childSetVisible("Light FOV", visible);
+	childSetVisible("Light Focus", visible);
+	childSetVisible("Light Ambiance", visible);
+	childSetVisible("light texture control", visible);
+
 }
 
 
@@ -361,6 +417,13 @@ void LLPanelVolume::clearCtrls()
 		LightColorSwatch->setEnabled( FALSE );
 		LightColorSwatch->setValid( FALSE );
 	}
+	LLTextureCtrl* LightTextureCtrl = getChild<LLTextureCtrl>("light texture control");
+	if(LightTextureCtrl)
+	{
+		LightTextureCtrl->setEnabled( FALSE );
+		LightTextureCtrl->setValid( FALSE );
+	}
+
 	childSetEnabled("Light Intensity",false);
 	childSetEnabled("Light Radius",false);
 	childSetEnabled("Light Falloff",false);
@@ -436,6 +499,15 @@ void LLPanelVolume::onLightCancelColor(const LLSD& data)
 	onLightSelectColor(data);
 }
 
+void LLPanelVolume::onLightCancelTexture(const LLSD& data)
+{
+	LLTextureCtrl* LightTextureCtrl = getChild<LLTextureCtrl>("light texture control");
+	if (LightTextureCtrl)
+	{
+		LightTextureCtrl->setImageAssetID(mLightSavedTexture);
+	}
+}
+
 void LLPanelVolume::onLightSelectColor(const LLSD& data)
 {
 	LLViewerObject* objectp = mObject;
@@ -456,6 +528,24 @@ void LLPanelVolume::onLightSelectColor(const LLSD& data)
 	}
 }
 
+void LLPanelVolume::onLightSelectTexture(const LLSD& data)
+{
+	if (mObject.isNull() || (mObject->getPCode() != LL_PCODE_VOLUME))
+	{
+		return;
+	}	
+	LLVOVolume *volobjp = (LLVOVolume *) mObject.get();
+
+
+	LLTextureCtrl*	LightTextureCtrl = getChild<LLTextureCtrl>("light texture control");
+	if(LightTextureCtrl)
+	{
+		LLUUID id = LightTextureCtrl->getImageAssetID();
+		volobjp->setLightTextureID(id);
+		mLightSavedTexture = id;
+	}
+}
+
 // static
 void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata )
 {
@@ -471,12 +561,47 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata )
 	volobjp->setLightIntensity((F32)self->childGetValue("Light Intensity").asReal());
 	volobjp->setLightRadius((F32)self->childGetValue("Light Radius").asReal());
 	volobjp->setLightFalloff((F32)self->childGetValue("Light Falloff").asReal());
+
 	LLColorSwatchCtrl*	LightColorSwatch = self->getChild<LLColorSwatchCtrl>("colorswatch");
 	if(LightColorSwatch)
 	{
 		LLColor4	clr = LightColorSwatch->get();
 		volobjp->setLightColor(LLColor3(clr));
 	}
+
+	LLTextureCtrl*	LightTextureCtrl = self->getChild<LLTextureCtrl>("light texture control");
+	if(LightTextureCtrl)
+	{
+		LLUUID id = LightTextureCtrl->getImageAssetID();
+		if (id.notNull())
+		{
+			if (volobjp->getLightTextureID().isNull())
+			{ //this commit is making this a spot light, set UI to default params
+				volobjp->setLightTextureID(id);
+				LLVector3 spot_params = volobjp->getSpotLightParams();
+				self->childSetValue("Light FOV", spot_params.mV[0]);
+				self->childSetValue("Light Focus", spot_params.mV[1]);
+				self->childSetValue("Light Ambiance", spot_params.mV[2]);
+			}
+			else
+			{ //modifying existing params
+				LLVector3 spot_params;
+				spot_params.mV[0] = (F32) self->childGetValue("Light FOV").asReal();
+				spot_params.mV[1] = (F32) self->childGetValue("Light Focus").asReal();
+				spot_params.mV[2] = (F32) self->childGetValue("Light Ambiance").asReal();
+				volobjp->setSpotLightParams(spot_params);
+			}
+		}
+		else if (volobjp->getLightTextureID().notNull())
+		{ //no longer a spot light
+			volobjp->setLightTextureID(id);
+			//self->childDisable("Light FOV");
+			//self->childDisable("Light Focus");
+			//self->childDisable("Light Ambiance");
+		}
+	}
+
+	
 }
 
 // static
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index f285141bbee..9d197aafa58 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -74,6 +74,10 @@ class LLPanelVolume : public LLPanel
 	void		onLightCancelColor(const LLSD& data);
 	void		onLightSelectColor(const LLSD& data);
 
+	void		onLightCancelTexture(const LLSD& data); 
+	void		onLightSelectTexture(const LLSD& data);
+
+
 protected:
 	void			getState();
 
@@ -99,6 +103,7 @@ class LLPanelVolume : public LLPanel
 */
 
 	LLColor4		mLightSavedColor;
+	LLUUID			mLightSavedTexture;
 	LLPointer<LLViewerObject> mObject;
 	LLPointer<LLViewerObject> mRootObject;
 };
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index dea9af06574..8a052b61dba 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -47,6 +47,7 @@
 #include "llrender.h"
 #include "lloctree.h"
 #include "llvoavatar.h"
+#include "lltextureatlas.h"
 
 static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling");
 static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound");
@@ -88,8 +89,6 @@ class LLOcclusionQueryPool : public LLGLNamePool
 
 static LLOcclusionQueryPool sQueryPool;
 
-BOOL LLSpatialPartition::sFreezeState = FALSE;
-
 //static counter for frame to switch LOD on
 
 void sg_assert(BOOL expr)
@@ -283,10 +282,10 @@ S32 LLSphereAABB(const LLVector3& center, const LLVector3& size, const LLVector3
 
 LLSpatialGroup::~LLSpatialGroup()
 {
-	if (sNoDelete)
+	/*if (sNoDelete)
 	{
 		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
-	}
+	}*/
 
 	if (isState(DEAD))
 	{
@@ -297,13 +296,136 @@ LLSpatialGroup::~LLSpatialGroup()
 
 	if (gGLManager.mHasOcclusionQuery && mOcclusionQuery)
 	{
-		sQueryPool.release(mOcclusionQuery);
+		sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 	}
 
 	delete [] mOcclusionVerts;
 
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	clearDrawMap();
+	clearAtlasList() ;
+}
+
+BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
+{
+	S8 type = atlasp->getComponents() - 1 ;
+	for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
+	{
+		if(atlasp == *iter)
+		{
+			return TRUE ;
+		}
+	}
+	return FALSE ;
+}
+
+void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) 
+{		
+	if(!hasAtlas(atlasp))
+	{
+		mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ;
+		atlasp->addSpatialGroup(this) ;
+	}
+	
+	--recursive_level;
+	if(recursive_level)//levels propagating up.
+	{
+		LLSpatialGroup* parent = getParent() ;
+		if(parent)
+		{
+			parent->addAtlas(atlasp, recursive_level) ;
+		}
+	}	
+}
+
+void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) 
+{
+	mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ;
+	if(remove_group)
+	{
+		atlasp->removeSpatialGroup(this) ;
+	}
+
+	--recursive_level;
+	if(recursive_level)//levels propagating up.
+	{
+		LLSpatialGroup* parent = getParent() ;
+		if(parent)
+		{
+			parent->removeAtlas(atlasp, recursive_level) ;
+		}
+	}	
+}
+
+void LLSpatialGroup::clearAtlasList() 
+{
+	std::list<LLTextureAtlas*>::iterator iter ;
+	for(S8 i = 0 ; i < 4 ; i++)
+	{
+		if(mAtlasList[i].size() > 0)
+		{
+			for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter)
+			{
+				((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ;			
+			}
+			mAtlasList[i].clear() ;
+		}
+	}
+}
+
+LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level)
+{
+	S8 type = ncomponents - 1 ;
+	if(mAtlasList[type].size() > 0)
+	{
+		for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter)
+		{
+			if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved))
+			{
+				return *iter ;
+			}
+		}
+	}
+
+	--recursive_level;
+	if(recursive_level)
+	{
+		LLSpatialGroup* parent = getParent() ;
+		if(parent)
+		{
+			return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ;
+		}
+	}
+	return NULL ;
+}
+
+void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) 
+{ 
+	mCurUpdatingSlotp = slotp;
+
+	//if(!hasAtlas(mCurUpdatingSlotp->getAtlas()))
+	//{
+	//	addAtlas(mCurUpdatingSlotp->getAtlas()) ;
+	//}
+}
+
+LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) 
+{ 
+	if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep)
+	{
+		return mCurUpdatingSlotp ;
+	}
+
+	//--recursive_level ;
+	//if(recursive_level)
+	//{
+	//	LLSpatialGroup* parent = getParent() ;
+	//	if(parent)
+	//	{
+	//		return parent->getCurUpdatingSlot(imagep, recursive_level) ;
+	//	}
+	//}
+	return NULL ;
 }
 
 void LLSpatialGroup::clearDrawMap()
@@ -313,15 +435,12 @@ void LLSpatialGroup::clearDrawMap()
 
 BOOL LLSpatialGroup::isVisible() const
 {
-	return mVisible == LLDrawable::getCurrentFrame() ? TRUE : FALSE;
+	return mVisible[LLViewerCamera::sCurCameraID] == LLDrawable::getCurrentFrame() ? TRUE : FALSE;
 }
 
 void LLSpatialGroup::setVisible()
 {
-	if (!LLSpatialPartition::sFreezeState)
-	{
-		mVisible = LLDrawable::getCurrentFrame();
-	}
+	mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame();
 }
 
 void LLSpatialGroup::validate()
@@ -380,63 +499,6 @@ void LLSpatialGroup::validate()
 #endif
 }
 
-
-
-class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
-{
-public:
-	U32 mInheritedMask;
-
-	LLOctreeStateCheck(): mInheritedMask(0) { }
-
-	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-		
-		node->accept(this);
-
-		U32 temp = mInheritedMask;
-		mInheritedMask |= group->getState() & 
-			(LLSpatialGroup::OCCLUDED);
-
-		for (U32 i = 0; i < node->getChildCount(); i++)
-		{
-			traverse(node->getChild(i));
-		}
-
-		mInheritedMask = temp;
-	}
-
-	virtual void visit(const LLOctreeNode<LLDrawable>* state)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
-
-		if (mInheritedMask && !group->isState(mInheritedMask))
-		{
-			llerrs << "Spatial group failed inherited mask test." << llendl;
-		}
-
-		if (group->isState(LLSpatialGroup::DIRTY))
-		{
-			assert_parent_state(group, LLSpatialGroup::DIRTY);
-		}
-	}
-
-	void assert_parent_state(LLSpatialGroup* group, U32 state)
-	{
-		LLSpatialGroup* parent = group->getParent();
-		while (parent)
-		{
-			if (!parent->isState(state))
-			{
-				llerrs << "Spatial group failed parent state check." << llendl;
-			}
-			parent = parent->getParent();
-		}
-	}	
-};
-
-
 void LLSpatialGroup::checkStates()
 {
 #if LL_OCTREE_PARANOIA_CHECK
@@ -470,17 +532,17 @@ void validate_draw_info(LLDrawInfo& params)
 	}
 	
 	//bad indices
-	U32* indicesp = (U32*) params.mVertexBuffer->getIndicesPointer();
+	U16* indicesp = (U16*) params.mVertexBuffer->getIndicesPointer();
 	if (indicesp)
 	{
 		for (U32 i = params.mOffset; i < params.mOffset+params.mCount; i++)
 		{
-			if (indicesp[i] < params.mStart)
+			if (indicesp[i] < (U16)params.mStart)
 			{
 				llerrs << "Draw batch has vertex buffer index out of range error (index too low)." << llendl;
 			}
 			
-			if (indicesp[i] > params.mEnd)
+			if (indicesp[i] > (U16)params.mEnd)
 			{
 				llerrs << "Draw batch has vertex buffer index out of range error (index too high)." << llendl;
 			}
@@ -541,7 +603,9 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc
 	{
 		drawablep->setSpatialGroup(this);
 		validate_drawable(drawablep);
-		setState(OBJECT_DIRTY | GEOM_DIRTY | DISCARD_QUERY);
+		setState(OBJECT_DIRTY | GEOM_DIRTY);
+		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
+		gPipeline.markRebuild(this, TRUE);
 		if (drawablep->isSpatialBridge())
 		{
 			mBridgeList.push_back((LLSpatialBridge*) drawablep);
@@ -576,22 +640,23 @@ static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
 
 void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 {
-	if (!gPipeline.hasRenderType(mDrawableType))
+	/*if (!gPipeline.hasRenderType(mDrawableType))
 	{
 		return;
-	}
-
-	if (!LLPipeline::sSkipUpdate && group->changeLOD())
-	{
-		group->mLastUpdateDistance = group->mDistance;
-		group->mLastUpdateViewAngle = group->mViewAngle;
-	}
+	}*/
 
 	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY))
 	{
+		/*if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && mRenderByGroup)
+		{
+			llerrs << "WTF?" << llendl;
+		}*/
 		return;
 	}
 
+	group->mLastUpdateDistance = group->mDistance;
+	group->mLastUpdateViewAngle = group->mViewAngle;
+	
 	LLFastTimer ftm(FTM_REBUILD_VBO);	
 
 	group->clearDrawMap();
@@ -629,6 +694,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	group->clearState(LLSpatialGroup::GEOM_DIRTY);
 }
 
+
 void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
 {
 
@@ -667,8 +733,11 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
 			drawablep = *i;
 			minMax = drawablep->getSpatialExtents();
 			
+			update_min_max(newMin, newMax, minMax[0]);
+			update_min_max(newMin, newMax, minMax[1]);
+
 			//bin up the object
-			for (U32 i = 0; i < 3; i++)
+			/*for (U32 i = 0; i < 3; i++)
 			{
 				if (minMax[0].mV[i] < newMin.mV[i])
 				{
@@ -678,7 +747,7 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
 				{
 					newMax.mV[i] = minMax[1].mV[i];
 				}
-			}
+			}*/
 		}
 		
 		mObjectBounds[0] = (newMin + newMax) * 0.5f;
@@ -742,6 +811,10 @@ LLSpatialGroup* LLSpatialGroup::getParent()
 		return NULL;
 	}
 
+	if(!mOctreeNode)
+	{
+		return NULL;
+	}
 	OctreeNode* parent = mOctreeNode->getOctParent();
 
 	if (parent)
@@ -767,6 +840,8 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 	{
 		drawablep->setSpatialGroup(NULL);
 		setState(GEOM_DIRTY);
+		gPipeline.markRebuild(this, TRUE);
+
 		if (drawablep->isSpatialBridge())
 		{
 			for (bridge_list_t::iterator i = mBridgeList.begin(); i != mBridgeList.end(); ++i)
@@ -803,6 +878,7 @@ void LLSpatialGroup::shift(const LLVector3 &offset)
 	//if (!mSpatialPartition->mRenderByGroup)
 	{
 		setState(GEOM_DIRTY);
+		gPipeline.markRebuild(this, TRUE);
 	}
 
 	if (mOcclusionVerts)
@@ -843,18 +919,21 @@ class LLSpatialSetStateDiff : public LLSpatialSetState
 
 void LLSpatialGroup::setState(U32 state) 
 { 
-	if (!LLSpatialPartition::sFreezeState)
+	mState |= state; 
+	
+	if (state > LLSpatialGroup::STATE_MASK)
 	{
-		mState |= state; 
+		llerrs << "WTF?" << llendl;
 	}
 }	
 
 void LLSpatialGroup::setState(U32 state, S32 mode) 
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	if (LLSpatialPartition::sFreezeState)
+
+	if (state > LLSpatialGroup::STATE_MASK)
 	{
-		return;
+		llerrs << "WTF?" << llendl;
 	}
 
 	if (mode > STATE_MODE_SINGLE)
@@ -902,20 +981,23 @@ class LLSpatialClearStateDiff : public LLSpatialClearState
 
 void LLSpatialGroup::clearState(U32 state)
 {
-	if (!LLSpatialPartition::sFreezeState)
+	if (state > LLSpatialGroup::STATE_MASK)
 	{
-		mState &= ~state; 
+		llerrs << "WTF?" << llendl;
 	}
+
+	mState &= ~state; 
 }
 
 void LLSpatialGroup::clearState(U32 state, S32 mode)
 {
-	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	if (LLSpatialPartition::sFreezeState)
+	if (state > LLSpatialGroup::STATE_MASK)
 	{
-		return;
+		llerrs << "WTF?" << llendl;
 	}
 
+	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	
 	if (mode > STATE_MODE_SINGLE)
 	{
 		if (mode == STATE_MODE_DIFF)
@@ -935,6 +1017,128 @@ void LLSpatialGroup::clearState(U32 state, S32 mode)
 	}
 }
 
+BOOL LLSpatialGroup::isState(U32 state) const
+{ 
+	if (state > LLSpatialGroup::STATE_MASK)
+	{
+		llerrs << "WTF?" << llendl;
+	}
+
+	return mState & state ? TRUE : FALSE; 
+}
+
+//=====================================
+//		Occlusion State Set/Clear
+//=====================================
+class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+	U32 mState;
+	LLSpatialSetOcclusionState(U32 state) : mState(state) { }
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }	
+};
+
+class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
+{
+public:
+	LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
+
+	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+		
+		if (!group->isOcclusionState(mState))
+		{
+			LLSpatialGroup::OctreeTraveler::traverse(n);
+		}
+	}
+};
+
+
+void LLSpatialGroup::setOcclusionState(U32 state, S32 mode) 
+{
+	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	
+	if (mode > STATE_MODE_SINGLE)
+	{
+		if (mode == STATE_MODE_DIFF)
+		{
+			LLSpatialSetOcclusionStateDiff setter(state);
+			setter.traverse(mOctreeNode);
+		}
+		else if (mode == STATE_MODE_BRANCH)
+		{
+			LLSpatialSetOcclusionState setter(state);
+			setter.traverse(mOctreeNode);
+		}
+		else
+		{
+			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+			{
+				mOcclusionState[i] |= state;
+			}
+		}
+	}
+	else
+	{
+		mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
+	}
+}
+
+class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler
+{
+public:
+	U32 mState;
+	
+	LLSpatialClearOcclusionState(U32 state) : mState(state) { }
+	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
+};
+
+class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
+{
+public:
+	LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
+
+	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+		
+		if (group->isOcclusionState(mState))
+		{
+			LLSpatialGroup::OctreeTraveler::traverse(n);
+		}
+	}
+};
+
+void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)
+{
+	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	
+	if (mode > STATE_MODE_SINGLE)
+	{
+		if (mode == STATE_MODE_DIFF)
+		{
+			LLSpatialClearOcclusionStateDiff clearer(state);
+			clearer.traverse(mOctreeNode);
+		}
+		else if (mode == STATE_MODE_BRANCH)
+		{
+			LLSpatialClearOcclusionState clearer(state);
+			clearer.traverse(mOctreeNode);
+		}
+		else
+		{
+			for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+			{
+				mOcclusionState[i] &= ~state;
+			}
+		}
+	}
+	else
+	{
+		mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state;
+	}
+}
 //======================================
 //		Octree Listener Implementation
 //======================================
@@ -946,13 +1150,16 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	mSpatialPartition(part),
 	mVertexBuffer(NULL), 
 	mBufferUsage(GL_STATIC_DRAW_ARB),
-	mVisible(0),
 	mDistance(0.f),
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
 	mLastUpdateTime(gFrameTimeSeconds),
 	mViewAngle(0.f),
-	mLastUpdateViewAngle(-1.f)
+	mLastUpdateViewAngle(-1.f),
+	mAtlasList(4),
+	mCurUpdatingTime(0),
+	mCurUpdatingSlotp(NULL),
+	mCurUpdatingTexture (NULL)
 {
 	sNodeCount++;
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
@@ -960,14 +1167,25 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	sg_assert(mOctreeNode->getListenerCount() == 0);
 	mOctreeNode->addListener(this);
 	setState(SG_INITIAL_STATE_MASK);
+	gPipeline.markRebuild(this, TRUE);
 
 	mBounds[0] = LLVector3(node->getCenter());
 	mBounds[1] = LLVector3(node->getSize());
 
 	part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
 	mLODHash = part->mLODSeed;
-	
-	mOcclusionQuery = 0;
+
+	OctreeNode* oct_parent = node->getOctParent();
+
+	LLSpatialGroup* parent = oct_parent ? (LLSpatialGroup*) oct_parent->getListener(0) : NULL;
+
+	for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+	{
+		mOcclusionQuery[i] = 0;
+		mOcclusionState[i] = parent ? SG_STATE_INHERIT_MASK & parent->mOcclusionState[i] : 0;
+		mVisible[i] = 0;
+	}
+
 	mOcclusionVerts = NULL;
 
 	mRadius = 1;
@@ -976,13 +1194,18 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 
 void LLSpatialGroup::updateDistance(LLCamera &camera)
 {
+	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
+	{
+		llerrs << "WTF?" << llendl;
+	}
+
 #if !LL_RELEASE_FOR_DOWNLOAD
 	if (isState(LLSpatialGroup::OBJECT_DIRTY))
 	{
 		llerrs << "Spatial group dirty on distance update." << llendl;
 	}
 #endif
-	if (!getData().empty() && !LLSpatialPartition::sFreezeState)
+	if (!getData().empty())
 	{
 		mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].magVec() :
 						(F32) mOctreeNode->getSize().magVec();
@@ -1018,6 +1241,7 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 					//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
 					//not setting this node to dirty would be a very good thing
 					group->setState(LLSpatialGroup::ALPHA_DIRTY);
+					gPipeline.markRebuild(group, FALSE);
 				}
 			}
 		}
@@ -1054,6 +1278,18 @@ F32 LLSpatialPartition::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
 	return LLPipeline::calcPixelArea(group->mObjectBounds[0], group->mObjectBounds[1], camera);
 }
 
+F32 LLSpatialGroup::getUpdateUrgency() const
+{
+	if (!isVisible())
+	{
+		return 0.f;
+	}
+	else
+	{
+		return (gFrameTimeSeconds - mLastUpdateTime+4.f)/mDistance;
+	}
+}
+
 BOOL LLSpatialGroup::needsUpdate()
 {
 	return (LLDrawable::getCurrentFrame()%mSpatialPartition->mLODPeriod == mLODHash) ? TRUE : FALSE;
@@ -1140,8 +1376,7 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	if (child->getListenerCount() == 0)
 	{
-		LLSpatialGroup* group = new LLSpatialGroup(child, mSpatialPartition);
-		group->setState(mState & SG_STATE_INHERIT_MASK);
+		new LLSpatialGroup(child, mSpatialPartition);
 	}
 	else
 	{
@@ -1161,16 +1396,21 @@ void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNo
 void LLSpatialGroup::destroyGL() 
 {
 	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
+	gPipeline.markRebuild(this, TRUE);
+
 	mLastUpdateTime = gFrameTimeSeconds;
 	mVertexBuffer = NULL;
 	mBufferMap.clear();
 
 	clearDrawMap();
 
-	if (mOcclusionQuery)
+	for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 	{
-		sQueryPool.release(mOcclusionQuery);
-		mOcclusionQuery = 0;
+		if (mOcclusionQuery[i])
+		{
+			sQueryPool.release(mOcclusionQuery[i]);
+			mOcclusionQuery[i] = 0;
+		}
 	}
 
 	delete [] mOcclusionVerts;
@@ -1266,38 +1506,43 @@ void LLSpatialGroup::checkOcclusion()
 	if (LLPipeline::sUseOcclusion > 1)
 	{
 		LLSpatialGroup* parent = getParent();
-		if (parent && parent->isState(LLSpatialGroup::OCCLUDED))
+		if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{	//if the parent has been marked as occluded, the child is implicitly occluded
-			clearState(QUERY_PENDING | DISCARD_QUERY);
+			clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
 		}
-		else if (isState(QUERY_PENDING))
+		else if (isOcclusionState(QUERY_PENDING))
 		{	//otherwise, if a query is pending, read it back
 			LLFastTimer t(FTM_OCCLUSION_READBACK);
 			GLuint res = 1;
-			if (!isState(DISCARD_QUERY) && mOcclusionQuery)
+			if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
 			{
-				glGetQueryObjectuivARB(mOcclusionQuery, GL_QUERY_RESULT_ARB, &res);	
+				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res);	
+			}
+
+			if (isOcclusionState(DISCARD_QUERY))
+			{
+				res = 2;
 			}
 
 			if (res > 0)
 			{
 				assert_states_valid(this);
-				clearState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+				clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 				assert_states_valid(this);
 			}
 			else
 			{
 				assert_states_valid(this);
-				setState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+				setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 				assert_states_valid(this);
 			}
 
-			clearState(QUERY_PENDING | DISCARD_QUERY);
+			clearOcclusionState(QUERY_PENDING | DISCARD_QUERY);
 		}
-		else if (mSpatialPartition->isOcclusionEnabled() && isState(LLSpatialGroup::OCCLUDED))
+		else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{	//check occlusion has been issued for occluded node that has not had a query issued
 			assert_states_valid(this);
-			clearState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+			clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 			assert_states_valid(this);
 		}
 	}
@@ -1309,9 +1554,9 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 	{
 		if (earlyFail(camera, this))
 		{
-			setState(LLSpatialGroup::DISCARD_QUERY);
+			setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
 			assert_states_valid(this);
-			clearState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+			clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
 			assert_states_valid(this);
 		}
 		else
@@ -1319,9 +1564,9 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 			{
 				LLFastTimer t(FTM_RENDER_OCCLUSION);
 
-				if (!mOcclusionQuery)
+				if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 				{
-					mOcclusionQuery = sQueryPool.allocate();
+					mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
 				}
 
 				if (!mOcclusionVerts || isState(LLSpatialGroup::OCCLUSION_DIRTY))
@@ -1329,22 +1574,33 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 					buildOcclusion();
 				}
 
-				glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery);					
+				glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
 				glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
-				glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
-							GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0]));
+				if (camera->getOrigin().isExactlyZero())
+				{ //origin is invalid, draw entire box
+					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+												GL_UNSIGNED_BYTE, sOcclusionIndices);
+					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+							GL_UNSIGNED_BYTE, sOcclusionIndices+b111*8);
+				}
+				else
+				{
+					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+								GL_UNSIGNED_BYTE, get_box_fan_indices(camera, mBounds[0]));
+				}
 				glEndQueryARB(GL_SAMPLES_PASSED_ARB);
 			}
 
-			setState(LLSpatialGroup::QUERY_PENDING);
-			clearState(LLSpatialGroup::DISCARD_QUERY);
+			setOcclusionState(LLSpatialGroup::QUERY_PENDING);
+			clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
 		}
 	}
 }
 
 //==============================================
 
-LLSpatialPartition::LLSpatialPartition(U32 data_mask, U32 buffer_usage)
+LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
+: mRenderByGroup(render_by_group)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	mOcclusionEnabled = TRUE;
@@ -1356,7 +1612,6 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, U32 buffer_usage)
 	mBufferUsage = buffer_usage;
 	mDepthMask = FALSE;
 	mSlopRatio = 0.25f;
-	mRenderByGroup = TRUE;
 	mInfiniteFarClip = FALSE;
 
 	LLGLNamePool::registerPool(&sQueryPool);
@@ -1393,9 +1648,9 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 	
 	LLSpatialGroup* group = drawablep->getSpatialGroup();
 
-	if (group && was_visible && group->isState(LLSpatialGroup::QUERY_PENDING))
+	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
 	{
-		group->setState(LLSpatialGroup::DISCARD_QUERY);
+		group->setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
 	}
 
 	return group;
@@ -1494,7 +1749,7 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 
 		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
 		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
-			group->isState(LLSpatialGroup::OCCLUDED))
+			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
 			gPipeline.markOccluder(group);
 			return true;
@@ -1576,7 +1831,7 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 	virtual void processGroup(LLSpatialGroup* group)
 	{
 		if (group->needsUpdate() ||
-			group->mVisible < LLDrawable::getCurrentFrame() - 1)
+			group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)
 		{
 			group->doOcclusion(mCamera);
 		}
@@ -1644,7 +1899,7 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 	{
 		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
 			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
-			group->isState(LLSpatialGroup::OCCLUDED))
+			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
 			return true;
 		}
@@ -1652,13 +1907,57 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 		return false;
 	}
 
+	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
+
+		if (earlyFail(group))
+		{
+			return;
+		}
+		
+		if (mRes == 2)
+		{
+			//fully in, don't traverse further (won't effect extents
+		}
+		else if (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))
+		{	//don't need to do frustum check
+			LLSpatialGroup::OctreeTraveler::traverse(n);
+		}
+		else
+		{  
+			mRes = frustumCheck(group);
+				
+			if (mRes)
+			{ //at least partially in, run on down
+				LLSpatialGroup::OctreeTraveler::traverse(n);
+			}
+
+			mRes = 0;
+		}
+	}
+
 	virtual void processGroup(LLSpatialGroup* group)
 	{
-		if (group->mObjectBounds[1].magVecSquared() < 256.f * 256.f)
-		{ //megaprims and water edge patches be damned!
+		if (group->isState(LLSpatialGroup::DIRTY) || group->getData().empty())
+		{
+			llerrs << "WTF?" << llendl;
+		}
+
+		if (mRes < 2)
+		{
+			if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0)
+			{
+				mEmpty = FALSE;
+				update_min_max(mMin, mMax, group->mObjectExtents[0]);
+				update_min_max(mMin, mMax, group->mObjectExtents[1]);
+			}
+		}
+		else
+		{
 			mEmpty = FALSE;
-			update_min_max(mMin, mMax, group->mObjectExtents[0]);
-			update_min_max(mMin, mMax, group->mObjectExtents[1]);
+			update_min_max(mMin, mMax, group->mExtents[0]);
+			update_min_max(mMin, mMax, group->mExtents[1]);
 		}
 	}
 
@@ -1678,7 +1977,7 @@ class LLOctreeCullDetectVisible: public LLOctreeCullShadow
 		if (mResult || //already found a node, don't check any more
 			group->mOctreeNode->getParent() &&	//never occlusion cull the root node
 			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
-			group->isState(LLSpatialGroup::OCCLUDED))
+			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
 			return true;
 		}
@@ -1857,6 +2156,12 @@ BOOL LLSpatialPartition::isOcclusionEnabled()
 
 BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 {
+	{
+		LLFastTimer ftm(FTM_CULL_REBOUND);		
+		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+		group->rebound();
+	}
+
 	LLOctreeCullVisExtents vis(&camera, visMin, visMax);
 	vis.traverse(mOctree);
 	return vis.mEmpty;
@@ -1876,12 +2181,9 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
 	{
-		BOOL temp = sFreezeState;
-		sFreezeState = FALSE;
 		LLFastTimer ftm(FTM_CULL_REBOUND);		
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 		group->rebound();
-		sFreezeState = temp;
 	}
 
 #if LL_OCTREE_PARANOIA_CHECK
@@ -1918,6 +2220,11 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 
 BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
 {
+	if (camera->getOrigin().isExactlyZero())
+	{
+		return FALSE;
+	}
+
 	const F32 vel = SG_OCCLUSION_FUDGE*2.f;
 	LLVector3 c = group->mBounds[0];
 	LLVector3 r = group->mBounds[1] + LLVector3(vel,vel,vel);
@@ -2195,7 +2502,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 	LLGLEnable cull(GL_CULL_FACE);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
-	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
 							!group->getData().empty();
 	if (render_objects)
 	{
@@ -2436,6 +2743,39 @@ void renderBatchSize(LLDrawInfo* params)
 	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
 }
 
+void renderShadowFrusta(LLDrawInfo* params)
+{
+	LLGLEnable blend(GL_BLEND);
+	gGL.setSceneBlendType(LLRender::BT_ADD);
+
+	LLVector3 center = (params->mExtents[1]+params->mExtents[0])*0.5f;
+	LLVector3 size = (params->mExtents[1]-params->mExtents[0])*0.5f;
+
+	if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
+	{
+		glColor3f(1,0,0);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+	if (gPipeline.mShadowCamera[5].AABBInFrustum(center, size))
+	{
+		glColor3f(0,1,0);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+	if (gPipeline.mShadowCamera[6].AABBInFrustum(center, size))
+	{
+		glColor3f(0,0,1);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+	if (gPipeline.mShadowCamera[7].AABBInFrustum(center, size))
+	{
+		glColor3f(1,0,1);
+		pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	}
+
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+}
+
+
 void renderLights(LLDrawable* drawablep)
 {
 	if (!drawablep->isLight())
@@ -2571,6 +2911,9 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			//draw tight fit bounding boxes for spatial group
 			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE))
 			{	
+				group->rebuildGeom();
+				group->rebuildMesh();
+
 				renderOctree(group);
 				stop_glerror();
 			}
@@ -2578,6 +2921,9 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			//render visibility wireframe
 			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
 			{
+				group->rebuildGeom();
+				group->rebuildMesh();
+
 				gGL.flush();
 				glPushMatrix();
 				gGLLastMatrix = NULL;
@@ -2603,6 +2949,19 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 		LLVector3 nodeCenter = group->mBounds[0];
 		LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter());
 
+		group->rebuildGeom();
+		group->rebuildMesh();
+
+		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
+		{
+			if (!group->getData().empty())
+			{
+				gGL.color3f(0,0,1);
+				drawBoxOutline(group->mObjectBounds[0],
+								group->mObjectBounds[1]);
+			}
+		}
+
 		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
 		{
 			LLDrawable* drawable = *i;
@@ -2612,6 +2971,16 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 				renderBoundingBox(drawable);			
 			}
 			
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
+			{
+				if (drawable->isState(LLDrawable::IN_REBUILD_Q2))
+				{
+					gGL.color4f(0.6f, 0.6f, 0.1f, 1.f);
+					const LLVector3* ext = drawable->getSpatialExtents();
+					drawBoxOutline((ext[0]+ext[1])*0.5f, (ext[1]-ext[0])*0.5f);
+				}
+			}	
+
 			if (drawable->getVOVolume() && gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
 			{
 				renderTexturePriority(drawable);
@@ -2660,6 +3029,10 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 				{
 					renderBatchSize(draw_info);
 				}
+				if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+				{
+					renderShadowFrusta(draw_info);
+				}
 			}
 		}
 	}
@@ -2710,6 +3083,79 @@ void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
 	pusher.traverse(mOctree);
 }
 
+class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
+{
+public:
+	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
+
+	LLOctreeStateCheck()
+	{ 
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+		{
+			mInheritedMask[i] = 0;
+		}
+	}
+
+	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		node->accept(this);
+
+
+		U32 temp[LLViewerCamera::NUM_CAMERAS];
+
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+		{
+			temp[i] = mInheritedMask[i];
+			mInheritedMask[i] |= group->mOcclusionState[i] & LLSpatialGroup::OCCLUDED; 
+		}
+
+		for (U32 i = 0; i < node->getChildCount(); i++)
+		{
+			traverse(node->getChild(i));
+		}
+
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+		{
+			mInheritedMask[i] = temp[i];
+		}
+	}
+	
+
+	virtual void visit(const LLOctreeNode<LLDrawable>* state)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
+
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+		{
+			if (mInheritedMask[i] && !(group->mOcclusionState[i] & mInheritedMask[i]))
+			{
+				llerrs << "Spatial group failed inherited mask test." << llendl;
+			}
+		}
+
+		if (group->isState(LLSpatialGroup::DIRTY))
+		{
+			assert_parent_state(group, LLSpatialGroup::DIRTY);
+		}
+	}
+
+	void assert_parent_state(LLSpatialGroup* group, U32 state)
+	{
+		LLSpatialGroup* parent = group->getParent();
+		while (parent)
+		{
+			if (!parent->isState(state))
+			{
+				llerrs << "Spatial group failed parent state check." << llendl;
+			}
+			parent = parent->getParent();
+		}
+	}	
+};
+
+
 void LLSpatialPartition::renderDebug()
 {
 	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCTREE |
@@ -2722,7 +3168,9 @@ void LLSpatialPartition::renderDebug()
 									  LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
 									  LLPipeline::RENDER_DEBUG_RAYCAST |
 									  LLPipeline::RENDER_DEBUG_AVATAR_VOLUME |
-									  LLPipeline::RENDER_DEBUG_AGENT_TARGET))
+									  LLPipeline::RENDER_DEBUG_AGENT_TARGET |
+									  LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
+									  LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)) 
 	{
 		return;
 	}
@@ -2757,6 +3205,12 @@ void LLSpatialPartition::renderDebug()
 	render_debug.traverse(mOctree);
 }
 
+void LLSpatialGroup::drawObjectBox(LLColor4 col)
+{
+	gGL.color4fv(col.mV);
+	drawBox(mObjectBounds[0], mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+}
+
 
 BOOL LLSpatialPartition::isVisible(const LLVector3& v)
 {
@@ -2937,10 +3391,10 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 
 LLDrawInfo::~LLDrawInfo()	
 {
-	if (LLSpatialGroup::sNoDelete)
+	/*if (LLSpatialGroup::sNoDelete)
 	{
 		llerrs << "LLDrawInfo deleted illegally!" << llendl;
-	}
+	}*/
 
 	if (mFace)
 	{
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 13ab35402c8..16e8782a8e0 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -44,6 +44,7 @@
 #include "llcubemap.h"
 #include "lldrawpool.h"
 #include "llface.h"
+#include "llviewercamera.h"
 
 #include <queue>
 
@@ -53,6 +54,8 @@
 class LLSpatialPartition;
 class LLSpatialBridge;
 class LLSpatialGroup;
+class LLTextureAtlas;
+class LLTextureAtlasSlot;
 
 S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
 S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);
@@ -72,7 +75,7 @@ class LLDrawInfo : public LLRefCount
 	
 
 	LLPointer<LLVertexBuffer> mVertexBuffer;
-	LLPointer<LLViewerTexture> mTexture;
+	LLPointer<LLViewerTexture>     mTexture;
 	LLColor4U mGlowColor;
 	S32 mDebugColor;
 	const LLMatrix4* mTextureMatrix;
@@ -154,12 +157,14 @@ class LLDrawInfo : public LLRefCount
 class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 {
 	friend class LLSpatialPartition;
+	friend class LLOctreeStateCheck;
 public:
 	static U32 sNodeCount;
 	static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE
 
 	typedef std::vector<LLPointer<LLSpatialGroup> > sg_vector_t;
 	typedef std::set<LLPointer<LLSpatialGroup> > sg_set_t;
+	typedef std::list<LLPointer<LLSpatialGroup> > sg_list_t;
 	typedef std::vector<LLPointer<LLSpatialBridge> > bridge_list_t;
 	typedef std::vector<LLPointer<LLDrawInfo> > drawmap_elem_t; 
 	typedef std::map<U32, drawmap_elem_t > draw_map_t;	
@@ -184,6 +189,14 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 		}
 	};
 
+	struct CompareUpdateUrgency
+	{
+		bool operator()(const LLPointer<LLSpatialGroup> lhs, const LLPointer<LLSpatialGroup> rhs)
+		{
+			return lhs->getUpdateUrgency() > rhs->getUpdateUrgency();
+		}
+	};
+
 	struct CompareDepthGreater
 	{
 		bool operator()(const LLSpatialGroup* const& lhs, const LLSpatialGroup* const& rhs)
@@ -194,35 +207,44 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 
 	typedef enum
 	{
-		OCCLUDED				= 0x00000001,
-		IN_QUEUE				= 0x00000002,
-		QUERY_PENDING			= 0x00000004,
-		ACTIVE_OCCLUSION		= 0x00000008,
-		DISCARD_QUERY			= 0x00000010,
-		DEAD					= 0x00000020,
-		EARLY_FAIL				= 0x00000040,
-		DIRTY					= 0x00000080,
-		OBJECT_DIRTY			= 0x00000100,
-		GEOM_DIRTY				= 0x00000200,
-		ALPHA_DIRTY				= 0x00000800,
-		SKIP_FRUSTUM_CHECK		= 0x00001000,
-		IN_IMAGE_QUEUE			= 0x00002000,
-		IMAGE_DIRTY				= 0x00004000,
-		OCCLUSION_DIRTY			= 0x00008000,
-		MESH_DIRTY				= 0x00010000,
+		OCCLUDED				= 0x00010000,
+		QUERY_PENDING			= 0x00020000,
+		ACTIVE_OCCLUSION		= 0x00040000,
+		DISCARD_QUERY			= 0x00080000,
+		EARLY_FAIL				= 0x00100000,
+	} eOcclusionState;
+
+	typedef enum
+	{
+		DEAD					= 0x00000001,
+		DIRTY					= 0x00000002,
+		OBJECT_DIRTY			= 0x00000004,
+		GEOM_DIRTY				= 0x00000008,
+		ALPHA_DIRTY				= 0x00000010,
+		SKIP_FRUSTUM_CHECK		= 0x00000020,
+		IN_IMAGE_QUEUE			= 0x00000040,
+		IMAGE_DIRTY				= 0x00000080,
+		OCCLUSION_DIRTY			= 0x00000100,
+		MESH_DIRTY				= 0x00000200,
+		NEW_DRAWINFO			= 0x00000400,
+		IN_BUILD_Q1				= 0x00000800,
+		IN_BUILD_Q2				= 0x00001000,
+		STATE_MASK				= 0x0000FFFF,
 	} eSpatialState;
 
 	typedef enum
 	{
 		STATE_MODE_SINGLE = 0,		//set one node
 		STATE_MODE_BRANCH,			//set entire branch
-		STATE_MODE_DIFF				//set entire branch as long as current state is different
+		STATE_MODE_DIFF,			//set entire branch as long as current state is different
+		STATE_MODE_ALL_CAMERAS,		//used for occlusion state, set state for all cameras
 	} eSetStateMode;
 
 	LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part);
 
 	BOOL isDead()							{ return isState(DEAD); }
-	BOOL isState(U32 state) const			{ return mState & state ? TRUE : FALSE; }
+	BOOL isState(U32 state) const;	
+	BOOL isOcclusionState(U32 state) const	{ return mOcclusionState[LLViewerCamera::sCurCameraID] & state ? TRUE : FALSE; }
 	U32 getState()							{ return mState; }
 	void setState(U32 state);	
 	void clearState(U32 state);	
@@ -233,10 +255,14 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	void validateDrawMap();
 	
 	void setState(U32 state, S32 mode);
+	void clearState(U32 state, S32 mode);
+
+	void setOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
+	void clearOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
 
 	LLSpatialGroup* getParent();
 
-	void clearState(U32 state, S32 mode);
+	
 	BOOL addObject(LLDrawable *drawablep, BOOL add_all = FALSE, BOOL from_octree = FALSE);
 	BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE);
 	BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group
@@ -253,6 +279,7 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	
 	void updateDistance(LLCamera& camera);
 	BOOL needsUpdate();
+	F32 getUpdateUrgency() const;
 	BOOL changeLOD();
 	void rebuildGeom();
 	void rebuildMesh();
@@ -262,6 +289,8 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	element_list& getData() { return mOctreeNode->getData(); }
 	U32 getElementCount() const { return mOctreeNode->getElementCount(); }
 
+	void drawObjectBox(LLColor4 col);
+
 	 //LISTENER FUNCTIONS
 	virtual void handleInsertion(const TreeNode* node, LLDrawable* face);
 	virtual void handleRemoval(const TreeNode* node, LLDrawable* face);
@@ -270,10 +299,41 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
 	virtual void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child);
 
+//-------------------
+//for atlas use
+//-------------------
+	//atlas	
+	void setCurUpdatingTime(U32 t) {mCurUpdatingTime = t ;}
+	U32  getCurUpdatingTime() const { return mCurUpdatingTime ;}
+	
+	void setCurUpdatingSlot(LLTextureAtlasSlot* slotp) ;
+	LLTextureAtlasSlot* getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level = 3) ;
+
+	void setCurUpdatingTexture(LLViewerTexture* tex){ mCurUpdatingTexture = tex ;}
+	LLViewerTexture* getCurUpdatingTexture() const { return mCurUpdatingTexture ;}
+	
+	BOOL hasAtlas(LLTextureAtlas* atlasp) ;
+	LLTextureAtlas* getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level = 3) ;
+	void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ;
+	void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ;
+	void clearAtlasList() ;
+private:
+	U32                     mCurUpdatingTime ;
+	//do not make the below two to use LLPointer
+	//because mCurUpdatingTime invalidates them automatically.
+	LLTextureAtlasSlot* mCurUpdatingSlotp ;
+	LLViewerTexture*          mCurUpdatingTexture ;
+
+	std::vector< std::list<LLTextureAtlas*> > mAtlasList ; 
+//-------------------
+//end for atlas use
+//-------------------
+
 protected:
 	virtual ~LLSpatialGroup();
 
 	U32 mState;
+	U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS];
 	S32 mLODHash;
 	static S32 sLODSeed;
 
@@ -292,12 +352,12 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 
 	LLPointer<LLVertexBuffer> mVertexBuffer;
 	F32*					mOcclusionVerts;
-	GLuint					mOcclusionQuery;
+	GLuint					mOcclusionQuery[LLViewerCamera::NUM_CAMERAS];
 
 	U32 mBufferUsage;
 	draw_map_t mDrawMap;
 	
-	S32 mVisible;
+	S32 mVisible[LLViewerCamera::NUM_CAMERAS];
 	F32 mDistance;
 	F32 mDepth;
 	F32 mLastUpdateDistance;
@@ -326,9 +386,7 @@ class LLGeometryManager
 class LLSpatialPartition: public LLGeometryManager
 {
 public:
-	static BOOL sFreezeState; //if true, no spatialgroup state updates will be made
-
-	LLSpatialPartition(U32 data_mask, U32 mBufferUsage = GL_STATIC_DRAW_ARB);
+	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage);
 	virtual ~LLSpatialPartition();
 
 	LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE);
@@ -374,7 +432,7 @@ class LLSpatialPartition: public LLGeometryManager
 	BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
 	BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
 	U32 mBufferUsage;
-	BOOL mRenderByGroup;
+	const BOOL mRenderByGroup;
 	U32 mLODSeed;
 	U32 mLODPeriod;	//number of frames between LOD updates for a given spatial group (staggered by mLODSeed)
 	U32 mVertexDataMask;
@@ -393,7 +451,7 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition
 public:
 	typedef std::vector<LLPointer<LLSpatialBridge> > bridge_vector_t;
 	
-	LLSpatialBridge(LLDrawable* root, U32 data_mask);
+	LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask);
 	
 	virtual BOOL isSpatialBridge() const		{ return TRUE; }
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 44e76a0bc11..dbb3062323b 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -436,8 +436,8 @@ bool idle_startup()
 	}
 	else
 	{
-		// Update images?
-		gTextureList.updateImages(0.01f);
+		//note: Removing this line will cause incorrect button size in the login screen. -- bao.
+		gTextureList.updateImages(0.01f) ;
 	}
 
 	if ( STATE_FIRST == LLStartUp::getStartupState() )
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index de3d80f0447..39f6a6c3960 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -214,7 +214,7 @@ void LLSurface::create(const S32 grids_per_edge,
 
 LLViewerTexture* LLSurface::getSTexture()
 {
-	if (mSTexturep.notNull() && !mSTexturep->hasValidGLTexture())
+	if (mSTexturep.notNull() && !mSTexturep->hasGLTexture())
 	{
 		createSTexture();
 	}
@@ -223,7 +223,7 @@ LLViewerTexture* LLSurface::getSTexture()
 
 LLViewerTexture* LLSurface::getWaterTexture()
 {
-	if (mWaterTexturep.notNull() && !mWaterTexturep->hasValidGLTexture())
+	if (mWaterTexturep.notNull() && !mWaterTexturep->hasGLTexture())
 	{
 		createWaterTexture();
 	}
@@ -235,8 +235,13 @@ void LLSurface::createSTexture()
 	if (!mSTexturep)
 	{
 		// Fill with dummy gray data.
-		LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize, sTextureSize, 3);
-		U8 *default_texture = raw->getData();
+	
+		mSTexturep =  LLViewerTextureManager::getLocalTexture(sTextureSize, sTextureSize, 3, FALSE);
+		mSTexturep->dontDiscard();
+		mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
+		
+		// GL NOT ACTIVE HERE
+		/*U8 *default_texture = raw->getData();
 		for (S32 i = 0; i < sTextureSize; i++)
 		{
 			for (S32 j = 0; j < sTextureSize; j++)
@@ -250,7 +255,8 @@ void LLSurface::createSTexture()
 		mSTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
 		mSTexturep->dontDiscard();
 		gGL.getTexUnit(0)->bind(mSTexturep);
-		mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);		
+		mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);*/
+		
 	}
 }
 
@@ -259,7 +265,7 @@ void LLSurface::createWaterTexture()
 	if (!mWaterTexturep)
 	{
 		// Create the water texture
-		LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4);
+		/*LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize/2, sTextureSize/2, 4);
 		U8 *default_texture = raw->getData();
 		for (S32 i = 0; i < sTextureSize/2; i++)
 		{
@@ -270,10 +276,11 @@ void LLSurface::createWaterTexture()
 				*(default_texture + (i*sTextureSize/2 + j)*4 + 2) = MAX_WATER_COLOR.mV[2];
 				*(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3];
 			}
-		}
-		mWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
+		}*/
+		
+		
+		mWaterTexturep = LLViewerTextureManager::getLocalTexture(sTextureSize/2, sTextureSize/2, 4, FALSE);
 		mWaterTexturep->dontDiscard();
-		gGL.getTexUnit(0)->bind(mWaterTexturep);
 		mWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	}
 }
@@ -1189,7 +1196,7 @@ F32 LLSurface::getWaterHeight() const
 BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y,
 									 const F32 width, const F32 height)
 {
-	if (!getWaterTexture() || !mWaterTexturep->hasGLTexture())
+	if (!getWaterTexture())
 	{
 		return FALSE;
 	}
@@ -1273,6 +1280,11 @@ BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y,
 		}
 	}
 
+	if (!mWaterTexturep->hasGLTexture())
+	{
+		mWaterTexturep->createGLTexture(0, raw);
+	}
+
 	mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin);
 	return TRUE;
 }
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 5fac5fd1e43..0ce794addb6 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -712,17 +712,7 @@ BOOL LLSurfacePatch::updateTexture()
 				if (mVObjp)
 				{
 					mVObjp->dirtyGeom();
-				}
-				updateCompositionStats();
-				F32 tex_patch_size = meters_per_grid*grids_per_patch_edge;
-				if (comp->generateTexture((F32)origin_region[VX], (F32)origin_region[VY],
-										  tex_patch_size, tex_patch_size))
-				{
-					mSTexUpdate = FALSE;
-
-					// Also generate the water texture
-					mSurfacep->generateWaterTexture((F32)origin_region.mdV[VX], (F32)origin_region.mdV[VY],
-													tex_patch_size, tex_patch_size);
+					gPipeline.markGLRebuild(mVObjp);
 					return TRUE;
 				}
 			}
@@ -735,6 +725,28 @@ BOOL LLSurfacePatch::updateTexture()
 	}
 }
 
+void LLSurfacePatch::updateGL()
+{
+	F32 meters_per_grid = getSurface()->getMetersPerGrid();
+	F32 grids_per_patch_edge = (F32)getSurface()->getGridsPerPatchEdge();
+
+	LLViewerRegion *regionp = getSurface()->getRegion();
+	LLVector3d origin_region = getOriginGlobal() - getSurface()->getOriginGlobal();
+
+	LLVLComposition* comp = regionp->getComposition();
+	
+	updateCompositionStats();
+	F32 tex_patch_size = meters_per_grid*grids_per_patch_edge;
+	if (comp->generateTexture((F32)origin_region[VX], (F32)origin_region[VY],
+							  tex_patch_size, tex_patch_size))
+	{
+		mSTexUpdate = FALSE;
+
+		// Also generate the water texture
+		mSurfacep->generateWaterTexture((F32)origin_region.mdV[VX], (F32)origin_region.mdV[VY],
+										tex_patch_size, tex_patch_size);
+	}
+}
 
 void LLSurfacePatch::dirtyZ()
 {
diff --git a/indra/newview/llsurfacepatch.h b/indra/newview/llsurfacepatch.h
index 4cac9773059..ebfb64c1d8b 100644
--- a/indra/newview/llsurfacepatch.h
+++ b/indra/newview/llsurfacepatch.h
@@ -90,6 +90,7 @@ class LLSurfacePatch
 
 	void updateCameraDistanceRegion( const LLVector3 &pos_region);
 	void updateVisibility();
+	void updateGL();
 
 	void dirtyZ(); // Dirty the z values of this patch
 	void setHasReceivedData();
diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h
index b0ac13913e6..6922eae0e14 100644
--- a/indra/newview/lltexlayer.h
+++ b/indra/newview/lltexlayer.h
@@ -193,7 +193,7 @@ class LLTexLayerSet
 	void					applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components);
 	void					renderAlphaMaskTextures(S32 width, S32 height, bool forceClear = false);
 	LLTexLayer*				findLayerByName(std::string name);
-
+	
 	LLVOAvatarSelf*		    getAvatar()	const { return mAvatar; }
 	const std::string		getBodyRegion() const;
 	BOOL					hasComposite() const { return (mComposite.notNull()); }
diff --git a/indra/newview/lltexlayerparams.cpp b/indra/newview/lltexlayerparams.cpp
index c9117a84a50..7a1ee95a65e 100644
--- a/indra/newview/lltexlayerparams.cpp
+++ b/indra/newview/lltexlayerparams.cpp
@@ -94,7 +94,7 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)
 		{
 			S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents();
 
-			if (tex->hasValidGLTexture())
+			if (tex->hasGLTexture())
 			{
 				*gl_bytes += bytes;
 			}
diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp
new file mode 100644
index 00000000000..79b36863860
--- /dev/null
+++ b/indra/newview/lltextureatlas.cpp
@@ -0,0 +1,422 @@
+/** 
+ * @file lltextureatlas.cpp
+ * @brief LLTextureAtlas class implementation.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+#include "llerror.h"
+#include "llimage.h"
+#include "llmath.h"
+#include "llgl.h"
+#include "llrender.h"
+#include "lltextureatlas.h"
+
+//-------------------
+S16 LLTextureAtlas::sMaxSubTextureSize = 64 ;
+S16 LLTextureAtlas::sSlotSize = 32 ;
+
+#ifndef DEBUG_ATLAS
+#define DEBUG_ATLAS 0
+#endif
+
+#ifndef DEBUG_USAGE_BITS
+#define DEBUG_USAGE_BITS 0
+#endif
+//**************************************************************************************************************
+LLTextureAtlas::LLTextureAtlas(U8 ncomponents, S16 atlas_dim) : 
+    LLViewerTexture(atlas_dim * sSlotSize, atlas_dim * sSlotSize, ncomponents, TRUE),
+	mAtlasDim(atlas_dim),
+	mNumSlotsReserved(0),
+	mMaxSlotsInAtlas(atlas_dim * atlas_dim)
+{
+	generateEmptyUsageBits() ;
+
+	//generate an empty texture
+	generateGLTexture() ;
+	LLPointer<LLImageRaw> image_raw = new LLImageRaw(mFullWidth, mFullHeight, mComponents);
+	createGLTexture(0, image_raw, 0);
+	image_raw = NULL;
+}
+
+LLTextureAtlas::~LLTextureAtlas() 
+{
+	if(mSpatialGroupList.size() > 0)
+	{
+		llerrs << "Not clean up the spatial groups!" << llendl ;
+	}
+	releaseUsageBits() ;
+}
+
+//virtual 
+S8 LLTextureAtlas::getType() const
+{
+	return LLViewerTexture::ATLAS_TEXTURE ;
+}
+
+void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset)
+{
+	xoffset = (F32)col / mAtlasDim ;
+	yoffset = (F32)row / mAtlasDim ;	
+}
+
+void LLTextureAtlas::getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale)
+{
+	xscale = (F32)w / (mAtlasDim * sSlotSize) ;
+	yscale = (F32)h / (mAtlasDim * sSlotSize) ;	
+}
+
+//insert a texture piece into the atlas
+LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row)
+{
+	if(!getTexName())
+	{
+		return 0 ;
+	}
+
+	S32 w = raw_image->getWidth() ;
+	S32 h = raw_image->getHeight() ;
+	if(w < 8 || w > sMaxSubTextureSize || h < 8 || h > sMaxSubTextureSize)
+	{
+		//size overflow
+		return 0 ;
+	}
+
+	BOOL res = gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getTexName());
+	if (!res) 
+	{
+		llerrs << "bindTexture failed" << llendl;
+	}
+	
+	GLint xoffset = sSlotSize * slot_col ;
+	GLint yoffset = sSlotSize * slot_row ;
+
+	if(!source_gl_tex->preAddToAtlas(discard_level, raw_image))
+	{
+		return 0 ;
+	}
+
+	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, TRUE);
+	glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h,
+						mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData());
+	
+	source_gl_tex->postAddToAtlas() ;
+	return getTexName();
+}
+	
+//release a sub-texture slot from the atlas
+void LLTextureAtlas::releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width)
+{
+	unmarkUsageBits(slot_width, slot_col, slot_row) ;
+	mNumSlotsReserved -= slot_width * slot_width ;
+}
+
+BOOL LLTextureAtlas::isEmpty() const 
+{
+	return !mNumSlotsReserved ;
+}
+	
+BOOL LLTextureAtlas::isFull(S8 to_be_reserved) const 
+{
+	return mNumSlotsReserved + to_be_reserved > mMaxSlotsInAtlas ;
+}
+F32  LLTextureAtlas::getFullness() const 
+{
+	return (F32)mNumSlotsReserved / mMaxSlotsInAtlas ;
+}
+
+void LLTextureAtlas::addSpatialGroup(LLSpatialGroup* groupp) 
+{
+	if(groupp && !hasSpatialGroup(groupp))
+	{
+		mSpatialGroupList.push_back(groupp);
+	}
+}
+
+void LLTextureAtlas::removeSpatialGroup(LLSpatialGroup* groupp) 
+{
+	if(groupp)
+	{
+		mSpatialGroupList.remove(groupp);
+	}
+}
+
+void LLTextureAtlas::clearSpatialGroup() 
+{
+	mSpatialGroupList.clear();
+}
+void LLTextureAtlas::removeLastSpatialGroup() 
+{
+	mSpatialGroupList.pop_back() ;
+}
+
+LLSpatialGroup* LLTextureAtlas::getLastSpatialGroup() 
+{
+	if(mSpatialGroupList.size() > 0)
+	{
+		return mSpatialGroupList.back() ;
+	}
+	return NULL ;
+}
+
+BOOL LLTextureAtlas::hasSpatialGroup(LLSpatialGroup* groupp) 
+{
+	for(std::list<LLSpatialGroup*>::iterator iter = mSpatialGroupList.begin(); iter != mSpatialGroupList.end() ; ++iter)
+	{
+		if(*iter == groupp)
+		{
+			return TRUE ;
+		}
+	}
+	return FALSE ;
+}
+
+//--------------------------------------------------------------------------------------
+//private
+void LLTextureAtlas::generateEmptyUsageBits()
+{
+	S32 col_len = (mAtlasDim + 7) >> 3 ;
+	mUsageBits = new U8*[mAtlasDim] ;
+	*mUsageBits = new U8[mAtlasDim * col_len] ;
+
+	mUsageBits[0] = *mUsageBits ;
+	for(S32 i = 1 ; i < mAtlasDim ; i++)
+	{
+	   mUsageBits[i] = mUsageBits[i-1] + col_len ;
+
+	   for(S32 j = 0 ; j < col_len ; j++)
+	   {
+		   //init by 0 for all bits.
+		   mUsageBits[i][j] = 0 ;
+	   }
+	}
+
+	//do not forget mUsageBits[0]!
+	for(S32 j = 0 ; j < col_len ; j++)
+	{
+		//init by 0 for all bits.
+		mUsageBits[0][j] = 0 ;
+	}
+
+	mTestBits = NULL ;
+#if DEBUG_USAGE_BITS
+	//------------
+	//test
+	mTestBits = new U8*[mAtlasDim] ;
+	*mTestBits = new U8[mAtlasDim * mAtlasDim] ;
+	mTestBits[0] = *mTestBits ;
+	for(S32 i = 1 ; i < mAtlasDim ; i++)
+	{
+	   mTestBits[i] = mTestBits[i-1] + mAtlasDim ;
+
+	   for(S32 j = 0 ; j < mAtlasDim ; j++)
+	   {
+		   //init by 0 for all bits.
+		   mTestBits[i][j] = 0 ;
+	   }
+	}
+
+	for(S32 j = 0 ; j < mAtlasDim ; j++)
+	{
+		//init by 0 for all bits.
+		mTestBits[0][j] = 0 ;
+	}
+#endif
+}
+
+void LLTextureAtlas::releaseUsageBits()
+{
+   if(mUsageBits)
+   {
+       delete[] *mUsageBits ;
+       delete[] mUsageBits ;
+   }
+   mUsageBits = NULL ;
+
+   //test
+   if( mTestBits)
+   {
+	   delete[] *mTestBits;
+	   delete[]  mTestBits;
+   }
+    mTestBits = NULL ;
+}
+
+void LLTextureAtlas::markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row)
+{
+	S16 x = col >> 3 ;
+	
+	for(S8 i = 0 ; i < bits_len ; i++)
+	{
+		mUsageBits[row + i][x] |= mask ;
+	}
+
+#if DEBUG_USAGE_BITS
+	//test
+	for(S8 i = row ; i < row + bits_len ; i++)
+	{
+		for(S8 j = col ; j < col + bits_len ; j++)
+		{
+			mTestBits[i][j] = 1 ;
+		}
+	}
+#endif
+}
+
+void LLTextureAtlas::unmarkUsageBits(S8 bits_len, S16 col, S16 row)
+{
+	S16 x = col >> 3 ;
+	U8  mask = 1 ;
+	for(S8 i = 1 ; i < bits_len ; i++)
+	{
+		mask |= (1 << i) ;
+	}
+	mask <<= (col & 7) ;
+	mask = ~mask ;
+	
+	for(S8 i = 0 ; i < bits_len ; i++)
+	{
+		mUsageBits[row + i][x] &= mask ;
+	}
+
+#if DEBUG_USAGE_BITS
+	//test
+	for(S8 i = row ; i < row + bits_len ; i++)
+	{
+		for(S8 j = col ; j < col + bits_len ; j++)
+		{
+			mTestBits[i][j] = 0 ;
+		}
+	}
+#endif
+}
+
+//return true if any of bits in the range marked.
+BOOL LLTextureAtlas::areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row)
+{
+	BOOL ret = FALSE ;	
+	S16 x = col >> 3 ;
+	
+	for(S8 i = 0 ; i < bits_len ; i++)
+	{
+		if(mUsageBits[row + i][x] & mask)
+		{
+			ret = TRUE ;
+			break ;
+			//return TRUE ;
+		}
+	}
+
+#if DEBUG_USAGE_BITS
+	//test
+	BOOL ret2 = FALSE ;
+	for(S8 i = row ; i < row + bits_len ; i++)
+	{
+		for(S8 j = col ; j < col + bits_len ; j++)
+		{
+			if(mTestBits[i][j])
+			{
+				ret2 = TRUE ;
+			}
+		}
+	}
+
+	if(ret != ret2)
+	{
+		llerrs << "bits map corrupted." << llendl ;
+	}
+#endif
+	return ret ;//FALSE ;
+}
+
+//----------------------------------------------------------------------
+//
+//index order: Z order, i.e.: 
+// |-----|-----|-----|-----|
+// |  10 |  11 | 14  | 15  |
+// |-----|-----|-----|-----|
+// |   8 |   9 | 12  | 13  |
+// |-----|-----|-----|-----|
+// |   2 |   3 |   6 |   7 |
+// |-----|-----|-----|-----|
+// |   0 |   1 |   4 |   5 |
+// |-----|-----|-----|-----|
+void LLTextureAtlas::getPositionFromIndex(S16 index, S16& col, S16& row)
+{
+	col = 0 ;
+	row = 0 ;
+
+	S16 index_copy = index ;
+	for(S16 i = 0 ; index_copy && i < 16 ; i += 2)
+	{
+		col |= ((index & (1 << i)) >> i) << (i >> 1) ;
+		row |= ((index & (1 << (i + 1))) >> (i + 1)) << (i >> 1) ;
+		index_copy >>= 2 ;
+	}
+}
+void LLTextureAtlas::getIndexFromPosition(S16 col, S16 row, S16& index)
+{
+	index = 0 ;
+	S16 col_copy = col ;
+	S16 row_copy = row ;
+	for(S16 i = 0 ; (col_copy || row_copy) && i < 16 ; i++)
+	{
+		index |= ((col & 1 << i) << i) | ((row & 1 << i) << ( i + 1)) ;
+		col_copy >>= 1 ;
+		row_copy >>= 1 ;
+	}
+}
+//----------------------------------------------------------------------
+//return TRUE if succeeds.
+BOOL LLTextureAtlas::getNextAvailableSlot(S8 bits_len, S16& col, S16& row)
+{
+    S16 index_step = bits_len * bits_len ;
+
+    U8 mask = 1 ;
+	for(S8 i = 1 ; i < bits_len ; i++)
+	{
+		mask |= (1 << i) ;
+	}	
+   
+	U8 cur_mask ;
+	for(S16 index = 0 ; index < mMaxSlotsInAtlas ; index += index_step)
+    {
+		getPositionFromIndex(index, col, row) ;
+		
+		cur_mask = mask << (col & 7) ;
+		if(!areUsageBitsMarked(bits_len, cur_mask, col, row))
+		{
+			markUsageBits(bits_len, cur_mask, col, row) ;
+			mNumSlotsReserved += bits_len * bits_len ;
+			
+			return TRUE ;
+		}
+    }
+
+   return FALSE ;
+}
diff --git a/indra/newview/lltextureatlas.h b/indra/newview/lltextureatlas.h
new file mode 100644
index 00000000000..1f756ccf1a8
--- /dev/null
+++ b/indra/newview/lltextureatlas.h
@@ -0,0 +1,95 @@
+/** 
+ * @file lltextureatlas.h
+ * @brief LLTextureAtlas base class.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_TEXTUREATLAS_H
+#define LL_TEXTUREATLAS_H
+
+#include "llviewertexture.h"
+class LLSpatialGroup ;
+
+class LLTextureAtlas : public LLViewerTexture
+{
+protected:
+	/*virtual*/ ~LLTextureAtlas() ;
+
+public:
+	LLTextureAtlas(U8 ncomponents, S16 atlas_dim = 16) ;	
+
+	/*virtual*/ S8 getType() const;
+
+	LLGLuint insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row) ;
+	void releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width);
+
+	BOOL getNextAvailableSlot(S8 bits_len, S16& col, S16& row) ;
+	void getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yOffset) ;
+	void getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale) ;
+
+	BOOL isEmpty() const ;
+	BOOL isFull(S8 to_be_reserved = 1) const ;
+	F32  getFullness() const ;
+
+	void addSpatialGroup(LLSpatialGroup* groupp) ;
+	void removeSpatialGroup(LLSpatialGroup* groupp) ;
+	LLSpatialGroup* getLastSpatialGroup() ;
+	void removeLastSpatialGroup() ;
+	BOOL hasSpatialGroup(LLSpatialGroup* groupp) ;
+	void clearSpatialGroup() ;
+	std::list<LLSpatialGroup*>* getSpatialGroupList() {return &mSpatialGroupList;}
+private:
+	void generateEmptyUsageBits() ;
+	void releaseUsageBits() ;
+
+	void markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row) ;
+	void unmarkUsageBits(S8 bits_len, S16 col, S16 row) ;
+
+	void getPositionFromIndex(S16 index, S16& col, S16& row) ;
+	void getIndexFromPosition(S16 col, S16 row, S16& index) ;
+	BOOL areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row) ;
+
+private:	
+	S16 mAtlasDim ; //number of slots per edge, i.e, there are "mAtlasDim * mAtlasDim" total slots in the atlas. 
+	S16 mNumSlotsReserved ;
+	S16 mMaxSlotsInAtlas ;
+	U8  **mUsageBits ;	
+	std::list<LLSpatialGroup*> mSpatialGroupList ;
+
+public:
+	//debug use only
+	U8  **mTestBits ;
+
+public:
+	static S16 sMaxSubTextureSize ;
+	static S16 sSlotSize ;
+};
+
+#endif
+
diff --git a/indra/newview/lltextureatlasmanager.cpp b/indra/newview/lltextureatlasmanager.cpp
new file mode 100644
index 00000000000..8f026787caa
--- /dev/null
+++ b/indra/newview/lltextureatlasmanager.cpp
@@ -0,0 +1,273 @@
+/** 
+ * @file lltextureatlasmanager.cpp
+ * @brief LLTextureAtlasManager class implementation.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+#include "llviewerprecompiledheaders.h"
+#include "linden_common.h"
+#include "llerror.h"
+#include "llmath.h"
+#include "lltextureatlas.h"
+#include "lltextureatlasmanager.h"
+#include "llspatialpartition.h"
+
+const S8 MAX_NUM_EMPTY_ATLAS = 2 ;
+const F32 MIN_ATLAS_FULLNESS = 0.6f ;
+
+//*********************************************************************************************
+//implementation of class LLTextureAtlasInfo
+//*********************************************************************************************
+LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) : 
+	mAtlasp(atlasp),
+	mGroupp(groupp),
+	mCol(col),
+	mRow(row),
+	mReservedSlotWidth(slot_width),
+	mValid(FALSE),
+	mUpdatedTime(0),
+	mTexCoordOffset(xoffset, yoffset),
+	mTexCoordScale(1.f, 1.f)
+{
+	llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ;
+}
+
+LLTextureAtlasSlot::~LLTextureAtlasSlot()
+{
+	if(mAtlasp)
+	{
+		mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ;
+		if(mAtlasp->isEmpty())
+		{
+			LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ;
+		}
+		mAtlasp = NULL ;
+	}
+}
+
+//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp) 
+//{
+//	mAtlasp = atlasp ;
+//}
+//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row) 
+//{
+//	mCol = col ;
+//	mRow = row ;
+//}
+//void LLTextureAtlasSlot::setSlotWidth(S8 width) 
+//{
+//	//slot is a square with each edge length a power-of-two number
+//	mReservedSlotWidth = width ;
+//}
+//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset) 
+//{
+//	mTexCoordOffset.mV[0] = xoffset ;
+//	mTexCoordOffset.mV[1] = yoffset ;
+//}
+
+void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp) 
+{
+	mGroupp = groupp ;
+}
+void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale) 
+{
+	mTexCoordScale.mV[0] = xscale ;
+	mTexCoordScale.mV[1] = yscale ;
+}
+//*********************************************************************************************
+//END of implementation of class LLTextureAtlasInfo
+//*********************************************************************************************
+
+//*********************************************************************************************
+//implementation of class LLTextureAtlasManager
+//*********************************************************************************************
+LLTextureAtlasManager::LLTextureAtlasManager() :
+	mAtlasMap(4),
+	mEmptyAtlasMap(4) 
+{
+}
+
+LLTextureAtlasManager::~LLTextureAtlasManager()
+{
+	for(S32 i = 0 ; i < 4 ; i++)
+	{
+		for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j)
+		{
+			*j = NULL ;
+		}
+		for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j)
+		{
+			*j = NULL ;
+		}
+
+		mAtlasMap[i].clear() ;
+		mEmptyAtlasMap[i].clear() ;
+	}
+	mAtlasMap.clear() ;
+	mEmptyAtlasMap.clear() ;
+}
+
+//return TRUE if qualified
+BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) 
+{
+	if(ncomponents < 1 || ncomponents > 4)
+	{
+		return FALSE ;
+	}
+	//only support GL_TEXTURE_2D
+	if(GL_TEXTURE_2D != target)
+	{
+		return FALSE ;
+	}
+	//real image size overflows
+	if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize)
+	{
+		return FALSE ;
+	}
+
+	//if non-power-of-two number
+	if((w & (w - 1)) || (h & (h - 1)))
+	{
+		return FALSE ;
+	}
+
+	return TRUE ;
+}
+
+void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp)
+{	
+	LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ;
+	while(groupp)
+	{
+		groupp->removeAtlas(atlasp, FALSE) ;
+		atlasp->removeLastSpatialGroup() ;
+
+		groupp = atlasp->getLastSpatialGroup() ;
+	}
+
+	S8 type = atlasp->getComponents() - 1 ;	
+	//insert to the empty list
+	if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS)
+	{					
+		mEmptyAtlasMap[type].push_back(atlasp) ;
+	}
+		
+	//delete the atlasp
+	mAtlasMap[type].remove(atlasp) ;
+}
+
+//
+//this function reserves an appropriate slot from atlas pool for an image.
+//return non-NULL if succeeds.
+//Note:
+//1, this function does not check if the image this slot assigned for qualifies for atlas or not, 
+//       call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function.
+//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway.
+//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching.
+//
+LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
+																		  LLSpatialGroup* groupp, LLViewerTexture* imagep)
+{
+	if(!groupp)
+	{
+		//do not insert to atlas if does not have a group.
+		return NULL ;
+	}
+
+	//bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8.
+	if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize)
+	{
+		sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ;
+	}
+	S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ;
+	if(bits_len < 1)
+	{
+	   bits_len = 1 ;
+	}
+		
+	S16 col = -1, row = -1;
+	S8 total_bits = bits_len * bits_len ;
+
+	//insert to the atlas reserved by the same spatial group
+	LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ;
+	if(atlasp.notNull())
+	{
+		if(!atlasp->getNextAvailableSlot(bits_len, col, row))
+		{
+			//failed
+			atlasp = NULL ;
+		}		
+	}
+
+   //search an atlas to fit for 'size'
+	if(!atlasp)
+	{
+		S8 atlas_index = ncomponents - 1 ;
+		ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ;
+		for(; iter != mAtlasMap[atlas_index].end(); ++iter) 
+		{
+			LLTextureAtlas* cur = (LLTextureAtlas*)*iter ;
+			if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary.
+			{
+				if(cur->getNextAvailableSlot(bits_len, col, row))
+				{
+					atlasp = cur ;
+					groupp->addAtlas(atlasp) ;				
+					break ;
+				}
+			}
+		}
+	}
+
+	//create a new atlas if necessary
+	if(!atlasp)
+	{
+		if(mEmptyAtlasMap[ncomponents - 1].size() > 0)
+		{
+			//there is an empty one
+			atlasp = mEmptyAtlasMap[ncomponents - 1].back() ;
+			mEmptyAtlasMap[ncomponents - 1].pop_back() ;
+		}
+		else
+		{
+			atlasp = new LLTextureAtlas(ncomponents, 16) ;
+		}
+		mAtlasMap[ncomponents - 1].push_back(atlasp) ;
+		atlasp->getNextAvailableSlot(bits_len, col, row) ;		
+		groupp->addAtlas(atlasp) ;
+	}
+
+	F32 xoffset, yoffset ;
+	atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ;
+	LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ;
+	
+	return slot_infop ;
+}
+
+//*********************************************************************************************
+//END of implementation of class LLTextureAtlasManager
+//*********************************************************************************************
diff --git a/indra/newview/lltextureatlasmanager.h b/indra/newview/lltextureatlasmanager.h
new file mode 100644
index 00000000000..4dba0759f94
--- /dev/null
+++ b/indra/newview/lltextureatlasmanager.h
@@ -0,0 +1,111 @@
+/** 
+ * @file lltextureatlasmanager.h
+ * @brief LLTextureAtlasManager base class.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-2009, Linden Research, Inc.
+ * 
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab.  Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlife.com/developers/opensource/gplv2
+ * 
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at http://secondlife.com/developers/opensource/flossexception
+ * 
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+
+#ifndef LL_TEXTUREATLASMANAGER_H
+#define LL_TEXTUREATLASMANAGER_H
+
+#include "llmemory.h"
+
+class LLSpatialGroup ;
+class LLViewerTexture ;
+
+//just use it as a structure.
+class LLTextureAtlasSlot : public LLRefCount
+{
+public:
+	LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) ;
+
+protected:
+	virtual ~LLTextureAtlasSlot();
+	
+public:
+
+	//
+	//do not allow to change those values
+	//
+	//void setAtlas(LLTextureAtlas* atlasp) ;	
+	//void setSlotPos(S16 col, S16 row) ;
+	//void setSlotWidth(S8 width) ;
+	//void setTexCoordOffset(F32 xoffser, F32 yoffset) ;
+	//
+
+	void setSpatialGroup(LLSpatialGroup* groupp) ;
+	void setTexCoordScale(F32 xscale, F32 yscale) ;
+	void setValid() {mValid = TRUE ;}
+
+	LLTextureAtlas* getAtlas()const {return mAtlasp;}
+	LLSpatialGroup* getSpatialGroup() const {return mGroupp ;} 
+	S16             getSlotCol()const {return mCol;}
+	S16             getSlotRow()const {return mRow;}
+	S8              getSlotWidth()const{return mReservedSlotWidth;}
+	BOOL            isValid()const { return mValid;}
+	const LLVector2*      getTexCoordOffset()const {return &mTexCoordOffset;}
+	const LLVector2*      getTexCoordScale() const {return &mTexCoordScale;}
+
+	void setUpdatedTime(U32 t) {mUpdatedTime = t;}
+	U32  getUpdatedTime()const {return mUpdatedTime;}
+
+private:
+	LLTextureAtlas* mAtlasp;
+	S16             mCol ;//col of the slot
+	S16             mRow ;//row of the slot
+	S8              mReservedSlotWidth ; //slot is a square with each edge length a power-of-two number	
+	LLSpatialGroup* mGroupp ;
+	BOOL            mValid ;
+
+	LLVector2       mTexCoordOffset ;
+	LLVector2       mTexCoordScale ;
+
+	U32             mUpdatedTime ;	
+} ;
+
+class LLTextureAtlasManager : public LLSingleton<LLTextureAtlasManager>
+{
+private:
+	typedef std::list<LLPointer<LLTextureAtlas> > ll_texture_atlas_list_t ;
+
+public:
+	LLTextureAtlasManager();
+	~LLTextureAtlasManager();
+
+	LLPointer<LLTextureAtlasSlot> reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, 
+		LLSpatialGroup* groupp, LLViewerTexture* imagep) ;
+	void releaseAtlas(LLTextureAtlas* atlasp);
+
+	BOOL canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) ;
+
+private:	
+	std::vector<ll_texture_atlas_list_t> mAtlasMap ;
+	std::vector<ll_texture_atlas_list_t> mEmptyAtlasMap ; //delay some empty atlases deletion to avoid possible creation of new atlas immediately.
+};
+
+#endif
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 9da24463542..ea675c5a6e4 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -56,6 +56,7 @@
 extern F32 texmem_lower_bound_scale;
 
 LLTextureView *gTextureView = NULL;
+LLTextureSizeView *gTextureSizeView = NULL;
 
 //static
 std::set<LLViewerFetchedTexture*> LLTextureView::sDebugImages;
@@ -315,7 +316,7 @@ void LLTextureBar::draw()
 	pip_x += pip_width + pip_space;
 
 	// we don't want to show bind/resident pips for textures using the default texture
-	if (mImagep->hasValidGLTexture())
+	if (mImagep->hasGLTexture())
 	{
 		// Draw the bound pip
 		last_event = mImagep->getTimePassedSinceLastBound();
@@ -535,6 +536,73 @@ LLRect LLGLTexMemBar::getRequiredRect()
 	return rect;
 }
 
+////////////////////////////////////////////////////////////////////////////
+class LLGLTexSizeBar
+{
+public:
+	LLGLTexSizeBar(S32 index, S32 left, S32 bottom, S32 right, S32 line_height)
+	{
+		mIndex = index ;
+		mLeft = left ;
+		mBottom = bottom ;
+		mRight = right ;
+		mLineHeight = line_height ;
+		mTopLoaded = 0 ;
+		mTopBound = 0 ;
+		mScale = 1.0f ;
+	}
+
+	void setTop(S32 loaded, S32 bound, F32 scale) {mTopLoaded = loaded ; mTopBound = bound; mScale = scale ;}
+
+	void draw();	
+	BOOL handleHover(S32 x, S32 y, MASK mask) ;
+	
+private:
+	S32 mIndex ;
+	S32 mLeft ;
+	S32 mBottom ;
+	S32 mRight ;
+	S32 mTopLoaded ;
+	S32 mTopBound ;
+	S32 mLineHeight ;
+	F32 mScale ;
+};
+
+BOOL LLGLTexSizeBar::handleHover(S32 x, S32 y, MASK mask) 
+{
+#if !LL_RELEASE_FOR_DOWNLOAD
+	if(y > mBottom && (y < mBottom + (S32)(mTopLoaded * mScale) || y < mBottom + (S32)(mTopBound * mScale)))
+	{
+		LLImageGL::setCurTexSizebar(mIndex);
+	}
+#endif
+	return TRUE ;
+}
+void LLGLTexSizeBar::draw()
+{
+#if !LL_RELEASE_FOR_DOWNLOAD
+	LLGLSUIDefault gls_ui;
+
+	if(LLImageGL::sCurTexSizeBar == mIndex)
+	{
+		F32 text_color[] = {1.f, 1.f, 1.f, 0.75f};	
+		std::string text;
+	
+		text = llformat("%d", mTopLoaded) ;
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, mLeft, mBottom + (S32)(mTopLoaded * mScale) + mLineHeight,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+		text = llformat("%d", mTopBound) ;
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, (mLeft + mRight) / 2, mBottom + (S32)(mTopBound * mScale) + mLineHeight,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	}
+
+	F32 loaded_color[] = {1.0f, 0.0f, 0.0f, 0.75f};
+	F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f};
+	gl_rect_2d(mLeft, mBottom + (S32)(mTopLoaded * mScale), (mLeft + mRight) / 2, mBottom, loaded_color) ;
+	gl_rect_2d((mLeft + mRight) / 2, mBottom + (S32)(mTopBound * mScale), mRight, mBottom, bound_color) ;
+#endif
+}
 ////////////////////////////////////////////////////////////////////////////
 
 LLTextureView::LLTextureView(const LLTextureView::Params& p)
@@ -820,4 +888,163 @@ BOOL LLTextureView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 	return FALSE;
 }
 
+//-----------------------------------------------------------------
+LLTextureSizeView::LLTextureSizeView(const LLTextureSizeView::Params& p)
+	: LLView(p)
+{
+	setVisible(FALSE) ;
+
+	mTextureSizeBarWidth = 30 ;
+}
+
+LLTextureSizeView::~LLTextureSizeView()
+{
+	if(mTextureSizeBar.size())
+	{
+		for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++)
+		{
+			delete mTextureSizeBar[i] ;
+		}
+		mTextureSizeBar.clear() ;
+	}
+}
+void LLTextureSizeView::draw()
+{
+#if !LL_RELEASE_FOR_DOWNLOAD
+	if(mTextureSizeBar.size() == 0)
+	{
+		S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+		mTextureSizeBar.resize(LLImageGL::sTextureLoadedCounter.size()) ;
+		mTextureSizeBarRect.set(700, line_height * 2 + 400, 700 + mTextureSizeBar.size() * mTextureSizeBarWidth, line_height * 2) ;
+		
+		for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++)
+		{				
+			mTextureSizeBar[i] = new LLGLTexSizeBar(i, mTextureSizeBarRect.mLeft + i * mTextureSizeBarWidth , 
+				line_height * 2, mTextureSizeBarRect.mLeft + (i + 1) * mTextureSizeBarWidth, line_height) ;				
+		}			
+	}
+
+	F32 size_bar_scale = drawTextureSizeDistributionGraph() ;		
+	for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++)
+	{
+		mTextureSizeBar[i]->setTop(LLImageGL::sTextureLoadedCounter[i], LLImageGL::sTextureBoundCounter[i], size_bar_scale) ;
+		mTextureSizeBar[i]->draw() ;
+	}		
+	LLImageGL::resetCurTexSizebar();
+
+	LLView::draw();
+#endif
+}
+
+BOOL LLTextureSizeView::handleHover(S32 x, S32 y, MASK mask) 
+{
+	if(x > mTextureSizeBarRect.mLeft && x < mTextureSizeBarRect.mRight)
+	{
+		mTextureSizeBar[(x - mTextureSizeBarRect.mLeft) / mTextureSizeBarWidth]->handleHover(x, y, mask) ;
+	}
+
+	return TRUE ;
+}
+
+//draw background of texture size bar graph
+F32 LLTextureSizeView::drawTextureSizeDistributionGraph()
+{	
+	F32 scale = 1.0f ;
+#if !LL_RELEASE_FOR_DOWNLOAD
+	LLGLSUIDefault gls_ui;
+
+	//scale	
+	{
+		S32 count = 0 ;
+		for(U32 i = 0 ; i < LLImageGL::sTextureLoadedCounter.size() ; i++)
+		{
+			if(LLImageGL::sTextureLoadedCounter[i] > count)
+			{
+				count = LLImageGL::sTextureLoadedCounter[i] ;
+			}
+		}
+		if(count > mTextureSizeBarRect.getHeight())
+		{
+			scale = (F32)mTextureSizeBarRect.getHeight() / count ;
+		}
+	}
+
+	S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+	S32 left = mTextureSizeBarRect.mLeft ;
+	S32 bottom = mTextureSizeBarRect.mBottom ;
+	S32 right = mTextureSizeBarRect.mRight ;
+	S32 top = mTextureSizeBarRect.mTop ;
+
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	
+	//background rect
+	gl_rect_2d(left - 25, top + 30, right + 100, bottom - 25, LLColor4(0.0f, 0.0f, 0.0f, 0.25f)) ;
+
+	//--------------------------------------------------
+	gGL.color4f(1.0f, 0.5f, 0.5f, 0.75f);
+	gl_line_2d(left, bottom, right, bottom) ; //x axis
+	gl_line_2d(left, bottom, left, top) ; //y axis
+
+	//ruler
+	//--------------------------------------------------
+	gGL.color4f(1.0f, 0.5f, 0.5f, 0.5f);
+	for(S32 i = bottom + 50 ; i <= top ; i += 50)
+	{
+		gl_line_2d(left, i, right, i) ;
+	}
+
+	//texts
+	//--------------------------------------------------
+	F32 text_color[] = {1.f, 1.f, 1.f, 0.75f};	
+	std::string text;
+	
+	//-------
+	//x axis: size label
+	text = llformat("%d", 0) ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 12, bottom - line_height / 2,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	for(U32 i = 1 ; i < mTextureSizeBar.size() ; i++)
+	{
+		text = llformat("%d", (1 << (i / 2)) + ((i & 1) ? ((1 << (i / 2)) >> 1) : 0)) ;
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + i * mTextureSizeBarWidth + 12, bottom - line_height / 2,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	}
+	text = llformat("(w + h)/2") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, right + 10, bottom - line_height / 2,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	//-------
+
+	//y axis: number label
+	for(S32 i = bottom + 50 ; i <= top ; i += 50)
+	{
+		text = llformat("%d", (S32)((i - bottom) / scale)) ;
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, i + line_height / 2 ,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, right + 5, i + line_height / 2 ,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	}
+
+	//--------------------------------------------------
+	F32 loaded_color[] = {1.0f, 0.0f, 0.0f, 0.75f};
+	gl_rect_2d(left + 70, top + line_height * 2, left + 90, top + line_height, loaded_color) ;
+	text = llformat("Loaded") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 100, top + line_height * 2,
+									 loaded_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+	F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f};
+	gl_rect_2d(left + 170, top + line_height * 2, left + 190, top + line_height, bound_color) ;
+	text = llformat("Bound") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 200, top + line_height * 2,
+									 bound_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+	//--------------------------------------------------
+
+	//title
+	text = llformat("Texture Size Distribution") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 250, top + line_height * 3,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+#endif	
+	return scale ;
+}
 
diff --git a/indra/newview/lltextureview.h b/indra/newview/lltextureview.h
index 20be17aef44..e917c0235e7 100644
--- a/indra/newview/lltextureview.h
+++ b/indra/newview/lltextureview.h
@@ -78,5 +78,25 @@ class LLTextureView : public LLContainerView
 	static std::set<LLViewerFetchedTexture*> sDebugImages;
 };
 
+class LLGLTexSizeBar;
+
+class LLTextureSizeView : public LLView
+{
+public:
+	LLTextureSizeView(const Params&);
+	~LLTextureSizeView();
+
+	/*virtual*/ void draw();
+	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) ;
+	
+private:
+	F32 drawTextureSizeDistributionGraph() ;
+	
+private:
+	std::vector<LLGLTexSizeBar*> mTextureSizeBar ;
+	LLRect mTextureSizeBarRect ;
+	S32    mTextureSizeBarWidth ;
+};
 extern LLTextureView *gTextureView;
+extern LLTextureSizeView *gTextureSizeView;
 #endif // LL_TEXTURE_VIEW_H
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index be6e539ffd5..328653d2b84 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -74,13 +74,12 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 	static void			selectionPropertiesReceived();
 
 	static void			showAvatarInspector(const LLUUID& id);
-
 private:
 	BOOL outsideSlop		(S32 x, S32 y, S32 start_x, S32 start_y);
 	BOOL pickLeftMouseDownCallback();
 	BOOL pickRightMouseDownCallback();
 	BOOL useClickAction		(MASK mask, LLViewerObject* object,LLViewerObject* parent);
-
+	
 	void showVisualContextMenuEffect();
 private:
 	BOOL				mGrabMouseButtonDown;
@@ -90,6 +89,7 @@ class LLToolPie : public LLTool, public LLSingleton<LLToolPie>
 	LLPointer<LLViewerObject> mClickActionObject;
 	U8					mClickAction;
 	LLSafeHandle<LLObjectSelection> mLeftClickSelection;
+
 };
 
 
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 3f3c10a7c79..1c2894dc375 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -56,6 +56,8 @@
 // System includes
 #include <iomanip> // for setprecision
 
+U32 LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
 //glu pick matrix implementation borrowed from Mesa3D
 glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLint* viewport)
 {
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index b99dd395847..90b77f771f3 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -55,6 +55,24 @@ const BOOL NOT_FOR_SELECTION = FALSE;
 class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
 {
 public:
+
+	typedef enum
+	{
+		CAMERA_WORLD = 0,
+		CAMERA_SHADOW0,
+		CAMERA_SHADOW1,
+		CAMERA_SHADOW2,
+		CAMERA_SHADOW3,
+		CAMERA_SHADOW4,
+		CAMERA_SHADOW5,
+		CAMERA_WATER0,
+		CAMERA_WATER1,
+		CAMERA_GI_SOURCE,
+		NUM_CAMERAS
+	} eCameraID;
+
+	static U32 sCurCameraID;
+
 	LLViewerCamera();
 
 	void updateCameraLocation(const LLVector3 &center,
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index be832ebe326..b888560fc76 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -493,6 +493,8 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("EnableRippleWater")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
@@ -523,6 +525,8 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2));
 	gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2));
 	gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+	gSavedSettings.getControl("RenderDeferredShadow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+	gSavedSettings.getControl("RenderDeferredGI")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2));
 	gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _2));
 	gSavedSettings.getControl("ChatPersistTime")->getSignal()->connect(boost::bind(&handleChatPersistTimeChanged, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 6d2482d3f0f..a6a72e96661 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -125,6 +125,11 @@ void display_startup()
 		return; 
 	}
 
+	gPipeline.updateGL();
+
+	// Update images?
+	//gImageList.updateImages(0.01f);
+	
 	LLGLSDefault gls_default;
 
 	// Required for HTML update in login screen
@@ -558,6 +563,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			stop_glerror();
 		}
 
+		gPipeline.updateGL();
+		stop_glerror();
+
 		S32 water_clip = 0;
 		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) &&
 			 gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER))
@@ -606,6 +614,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLGLState::checkClientArrays();
 
 		static LLCullResult result;
+		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
 		stop_glerror();
 
@@ -647,6 +656,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 					gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
 				}
 
+				LLVertexBuffer::unbind();
+
 				LLGLState::checkStates();
 				LLGLState::checkTextureChannels();
 				LLGLState::checkClientArrays();
@@ -678,6 +689,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION);
 			LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery");
 			gPipeline.generateWaterReflection(*LLViewerCamera::getInstance());
+			gPipeline.generateHighlight(*LLViewerCamera::getInstance());
 		}
 
 		//////////////////////////////////////
@@ -702,6 +714,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 			const F32 max_image_decode_time = llmin(0.005f, 0.005f*10.f*gFrameIntervalSeconds); // 50 ms/second decode time (no more than 5ms/frame)
 			gTextureList.updateImages(max_image_decode_time);
+
+			//remove dead textures from GL
+			LLImageGL::deleteDeadTextures();
 			stop_glerror();
 		}
 		llpushcallstacks ;
@@ -715,6 +730,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//
 		LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort");
 		{
+			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 			LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT);
 			gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
 			stop_glerror();
@@ -797,6 +813,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 			{
 				gPipeline.mDeferredScreen.bindTarget();
+				glClearColor(0,0,0,0);
 				gPipeline.mDeferredScreen.clear();
 			}
 			else
@@ -813,6 +830,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot())
 				&& !gRestoreGL)
 		{
+			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 			LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM);
 			gGL.setColorMask(true, false);
 			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
@@ -831,6 +849,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			for (U32 i = 0; i < 16; i++)
 			{
 				gGLLastModelView[i] = gGLModelView[i];
+				gGLLastProjection[i] = gGLProjection[i];
 			}
 			stop_glerror();
 		}
@@ -870,6 +889,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			render_ui();
 		}
 
+		gPipeline.rebuildGroups();
+
 		LLSpatialGroup::sNoDelete = FALSE;
 	}
 
@@ -944,6 +965,7 @@ void render_hud_attachments()
 		static LLCullResult result;
 		LLSpatialGroup::sNoDelete = TRUE;
 
+		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 		gPipeline.updateCull(hud_cam, result);
 
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_BUMP);
@@ -951,6 +973,15 @@ void render_hud_attachments()
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_SHINY);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISIBLE);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
 		
 		gPipeline.stateSort(hud_cam, result);
 
@@ -1259,7 +1290,73 @@ void render_ui_2d()
 		glPopMatrix();
 		stop_glerror();
 	}
-	gViewerWindow->draw();
+	
+
+	if (gSavedSettings.getBOOL("RenderUIBuffer"))
+	{
+		if (LLUI::sDirty)
+		{
+			LLUI::sDirty = FALSE;
+			LLRect t_rect;
+
+			gPipeline.mUIScreen.bindTarget();
+			gGL.setColorMask(true, true);
+			{
+				static const S32 pad = 8;
+
+				LLUI::sDirtyRect.mLeft -= pad;
+				LLUI::sDirtyRect.mRight += pad;
+				LLUI::sDirtyRect.mBottom -= pad;
+				LLUI::sDirtyRect.mTop += pad;
+
+				LLGLEnable scissor(GL_SCISSOR_TEST);
+				static LLRect last_rect = LLUI::sDirtyRect;
+
+				//union with last rect to avoid mouse poop
+				last_rect.unionWith(LLUI::sDirtyRect);
+								
+				t_rect = LLUI::sDirtyRect;
+				LLUI::sDirtyRect = last_rect;
+				last_rect = t_rect;
+			
+				last_rect.mLeft = LLRect::tCoordType(last_rect.mLeft / LLUI::sGLScaleFactor.mV[0]);
+				last_rect.mRight = LLRect::tCoordType(last_rect.mRight / LLUI::sGLScaleFactor.mV[0]);
+				last_rect.mTop = LLRect::tCoordType(last_rect.mTop / LLUI::sGLScaleFactor.mV[1]);
+				last_rect.mBottom = LLRect::tCoordType(last_rect.mBottom / LLUI::sGLScaleFactor.mV[1]);
+
+				LLRect clip_rect(last_rect);
+				
+				glClear(GL_COLOR_BUFFER_BIT);
+
+				gViewerWindow->draw();
+			}
+
+			gPipeline.mUIScreen.flush();
+			gGL.setColorMask(true, false);
+
+			LLUI::sDirtyRect = t_rect;
+			
+	}
+
+		LLGLDisable cull(GL_CULL_FACE);
+		LLGLDisable blend(GL_BLEND);
+		S32 width = gViewerWindow->getWindowWidth();
+		S32 height = gViewerWindow->getWindowHeight();
+		gGL.getTexUnit(0)->bind(&gPipeline.mUIScreen);
+		gGL.begin(LLRender::TRIANGLE_STRIP);
+		gGL.color4f(1,1,1,1);
+		gGL.texCoord2f(0, 0);			gGL.vertex2i(0, 0);
+		gGL.texCoord2f(width, 0);		gGL.vertex2i(width, 0);
+		gGL.texCoord2f(0, height);		gGL.vertex2i(0, height);
+		gGL.texCoord2f(width, height);	gGL.vertex2i(width, height);
+		gGL.end();
+	}
+	else
+	{
+		gViewerWindow->draw();
+	}
+
+
 
 	// reset current origin for font rendering, in case of tiling render
 	LLFontGL::sCurOrigin.set(0, 0);
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 28f883312ae..cd60a8d5606 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -564,7 +564,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 			// Ignore the warning if that's the case.
 			if (!gSavedSettings.getBOOL("RenderUnloadedAvatar"))
 			{
-				llwarns << "Layerset without composite" << llendl;
+				//llwarns << "Layerset without composite" << llendl;
 			}
 			gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
 		}
@@ -576,6 +576,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		{
 			old_mode = mTexture->getAddressMode();
 		}
+		gGL.getTexUnit(0)->bind(mTexture.get());
 		gGL.getTexUnit(0)->bind(mTexture);
 		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 	}
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 12d5687877d..70f2331efad 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -979,6 +979,10 @@ U32 info_display_from_string(std::string info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME;
 	}
+	else if ("raycast" == info_display)
+	{
+		return LLPipeline::RENDER_DEBUG_RAYCAST;
+	}
 	else if ("agent target" == info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_AGENT_TARGET;
@@ -1172,6 +1176,29 @@ class LLAdvancedCheckDisableTextures : public view_listener_t
 	}
 };
 
+//////////////////////
+// TEXTURE ATLAS //
+//////////////////////
+
+class LLAdvancedToggleTextureAtlas : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		LLViewerTexture::sUseTextureAtlas = !LLViewerTexture::sUseTextureAtlas;
+		gSavedSettings.setBOOL("EnableTextureAtlas", LLViewerTexture::sUseTextureAtlas) ;
+		return true;
+	}
+};
+
+class LLAdvancedCheckTextureAtlas : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		bool new_value = LLViewerTexture::sUseTextureAtlas; // <-- make this using LLCacheControl
+		return new_value;
+	}
+};
+
 //////////////////////////
 // DUMP SCRIPTED CAMERA //
 //////////////////////////
@@ -2145,11 +2172,48 @@ class LLAdvancedEnableObjectObjectOcclusion: public view_listener_t
 	bool handleEvent(const LLSD& userdata)
 	{
 	
-		bool new_value = gGLManager.mHasOcclusionQuery && LLFeatureManager::getInstance()->isFeatureAvailable(userdata.asString());
+		bool new_value = gGLManager.mHasOcclusionQuery; // && LLFeatureManager::getInstance()->isFeatureAvailable(userdata.asString());
 		return new_value;
 }
 };
 
+/////////////////////////////////////
+// Enable Framebuffer Objects	  ///
+/////////////////////////////////////
+class LLAdvancedEnableRenderFBO: public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		bool new_value = gGLManager.mHasFramebufferObject;
+		return new_value;
+	}
+};
+
+/////////////////////////////////////
+// Enable Deferred Rendering	  ///
+/////////////////////////////////////
+class LLAdvancedEnableRenderDeferred: public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) &&
+			LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0;
+		return new_value;
+	}
+};
+
+/////////////////////////////////////
+// Enable Global Illumination 	  ///
+/////////////////////////////////////
+class LLAdvancedEnableRenderDeferredGI: public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && gSavedSettings.getBOOL("RenderDeferred");
+		return new_value;
+	}
+};
+
 
 
 //////////////////
@@ -7792,7 +7856,12 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
 	view_listener_t::addMenu(new LLAdvancedToggleDisableTextures(), "Advanced.ToggleDisableTextures");
 	view_listener_t::addMenu(new LLAdvancedCheckDisableTextures(), "Advanced.CheckDisableTextures");
+	view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas");
+	view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas");
 	view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
+	view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO");
+	view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred");
+	view_listener_t::addMenu(new LLAdvancedEnableRenderDeferredGI(), "Advanced.EnableRenderDeferredGI");
 	view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate");
 	view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate");
 	view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 7e2183f1f39..e37bad6b0ea 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3267,7 +3267,6 @@ void process_object_update(LLMessageSystem *mesgsys, void **user_data)
 
 	// Update the object...
 	gObjectList.processObjectUpdate(mesgsys, user_data, OUT_FULL);
-	stop_glerror();
 }
 
 void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data)
@@ -3285,7 +3284,6 @@ void process_compressed_object_update(LLMessageSystem *mesgsys, void **user_data
 
 	// Update the object...
 	gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_FULL_COMPRESSED);
-	stop_glerror();
 }
 
 void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data)
@@ -3303,7 +3301,6 @@ void process_cached_object_update(LLMessageSystem *mesgsys, void **user_data)
 
 	// Update the object...
 	gObjectList.processCachedObjectUpdate(mesgsys, user_data, OUT_FULL_CACHED);
-	stop_glerror();
 }
 
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index cf77f7e2b61..8c223557bf2 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2803,6 +2803,11 @@ BOOL LLViewerObject::updateGeometry(LLDrawable *drawable)
 	return TRUE;
 }
 
+void LLViewerObject::updateGL()
+{
+
+}
+
 void LLViewerObject::updateFaceSize(S32 idx)
 {
 	
@@ -4188,6 +4193,11 @@ void LLViewerObject::updateText()
 	}
 }
 
+LLVOAvatar* LLViewerObject::asAvatar()
+{
+	return NULL;
+}
+
 BOOL LLViewerObject::isParticleSource() const
 {
 	return !mPartSourcep.isNull() && !mPartSourcep->isDead();
@@ -4494,7 +4504,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
 		  new_block = new LLSculptParams();
 		  break;
 	  }
-
+	  case LLNetworkData::PARAMS_LIGHT_IMAGE:
+	  {
+		  new_block = new LLLightImageParams();
+		  break;
+	  }
 	  default:
 	  {
 		  llinfos << "Unknown param type." << llendl;
@@ -4585,7 +4599,7 @@ bool LLViewerObject::setParameterEntry(U16 param_type, const LLNetworkData& new_
 bool LLViewerObject::setParameterEntryInUse(U16 param_type, BOOL in_use, bool local_origin)
 {
 	ExtraParameter* param = getExtraParameterEntryCreate(param_type);
-	if (param->in_use != in_use)
+	if (param && param->in_use != in_use)
 	{
 		param->in_use = in_use;
 		parameterChanged(param_type, param->data, in_use, local_origin);
@@ -4998,7 +5012,7 @@ U32 LLViewerObject::getPartitionType() const
 	return LLViewerRegion::PARTITION_NONE; 
 }
 
-void LLViewerObject::dirtySpatialGroup() const
+void LLViewerObject::dirtySpatialGroup(BOOL priority) const
 {
 	if (mDrawable)
 	{
@@ -5006,6 +5020,7 @@ void LLViewerObject::dirtySpatialGroup() const
 		if (group)
 		{
 			group->dirtyGeom();
+			gPipeline.markRebuild(group, priority);
 		}
 	}
 }
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 836e05728fe..08e2ec47cd9 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -75,6 +75,7 @@ class LLViewerPartSourceScript;
 class LLViewerRegion;
 class LLViewerObjectMedia;
 class LLVOInventoryListener;
+class LLVOAvatar;
 
 typedef enum e_object_update_type
 {
@@ -117,7 +118,7 @@ struct LLMaterialExportInfo
 
 //============================================================================
 
-class LLViewerObject : public LLPrimitive, public LLRefCount
+class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 {
 protected:
 	~LLViewerObject(); // use unref()
@@ -144,6 +145,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 	BOOL isOrphaned() const								{ return mOrphaned; }
 	BOOL isParticleSource() const;
 
+	virtual LLVOAvatar* asAvatar();
+
 	static void initVOClasses();
 	static void cleanupVOClasses();
 
@@ -195,6 +198,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 	
 	virtual LLDrawable* createDrawable(LLPipeline *pipeline);
 	virtual BOOL		updateGeometry(LLDrawable *drawable);
+	virtual void		updateGL();
 	virtual void		updateFaceSize(S32 idx);
 	virtual BOOL		updateLOD();
 	virtual BOOL		setDrawableParent(LLDrawable* parentp);
@@ -219,6 +223,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 
 	virtual BOOL isFlexible() const					{ return FALSE; }
 	virtual BOOL isSculpted() const 				{ return FALSE; }
+	virtual BOOL hasLightTexture() const			{ return FALSE; }
 
 	// This method returns true if the object is over land owned by
 	// the agent.
@@ -470,7 +475,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount
 
 	virtual S32 getLOD() const { return 3; } 
 	virtual U32 getPartitionType() const;
-	virtual void dirtySpatialGroup() const;
+	virtual void dirtySpatialGroup(BOOL priority = FALSE) const;
 	virtual void dirtyMesh();
 
 	virtual LLNetworkData* getParameterEntry(U16 param_type) const;
diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp
index 1a91240abb2..9896adad974 100644
--- a/indra/newview/llviewerparceloverlay.cpp
+++ b/indra/newview/llviewerparceloverlay.cpp
@@ -53,6 +53,8 @@
 #include "llselectmgr.h"
 #include "llfloatertools.h"
 #include "llglheaders.h"
+#include "pipeline.h"
+
 
 const U8  OVERLAY_IMG_COMPONENTS = 4;
 
@@ -72,8 +74,6 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_
 	// Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges	
 	mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS);
 	mTexture = LLViewerTextureManager::getLocalTexture(mImageRaw.get(), FALSE);
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->bind(mTexture);
 	mTexture->setAddressMode(LLTexUnit::TAM_CLAMP);
 	mTexture->setFilteringOption(LLTexUnit::TFO_POINT);
 
@@ -87,7 +87,7 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_
 	{
 		raw[i] = 0;
 	}
-	mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
+	//mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
 
 	// Create storage for ownership information from simulator
 	// and initialize it.
@@ -97,8 +97,7 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_
 		mOwnership[i] = PARCEL_PUBLIC;
 	}
 
-	// Make sure the texture matches the ownership information.
-	updateOverlayTexture();
+	gPipeline.markGLRebuild(this);
 }
 
 
@@ -283,6 +282,10 @@ void LLViewerParcelOverlay::updateOverlayTexture()
 	// Copy data into GL texture from raw data
 	if (i >= COUNT)
 	{
+		if (!mTexture->hasGLTexture())
+		{
+			mTexture->createGLTexture(0, mImageRaw);
+		}
 		mTexture->setSubImage(mImageRaw, 0, 0, mParcelGridsPerEdge, mParcelGridsPerEdge);
 		mOverlayTextureIdx = -1;
 	}
@@ -709,6 +712,11 @@ void LLViewerParcelOverlay::setDirty()
 	mDirty = TRUE;
 }
 
+void LLViewerParcelOverlay::updateGL()
+{
+	updateOverlayTexture();
+}
+
 void LLViewerParcelOverlay::idleUpdate(bool force_update)
 {
 	LLMemType mt_iup(LLMemType::MTYPE_IDLE_UPDATE_PARCEL_OVERLAY);
@@ -719,7 +727,7 @@ void LLViewerParcelOverlay::idleUpdate(bool force_update)
 	if (mOverlayTextureIdx >= 0 && (!(mDirty && force_update)))
 	{
 		// We are in the middle of updating the overlay texture
-		updateOverlayTexture();
+		gPipeline.markGLRebuild(this);
 		return;
 	}
 	// Only if we're dirty and it's been a while since the last update.
diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h
index e673b811edd..161b7a386b6 100644
--- a/indra/newview/llviewerparceloverlay.h
+++ b/indra/newview/llviewerparceloverlay.h
@@ -40,13 +40,14 @@
 #include "llframetimer.h"
 #include "lluuid.h"
 #include "llviewertexture.h"
+#include "llgl.h"
 
 class LLViewerRegion;
 class LLVector3;
 class LLColor4U;
 class LLVector2;
 
-class LLViewerParcelOverlay
+class LLViewerParcelOverlay : public LLGLUpdate
 {
 public:
 	LLViewerParcelOverlay(LLViewerRegion* region, F32 region_width_meters);
@@ -76,6 +77,7 @@ class LLViewerParcelOverlay
 	void	setDirty();
 
 	void	idleUpdate(bool update_now = false);
+	void	updateGL();
 
 private:
 	// This is in parcel rows and columns, not grid rows and columns
diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp
index a8cbcd86c6c..4752bf1a856 100644
--- a/indra/newview/llviewerpartsource.cpp
+++ b/indra/newview/llviewerpartsource.cpp
@@ -101,7 +101,7 @@ LLViewerPartSourceScript::LLViewerPartSourceScript(LLViewerObject *source_objp)
 	mSourceObjectp = source_objp;
 	mPosAgent = mSourceObjectp->getPositionAgent();
 	mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c");
-	gGL.getTexUnit(0)->bind(mImagep);
+	
 	mImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 }
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index b5bd2f93af8..6dc9f5c4652 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -104,6 +104,7 @@ LLGLSLShader			gPostNightVisionProgram;
 
 // Deferred rendering shaders
 LLGLSLShader			gDeferredImpostorProgram;
+LLGLSLShader			gDeferredEdgeProgram;
 LLGLSLShader			gDeferredWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
 LLGLSLShader			gDeferredBumpProgram;
@@ -113,6 +114,8 @@ LLGLSLShader			gDeferredAvatarProgram;
 LLGLSLShader			gDeferredAvatarAlphaProgram;
 LLGLSLShader			gDeferredLightProgram;
 LLGLSLShader			gDeferredMultiLightProgram;
+LLGLSLShader			gDeferredSpotLightProgram;
+LLGLSLShader			gDeferredMultiSpotLightProgram;
 LLGLSLShader			gDeferredSunProgram;
 LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
@@ -120,6 +123,13 @@ LLGLSLShader			gDeferredShadowProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
 LLGLSLShader			gDeferredAlphaProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
+LLGLSLShader			gDeferredGIProgram;
+LLGLSLShader			gDeferredGIFinalProgram;
+LLGLSLShader			gDeferredPostGIProgram;
+LLGLSLShader			gDeferredPostProgram;
+
+LLGLSLShader			gLuminanceGatherProgram;
+
 
 //current avatar shader parameter pointer
 GLint				gAvatarMatrixParam;
@@ -151,6 +161,11 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredMultiLightProgram);
 	mShaderList.push_back(&gDeferredAlphaProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
+	mShaderList.push_back(&gDeferredPostGIProgram);
+	mShaderList.push_back(&gDeferredEdgeProgram);
+	mShaderList.push_back(&gDeferredPostProgram);
+	mShaderList.push_back(&gDeferredGIProgram);
+	mShaderList.push_back(&gDeferredGIFinalProgram);
 	mShaderList.push_back(&gDeferredWaterProgram);
 	mShaderList.push_back(&gDeferredAvatarAlphaProgram);
 }
@@ -220,13 +235,35 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void)
 		mReservedUniforms.push_back("shadowMap1");
 		mReservedUniforms.push_back("shadowMap2");
 		mReservedUniforms.push_back("shadowMap3");
+		mReservedUniforms.push_back("shadowMap4");
+		mReservedUniforms.push_back("shadowMap5");
+
 		mReservedUniforms.push_back("normalMap");
 		mReservedUniforms.push_back("positionMap");
 		mReservedUniforms.push_back("diffuseRect");
 		mReservedUniforms.push_back("specularRect");
 		mReservedUniforms.push_back("noiseMap");
+		mReservedUniforms.push_back("lightFunc");
 		mReservedUniforms.push_back("lightMap");
-			
+		mReservedUniforms.push_back("luminanceMap");
+		mReservedUniforms.push_back("giLightMap");
+		mReservedUniforms.push_back("giMip");
+		mReservedUniforms.push_back("edgeMap");
+		mReservedUniforms.push_back("bloomMap");
+		mReservedUniforms.push_back("sunLightMap");
+		mReservedUniforms.push_back("localLightMap");
+		mReservedUniforms.push_back("projectionMap");
+		mReservedUniforms.push_back("diffuseGIMap");
+		mReservedUniforms.push_back("specularGIMap");
+		mReservedUniforms.push_back("normalGIMap");
+		mReservedUniforms.push_back("minpGIMap");
+		mReservedUniforms.push_back("maxpGIMap");
+		mReservedUniforms.push_back("depthGIMap");
+		mReservedUniforms.push_back("lastDiffuseGIMap");
+		mReservedUniforms.push_back("lastNormalGIMap");
+		mReservedUniforms.push_back("lastMinpGIMap");
+		mReservedUniforms.push_back("lastMaxpGIMap");
+					
 		mWLUniforms.push_back("camPosLocal");
 
 		mTerrainUniforms.reserve(5);
@@ -340,7 +377,21 @@ void LLViewerShaderMgr::setShaders()
 
 		if (LLPipeline::sRenderDeferred)
 		{
-			deferred_class = 1;
+			if (gSavedSettings.getBOOL("RenderDeferredShadow"))
+			{
+				if (gSavedSettings.getBOOL("RenderDeferredGI"))
+				{ //shadows + gi
+					deferred_class = 3;
+				}
+				else
+				{ //shadows
+					deferred_class = 2;
+				}
+			}
+			else
+			{ //no shadows
+				deferred_class = 1;
+			}
 		}
 
 		if(!gSavedSettings.getBOOL("EnableRippleWater"))
@@ -814,6 +865,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredTerrainProgram.unload();
 		gDeferredLightProgram.unload();
 		gDeferredMultiLightProgram.unload();
+		gDeferredSpotLightProgram.unload();
+		gDeferredMultiSpotLightProgram.unload();
 		gDeferredSunProgram.unload();
 		gDeferredBlurLightProgram.unload();
 		gDeferredSoftenProgram.unload();
@@ -823,6 +876,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarAlphaProgram.unload();
 		gDeferredAlphaProgram.unload();
 		gDeferredFullbrightProgram.unload();
+		gDeferredPostGIProgram.unload();		
+		gDeferredEdgeProgram.unload();		
+		gDeferredPostProgram.unload();		
+		gLuminanceGatherProgram.unload();
+		gDeferredGIProgram.unload();
+		gDeferredGIFinalProgram.unload();
 		gDeferredWaterProgram.unload();
 		return FALSE;
 	}
@@ -891,6 +950,26 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredMultiLightProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredSpotLightProgram.mName = "Deferred SpotLight Shader";
+		gDeferredSpotLightProgram.mShaderFiles.clear();
+		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSpotLightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredMultiSpotLightProgram.mName = "Deferred MultiSpotLight Shader";
+		gDeferredMultiSpotLightProgram.mShaderFiles.clear();
+		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredSunProgram.mName = "Deferred Sun Shader";
@@ -1022,6 +1101,72 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredAvatarAlphaProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
 	}
 
+	if (mVertexShaderLevel[SHADER_DEFERRED] > 1)
+	{
+		if (success)
+		{
+			gDeferredEdgeProgram.mName = "Deferred Edge Shader";
+			gDeferredEdgeProgram.mShaderFiles.clear();
+			gDeferredEdgeProgram.mShaderFiles.push_back(make_pair("deferred/edgeV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredEdgeProgram.mShaderFiles.push_back(make_pair("deferred/edgeF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredEdgeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			success = gDeferredEdgeProgram.createShader(NULL, NULL);
+		}
+	}
+
+	if (mVertexShaderLevel[SHADER_DEFERRED] > 2)
+	{
+		if (success)
+		{
+			gDeferredPostProgram.mName = "Deferred Post Shader";
+			gDeferredPostProgram.mShaderFiles.clear();
+			gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredPostProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredPostProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			success = gDeferredPostProgram.createShader(NULL, NULL);
+		}
+
+		if (success)
+		{
+			gDeferredPostGIProgram.mName = "Deferred Post GI Shader";
+			gDeferredPostGIProgram.mShaderFiles.clear();
+			gDeferredPostGIProgram.mShaderFiles.push_back(make_pair("deferred/postgiV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredPostGIProgram.mShaderFiles.push_back(make_pair("deferred/postgiF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredPostGIProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			success = gDeferredPostGIProgram.createShader(NULL, NULL);
+		}
+
+		if (success)
+		{
+			gDeferredGIProgram.mName = "Deferred GI Shader";
+			gDeferredGIProgram.mShaderFiles.clear();
+			gDeferredGIProgram.mShaderFiles.push_back(make_pair("deferred/giV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredGIProgram.mShaderFiles.push_back(make_pair("deferred/giF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredGIProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			success = gDeferredGIProgram.createShader(NULL, NULL);
+		}
+
+		if (success)
+		{
+			gDeferredGIFinalProgram.mName = "Deferred GI Final Shader";
+			gDeferredGIFinalProgram.mShaderFiles.clear();
+			gDeferredGIFinalProgram.mShaderFiles.push_back(make_pair("deferred/giFinalV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredGIFinalProgram.mShaderFiles.push_back(make_pair("deferred/giFinalF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredGIFinalProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			success = gDeferredGIFinalProgram.createShader(NULL, NULL);
+		}
+
+		if (success)
+		{
+			gLuminanceGatherProgram.mName = "Luminance Gather Shader";
+			gLuminanceGatherProgram.mShaderFiles.clear();
+			gLuminanceGatherProgram.mShaderFiles.push_back(make_pair("deferred/luminanceV.glsl", GL_VERTEX_SHADER_ARB));
+			gLuminanceGatherProgram.mShaderFiles.push_back(make_pair("deferred/luminanceF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gLuminanceGatherProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			success = gLuminanceGatherProgram.createShader(NULL, NULL);
+		}
+	}
+
 	return success;
 }
 
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index a743966d93c..ac2b4624e02 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -116,12 +116,33 @@ class LLViewerShaderMgr: public LLShaderMgr
 		DEFERRED_SHADOW1,
 		DEFERRED_SHADOW2,
 		DEFERRED_SHADOW3,
+		DEFERRED_SHADOW4,
+		DEFERRED_SHADOW5,
 		DEFERRED_NORMAL,
 		DEFERRED_POSITION,
 		DEFERRED_DIFFUSE,
 		DEFERRED_SPECULAR,
 		DEFERRED_NOISE,
+		DEFERRED_LIGHTFUNC,
 		DEFERRED_LIGHT,
+		DEFERRED_LUMINANCE,
+		DEFERRED_GI_LIGHT,
+		DEFERRED_GI_MIP,
+		DEFERRED_EDGE,
+		DEFERRED_BLOOM,
+		DEFERRED_SUN_LIGHT,
+		DEFERRED_LOCAL_LIGHT,
+		DEFERRED_PROJECTION,
+		DEFERRED_GI_DIFFUSE,
+		DEFERRED_GI_SPECULAR,
+		DEFERRED_GI_NORMAL,
+		DEFERRED_GI_MIN_POS,
+		DEFERRED_GI_MAX_POS,
+		DEFERRED_GI_DEPTH,
+		DEFERRED_GI_LAST_DIFFUSE,
+		DEFERRED_GI_LAST_NORMAL,
+		DEFERRED_GI_LAST_MIN_POS,
+		DEFERRED_GI_LAST_MAX_POS,
 		END_RESERVED_UNIFORMS
 	} eGLSLReservedUniforms;
 
@@ -319,6 +340,7 @@ extern LLGLSLShader			gPostNightVisionProgram;
 
 // Deferred rendering shaders
 extern LLGLSLShader			gDeferredImpostorProgram;
+extern LLGLSLShader			gDeferredEdgeProgram;
 extern LLGLSLShader			gDeferredWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
 extern LLGLSLShader			gDeferredBumpProgram;
@@ -326,16 +348,24 @@ extern LLGLSLShader			gDeferredTerrainProgram;
 extern LLGLSLShader			gDeferredTreeProgram;
 extern LLGLSLShader			gDeferredLightProgram;
 extern LLGLSLShader			gDeferredMultiLightProgram;
+extern LLGLSLShader			gDeferredSpotLightProgram;
+extern LLGLSLShader			gDeferredMultiSpotLightProgram;
 extern LLGLSLShader			gDeferredSunProgram;
+extern LLGLSLShader			gDeferredGIProgram;
+extern LLGLSLShader			gDeferredGIFinalProgram;
 extern LLGLSLShader			gDeferredBlurLightProgram;
 extern LLGLSLShader			gDeferredAvatarProgram;
 extern LLGLSLShader			gDeferredSoftenProgram;
 extern LLGLSLShader			gDeferredShadowProgram;
+extern LLGLSLShader			gDeferredPostGIProgram;
+extern LLGLSLShader			gDeferredPostProgram;
 extern LLGLSLShader			gDeferredAvatarShadowProgram;
 extern LLGLSLShader			gDeferredAlphaProgram;
 extern LLGLSLShader			gDeferredFullbrightProgram;
 extern LLGLSLShader			gDeferredAvatarAlphaProgram;
 
+extern LLGLSLShader			gLuminanceGatherProgram;
+
 //current avatar shader parameter pointer
 extern GLint				gAvatarMatrixParam;
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index c479a232c5e..e3d657068f4 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -60,6 +60,8 @@
 #include "llviewercontrol.h"
 #include "pipeline.h"
 #include "llappviewer.h"
+#include "lltextureatlas.h"
+#include "lltextureatlasmanager.h"
 ///////////////////////////////////////////////////////////////////////////////
 
 // statics
@@ -83,6 +85,7 @@ S32 LLViewerTexture::sMaxBoundTextureMemInMegaBytes = 0;
 S32 LLViewerTexture::sMaxTotalTextureMemInMegaBytes = 0;
 S32 LLViewerTexture::sMaxDesiredTextureMemInBytes = 0 ;
 BOOL LLViewerTexture::sDontLoadVolumeTextures = FALSE;
+BOOL LLViewerTexture::sUseTextureAtlas        = FALSE ;
 
 const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve image quality by
 const F32 desired_discard_bias_max = 1.5f; // max number of levels to reduce image quality by
@@ -368,6 +371,7 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
 		}
 	}
 	sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max);
+	LLViewerTexture::sUseTextureAtlas = gSavedSettings.getBOOL("EnableTextureAtlas") ;
 }
 
 //end of static functions
@@ -667,7 +671,7 @@ LLGLuint LLViewerTexture::getTexName() const
 	return mGLTexturep->getTexName() ; 
 }
 
-BOOL LLViewerTexture::hasValidGLTexture() const 
+BOOL LLViewerTexture::hasGLTexture() const 
 {
 	if(mGLTexturep.notNull())
 	{
@@ -676,11 +680,6 @@ BOOL LLViewerTexture::hasValidGLTexture() const
 	return FALSE ;
 }
 
-BOOL LLViewerTexture::hasGLTexture() const 
-{
-	return mGLTexturep.notNull() ;
-}
-
 BOOL LLViewerTexture::getBoundRecently() const
 {
 	if(mGLTexturep.notNull())
@@ -779,6 +778,34 @@ BOOL LLViewerTexture::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool
 	return mGLTexturep->readBackRaw(discard_level, imageraw, compressed_ok) ;
 }
 
+U32 LLViewerTexture::getTexelsInAtlas() const
+{
+	llassert_always(mGLTexturep.notNull()) ;
+
+	return mGLTexturep->getTexelsInAtlas() ;
+}
+
+U32 LLViewerTexture::getTexelsInGLTexture() const
+{
+	llassert_always(mGLTexturep.notNull()) ;
+
+	return mGLTexturep->getTexelsInGLTexture() ;
+}
+
+BOOL LLViewerTexture::isGLTextureCreated() const
+{
+	llassert_always(mGLTexturep.notNull()) ;
+
+	return mGLTexturep->isGLTextureCreated() ;
+}
+
+S32  LLViewerTexture::getDiscardLevelInAtlas() const
+{
+	llassert_always(mGLTexturep.notNull()) ;
+
+	return mGLTexturep->getDiscardLevelInAtlas() ;
+}
+
 void LLViewerTexture::destroyGLTexture() 
 {
 	if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture())
@@ -796,6 +823,7 @@ void LLViewerTexture::updateBindStatsForTester()
 		LLViewerTextureManager::sTesterp->updateTextureBindingStats(this) ;
 	}
 }
+
 //----------------------------------------------------------------------------------------------
 //end of LLViewerTexture
 //----------------------------------------------------------------------------------------------
@@ -1044,7 +1072,11 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
 			return FALSE;
 		}
 		
-		res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename);
+		if(!(res = insertToAtlas()))
+		{
+			res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename);
+			resetFaceAtlas() ;
+		}
 		setActive() ;
 	}
 
@@ -1741,6 +1773,197 @@ void LLViewerFetchedTexture::destroyRawImage()
 	mIsRawImageValid = FALSE;
 	mRawDiscardLevel = INVALID_DISCARD_LEVEL;
 }
+
+//----------------------------------------------------------------------------------------------
+//atlasing
+//----------------------------------------------------------------------------------------------
+void LLViewerFetchedTexture::resetFaceAtlas()
+{
+	//Nothing should be done here.
+}
+
+//invalidate all atlas slots for this image.
+void LLViewerFetchedTexture::invalidateAtlas(BOOL rebuild_geom)
+{
+	for(ll_face_list_t::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter)
+	{
+		if(*iter)
+		{
+			LLFace* facep = (LLFace*)*iter ;
+			facep->removeAtlas() ;
+			if(rebuild_geom && facep->getDrawable() && facep->getDrawable()->getSpatialGroup())
+			{
+				facep->getDrawable()->getSpatialGroup()->setState(LLSpatialGroup::GEOM_DIRTY);
+			}
+		}
+	}
+}
+
+BOOL LLViewerFetchedTexture::insertToAtlas()
+{
+	if(!LLViewerTexture::sUseTextureAtlas)
+	{
+		return FALSE ;
+	}
+	if(mFaceList.size() < 1)
+	{
+		return FALSE ;
+	}						
+	if(mGLTexturep->getDiscardLevelInAtlas() > 0 && mRawDiscardLevel >= mGLTexturep->getDiscardLevelInAtlas())
+	{
+		return FALSE ;
+	}
+	if(!LLTextureAtlasManager::getInstance()->canAddToAtlas(mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents(), mGLTexturep->getTexTarget()))
+	{
+		return FALSE ;
+	}
+
+	BOOL ret = TRUE ;//if ret is set to false, will generate a gl texture for this image.
+	S32 raw_w = mRawImage->getWidth() ;
+	S32 raw_h = mRawImage->getHeight() ;
+	F32 xscale = 1.0f, yscale = 1.0f ;
+	LLPointer<LLTextureAtlasSlot> slot_infop;
+	LLTextureAtlasSlot* cur_slotp ;//no need to be smart pointer.
+	LLSpatialGroup* groupp ;
+	LLFace* facep;
+
+	//if the atlas slot pointers for some faces are null, process them later.
+	ll_face_list_t waiting_list ;
+
+	for(ll_face_list_t::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter)
+	{
+		if(*iter)
+		{
+			facep = (LLFace*)*iter ;
+			
+			//face can not use atlas.
+			if(!facep->canUseAtlas())
+			{
+				if(facep->getAtlasInfo())
+				{
+					facep->removeAtlas() ;	
+				}
+				ret = FALSE ;
+				continue ;
+			}
+
+			//the atlas slot is updated
+			slot_infop = facep->getAtlasInfo() ;
+			groupp = facep->getDrawable()->getSpatialGroup() ;	
+
+			if(slot_infop) 
+			{
+				if(slot_infop->getSpatialGroup() != groupp)
+				{
+					if((cur_slotp = groupp->getCurUpdatingSlot(this))) //switch slot
+					{
+						facep->setAtlasInfo(cur_slotp) ;
+						facep->setAtlasInUse(TRUE) ;
+						continue ;
+					}
+					else //do not forget to update slot_infop->getSpatialGroup().
+					{
+						LLSpatialGroup* gp = slot_infop->getSpatialGroup() ;
+						gp->setCurUpdatingTime(gFrameCount) ;
+						gp->setCurUpdatingTexture(this) ;
+						gp->setCurUpdatingSlot(slot_infop) ;
+					}
+				}
+				else //same group
+				{
+					if(gFrameCount && slot_infop->getUpdatedTime() == gFrameCount)//slot is just updated
+					{
+						facep->setAtlasInUse(TRUE) ;
+						continue ;
+					}
+				}
+			}				
+			else
+			{
+				//if the slot is null, wait to process them later.
+				waiting_list.push_back(facep) ;
+				continue ;
+			}
+						
+			//----------
+			//insert to atlas
+			if(!slot_infop->getAtlas()->insertSubTexture(mGLTexturep, mRawDiscardLevel, mRawImage, slot_infop->getSlotCol(), slot_infop->getSlotRow()))			
+			{
+				
+				//the texture does not qualify to add to atlas, do not bother to try for other faces.
+				//invalidateAtlas();
+				return FALSE ;
+			}
+			
+			//update texture scale		
+			slot_infop->getAtlas()->getTexCoordScale(raw_w, raw_h, xscale, yscale) ;
+			slot_infop->setTexCoordScale(xscale, yscale) ;
+			slot_infop->setValid() ;
+			slot_infop->setUpdatedTime(gFrameCount) ;
+			
+			//update spatial group atlas info
+			groupp->setCurUpdatingTime(gFrameCount) ;
+			groupp->setCurUpdatingTexture(this) ;
+			groupp->setCurUpdatingSlot(slot_infop) ;
+
+			//make the face to switch to the atlas.
+			facep->setAtlasInUse(TRUE) ;
+		}
+	}
+
+	//process the waiting_list
+	for(ll_face_list_t::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter)
+	{
+		facep = (LLFace*)*iter ;	
+		groupp = facep->getDrawable()->getSpatialGroup() ;
+
+		//check if this texture already inserted to atlas for this group
+		if((cur_slotp = groupp->getCurUpdatingSlot(this)))
+		{
+			facep->setAtlasInfo(cur_slotp) ;
+			facep->setAtlasInUse(TRUE) ;		
+			continue ;
+		}
+
+		//need to reserve a slot from atlas
+		slot_infop = LLTextureAtlasManager::getInstance()->reserveAtlasSlot(llmax(mFullWidth, mFullHeight), getComponents(), groupp, this) ;	
+
+		facep->setAtlasInfo(slot_infop) ;
+		
+		groupp->setCurUpdatingTime(gFrameCount) ;
+		groupp->setCurUpdatingTexture(this) ;
+		groupp->setCurUpdatingSlot(slot_infop) ;
+
+		//slot allocation failed.
+		if(!slot_infop || !slot_infop->getAtlas())
+		{			
+			ret = FALSE ;
+			facep->setAtlasInUse(FALSE) ;
+			continue ;
+		}
+				
+		//insert to atlas
+		if(!slot_infop->getAtlas()->insertSubTexture(mGLTexturep, mRawDiscardLevel, mRawImage, slot_infop->getSlotCol(), slot_infop->getSlotRow()))
+		{
+			//the texture does not qualify to add to atlas, do not bother to try for other faces.
+			ret = FALSE ;
+			//invalidateAtlas();
+			break ; 
+		}
+		
+		//update texture scale		
+		slot_infop->getAtlas()->getTexCoordScale(raw_w, raw_h, xscale, yscale) ;
+		slot_infop->setTexCoordScale(xscale, yscale) ;
+		slot_infop->setValid() ;
+		slot_infop->setUpdatedTime(gFrameCount) ;
+
+		//make the face to switch to the atlas.
+		facep->setAtlasInUse(TRUE) ;
+	}
+	
+	return ret ;
+}
+
 //----------------------------------------------------------------------------------------------
 //end of LLViewerFetchedTexture
 //----------------------------------------------------------------------------------------------
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 142c212435a..0be1bf81de3 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -98,6 +98,7 @@ class LLViewerTexture : public LLTexture
 		DYNAMIC_TEXTURE,
 		FETCHED_TEXTURE,
 		LOD_TEXTURE,
+		ATLAS_TEXTURE,
 		INVALID_TEXTURE_TYPE
 	};
 
@@ -171,7 +172,6 @@ class LLViewerTexture : public LLTexture
 	/*virtual*/S32	       getHeight(S32 discard_level = -1) const;
 	
 	BOOL       hasGLTexture() const ;
-	BOOL       hasValidGLTexture() const ;
 	LLGLuint   getTexName() const ;		
 	BOOL       createGLTexture() ;
 	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0);
@@ -197,6 +197,11 @@ class LLViewerTexture : public LLTexture
 	BOOL       getMissed() const ;
 	BOOL       isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ;
 	BOOL       readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
+
+	U32        getTexelsInAtlas() const ;
+	U32        getTexelsInGLTexture() const ;
+	BOOL       isGLTextureCreated() const ;
+	S32        getDiscardLevelInAtlas() const ;
 	//---------------------------------------------------------------------------------------------
 	//end of functions to access LLImageGL
 	//---------------------------------------------------------------------------------------------
@@ -263,6 +268,7 @@ class LLViewerTexture : public LLTexture
 	static S32 sMaxTotalTextureMemInMegaBytes;
 	static S32 sMaxDesiredTextureMemInBytes ;
 	static BOOL sDontLoadVolumeTextures;
+	static BOOL sUseTextureAtlas ;
 
 	static LLPointer<LLViewerTexture> sNullImagep; // Null texture for non-textured objects.
 };
@@ -388,6 +394,11 @@ class LLViewerFetchedTexture : public LLViewerTexture
 
 	F32 calcDecodePriorityForUnknownTexture(F32 pixel_priority) ;
 
+	//for atlas
+	void resetFaceAtlas() ;
+	void invalidateAtlas(BOOL rebuild_geom) ;
+	BOOL insertToAtlas() ;
+
 private:
 	BOOL  mFullyLoaded;
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index f7fbe96aa7e..fd6ffbe07a2 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1898,6 +1898,11 @@ void LLViewerWindow::draw()
 
 	//S32 screen_x, screen_y;
 
+	if (!gSavedSettings.getBOOL("RenderUIBuffer"))
+	{
+		LLUI::sDirtyRect = this->getWindowRect();
+	}
+
 	// HACK for timecode debugging
 	if (gSavedSettings.getBOOL("DisplayTimecode"))
 	{
@@ -3874,7 +3879,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 	{
 		if(image_width > window_width || image_height > window_height) //need to enlarge the scene
 		{
-			if (gGLManager.mHasFramebufferObject && !show_ui)
+			if (!LLPipeline::sRenderDeferred && gGLManager.mHasFramebufferObject && !show_ui)
 			{
 				GLint max_size = 0;
 				glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &max_size);
@@ -3962,9 +3967,17 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 			else
 			{
 				const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
-				display(do_rebuild, scale_factor, subfield, TRUE);
-				// Required for showing the GUI in snapshots?  See DEV-16350 for details. JC
-				render_ui(scale_factor, subfield);
+
+				if (LLPipeline::sRenderDeferred)
+				{
+					display(do_rebuild, scale_factor, subfield, FALSE);
+				}
+				else
+				{
+					display(do_rebuild, scale_factor, subfield, TRUE);
+					// Required for showing the GUI in snapshots?  See DEV-16350 for details. JC
+					render_ui(scale_factor, subfield);
+				}
 			}
 
 			S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index f26ba6f46ef..d124cbcdced 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -448,6 +448,10 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
 		}
 	}
 
+	if (!texturep->hasGLTexture())
+	{
+		texturep->createGLTexture(0, raw);
+	}
 	texturep->setSubImage(raw, tex_x_begin, tex_y_begin, tex_x_end - tex_x_begin, tex_y_end - tex_y_begin);
 	LLSurface::sTextureUpdateTime += gen_timer.getElapsedTimeF32();
 	LLSurface::sTexelsUpdated += (tex_x_end - tex_x_begin) * (tex_y_end - tex_y_begin);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 018cce4b494..1d9ca12af82 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -680,6 +680,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	}
 
 	mDirtyMesh = TRUE;	// Dirty geometry, need to regenerate.
+	mMeshTexturesDirty = FALSE;
 	mShadow0Facep = NULL;
 	mShadow1Facep = NULL;
 	mHeadp = NULL;
@@ -718,8 +719,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mRippleTimeLast = 0.f;
 
 	mShadowImagep = LLViewerTextureManager::getFetchedTextureFromFile("foot_shadow.j2c");
-	gGL.getTexUnit(0)->bind(mShadowImagep);
-	mShadowImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
+	
+	// GL NOT ACTIVE HERE
+	//gGL.getTexUnit(0)->bind(mShadowImagep.get());
+	//mShadowImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
 	
 	mInAir = FALSE;
 
@@ -1612,6 +1615,11 @@ BOOL LLVOAvatar::buildSkeleton(const LLVOAvatarSkeletonInfo *info)
 	return TRUE;
 }
 
+LLVOAvatar* LLVOAvatar::asAvatar()
+{
+	return this;
+}
+
 //-----------------------------------------------------------------------------
 // LLVOAvatar::startDefaultMotions()
 //-----------------------------------------------------------------------------
@@ -2176,10 +2184,14 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	idleUpdateVoiceVisualizer( voice_enabled );
 	idleUpdateMisc( detailed_update );
 	idleUpdateAppearanceAnimation();
-	idleUpdateLipSync( voice_enabled );
-	idleUpdateLoadingEffect();
-	idleUpdateBelowWater();	// wind effect uses this
-	idleUpdateWindEffect();
+	if (detailed_update)
+	{
+		idleUpdateLipSync( voice_enabled );
+		idleUpdateLoadingEffect();
+		idleUpdateBelowWater();	// wind effect uses this
+		idleUpdateWindEffect();
+	}
+	
 	idleUpdateNameTag( root_pos_last );
 	idleUpdateRenderCost();
 	idleUpdateTractorBeam();
@@ -3032,7 +3044,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 
 	if (!visible)
 	{
-		updateMotions(LLCharacter::HIDDEN_UPDATE);
+		//updateMotions(LLCharacter::HIDDEN_UPDATE);
 		return FALSE;
 	}
 
@@ -3702,7 +3714,8 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 
 	if (pass == AVATAR_RENDER_PASS_SINGLE)
 	{
-		const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha; // Don't alpha mask if "Highlight Transparent" checked
+		const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha // Don't alpha mask if "Highlight Transparent" checked
+								&& !LLDrawPoolAvatar::sSkipTransparent;
 
 		LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
 		
@@ -3817,20 +3830,8 @@ U32 LLVOAvatar::renderRigid()
 
 	if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy)
 	{
-		// If the meshes need to be drawn, enable alpha masking but not blending
-		bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha;
-
-		LLGLState test(GL_ALPHA_TEST, should_alpha_mask);
-		
-		if (should_alpha_mask)
-		{
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f);
-		}
-
 		num_indices += mMeshLOD[MESH_ID_EYEBALL_LEFT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
 		num_indices += mMeshLOD[MESH_ID_EYEBALL_RIGHT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
-
-		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	}
 	
 	return num_indices;
@@ -3875,7 +3876,7 @@ U32 LLVOAvatar::renderFootShadows()
 	LLGLDepthTest test(GL_TRUE, GL_FALSE);
 	//render foot shadows
 	LLGLEnable blend(GL_BLEND);
-	gGL.getTexUnit(0)->bind(mShadowImagep);
+	gGL.getTexUnit(0)->bind(mShadowImagep.get());
 	glColor4fv(mShadow0Facep->getRenderColor().mV);
 	mShadow0Facep->renderIndexed(foot_mask);
 	glColor4fv(mShadow1Facep->getRenderColor().mV);
@@ -3884,7 +3885,7 @@ U32 LLVOAvatar::renderFootShadows()
 	return num_indices;
 }
 
-U32 LLVOAvatar::renderImpostor(LLColor4U color)
+U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
 {
 	if (!mImpostor.isComplete())
 	{
@@ -3904,7 +3905,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color)
 	gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f);
 
 	gGL.color4ubv(color.mV);
-	gGL.getTexUnit(0)->bind(&mImpostor);
+	gGL.getTexUnit(diffuse_channel)->bind(&mImpostor);
 	gGL.begin(LLRender::QUADS);
 	gGL.texCoord2f(0,0);
 	gGL.vertex3fv((pos+left-up).mV);
@@ -3942,6 +3943,7 @@ void LLVOAvatar::updateTextures(LLAgent &agent)
 	}
 
 	std::vector<BOOL> layer_baked;
+	// GL NOT ACTIVE HERE - *TODO
 	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
 	{
 		layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex));
@@ -5171,6 +5173,15 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline)
 }
 
 
+void LLVOAvatar::updateGL()
+{
+	if (mMeshTexturesDirty)
+	{
+		updateMeshTextures();
+		mMeshTexturesDirty = FALSE;
+	}
+}
+
 //-----------------------------------------------------------------------------
 // updateGeometry()
 //-----------------------------------------------------------------------------
@@ -5222,7 +5233,7 @@ void LLVOAvatar::updateShadowFaces()
 	sprite.setSize(0.4f + cos_elev * 0.8f, 0.3f);
 	LLVector3 sun_vec = gSky.mVOSkyp ? gSky.mVOSkyp->getToSun() : LLVector3(0.f, 0.f, 0.f);
 
-	if (mShadowImagep->hasValidGLTexture())
+	if (mShadowImagep->hasGLTexture())
 	{
 		LLVector3 normal;
 		LLVector3d shadow_pos;
@@ -6354,7 +6365,8 @@ void LLVOAvatar::onFirstTEMessageReceived()
 			}
 		}
 
-		updateMeshTextures();
+		mMeshTexturesDirty = TRUE;
+		gPipeline.markGLRebuild(this);
 	}
 }
 
@@ -6417,6 +6429,8 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 	}
 
 	setCompositeUpdatesEnabled( FALSE );
+	mMeshTexturesDirty = TRUE;
+	gPipeline.markGLRebuild(this);
 
 	// ! BACKWARDS COMPATIBILITY !
 	// Non-self avatars will no longer have component textures
@@ -6425,8 +6439,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 		releaseComponentTextures();
 	}
 	
-	updateMeshTextures(); // enables updates for laysets without baked textures.
-
+	
 	// parse visual params
 	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
 	if( num_blocks > 1 )
@@ -7436,6 +7449,11 @@ void LLVOAvatar::updateFreezeCounter(S32 counter)
 
 BOOL LLVOAvatar::updateLOD()
 {
+	if (isImpostor())
+	{
+		return TRUE;
+	}
+
 	BOOL res = updateJointLODs();
 
 	LLFace* facep = mDrawable->getFace(0);
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 4dc70511cea..ef5358198da 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -114,6 +114,8 @@ class LLVOAvatar :
 	// LLViewerObject interface and related
 	//--------------------------------------------------------------------
 public:
+	virtual void			updateGL();
+	virtual	LLVOAvatar*		asAvatar();
 	virtual U32    	 	 	processUpdateMessage(LLMessageSystem *mesgsys,
 													 void **user_data,
 													 U32 block_num,
@@ -329,7 +331,7 @@ class LLVOAvatar :
 
 public:
 	U32 		renderFootShadows();
-	U32 		renderImpostor(LLColor4U color = LLColor4U(255,255,255,255));
+	U32 		renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
 	U32 		renderRigid();
 	U32 		renderSkinned(EAvatarRenderPass pass);
 	U32 		renderTransparent(BOOL first_pass);
@@ -560,6 +562,7 @@ class LLVOAvatar :
 	/*virtual*/ void restoreMeshData();
 private:
 	BOOL 			mDirtyMesh;
+	BOOL			mMeshTexturesDirty;
 
 	typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
 	polymesh_map_t 									mMeshes;
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index a7b5b608429..dfc82ea8d5a 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1331,7 +1331,7 @@ void LLVOAvatarSelf::getLocalTextureByteCount(S32* gl_bytes) const
 				{
 					S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents();
 					
-					if (image_gl->hasValidGLTexture())
+					if (image_gl->hasGLTexture())
 					{
 						*gl_bytes += bytes;
 					}
@@ -1539,7 +1539,7 @@ BOOL LLVOAvatarSelf::updateIsFullyLoaded()
 
 			// Check for the case that texture is defined but not sufficiently loaded to display anything.
 			LLViewerTexture* baked_img = getImage( texture_data.mTextureIndex );
-			if (!baked_img || !baked_img->hasValidGLTexture())
+			if (!baked_img || !baked_img->hasGLTexture())
 			{
 				loading = TRUE;
 			}
diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp
index 130e1fd749a..8d3c8b6f1a9 100644
--- a/indra/newview/llvoclouds.cpp
+++ b/indra/newview/llvoclouds.cpp
@@ -125,7 +125,10 @@ BOOL LLVOClouds::updateGeometry(LLDrawable *drawable)
 		return TRUE;
 	}
 	
-	dirtySpatialGroup();
+	if (drawable->isVisible())
+	{
+		dirtySpatialGroup(TRUE);
+	}
 
 	LLFace *facep;
 	
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 38c9ce28c46..7585842623b 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -155,6 +155,11 @@ BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
 		group = drawable->getSpatialGroup();
 	}
 
+	if (group && group->isVisible())
+	{
+		dirtySpatialGroup(TRUE);
+	}
+
 	if (!num_parts)
 	{
 		if (group && drawable->getNumFaces())
@@ -353,12 +358,11 @@ U32 LLVOPartGroup::getPartitionType() const
 }
 
 LLParticlePartition::LLParticlePartition()
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB)
 {
 	mRenderPass = LLRenderPass::PASS_ALPHA;
 	mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
 	mPartitionType = LLViewerRegion::PARTITION_PARTICLE;
-	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 	mSlopRatio = 0.f;
 	mLODPeriod = 1;
 }
@@ -485,7 +489,9 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 			U32 end = start + facep->getGeomCount()-1;
 			U32 offset = facep->getIndicesStart();
 			U32 count = facep->getIndicesCount();
-			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), buffer, fullbright); 
+			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), 
+				//facep->getTexture(),
+				buffer, fullbright); 
 			info->mExtents[0] = group->mObjectExtents[0];
 			info->mExtents[1] = group->mObjectExtents[1];
 			info->mVSize = vsize;
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 157d719fcca..164f0f0cade 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -178,11 +178,19 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline)
 
 static LLFastTimer::DeclareTimer FTM_UPDATE_TERRAIN("Update Terrain");
 
+void LLVOSurfacePatch::updateGL()
+{
+	if (mPatchp)
+	{
+		mPatchp->updateGL();
+	}
+}
+
 BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer ftm(FTM_UPDATE_TERRAIN);
 
-	dirtySpatialGroup();
+	dirtySpatialGroup(TRUE);
 	
 	S32 min_comp, max_comp, range;
 	min_comp = lltrunc(mPatchp->getMinComposition());
@@ -1014,12 +1022,10 @@ U32 LLVOSurfacePatch::getPartitionType() const
 }
 
 LLTerrainPartition::LLTerrainPartition()
-: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK)
+: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB)
 {
 	mOcclusionEnabled = FALSE;
-	mRenderByGroup = FALSE;
 	mInfiniteFarClip = TRUE;
-	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 	mDrawableType = LLPipeline::RENDER_TYPE_TERRAIN;
 	mPartitionType = LLViewerRegion::PARTITION_TERRAIN;
 }
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index 2dd86518992..aaf4d41fa1e 100644
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -64,6 +64,7 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 	virtual U32 getPartitionType() const;
 
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
+	/*virtual*/ void		updateGL();
 	/*virtual*/ BOOL        updateGeometry(LLDrawable *drawable);
 	/*virtual*/ BOOL		updateLOD();
 	/*virtual*/ void		updateFaceSize(S32 idx);
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 86d9f31d071..615ae13bc2c 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -312,10 +312,6 @@ U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys,
 	//  Load Species-Specific data 
 	//
 	mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-	if (mTreeImagep)
-	{
-		gGL.getTexUnit(0)->bind(mTreeImagep);
-	}
 	mBranchLength = sSpeciesTable[mSpecies]->mBranchLength;
 	mTrunkLength = sSpeciesTable[mSpecies]->mTrunkLength;
 	mLeafScale = sSpeciesTable[mSpecies]->mLeafScale;
@@ -1305,9 +1301,8 @@ U32 LLVOTree::getPartitionType() const
 }
 
 LLTreePartition::LLTreePartition()
-: LLSpatialPartition(0)
+: LLSpatialPartition(0, FALSE, 0)
 {
-	mRenderByGroup = FALSE;
 	mDrawableType = LLPipeline::RENDER_TYPE_TREE;
 	mPartitionType = LLViewerRegion::PARTITION_TREE;
 	mSlopRatio = 0.f;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 940accdd062..02173248088 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -69,8 +69,10 @@
 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
 const F32 FORCE_CULL_AREA = 8.f;
+const F32 MAX_LOD_DISTANCE = 24.f;
 const S32 MAX_SCULPT_REZ = 128;
 
+
 BOOL gAnimateTextures = TRUE;
 //extern BOOL gHideSelectedObjects;
 
@@ -97,6 +99,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 	mNumFaces = 0;
 	mLODChanged = FALSE;
 	mSculptChanged = FALSE;
+	mSpotLightPriority = 0.f;
 }
 
 LLVOVolume::~LLVOVolume()
@@ -320,11 +323,6 @@ void LLVOVolume::animateTextures()
 				te->getScale(&scale_s, &scale_t);
 			}
 
-			LLVector3 scale(scale_s, scale_t, 1.f);
-			LLVector3 trans(off_s+0.5f, off_t+0.5f, 0.f);
-			LLQuaternion quat;
-			quat.setQuat(rot, 0, 0, -1.f);
-		
 			if (!facep->mTextureMatrix)
 			{
 				facep->mTextureMatrix = new LLMatrix4();
@@ -332,7 +330,43 @@ void LLVOVolume::animateTextures()
 
 			LLMatrix4& tex_mat = *facep->mTextureMatrix;
 			tex_mat.setIdentity();
-			tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
+			LLVector3 trans ;
+
+			if(facep->isAtlasInUse())
+			{
+				//
+				//if use atlas for animated texture
+				//apply the following transform to the animation matrix.
+				//
+
+				F32 tcoord_xoffset = 0.f ;
+				F32 tcoord_yoffset = 0.f ;
+				F32 tcoord_xscale = 1.f ;
+				F32 tcoord_yscale = 1.f ;			
+				if(facep->isAtlasInUse())
+				{
+					const LLVector2* tmp = facep->getTexCoordOffset() ;
+					tcoord_xoffset = tmp->mV[0] ; 
+					tcoord_yoffset = tmp->mV[1] ;
+
+					tmp = facep->getTexCoordScale() ;
+					tcoord_xscale = tmp->mV[0] ; 
+					tcoord_yscale = tmp->mV[1] ;	
+				}
+				trans.set(LLVector3(tcoord_xoffset + tcoord_xscale * (off_s+0.5f), tcoord_yoffset + tcoord_yscale * (off_t+0.5f), 0.f));
+
+				tex_mat.translate(LLVector3(-(tcoord_xoffset + tcoord_xscale * 0.5f), -(tcoord_yoffset + tcoord_yscale * 0.5f), 0.f));
+			}
+			else	//non atlas
+			{
+				trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f));			
+				tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
+			}
+
+			LLVector3 scale(scale_s, scale_t, 1.f);			
+			LLQuaternion quat;
+			quat.setQuat(rot, 0, 0, -1.f);
+		
 			tex_mat.rotate(quat);				
 
 			LLMatrix4 mat;
@@ -541,6 +575,19 @@ void LLVOVolume::updateTextures()
 			}
 	}
 
+	if (getLightTextureID().notNull())
+	{
+		LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+		LLUUID id = params->getLightTexture();
+		mLightTexture = LLViewerTextureManager::getFetchedTexture(id);
+		if (mLightTexture.notNull())
+		{
+			F32 rad = getLightRadius();
+			mLightTexture->addTextureStats(gPipeline.calcPixelArea(getPositionAgent(), 
+																	LLVector3(rad,rad,rad),
+																	*LLViewerCamera::getInstance()));
+		}	
+	}
 
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
 	{
@@ -711,7 +758,17 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 			mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
 			if (mSculptTexture.notNull())
 			{
-				sculpt();
+				//ignore sculpt GL usage since bao fixed this in a separate branch
+				if (!gGLActive)
+				{
+					gGLActive = TRUE;
+					sculpt();
+					gGLActive = FALSE;
+				}
+				else
+				{
+					sculpt();
+				}
 				mSculptLevel = getVolume()->getSculptLevel();
 			}
 		}
@@ -836,12 +893,15 @@ BOOL LLVOVolume::calcLOD()
 	}
 
 	//update face texture sizes on lod calculation
-	updateTextures();
+	//if (mDrawable->isVisible())
+	//{
+	//	updateTextures();
+	//}
 
 	S32 cur_detail = 0;
 	
 	F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
-	F32 distance = mDrawable->mDistanceWRTCamera;
+	F32 distance = llmin(mDrawable->mDistanceWRTCamera, MAX_LOD_DISTANCE);
 	distance *= sDistanceFactor;
 			
 	F32 rampDist = LLVOVolume::sLODFactor * 2;
@@ -1452,6 +1512,41 @@ void LLVOVolume::updateTEData()
 
 //----------------------------------------------------------------------------
 
+void LLVOVolume::setLightTextureID(LLUUID id)
+{
+	if (id.notNull())
+	{
+		if (!hasLightTexture())
+		{
+			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, TRUE, true);
+		}
+		LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+		if (param_block && param_block->getLightTexture() != id)
+		{
+			param_block->setLightTexture(id);
+			parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true);
+		}
+	}
+	else
+	{
+		if (hasLightTexture())
+		{
+			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true);
+			mLightTexture = NULL;
+		}
+	}		
+}
+
+void LLVOVolume::setSpotLightParams(LLVector3 params)
+{
+	LLLightImageParams* param_block = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+	if (param_block && param_block->getParams() != params)
+	{
+		param_block->setParams(params);
+		parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true);
+	}
+}
+		
 void LLVOVolume::setIsLight(BOOL is_light)
 {
 	if (is_light != getIsLight())
@@ -1578,6 +1673,83 @@ LLColor3 LLVOVolume::getLightColor() const
 	}
 }
 
+LLUUID LLVOVolume::getLightTextureID() const
+{
+	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
+	{
+		const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+		if (param_block)
+		{
+			return param_block->getLightTexture();
+		}
+	}
+	
+	return LLUUID::null;
+}
+
+
+LLVector3 LLVOVolume::getSpotLightParams() const
+{
+	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
+	{
+		const LLLightImageParams *param_block = (const LLLightImageParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+		if (param_block)
+		{
+			return param_block->getParams();
+		}
+	}
+	
+	return LLVector3();
+}
+
+F32 LLVOVolume::getSpotLightPriority() const
+{
+	return mSpotLightPriority;
+}
+
+void LLVOVolume::updateSpotLightPriority()
+{
+	LLVector3 pos = mDrawable->getPositionAgent();
+	LLVector3 at(0,0,-1);
+	at *= getRenderRotation();
+
+	F32 r = getLightRadius()*0.5f;
+
+	pos += at * r;
+
+	at = LLViewerCamera::getInstance()->getAtAxis();
+
+	pos -= at * r;
+	
+	mSpotLightPriority = gPipeline.calcPixelArea(pos, LLVector3(r,r,r), *LLViewerCamera::getInstance());
+
+	if (mLightTexture.notNull())
+	{
+		mLightTexture->addTextureStats(mSpotLightPriority);
+		mLightTexture->setBoostLevel(LLViewerTexture::BOOST_CLOUDS);
+	}
+}
+
+
+LLViewerTexture* LLVOVolume::getLightTexture()
+{
+	LLUUID id = getLightTextureID();
+
+	if (id.notNull())
+	{
+		if (mLightTexture.isNull() || id != mLightTexture->getID())
+		{
+			mLightTexture = LLViewerTextureManager::getFetchedTexture(id);
+		}
+	}
+	else
+	{
+		mLightTexture = NULL;
+	}
+
+	return mLightTexture;
+}
+
 F32 LLVOVolume::getLightIntensity() const
 {
 	const LLLightParams *param_block = (const LLLightParams *)getParameterEntry(LLNetworkData::PARAMS_LIGHT);
@@ -1669,6 +1841,16 @@ BOOL LLVOVolume::isSculpted() const
 	return FALSE;
 }
 
+BOOL LLVOVolume::hasLightTexture() const
+{
+	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
+	{
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
 BOOL LLVOVolume::isVolumeGlobal() const
 {
 	if (mVolumeImpl)
@@ -2116,9 +2298,9 @@ U32 LLVOVolume::getPartitionType() const
 }
 
 LLVolumePartition::LLVolumePartition()
-: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, FALSE)
+: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB)
 {
-	mLODPeriod = 16;
+	mLODPeriod = 32;
 	mDepthMask = FALSE;
 	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
 	mPartitionType = LLViewerRegion::PARTITION_VOLUME;
@@ -2127,10 +2309,10 @@ LLVolumePartition::LLVolumePartition()
 }
 
 LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
-: LLSpatialBridge(drawablep, LLVOVolume::VERTEX_DATA_MASK)
+: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK)
 {
 	mDepthMask = FALSE;
-	mLODPeriod = 16;
+	mLODPeriod = 32;
 	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
 	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
 	
@@ -2154,8 +2336,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	S32 idx = draw_vec.size()-1;
 
 
-	BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT ||
-					  type == LLRenderPass::PASS_ALPHA) ? facep->isState(LLFace::FULLBRIGHT) : FALSE;
+	BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
+					  (type == LLRenderPass::PASS_ALPHA ? facep->isState(LLFace::FULLBRIGHT) : FALSE);
+
+	if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL))
+	{
+		llwarns << "Non fullbright face has no normals!" << llendl;
+		return;
+	}
 
 	const LLMatrix4* tex_mat = NULL;
 	if (facep->isState(LLFace::TEXTURE_ANIM) && facep->getVirtualSize() > MIN_TEX_ANIM_SIZE)
@@ -2218,7 +2406,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		U32 end = start + facep->getGeomCount()-1;
 		U32 offset = facep->getIndicesStart();
 		U32 count = facep->getIndicesCount();
-		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset,tex, 
+		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, 
 			facep->mVertexBuffer, fullbright, bump); 
 		draw_info->mGroup = group;
 		draw_info->mVSize = facep->getVirtualSize();
@@ -2246,11 +2434,6 @@ static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
-	if (LLPipeline::sSkipUpdate)
-	{
-		return;
-	}
-
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -2312,6 +2495,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		vobj->updateTextures();
 		vobj->preRebuild();
 
+		drawablep->clearState(LLDrawable::HAS_ALPHA);
+
 		//for each face
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 		{
@@ -2373,13 +2558,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				if (type == LLDrawPool::POOL_ALPHA)
 				{
 					if (LLPipeline::sFastAlpha &&
-						(te->getColor().mV[VW] == 1.0f) &&
-						facep->getTexture()->getIsAlphaMask())
+					    (te->getColor().mV[VW] == 1.0f) &&
+					    (!te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible, need to figure out why - for now, avoid
+					    facep->getTexture()->getIsAlphaMask())
 					{ //can be treated as alpha mask
 						simple_faces.push_back(facep);
 					}
 					else
 					{
+						drawablep->setState(LLDrawable::HAS_ALPHA);
 						alpha_faces.push_back(facep);
 					}
 				}
@@ -2468,16 +2655,18 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	if (LLPipeline::sDelayVBUpdate)
 	{
-		group->setState(LLSpatialGroup::MESH_DIRTY);
+		group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 	}
 
 	mFaceList.clear();
 }
 
+static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
-	if (group->isState(LLSpatialGroup::MESH_DIRTY))
+	if (group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY))
 	{
+		LLFastTimer tm(FTM_VOLUME_GEOM);
 		S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ;
 
 		group->mBuilt = 1.f;
@@ -2554,7 +2743,12 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 			} 
 		}
 
-		group->clearState(LLSpatialGroup::MESH_DIRTY);
+		group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
+	}
+
+	if (group->isState(LLSpatialGroup::NEW_DRAWINFO))
+	{
+		llerrs << "WTF?" << llendl;
 	}
 }
 
@@ -2699,6 +2893,11 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 
 			BOOL force_simple = facep->mPixelArea < FORCE_SIMPLE_RENDER_AREA;
 			BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
+			if ((mask & LLVertexBuffer::MAP_NORMAL) == 0)
+			{ //paranoia check to make sure GL doesn't try to read non-existant normals
+				fullbright = TRUE;
+			}
+
 			const LLTextureEntry* te = facep->getTextureEntry();
 
 			BOOL is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA ? TRUE : FALSE;
@@ -2708,6 +2907,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				// can we safely treat this as an alpha mask?
 				if (LLPipeline::sFastAlpha &&
 				    (te->getColor().mV[VW] == 1.0f) &&
+				    (!te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible, need to figure out why - for now, avoid
 				    facep->getTexture()->getIsAlphaMask())
 				{
 					if (te->getFullbright())
@@ -2730,6 +2930,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				}
 			}
 			else if (gPipeline.canUseVertexShaders()
+				&& group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD 
 				&& LLPipeline::sRenderBump 
 				&& te->getShiny())
 			{
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index d343d4db74e..1b90219836c 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -198,9 +198,18 @@ class LLVOVolume : public LLViewerObject
 	void setLightRadius(F32 radius);
 	void setLightFalloff(F32 falloff);
 	void setLightCutoff(F32 cutoff);
+	void setLightTextureID(LLUUID id);
+	void setSpotLightParams(LLVector3 params);
+
 	BOOL getIsLight() const;
 	LLColor3 getLightBaseColor() const; // not scaled by intensity
 	LLColor3 getLightColor() const; // scaled by intensity
+	LLUUID	getLightTextureID() const;
+	LLVector3 getSpotLightParams() const;
+	void	updateSpotLightPriority();
+	F32		getSpotLightPriority() const;
+
+	LLViewerTexture* getLightTexture();
 	F32 getLightIntensity() const;
 	F32 getLightRadius() const;
 	F32 getLightFalloff() const;
@@ -210,6 +219,8 @@ class LLVOVolume : public LLViewerObject
 	U32 getVolumeInterfaceID() const;
 	virtual BOOL isFlexible() const;
 	virtual BOOL isSculpted() const;
+	virtual BOOL hasLightTexture() const;
+
 	BOOL isVolumeGlobal() const;
 	BOOL canBeFlexible() const;
 	BOOL setIsFlexible(BOOL is_flexible);
@@ -232,12 +243,14 @@ class LLVOVolume : public LLViewerObject
 	BOOL		mLODChanged;
 	S32         mSculptLevel;
 	BOOL		mSculptChanged;
+	F32			mSpotLightPriority;
 	LLMatrix4	mRelativeXform;
 	LLMatrix3	mRelativeXformInvTrans;
 	BOOL		mVolumeChanged;
 	F32			mVObjRadius;
 	LLVolumeInterface *mVolumeImpl;
 	LLPointer<LLViewerFetchedTexture> mSculptTexture;
+	LLPointer<LLViewerFetchedTexture> mLightTexture;
 	
 	// statics
 public:
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index e2357957abb..0c967f9020c 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -277,9 +277,8 @@ U32 LLVOWater::getPartitionType() const
 }
 
 LLWaterPartition::LLWaterPartition()
-: LLSpatialPartition(0)
+: LLSpatialPartition(0, FALSE, 0)
 {
-	mRenderByGroup = FALSE;
 	mInfiniteFarClip = TRUE;
 	mDrawableType = LLPipeline::RENDER_TYPE_WATER;
 	mPartitionType = LLViewerRegion::PARTITION_WATER;
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index 3661be500bf..136ffe607d7 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -154,7 +154,7 @@ void LLWaterParamManager::loadPreset(const std::string & name,bool propagate)
 	std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight/water", escaped_filename));
 	llinfos << "Loading water settings from " << pathName << llendl;
 	
-	std::ifstream presetsXML;
+	llifstream presetsXML;
 	presetsXML.open(pathName.c_str());
 	
 	// That failed, try loading from the users area instead.
@@ -162,7 +162,8 @@ void LLWaterParamManager::loadPreset(const std::string & name,bool propagate)
 	{
 		pathName=gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", escaped_filename);
 		llinfos << "Loading User water setting from " << pathName << llendl;
-		presetsXML.open(pathName.c_str());
+		presetsXML.clear();
+        presetsXML.open(pathName.c_str());
 	}
 
 	if (presetsXML)
@@ -279,8 +280,6 @@ void LLWaterParamManager::update(LLViewerCamera * cam)
 		waterfloater->syncMenu();
 	}
 
-	stop_glerror();
-
 	// only do this if we're dealing with shaders
 	if(gPipeline.canUseVertexShaders()) 
 	{
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index 7d9d0a6191f..4bf64816c7b 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -206,7 +206,8 @@ void LLWLParamManager::loadPreset(const std::string & name,bool propagate)
 	{
 		pathName=gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", escaped_filename);
 		llinfos << "Loading User WindLight sky setting from " << pathName << llendl;
-		presetsXML.open(pathName.c_str());
+		presetsXML.clear();
+        presetsXML.open(pathName.c_str());
 	}
 
 	if (presetsXML)
@@ -396,8 +397,6 @@ void LLWLParamManager::update(LLViewerCamera * cam)
 
 	F32 camYaw = cam->getYaw();
 
-	stop_glerror();
-
 	// *TODO: potential optimization - this block may only need to be
 	// executed some of the time.  For example for water shaders only.
 	{
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index 700971dcc47..b8ecd9556f9 100644
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -635,7 +635,6 @@ void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**)
 
 #ifdef IMMEDIATE_IMAGE_LOAD
 			siminfo->mCurrentImage = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-			gGL.getTexUnit(0)->bind(siminfo->mCurrentImage);
 			siminfo->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP);
 #endif
 			
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index 4d7423eaae4..79308f7e167 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -372,7 +372,7 @@ void LLWorldMapView::draw()
 		current_image->setBoostLevel(LLViewerTexture::BOOST_MAP_LAYER);
 		current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY]));
 		
-		if (!current_image->hasValidGLTexture())
+		if (!current_image->hasGLTexture())
 		{
 			continue; // better to draw nothing than the default image
 		}
@@ -474,7 +474,7 @@ void LLWorldMapView::draw()
 		bool sim_visible =
 			(gMapScale >= map_scale_cutoff) &&
 			(simimage != NULL) &&
-			(simimage->hasValidGLTexture());
+			(simimage->hasGLTexture());
 
 		if (sim_visible)
 		{
@@ -583,7 +583,7 @@ void LLWorldMapView::draw()
 				gGL.vertex3f(right, top, 0.f);
 			gGL.end();
 
-			if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->hasValidGLTexture())
+			if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->hasGLTexture())
 			{
 				gGL.getTexUnit(0)->bind(overlayimage);
 				gGL.color4f(1.f, 1.f, 1.f, alpha);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index b0c3e8d7113..38052abfa3f 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -102,6 +102,8 @@
 #include "llwaterparammanager.h"
 #include "llspatialpartition.h"
 #include "llmutelist.h"
+#include "lltoolpie.h"
+
 
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
@@ -161,6 +163,8 @@ LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
 LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
 LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
 LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy");
+LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
+
 
 static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
 static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
@@ -186,6 +190,8 @@ std::string gPoolNames[] =
 	"POOL_ALPHA",
 };
 
+void drawBox(const LLVector3& c, const LLVector3& r);
+
 U32 nhpo2(U32 v) 
 {
 	U32 r = 1;
@@ -267,7 +273,6 @@ BOOL	LLPipeline::sDisableShaders = FALSE;
 BOOL	LLPipeline::sRenderBump = TRUE;
 BOOL	LLPipeline::sUseFarClip = TRUE;
 BOOL	LLPipeline::sShadowRender = FALSE;
-BOOL	LLPipeline::sSkipUpdate = FALSE;
 BOOL	LLPipeline::sWaterReflections = FALSE;
 BOOL	LLPipeline::sRenderGlow = FALSE;
 BOOL	LLPipeline::sReflectionRender = FALSE;
@@ -279,6 +284,8 @@ BOOL	LLPipeline::sRenderAttachedLights = TRUE;
 BOOL	LLPipeline::sRenderAttachedParticles = TRUE;
 BOOL	LLPipeline::sRenderDeferred = FALSE;
 S32		LLPipeline::sVisibleLightCount = 0;
+F32		LLPipeline::sMinRenderSize = 0.f;
+
 
 static LLCullResult* sCull = NULL;
 
@@ -294,11 +301,11 @@ static const U32 gl_cube_face[] =
 
 void validate_framebuffer_object();
 
+
 void addDeferredAttachments(LLRenderTarget& target)
 {
-	target.addColorAttachment(GL_RGBA16F_ARB); //specular
-	target.addColorAttachment(GL_RGBA16F_ARB); //normal+z	
-	target.addColorAttachment(GL_RGBA16F_ARB); //position
+	target.addColorAttachment(GL_RGBA); //specular
+	target.addColorAttachment(GL_RGBA); //normal+z	
 }
 
 LLPipeline::LLPipeline() :
@@ -340,6 +347,8 @@ LLPipeline::LLPipeline() :
 	mLightingDetail(0)
 {
 	mNoiseMap = 0;
+	mTrueNoiseMap = 0;
+	mLightFunc = 0;
 }
 
 void LLPipeline::init()
@@ -389,6 +398,11 @@ void LLPipeline::init()
 	LLViewerShaderMgr::instance()->setShaders();
 
 	stop_glerror();
+
+	for (U32 i = 0; i < 2; ++i)
+	{
+		mSpotLightFade[i] = 1.f;
+	}
 }
 
 LLPipeline::~LLPipeline()
@@ -496,13 +510,6 @@ void LLPipeline::resizeScreenTexture()
 		GLuint resX = gViewerWindow->getWorldViewWidth();
 		GLuint resY = gViewerWindow->getWorldViewHeight();
 	
-		U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
-		if (res_mod > 1 && res_mod < resX && res_mod < resY)
-		{
-			resX /= res_mod;
-			resY /= res_mod;
-		}
-
 		allocateScreenBuffer(resX,resY);
 
 		llinfos << "RESIZED SCREEN TEXTURE: " << resX << "x" << resY << llendl;
@@ -512,17 +519,59 @@ void LLPipeline::resizeScreenTexture()
 void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
 {
 	U32 samples = gSavedSettings.getU32("RenderFSAASamples");
+
+	U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
+	if (res_mod > 1 && res_mod < resX && res_mod < resY)
+	{
+		resX /= res_mod;
+		resY /= res_mod;
+	}
+
+	if (gSavedSettings.getBOOL("RenderUIBuffer"))
+	{
+		mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+	}	
+
 	if (LLPipeline::sRenderDeferred)
 	{
 		//allocate deferred rendering color buffers
-		mDeferredScreen.allocate(resX, resY, GL_RGBA16F_ARB, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+		mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+		mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
 		addDeferredAttachments(mDeferredScreen);
-		mScreen.allocate(resX, resY, GL_RGBA16F_ARB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);		
-		
+		mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);		
+		mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+
+		for (U32 i = 0; i < 3; i++)
+		{
+			mDeferredLight[i].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+		}
+
 		for (U32 i = 0; i < 2; i++)
 		{
-			mDeferredLight[i].allocate(resX, resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+			mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+		}
+
+		F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale");
+
+		for (U32 i = 0; i < 4; i++)
+		{
+			mShadow[i].allocate(U32(resX*scale),U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+		}
+
+
+		U32 width = nhpo2(U32(resX*scale))/2;
+		U32 height = width;
+
+		for (U32 i = 4; i < 6; i++)
+		{
+			mShadow[i].allocate(width, height, 0, TRUE, FALSE);
 		}
+
+
+
+		width = nhpo2(resX)/2;
+		height = nhpo2(resY)/2;
+		mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE);
 	}
 	else
 	{
@@ -532,25 +581,23 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
 
 	if (gGLManager.mHasFramebufferMultisample && samples > 1)
 	{
+		mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
+		mScreen.setSampleBuffer(&mSampleBuffer);
+
 		if (LLPipeline::sRenderDeferred)
 		{
-			mSampleBuffer.allocate(resX,resY,GL_RGBA16F_ARB,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
 			addDeferredAttachments(mSampleBuffer);
 			mDeferredScreen.setSampleBuffer(&mSampleBuffer);
 		}
-		else
-		{
-			mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
-		}
 
-		mScreen.setSampleBuffer(&mSampleBuffer);
 		stop_glerror();
 	}
-	else if (LLPipeline::sRenderDeferred)
+	
+	if (LLPipeline::sRenderDeferred)
 	{ //share depth buffer between deferred targets
 		mDeferredScreen.shareDepthBuffer(mScreen);
-		for (U32 i = 0; i < 2; i++)
-		{
+		for (U32 i = 0; i < 3; i++)
+		{ //share stencil buffer with screen space lightmap to stencil out sky
 			mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
 		}
 	}
@@ -583,17 +630,42 @@ void LLPipeline::releaseGLBuffers()
 		mNoiseMap = 0;
 	}
 
+	if (mTrueNoiseMap)
+	{
+		LLImageGL::deleteTextures(1, &mTrueNoiseMap);
+		mTrueNoiseMap = 0;
+	}
+
+	if (mLightFunc)
+	{
+		LLImageGL::deleteTextures(1, &mLightFunc);
+		mLightFunc = 0;
+	}
+
 	mWaterRef.release();
 	mWaterDis.release();
 	mScreen.release();
+	mUIScreen.release();
 	mSampleBuffer.releaseSampleBuffer();
 	mDeferredScreen.release();
+	mDeferredDepth.release();
+	for (U32 i = 0; i < 3; i++)
+	{
+		mDeferredLight[i].release();
+	}
+
+	mEdgeMap.release();
+	mGIMap.release();
+	mGIMapPost[0].release();
+	mGIMapPost[1].release();
+	mHighlight.release();
+	mLuminanceMap.release();
 	
-	
-	for (U32 i = 0; i < 4; i++)
+	for (U32 i = 0; i < 6; i++)
 	{
-		mSunShadow[i].release();
+		mShadow[i].release();
 	}
+
 	for (U32 i = 0; i < 3; i++)
 	{
 		mGlow[i].release();
@@ -617,6 +689,7 @@ void LLPipeline::createGLBuffers()
 		mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
 	}
 
+	mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
 
 	stop_glerror();
 
@@ -638,11 +711,6 @@ void LLPipeline::createGLBuffers()
 	
 	if (sRenderDeferred)
 	{
-		mSunShadow[0].allocate(1024,1024, 0, TRUE, FALSE);
-		mSunShadow[1].allocate(1024,1024, 0, TRUE, FALSE);
-		mSunShadow[2].allocate(1024,1024, 0, TRUE, FALSE);
-		mSunShadow[3].allocate(1024,1024, 0, TRUE, FALSE);
-		
 		if (!mNoiseMap)
 		{
 			const U32 noiseRes = 128;
@@ -662,6 +730,66 @@ void LLPipeline::createGLBuffers()
 			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 		}
+
+		if (!mTrueNoiseMap)
+		{
+			const U32 noiseRes = 128;
+			F32 noise[noiseRes*noiseRes*3];
+			for (U32 i = 0; i < noiseRes*noiseRes*3; i++)
+			{
+				noise[i] = ll_frand()*2.0-1.0;
+			}
+
+			LLImageGL::generateTextures(1, &mTrueNoiseMap);
+			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
+			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise);
+			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		}
+
+		if (!mLightFunc)
+		{
+			U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
+			U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
+			U8* lg = new U8[lightResX*lightResY];
+
+			for (U32 y = 0; y < lightResY; ++y)
+			{
+				for (U32 x = 0; x < lightResX; ++x)
+				{
+					//spec func
+					F32 sa = (F32) x/(lightResX-1);
+					F32 spec = (F32) y/(lightResY-1);
+					//lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
+
+					//F32 sp = acosf(sa)/(1.f-spec);
+
+					sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
+					F32 a = acosf(sa*0.25f+0.75f);
+					F32 m = llmax(0.5f-spec*0.5f, 0.001f);
+					F32 t2 = tanf(a)/m;
+					t2 *= t2;
+
+					F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
+					F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
+
+					lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
+				}
+			}
+
+			LLImageGL::generateTextures(1, &mLightFunc);
+			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg);
+			gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+
+			delete [] lg;
+		}
+
+		if (gSavedSettings.getBOOL("RenderDeferredGI"))
+		{
+			mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE);
+			addDeferredAttachments(mGIMap);
+		}
 	}
 }
 
@@ -1038,6 +1166,31 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 			break;
 		}
 	}
+
+	{
+		HighlightItem item(drawablep);
+		mHighlightSet.erase(item);
+
+		if (mHighlightObject == drawablep)
+		{
+			mHighlightObject = NULL;
+		}
+	}
+
+	for (U32 i = 0; i < 2; ++i)
+	{
+		if (mShadowSpotLight[i] == drawablep)
+		{
+			mShadowSpotLight[i] = NULL;
+		}
+
+		if (mTargetShadowSpotLight[i] == drawablep)
+		{
+			mTargetShadowSpotLight[i] = NULL;
+		}
+	}
+
+
 }
 
 U32 LLPipeline::addObject(LLViewerObject *vobj)
@@ -1357,6 +1510,8 @@ BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3&
 	min = LLVector3(F32_MAX, F32_MAX, F32_MAX);
 	max = LLVector3(-F32_MAX, -F32_MAX, -F32_MAX);
 
+	U32 saved_camera_id = LLViewerCamera::sCurCameraID;
+	LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
 	BOOL res = TRUE;
 
@@ -1381,6 +1536,8 @@ BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3&
 		}
 	}
 
+	LLViewerCamera::sCurCameraID = saved_camera_id;
+
 	return res;
 }
 
@@ -1397,8 +1554,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	BOOL to_texture =	LLPipeline::sUseOcclusion > 1 &&
 						!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && 
-						!sReflectionRender &&
-						!sShadowRender &&
+						LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
 						gPipeline.canUseVertexShaders() &&
 						sRenderGlow;
 
@@ -1407,11 +1563,15 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 		mScreen.bindTarget();
 	}
 
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadMatrixd(gGLLastProjection);
+	glMatrixMode(GL_MODELVIEW);
 	glPushMatrix();
 	gGLLastMatrix = NULL;
-	//glLoadMatrixd(gGLModelView);
 	glLoadMatrixd(gGLLastModelView);
 
+
 	LLVertexBuffer::unbind();
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable test(GL_ALPHA_TEST);
@@ -1480,6 +1640,9 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	}
 	
 	
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
 	glPopMatrix();
 
 	if (sUseOcclusion > 1)
@@ -1491,10 +1654,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	{
 		mScreen.flush();
 	}
-	else if (LLPipeline::sUseOcclusion > 1)
-	{
-		glFlush();
-	}
 }
 
 void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
@@ -1506,7 +1665,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 	
 	group->setVisible();
 
-	if (!sSkipUpdate)
+	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
 	{
 		group->updateDistance(camera);
 	}
@@ -1518,6 +1677,12 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 		return;
 	}
 
+	if (sMinRenderSize > 0.f && 
+			llmax(llmax(group->mBounds[1].mV[0], group->mBounds[1].mV[1]), group->mBounds[1].mV[2]) < sMinRenderSize)
+	{
+		return;
+	}
+
 	assertInitialized();
 	
 	if (!group->mSpatialPartition->mRenderByGroup)
@@ -1534,22 +1699,22 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 
 void LLPipeline::markOccluder(LLSpatialGroup* group)
 {
-	if (sUseOcclusion > 1 && group && !group->isState(LLSpatialGroup::ACTIVE_OCCLUSION))
+	if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION))
 	{
 		LLSpatialGroup* parent = group->getParent();
 
-		if (!parent || !parent->isState(LLSpatialGroup::OCCLUDED))
+		if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{ //only mark top most occluders as active occlusion
 			sCull->pushOcclusionGroup(group);
-			group->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
+			group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
 				
 			if (parent && 
-				!parent->isState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
+				!parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
 				parent->getElementCount() == 0 &&
 				parent->needsUpdate())
 			{
 				sCull->pushOcclusionGroup(group);
-				parent->setState(LLSpatialGroup::ACTIVE_OCCLUSION);
+				parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
 			}
 		}
 	}
@@ -1572,18 +1737,18 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
+	LLGLDisable cull(GL_CULL_FACE);
 	if (LLPipeline::sUseOcclusion > 1)
 	{
 		for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			group->doOcclusion(&camera);
-			group->clearState(LLSpatialGroup::ACTIVE_OCCLUSION);
+			group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
 		}
 	}
 
 	gGL.setColorMask(true, false);
-	glFlush();
 }
 	
 BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
@@ -1597,6 +1762,78 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
 	return update_complete;
 }
 
+void LLPipeline::updateGL()
+{
+	while (!LLGLUpdate::sGLQ.empty())
+	{
+		LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
+		glu->updateGL();
+		glu->mInQ = FALSE;
+		LLGLUpdate::sGLQ.pop_front();
+	}
+}
+
+void LLPipeline::rebuildPriorityGroups()
+{
+	LLTimer update_timer;
+	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+	
+	assertInitialized();
+
+	// Iterate through all drawables on the priority build queue,
+	for (LLSpatialGroup::sg_list_t::iterator iter = mGroupQ1.begin();
+		 iter != mGroupQ1.end(); ++iter)
+	{
+		LLSpatialGroup* group = *iter;
+		group->rebuildGeom();
+		group->clearState(LLSpatialGroup::IN_BUILD_Q1);
+	}
+
+	mGroupQ1.clear();
+}
+		
+void LLPipeline::rebuildGroups()
+{
+	// Iterate through some drawables on the non-priority build queue
+	S32 size = (S32) mGroupQ2.size();
+	S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
+			
+	S32 count = 0;
+	
+	std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency());
+
+	LLSpatialGroup::sg_vector_t::iterator iter;
+	for (iter = mGroupQ2.begin();
+		 iter != mGroupQ2.end(); ++iter)
+	{
+		LLSpatialGroup* group = *iter;
+
+		if (group->isDead())
+		{
+			continue;
+		}
+
+		group->rebuildGeom();
+		
+		if (group->mSpatialPartition->mRenderByGroup)
+		{
+			count++;
+		}
+			
+		group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+
+		if (count > min_count)
+		{
+			++iter;
+			break;
+		}
+	}	
+
+	mGroupQ2.erase(mGroupQ2.begin(), iter);
+
+	updateMovedList(mMovedBridge);
+}
+
 void LLPipeline::updateGeom(F32 max_dtime)
 {
 	LLTimer update_timer;
@@ -1711,6 +1948,16 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
 	
 	if (drawablep->isSpatialBridge())
 	{
+		LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
+
+		if (root && root->getParent() && root->getVObj() && root->getVObj()->isAttachment())
+		{
+			LLVOAvatar* av = root->getParent()->getVObj()->asAvatar();
+			if (av->isImpostor())
+			{
+				return;
+			}
+		}
 		sCull->pushBridge((LLSpatialBridge*) drawablep);
 	}
 	else
@@ -1840,6 +2087,59 @@ void LLPipeline::markTextured(LLDrawable *drawablep)
 	}
 }
 
+void LLPipeline::markGLRebuild(LLGLUpdate* glu)
+{
+	if (glu && !glu->mInQ)
+	{
+		LLGLUpdate::sGLQ.push_back(glu);
+		glu->mInQ = TRUE;
+	}
+}
+
+void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
+{
+	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+	//assert_main_thread();
+
+	if (group && !group->isDead() && group->mSpatialPartition)
+	{
+		if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
+		{
+			priority = TRUE;
+		}
+
+		if (priority)
+		{
+			if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
+			{
+				mGroupQ1.push_back(group);
+				group->setState(LLSpatialGroup::IN_BUILD_Q1);
+
+				if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
+				{
+					LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
+					if (iter != mGroupQ2.end())
+					{
+						mGroupQ2.erase(iter);
+					}
+					group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+				}
+			}
+		}
+		else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
+		{
+			//llerrs << "Non-priority updates not yet supported!" << llendl;
+			if (std::find(mGroupQ2.begin(), mGroupQ2.end(), group) != mGroupQ2.end())
+			{
+				llerrs << "WTF?" << llendl;
+			}
+			mGroupQ2.push_back(group);
+			group->setState(LLSpatialGroup::IN_BUILD_Q2);
+
+		}
+	}
+}
+
 void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD);
@@ -1896,48 +2196,48 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 
 	grabReferences(result);
 
+	for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
 	{
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		LLSpatialGroup* group = *iter;
+		group->checkOcclusion();
+		if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
-			LLSpatialGroup* group = *iter;
-			group->checkOcclusion();
-			if (sUseOcclusion && group->isState(LLSpatialGroup::OCCLUDED))
-			{
-				markOccluder(group);
-			}
-			else
+			markOccluder(group);
+		}
+		else
+		{
+			group->setVisible();
+			for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 			{
-				group->setVisible();
-				for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
-				{
-					markVisible(*i, camera);
-				}
+				markVisible(*i, camera);
 			}
 		}
+	}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+	for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+	{
+		LLSpatialGroup* group = *iter;
+		group->checkOcclusion();
+		if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
-			LLSpatialGroup* group = *iter;
-			group->checkOcclusion();
-			if (sUseOcclusion && group->isState(LLSpatialGroup::OCCLUDED))
-			{
-				markOccluder(group);
-			}
-			else
-			{
-				group->setVisible();
-				stateSort(group, camera);
-			}
+			markOccluder(group);
+		}
+		else
+		{
+			group->setVisible();
+			stateSort(group, camera);
 		}
 	}
+	
 
+	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
 	{
 		for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 		{
 			LLCullResult::bridge_list_t::iterator cur_iter = i;
 			LLSpatialBridge* bridge = *cur_iter;
 			LLSpatialGroup* group = bridge->getSpatialGroup();
-			if (!bridge->isDead() && group && !group->isState(LLSpatialGroup::OCCLUDED))
+			if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 			{
 				stateSort(bridge, camera);
 			}
@@ -1968,7 +2268,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-	if (!sSkipUpdate && group->changeLOD())
+	if (group->changeLOD())
 	{
 		for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
 		{
@@ -1982,7 +2282,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-	if (!sSkipUpdate && bridge->getSpatialGroup()->changeLOD())
+	if (!sShadowRender && bridge->getSpatialGroup()->changeLOD())
 	{
 		bool force_update = false;
 		bridge->updateDistance(camera, force_update);
@@ -2039,41 +2339,48 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 		}
 	}
 
-	LLSpatialGroup* group = drawablep->getSpatialGroup();
-	if (!group || group->changeLOD())
+	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
 	{
-		if (drawablep->isVisible() && !sSkipUpdate)
+		LLSpatialGroup* group = drawablep->getSpatialGroup();
+		if (!group || group->changeLOD())
 		{
-			if (!drawablep->isActive())
+			if (drawablep->isVisible())
 			{
-				bool force_update = false;
-				drawablep->updateDistance(camera, force_update);
+				if (!drawablep->isActive())
+				{
+					bool force_update = false;
+					drawablep->updateDistance(camera, force_update);
+				}
+				else if (drawablep->isAvatar())
+				{
+					bool force_update = false;
+					drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
+				}
 			}
-			else if (drawablep->isAvatar())
-			{
-				bool force_update = false;
-				drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
-		}
 		}
 	}
 
-	for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
-			iter != drawablep->mFaces.end(); iter++)
+	if (!drawablep->getVOVolume())
 	{
-		LLFace* facep = *iter;
-
-		if (facep->hasGeometry())
+		for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
+				iter != drawablep->mFaces.end(); iter++)
 		{
-			if (facep->getPool())
-			{
-				facep->getPool()->enqueue(facep);
-			}
-			else
+			LLFace* facep = *iter;
+
+			if (facep->hasGeometry())
 			{
-				break;
+				if (facep->getPool())
+				{
+					facep->getPool()->enqueue(facep);
+				}
+				else
+				{
+					break;
+				}
 			}
 		}
 	}
+	
 
 	mNumVisibleFaces += drawablep->getNumFaces();
 }
@@ -2230,7 +2537,7 @@ void LLPipeline::postSort(LLCamera& camera)
 	{
 		LLSpatialGroup* group = *i;
 		if (!sUseOcclusion || 
-			!group->isState(LLSpatialGroup::OCCLUDED))
+			!group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
 			group->rebuildGeom();
 		}
@@ -2239,7 +2546,7 @@ void LLPipeline::postSort(LLCamera& camera)
 	//rebuild groups
 	sCull->assertDrawMapsEmpty();
 
-	LLSpatialGroup::sNoDelete = FALSE;
+	/*LLSpatialGroup::sNoDelete = FALSE;
 	for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
@@ -2251,8 +2558,10 @@ void LLPipeline::postSort(LLCamera& camera)
 		
 		group->rebuildGeom();
 	}
-	LLSpatialGroup::sNoDelete = TRUE;
+	LLSpatialGroup::sNoDelete = TRUE;*/
+
 
+	rebuildPriorityGroups();
 
 	const S32 bin_count = 1024*8;
 		
@@ -2274,42 +2583,65 @@ void LLPipeline::postSort(LLCamera& camera)
 	{
 		LLSpatialGroup* group = *i;
 		if (sUseOcclusion && 
-			group->isState(LLSpatialGroup::OCCLUDED))
+			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
 			continue;
 		}
-		
+
+		if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
+		{ //no way this group is going to be drawable without a rebuild
+			group->rebuildGeom();
+		}
+
 		for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
 		{
 			LLSpatialGroup::drawmap_elem_t& src_vec = j->second;	
+			if (!hasRenderType(j->first))
+			{
+				continue;
+			}
 			
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
 			{
-				sCull->pushDrawInfo(j->first, *k);
-			}
-		}
-
-		LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
-		
-		if (alpha != group->mDrawMap.end())
-		{ //store alpha groups for sorting
-			LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
-			if (!sSkipUpdate)
-			{
-				if (bridge)
+				if (sMinRenderSize > 0.f)
 				{
-					LLCamera trans_camera = bridge->transformCamera(camera);
-					group->updateDistance(trans_camera);
+					LLVector3 bounds = (*k)->mExtents[1]-(*k)->mExtents[0];
+					if (llmax(llmax(bounds.mV[0], bounds.mV[1]), bounds.mV[2]) > sMinRenderSize)
+					{
+						sCull->pushDrawInfo(j->first, *k);
+					}
 				}
 				else
 				{
-					group->updateDistance(camera);
+					sCull->pushDrawInfo(j->first, *k);
 				}
 			}
+		}
+
+		if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA))
+		{
+			LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
 			
-			if (hasRenderType(LLDrawPool::POOL_ALPHA))
-			{
-				sCull->pushAlphaGroup(group);
+			if (alpha != group->mDrawMap.end())
+			{ //store alpha groups for sorting
+				LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+				if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+				{
+					if (bridge)
+					{
+						LLCamera trans_camera = bridge->transformCamera(camera);
+						group->updateDistance(trans_camera);
+					}
+					else
+					{
+						group->updateDistance(camera);
+					}
+				}
+							
+				if (hasRenderType(LLDrawPool::POOL_ALPHA))
+				{
+					sCull->pushAlphaGroup(group);
+				}
 			}
 		}
 	}
@@ -2408,7 +2740,7 @@ void LLPipeline::postSort(LLCamera& camera)
 		}
 	}
 
-	LLSpatialGroup::sNoDelete = FALSE;
+	//LLSpatialGroup::sNoDelete = FALSE;
 }
 
 
@@ -2470,6 +2802,103 @@ void LLPipeline::renderHighlights()
 	LLGLEnable color_mat(GL_COLOR_MATERIAL);
 	disableLights();
 
+	if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty())
+	{ //draw blurry highlight image over screen
+		LLGLEnable blend(GL_BLEND);
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+		LLGLDisable test(GL_ALPHA_TEST);
+
+		LLGLEnable stencil(GL_STENCIL_TEST);
+		gGL.flush();
+		glStencilMask(0xFFFFFFFF);
+		glClearStencil(1);
+		glClear(GL_STENCIL_BUFFER_BIT);
+
+		glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
+		glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+				
+		gGL.setColorMask(false, false);
+		for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
+		{
+			renderHighlight(iter->mItem->getVObj(), 1.f);
+		}
+		gGL.setColorMask(true, false);
+
+		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+		glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
+		
+		//gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+		gGL.pushMatrix();
+		glLoadIdentity();
+		glMatrixMode(GL_PROJECTION);
+		gGL.pushMatrix();
+		glLoadIdentity();
+
+		gGL.getTexUnit(0)->bind(&mHighlight);
+
+		LLVector2 tc1;
+		LLVector2 tc2;
+
+		tc1.setVec(0,0);
+		tc2.setVec(2,2);
+
+		gGL.begin(LLRender::TRIANGLES);
+				
+		F32 scale = gSavedSettings.getF32("RenderHighlightBrightness");
+		LLColor4 color = gSavedSettings.getColor4("RenderHighlightColor");
+		F32 thickness = gSavedSettings.getF32("RenderHighlightThickness");
+
+		for (S32 pass = 0; pass < 2; ++pass)
+		{
+			if (pass == 0)
+			{
+				gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+			}
+			else
+			{
+				gGL.setSceneBlendType(LLRender::BT_ALPHA);
+			}
+
+			for (S32 i = 0; i < 8; ++i)
+			{
+				for (S32 j = 0; j < 8; ++j)
+				{
+					LLVector2 tc(i-4+0.5f, j-4+0.5f);
+
+					F32 dist = 1.f-(tc.length()/sqrtf(32.f));
+					dist *= scale/64.f;
+
+					tc *= thickness;
+					tc.mV[0] = (tc.mV[0])/mHighlight.getWidth();
+					tc.mV[1] = (tc.mV[1])/mHighlight.getHeight();
+
+					gGL.color4f(color.mV[0],
+								color.mV[1],
+								color.mV[2],
+								color.mV[3]*dist);
+					
+					gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]);
+					gGL.vertex2f(-1,3);
+					
+					gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]);
+					gGL.vertex2f(-1,-1);
+					
+					gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]);
+					gGL.vertex2f(3,-1);
+				}
+			}
+		}
+
+		gGL.end();
+
+		gGL.popMatrix();
+		glMatrixMode(GL_MODELVIEW);
+		gGL.popMatrix();
+		
+		//gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	}
+
 	if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
 	{
 		gHighlightProgram.bind();
@@ -2611,6 +3040,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 	stop_glerror();
 	
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
+
 	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
 	{
 		LLDrawPool *poolp = *iter;
@@ -2859,15 +3289,18 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 				poolp->endDeferredPass(i);
 				LLVertexBuffer::unbind();
 
-				GLint depth;
-				glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
-				if (depth > 3)
+				if (gDebugGL || gDebugPipeline)
 				{
-					llerrs << "GL matrix stack corrupted!" << llendl;
+					GLint depth;
+					glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+					if (depth > 3)
+					{
+						llerrs << "GL matrix stack corrupted!" << llendl;
+					}
+					LLGLState::checkStates();
+					LLGLState::checkTextureChannels();
+					LLGLState::checkClientArrays();
 				}
-				LLGLState::checkStates();
-				LLGLState::checkTextureChannels();
-				LLGLState::checkClientArrays();
 			}
 		}
 		else
@@ -2950,15 +3383,18 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 				poolp->endPostDeferredPass(i);
 				LLVertexBuffer::unbind();
 
-				GLint depth;
-				glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
-				if (depth > 3)
+				if (gDebugGL || gDebugPipeline)
 				{
-					llerrs << "GL matrix stack corrupted!" << llendl;
+					GLint depth;
+					glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+					if (depth > 3)
+					{
+						llerrs << "GL matrix stack corrupted!" << llendl;
+					}
+					LLGLState::checkStates();
+					LLGLState::checkTextureChannels();
+					LLGLState::checkClientArrays();
 				}
-				LLGLState::checkStates();
-				LLGLState::checkTextureChannels();
-				LLGLState::checkClientArrays();
 			}
 		}
 		else
@@ -3118,7 +3554,7 @@ void LLPipeline::renderDebug()
 	for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 	{
 		LLSpatialBridge* bridge = *i;
-		if (!bridge->isDead() && !bridge->isState(LLSpatialGroup::OCCLUDED) && hasRenderType(bridge->mDrawableType))
+		if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
 		{
 			glPushMatrix();
 			glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
@@ -3129,79 +3565,91 @@ void LLPipeline::renderDebug()
 
 	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
 	{
+		LLGLEnable blend(GL_BLEND);
+		LLGLDepthTest depth(TRUE, FALSE);
+		LLGLDisable cull(GL_CULL_FACE);
+
 		gGL.color4f(1,1,1,1);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 				
+		F32 a = 0.1f;
+
 		F32 col[] =
 		{
-			1,1,0,
-			0,1,1,
-			1,0,1,
-			1,1,1,
-			1,0,0,
-			0,1,0,
-			0,0,1,
-			0,0,0
+			1,0,0,a,
+			0,1,0,a,
+			0,0,1,a,
+			1,0,1,a,
+			
+			1,1,0,a,
+			0,1,1,a,
+			1,1,1,a,
+			1,0,1,a,
 		};
 
 		for (U32 i = 0; i < 8; i++)
 		{
-			gGL.color3fv(col+i*3);	
-
-			gGL.begin(LLRender::LINES);
-
-			LLVector3* frust = mShadowCamera[i].mAgentFrustum;
-
-			gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
-			gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
-			gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
-			gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
-
-			gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
-			gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
-			gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
-			gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
-
-			gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
-			gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
-			gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
-			gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+			if (i > 3)
+			{
+				gGL.color4fv(col+(i-4)*4);	
 			
+				LLVector3* frust = mShadowCamera[i].mAgentFrustum;
+
+				gGL.begin(LLRender::TRIANGLE_STRIP);
+				gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+				gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+				gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+				gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+				gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+				gGL.end();
+				
+				
+				gGL.begin(LLRender::TRIANGLE_STRIP);
+				gGL.vertex3fv(frust[0].mV);
+				gGL.vertex3fv(frust[1].mV);
+				gGL.vertex3fv(frust[3].mV);
+				gGL.vertex3fv(frust[2].mV);
+				gGL.end();
+				
+				gGL.begin(LLRender::TRIANGLE_STRIP);
+				gGL.vertex3fv(frust[4].mV);
+				gGL.vertex3fv(frust[5].mV);
+				gGL.vertex3fv(frust[7].mV);
+				gGL.vertex3fv(frust[6].mV);
+				gGL.end();		
+			}
+
+	
 			if (i < 4)
 			{
-				LLVector3* ext = mShadowExtents[i];
+				gGL.begin(LLRender::LINES);
 				
-				LLVector3 box[] =
+				F32* c = col+i*4;
+				for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
 				{
-					LLVector3(ext[0][0], ext[0][1], ext[0][2]),
-					LLVector3(ext[1][0], ext[0][1], ext[0][2]),
-					LLVector3(ext[1][0], ext[1][1], ext[0][2]),
-					LLVector3(ext[0][0], ext[1][1], ext[0][2]),
-					LLVector3(ext[0][0], ext[0][1], ext[1][2]),
-					LLVector3(ext[1][0], ext[0][1], ext[1][2]),
-					LLVector3(ext[1][0], ext[1][1], ext[1][2]),
-					LLVector3(ext[0][0], ext[1][1], ext[1][2]),
-				};
 					
-				gGL.vertex3fv(box[0].mV); gGL.vertex3fv(box[1].mV);
-				gGL.vertex3fv(box[1].mV); gGL.vertex3fv(box[2].mV);
-				gGL.vertex3fv(box[2].mV); gGL.vertex3fv(box[3].mV);
-				gGL.vertex3fv(box[3].mV); gGL.vertex3fv(box[0].mV);
-
-				gGL.vertex3fv(box[4].mV); gGL.vertex3fv(box[5].mV);
-				gGL.vertex3fv(box[5].mV); gGL.vertex3fv(box[6].mV);
-				gGL.vertex3fv(box[6].mV); gGL.vertex3fv(box[7].mV);
-				gGL.vertex3fv(box[7].mV); gGL.vertex3fv(box[4].mV);
-
-				gGL.vertex3fv(box[0].mV); gGL.vertex3fv(box[4].mV);
-				gGL.vertex3fv(box[1].mV); gGL.vertex3fv(box[5].mV);
-				gGL.vertex3fv(box[2].mV); gGL.vertex3fv(box[6].mV);
-				gGL.vertex3fv(box[3].mV); gGL.vertex3fv(box[7].mV);
+					gGL.color3fv(c);
+
+					for (U32 k = 0; k < mShadowFrustPoints[i].size(); ++k)
+					{
+						if (j != k)
+						{
+							gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
+							gGL.vertex3fv(mShadowFrustPoints[i][k].mV);
+						}
+					}
+
+					if (!mShadowFrustOrigin[i].isExactlyZero())
+					{
+						gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
+						gGL.color4f(1,1,1,1);
+						gGL.vertex3fv(mShadowFrustOrigin[i].mV);
+					}
+				}
+				gGL.end();
 			}
 
-			gGL.end();
-			
-			for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+			/*for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 					iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 			{
 				LLViewerRegion* region = *iter;
@@ -3216,7 +3664,7 @@ void LLPipeline::renderDebug()
 						}
 					}
 				}
-			}
+			}*/
 		}
 	}
 
@@ -3253,6 +3701,55 @@ void LLPipeline::renderDebug()
 		}
 	}
 
+	if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
+	{
+		U32 count = 0;
+		U32 size = mBuildQ2.size();
+		LLColor4 col;
+
+		LLGLEnable blend(GL_BLEND);
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+		
+		for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			if (group->isDead())
+			{
+				continue;
+			}
+
+			LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+
+			if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
+			{
+				continue;
+			}
+
+			if (bridge)
+			{
+				gGL.pushMatrix();
+				glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+			}
+
+			F32 alpha = (F32) (size-count)/size;
+
+			
+			LLVector2 c(1.f-alpha, alpha);
+			c.normVec();
+
+			
+			++count;
+			col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.1f);
+			group->drawObjectBox(col);
+
+			if (bridge)
+			{
+				gGL.popMatrix();
+			}
+		}
+	}
+
 	gGL.flush();
 }
 
@@ -3871,37 +4368,34 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)
 		F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad
 		
 		// UPDATE THE EXISTING NEARBY LIGHTS
-		if (!LLPipeline::sSkipUpdate)
+		light_set_t cur_nearby_lights;
+		for (light_set_t::iterator iter = mNearbyLights.begin();
+			iter != mNearbyLights.end(); iter++)
 		{
-			light_set_t cur_nearby_lights;
-			for (light_set_t::iterator iter = mNearbyLights.begin();
-				iter != mNearbyLights.end(); iter++)
+			const Light* light = &(*iter);
+			LLDrawable* drawable = light->drawable;
+			LLVOVolume* volight = drawable->getVOVolume();
+			if (!volight || !drawable->isState(LLDrawable::LIGHT))
 			{
-				const Light* light = &(*iter);
-				LLDrawable* drawable = light->drawable;
-				LLVOVolume* volight = drawable->getVOVolume();
-				if (!volight || !drawable->isState(LLDrawable::LIGHT))
-				{
-					drawable->clearState(LLDrawable::NEARBY_LIGHT);
-					continue;
-				}
-				if (light->fade <= -LIGHT_FADE_TIME)
-				{
-					drawable->clearState(LLDrawable::NEARBY_LIGHT);
-					continue;
-				}
-				if (!sRenderAttachedLights && volight && volight->isAttachment())
-				{
-					drawable->clearState(LLDrawable::NEARBY_LIGHT);
-					continue;
-				}
-
-				F32 dist = calc_light_dist(volight, cam_pos, max_dist);
-				cur_nearby_lights.insert(Light(drawable, dist, light->fade));
+				drawable->clearState(LLDrawable::NEARBY_LIGHT);
+				continue;
 			}
-			mNearbyLights = cur_nearby_lights;
+			if (light->fade <= -LIGHT_FADE_TIME)
+			{
+				drawable->clearState(LLDrawable::NEARBY_LIGHT);
+				continue;
+			}
+			if (!sRenderAttachedLights && volight && volight->isAttachment())
+			{
+				drawable->clearState(LLDrawable::NEARBY_LIGHT);
+				continue;
+			}
+
+			F32 dist = calc_light_dist(volight, cam_pos, max_dist);
+			cur_nearby_lights.insert(Light(drawable, dist, light->fade));
 		}
-		
+		mNearbyLights = cur_nearby_lights;
+				
 		// FIND NEW LIGHTS THAT ARE IN RANGE
 		light_set_t new_nearby_lights;
 		for (LLDrawable::drawable_set_t::iterator iter = mLights.begin();
@@ -5169,8 +5663,6 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 	tc1.setVec(0,0);
 	tc2.setVec(2,2);
 
-
-
 	// power of two between 1 and 1024
 	U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow");
 	const U32 glow_res = llmax(1, 
@@ -5245,15 +5737,40 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 	gGLViewport[3] = gViewerWindow->getWorldViewRect().getHeight();
 	glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
 
+	tc2.setVec((F32) gViewerWindow->getWorldViewWidth(),
+			(F32) gViewerWindow->getWorldViewHeight());
+
 	gGL.flush();
 	
+	LLVertexBuffer::unbind();
+
+	if (LLPipeline::sRenderDeferred && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
 	{
-		LLVertexBuffer::unbind();
+		LLGLDisable blend(GL_BLEND);
+		bindDeferredShader(gDeferredGIFinalProgram);
+
+		S32 channel = gDeferredGIFinalProgram.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+		if (channel > -1)
+		{
+			mScreen.bindTexture(0, channel);
+		}
 
+		gGL.begin(LLRender::TRIANGLE_STRIP);
+		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+		gGL.vertex2f(-1,-1);
 		
+		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+		gGL.vertex2f(-1,3);
 		
-		tc2.setVec((F32) gViewerWindow->getWorldViewWidth(),
-			(F32) gViewerWindow->getWorldViewHeight());
+		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+		gGL.vertex2f(3,-1);
+		
+		gGL.end();
+
+		unbindDeferredShader(gDeferredGIFinalProgram);
+	}
+	else
+	{
 
 		if (res_mod > 1)
 		{
@@ -5294,7 +5811,8 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 		gGL.getTexUnit(0)->bind(&mGlow[1]);
 		gGL.getTexUnit(1)->activate();
 		gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE);
-		
+
+
 		//tex unit 1
 		gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
 		
@@ -5313,6 +5831,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 	}
 	
+
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	glMatrixMode(GL_PROJECTION);
 	glPopMatrix();
@@ -5326,108 +5845,320 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 
 }
 
-void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index)
+void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map)
 {
+	if (noise_map == 0xFFFFFFFF)
+	{
+		noise_map = mNoiseMap;
+	}
+
+	LLGLState::checkTextureChannels();
+
 	shader.bind();
 	S32 channel = 0;
 	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
 	if (channel > -1)
 	{
 		mDeferredScreen.bindTexture(0,channel);
-		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-		//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 	}
 
 	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
 	if (channel > -1)
 	{
 		mDeferredScreen.bindTexture(1, channel);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 	}
 
 	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
 	if (channel > -1)
 	{
 		mDeferredScreen.bindTexture(2, channel);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 	}
 
-	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
-	if (channel > -1)
-	{
-		mDeferredScreen.bindTexture(3, channel);
-	}
-
-	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
-	if (channel > -1)
-	{
-		gGL.getTexUnit(channel)->bind(&mDeferredScreen, TRUE);
-	}
-
-	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
-	if (channel > -1)
-	{
-		gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
-	}
-
-	stop_glerror();
-
-	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
-	if (channel > -1)
-	{
-		mDeferredLight[light_index].bindTexture(0, channel);
-	}
-
-	stop_glerror();
-
-	for (U32 i = 0; i < 4; i++)
+	if (gi_source)
 	{
-		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i);
-		stop_glerror();
+		BOOL has_gi = FALSE;
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
 		if (channel > -1)
 		{
-			stop_glerror();
-			gGL.getTexUnit(channel)->bind(&mSunShadow[i], TRUE);
+			has_gi = TRUE;
+			gi_source->bindTexture(0, channel);
 			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
-			stop_glerror();
-			
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
-			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
-			stop_glerror();
 		}
-	}
-
-	stop_glerror();
-
-	F32 mat[64];
-	for (U32 i = 0; i < 16; i++)
-	{
-		mat[i] = mSunShadowMatrix[0].m[i];
-		mat[i+16] = mSunShadowMatrix[1].m[i];
-		mat[i+32] = mSunShadowMatrix[2].m[i];
-		mat[i+48] = mSunShadowMatrix[3].m[i];
-	}
-
-	shader.uniformMatrix4fv("shadow_matrix[0]", 4, FALSE, mat);
-	shader.uniformMatrix4fv("shadow_matrix", 4, FALSE, mat);
-
-	stop_glerror();
-
-	channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
-	if (channel > -1)
-	{
-		LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
-		if (cube_map)
-		{
-			cube_map->enable(channel);
-			cube_map->bind();
-			F64* m = gGLModelView;
-
-			
-			F32 mat[] = { m[0], m[1], m[2],
-						  m[4], m[5], m[6],
-						  m[8], m[9], m[10] };
 		
-			shader.uniform3fv("env_mat[0]", 3, mat);
-			shader.uniform3fv("env_mat", 3, mat);
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			gi_source->bindTexture(1, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			gi_source->bindTexture(2, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			gi_source->bindTexture(1, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			gi_source->bindTexture(3, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			last_gi_post->bindTexture(0, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			last_gi_post->bindTexture(2, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			last_gi_post->bindTexture(1, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			last_gi_post->bindTexture(3, channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+		}
+		
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
+		if (channel > -1)
+		{
+			has_gi = TRUE;
+			gGL.getTexUnit(channel)->bind(gi_source, TRUE);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+			stop_glerror();
+			
+			glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);		
+			glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);		
+
+			stop_glerror();
+		}
+
+		if (has_gi)
+		{
+			F32 range_x = llmin(mGIRange.mV[0], 1.f);
+			F32 range_y = llmin(mGIRange.mV[1], 1.f);
+
+			LLVector2 scale(range_x,range_y);
+
+			LLVector2 kern[25];
+
+			for (S32 i = 0; i < 5; ++i)
+			{
+				for (S32 j = 0; j < 5; ++j)
+				{
+					S32 idx = i*5+j;
+					kern[idx].mV[0] = (i-2)*0.5f;
+					kern[idx].mV[1] = (j-2)*0.5f;
+					kern[idx].scaleVec(scale);
+				}
+			}
+
+			shader.uniform2fv("gi_kern", 25, (F32*) kern);
+			shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m);
+			shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m);
+			shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m);
+			shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m);
+		}
+	}
+	
+	/*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredScreen.bindTexture(3, channel);
+	}*/
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		stop_glerror();
+		
+		glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);		
+		glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);		
+
+		stop_glerror();
+
+		glh::matrix4f projection = glh_get_current_projection();
+		glh::matrix4f inv_proj = projection.inverse();
+		
+		shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m);
+		shader.uniform4f("viewport", (F32) gGLViewport[0],
+									(F32) gGLViewport[1],
+									(F32) gGLViewport[2],
+									(F32) gGLViewport[3]);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+	if (channel > -1)
+	{
+		gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
+	if (channel > -1)
+	{
+		gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+	}
+
+	stop_glerror();
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredLight[light_index].bindTexture(0, channel);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
+	if (channel > -1)
+	{
+		gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
+	if (channel > -1)
+	{
+		mGlow[1].bindTexture(0, channel);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		gi_source->bindTexture(0, channel);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mEdgeMap.bindTexture(0, channel);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredLight[1].bindTexture(0, channel);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	}
+
+	channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	if (channel > -1)
+	{
+		mDeferredLight[2].bindTexture(0, channel);
+		gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	}
+
+
+	stop_glerror();
+
+	for (U32 i = 0; i < 4; i++)
+	{
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE);
+		stop_glerror();
+		if (channel > -1)
+		{
+			stop_glerror();
+			gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+			gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+			stop_glerror();
+			
+			glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+			glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+			stop_glerror();
+		}
+	}
+
+	for (U32 i = 4; i < 6; i++)
+	{
+		channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i);
+		stop_glerror();
+		if (channel > -1)
+		{
+			stop_glerror();
+			gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+			gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+			stop_glerror();
+			
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+			stop_glerror();
+		}
+	}
+
+	stop_glerror();
+
+	F32 mat[16*6];
+	for (U32 i = 0; i < 16; i++)
+	{
+		mat[i] = mSunShadowMatrix[0].m[i];
+		mat[i+16] = mSunShadowMatrix[1].m[i];
+		mat[i+32] = mSunShadowMatrix[2].m[i];
+		mat[i+48] = mSunShadowMatrix[3].m[i];
+		mat[i+64] = mSunShadowMatrix[4].m[i];
+		mat[i+80] = mSunShadowMatrix[5].m[i];
+	}
+
+	shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat);
+	shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat);
+
+	stop_glerror();
+
+	channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+	if (channel > -1)
+	{
+		LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+		if (cube_map)
+		{
+			cube_map->enable(channel);
+			cube_map->bind();
+			F64* m = gGLModelView;
+
+			
+			F32 mat[] = { m[0], m[1], m[2],
+						  m[4], m[5], m[6],
+						  m[8], m[9], m[10] };
+		
+			shader.uniform3fv("env_mat[0]", 3, mat);
+			shader.uniform3fv("env_mat", 3, mat);
 		}
 	}
 
@@ -5456,7 +6187,44 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index)
 	shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
 	shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f);
 	shader.uniform1f("alpha_soften", gSavedSettings.getF32("RenderDeferredAlphaSoften"));
-}
+	shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset"));
+	shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias"));
+	shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale"));
+	shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale"));
+	shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset"));
+	shader.uniform1f("lum_lod", gSavedSettings.getF32("RenderLuminanceDetail"));
+	shader.uniform1f("gi_range", gSavedSettings.getF32("RenderGIRange"));
+	shader.uniform1f("gi_brightness", gSavedSettings.getF32("RenderGIBrightness"));
+	shader.uniform1f("gi_luminance", gSavedSettings.getF32("RenderGILuminance"));
+	shader.uniform1f("gi_edge_weight", gSavedSettings.getF32("RenderGIBlurEdgeWeight"));
+	shader.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
+	shader.uniform1f("gi_sample_width", mGILightRadius);
+	shader.uniform1f("gi_noise", gSavedSettings.getF32("RenderGINoise"));
+	shader.uniform1f("gi_attenuation", gSavedSettings.getF32("RenderGIAttenuation"));
+	shader.uniform1f("gi_ambiance", gSavedSettings.getF32("RenderGIAmbiance"));
+	shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight());
+	shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight());
+	shader.uniform1f("depth_cutoff", gSavedSettings.getF32("RenderEdgeDepthCutoff"));
+	shader.uniform1f("norm_cutoff", gSavedSettings.getF32("RenderEdgeNormCutoff"));
+
+	if (shader.getUniformLocation("norm_mat") >= 0)
+	{
+		glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
+		shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m);
+	}
+}
+
+static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
+static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
+static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
+static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften");
+static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges");
+static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights");
+static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics");
+static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
+static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors");
+static LLFastTimer::DeclareTimer FTM_POST("Post");
+
 
 void LLPipeline::renderDeferredLighting()
 {
@@ -5465,335 +6233,673 @@ void LLPipeline::renderDeferredLighting()
 		return;
 	}
 
-	LLGLEnable multisample(GL_MULTISAMPLE_ARB);
-
-	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
 	{
-		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
-	}
-
-	//ati doesn't seem to love actually using the stencil buffer on FBO's
-	LLGLEnable stencil(GL_STENCIL_TEST);
-	glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
-	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+		LLFastTimer ftm(FTM_RENDER_DEFERRED);
 
-	gGL.setColorMask(true, true);
+		{
+			LLGLDepthTest depth(GL_TRUE);
+			mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+							0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);	
+		}
 
-	mDeferredLight[0].bindTarget();
+		LLGLEnable multisample(GL_MULTISAMPLE_ARB);
 
-	//mDeferredLight[0].copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
-	//					0, 0, mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);	
-	
-	//draw a cube around every light
-	LLVertexBuffer::unbind();
+		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+		{
+			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+		}
 
-	glBlendFunc(GL_ONE, GL_ONE);
-	LLGLEnable cull(GL_CULL_FACE);
-	LLGLEnable blend(GL_BLEND);
+		//ati doesn't seem to love actually using the stencil buffer on FBO's
+		LLGLEnable stencil(GL_STENCIL_TEST);
+		glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
+		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 
-	glh::matrix4f mat = glh_copy_matrix(gGLModelView);
+		gGL.setColorMask(true, true);
+		
+		//draw a cube around every light
+		LLVertexBuffer::unbind();
 
-	F32 vert[] = 
-	{
-		-1,1,
-		-1,-3,
-		3,1,
-	};
+		LLGLEnable cull(GL_CULL_FACE);
+		LLGLEnable blend(GL_BLEND);
 
-	bindDeferredShader(gDeferredSunProgram);
+		glh::matrix4f mat = glh_copy_matrix(gGLModelView);
 
-	glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
+		F32 vert[] = 
+		{
+			-1,1,
+			-1,-3,
+			3,1,
+		};
+		glVertexPointer(2, GL_FLOAT, 0, vert);
+		glColor3f(1,1,1);
 
-	const U32 slice = 32;
-	F32 offset[slice*3];
-	for (U32 i = 0; i < 4; i++)
-	{
-		for (U32 j = 0; j < 8; j++)
 		{
-			glh::vec3f v;
-			v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
-			v.normalize();
-			inv_trans.mult_matrix_vec(v);
-			v.normalize();
-			offset[(i*8+j)*3+0] = v.v[0];
-			offset[(i*8+j)*3+1] = v.v[2];
-			offset[(i*8+j)*3+2] = v.v[1];
+			setupHWLights(NULL); //to set mSunDir;
+			LLVector4 dir(mSunDir, 0.f);
+			glh::vec4f tc(dir.mV);
+			mat.mult_matrix_vec(tc);
+			glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
 		}
-	}
 
-	gDeferredSunProgram.uniform3fv("offset", slice, offset);
-	gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
-
-	setupHWLights(NULL); //to set mSunDir;
+		if (gSavedSettings.getBOOL("RenderDeferredShadow"))
+		{
+			glPushMatrix();
+			glLoadIdentity();
+			glMatrixMode(GL_PROJECTION);
+			glPushMatrix();
+			glLoadIdentity();
 
-	glPushMatrix();
-	glLoadIdentity();
-	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
-	glLoadIdentity();
+			mDeferredLight[0].bindTarget();
+			if (gSavedSettings.getBOOL("RenderDeferredSun"))
+			{ //paint shadow/SSAO light map (direct lighting lightmap)
+				LLFastTimer ftm(FTM_SUN_SHADOW);
+				bindDeferredShader(gDeferredSunProgram, 0);
 
-	LLVector4 dir(mSunDir, 0.f);
+				glClearColor(1,1,1,1);
+				mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
+				glClearColor(0,0,0,0);
 
-	glh::vec4f tc(dir.mV);
-	mat.mult_matrix_vec(tc);
-	glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
-	glColor3f(1,1,1);
+				glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
 
-	glVertexPointer(2, GL_FLOAT, 0, vert);
-	{
-		LLGLDisable blend(GL_BLEND);
-		LLGLDepthTest depth(GL_FALSE);
-		stop_glerror();
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
-		stop_glerror();
-	}
-	
-	unbindDeferredShader(gDeferredSunProgram);
+				const U32 slice = 32;
+				F32 offset[slice*3];
+				for (U32 i = 0; i < 4; i++)
+				{
+					for (U32 j = 0; j < 8; j++)
+					{
+						glh::vec3f v;
+						v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
+						v.normalize();
+						inv_trans.mult_matrix_vec(v);
+						v.normalize();
+						offset[(i*8+j)*3+0] = v.v[0];
+						offset[(i*8+j)*3+1] = v.v[2];
+						offset[(i*8+j)*3+2] = v.v[1];
+					}
+				}
 
-	mDeferredLight[0].flush();
+				gDeferredSunProgram.uniform3fv("offset", slice, offset);
+				gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
+				
+				{
+					LLGLDisable blend(GL_BLEND);
+					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+					stop_glerror();
+					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+					stop_glerror();
+				}
+				
+				unbindDeferredShader(gDeferredSunProgram);
+			}
+			else
+			{
+				mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
+			}
 
-	//blur lightmap
-	mDeferredLight[1].bindTarget();
+			mDeferredLight[0].flush();
 
-	//mDeferredLight[1].copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
-	//					0, 0, mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);	
-	
-	bindDeferredShader(gDeferredBlurLightProgram);
+			if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
+			{
+				LLFastTimer ftm(FTM_EDGE_DETECTION);
+				//get edge map
+				LLGLDisable blend(GL_BLEND);
+				LLGLDisable test(GL_ALPHA_TEST);
+				LLGLDepthTest depth(GL_FALSE);
+				LLGLDisable stencil(GL_STENCIL_TEST);
 
-	LLVector3 gauss[32]; // xweight, yweight, offset
+				{
+					gDeferredEdgeProgram.bind();
+					mEdgeMap.bindTarget();
+					bindDeferredShader(gDeferredEdgeProgram);
+					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+					unbindDeferredShader(gDeferredEdgeProgram);
+					mEdgeMap.flush();
+				}
+			}
 
-	LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
-	U32 kern_length = llclamp(gSavedSettings.getU32("RenderShadowBlurSamples"), (U32) 1, (U32) 16)*2 - 1;
-	F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
+			if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+			{
+				{ //get luminance map from previous frame's light map
+					LLGLEnable blend(GL_BLEND);
+					LLGLDisable test(GL_ALPHA_TEST);
+					LLGLDepthTest depth(GL_FALSE);
+					LLGLDisable stencil(GL_STENCIL_TEST);
 
-	// sample symmetrically with the middle sample falling exactly on 0.0
-	F32 x = -(kern_length/2.0f) + 0.5f;
+					//static F32 fade = 1.f;
 
-	for (U32 i = 0; i < kern_length; i++)
-	{
-		gauss[i].mV[0] = llgaussian(x, go.mV[0]);
-		gauss[i].mV[1] = llgaussian(x, go.mV[1]);
-		gauss[i].mV[2] = x;
-		x += 1.f;
-	}
-	/* swap the x=0 position to the start of gauss[] so we can
-	   treat it specially as an optimization. */
-	LLVector3 swap;
-	swap = gauss[kern_length/2];
-	gauss[kern_length/2] = gauss[0];
-	gauss[0] = swap;
-	llassert(gauss[0].mV[2] == 0.0f);
+					{
+						gGL.setSceneBlendType(LLRender::BT_ALPHA);
+						gLuminanceGatherProgram.bind();
+						gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
+						mLuminanceMap.bindTarget();
+						bindDeferredShader(gLuminanceGatherProgram);
+						glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+						unbindDeferredShader(gLuminanceGatherProgram);
+						mLuminanceMap.flush();
+						gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
+						gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+						glGenerateMipmapEXT(GL_TEXTURE_2D);
+					}
+				}
 
-	gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
-	gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
-	gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
-	gDeferredBlurLightProgram.uniform1i("kern_length", kern_length);
-	gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+				{ //paint noisy GI map (bounce lighting lightmap)
+					LLFastTimer ftm(FTM_GI_TRACE);
+					LLGLDisable blend(GL_BLEND);
+					LLGLDepthTest depth(GL_FALSE);
+					LLGLDisable test(GL_ALPHA_TEST);
 
-	{
-		LLGLDisable blend(GL_BLEND);
-		LLGLDepthTest depth(GL_FALSE);
-		stop_glerror();
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
-		stop_glerror();
-	}
-	
-	mDeferredLight[1].flush();
-	unbindDeferredShader(gDeferredBlurLightProgram);
+					mGIMapPost[0].bindTarget();
 
-	bindDeferredShader(gDeferredBlurLightProgram, 1);
-	mDeferredLight[0].bindTarget();
+					bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap);
+					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+					unbindDeferredShader(gDeferredGIProgram);
+					mGIMapPost[0].flush();
+				}
 
-	gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
-	gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
-	gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
-	gDeferredBlurLightProgram.uniform1i("kern_length", kern_length);
-	gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+				U32 pass_count = 0;
+				if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
+				{
+					pass_count = llclamp(gSavedSettings.getU32("RenderGIBlurPasses"), (U32) 1, (U32) 128);
+				}
 
-	{
-		LLGLDisable blend(GL_BLEND);
-		LLGLDepthTest depth(GL_FALSE);
-		stop_glerror();
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-		stop_glerror();
-	}
-	mDeferredLight[0].flush();
-	unbindDeferredShader(gDeferredBlurLightProgram);
+				for (U32 i = 0; i < pass_count; ++i)
+				{ //gather/soften indirect lighting map
+					LLFastTimer ftm(FTM_GI_GATHER);
+					bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap);
+					F32 blur_size = gSavedSettings.getF32("RenderGIBlurSize")/((F32) i * gSavedSettings.getF32("RenderGIBlurIncrement")+1.f);
+					gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f);
+					gDeferredPostGIProgram.uniform1f("kern_scale", blur_size);
+					gDeferredPostGIProgram.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
+				
+					mGIMapPost[1].bindTarget();
+					{
+						LLGLDisable blend(GL_BLEND);
+						LLGLDepthTest depth(GL_FALSE);
+						stop_glerror();
+						glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+						stop_glerror();
+					}
+					
+					mGIMapPost[1].flush();
+					unbindDeferredShader(gDeferredPostGIProgram);
+					bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap);
+					mGIMapPost[0].bindTarget();
 
-	stop_glerror();
-	glPopMatrix();
-	stop_glerror();
-	glMatrixMode(GL_MODELVIEW);
-	stop_glerror();
-	glPopMatrix();
-	stop_glerror();
+					gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f);
 
-	//copy depth and stencil from deferred screen
-	//mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
-	//					0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+					{
+						LLGLDisable blend(GL_BLEND);
+						LLGLDepthTest depth(GL_FALSE);
+						stop_glerror();
+						glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+						stop_glerror();
+					}
+					mGIMapPost[0].flush();
+					unbindDeferredShader(gDeferredPostGIProgram);
+				}
+			}
 
-	mScreen.bindTarget();
-	mScreen.clear(GL_COLOR_BUFFER_BIT);
-		
-	bindDeferredShader(gDeferredSoftenProgram);	
-	{
-		LLGLDepthTest depth(GL_FALSE);
-		LLGLDisable blend(GL_BLEND);
-		LLGLDisable test(GL_ALPHA_TEST);
+			if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
+			{ //soften direct lighting lightmap
+				LLFastTimer ftm(FTM_SOFTEN_SHADOW);
+				//blur lightmap
+				mDeferredLight[1].bindTarget();
 
-		//full screen blit
-		glPushMatrix();
-		glLoadIdentity();
-		glMatrixMode(GL_PROJECTION);
-		glPushMatrix();
-		glLoadIdentity();
+				glClearColor(1,1,1,1);
+				mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
+				glClearColor(0,0,0,0);
+				
+				bindDeferredShader(gDeferredBlurLightProgram);
 
-		glVertexPointer(2, GL_FLOAT, 0, vert);
-		
-		glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
-		
-		glPopMatrix();
-		glMatrixMode(GL_MODELVIEW);
-		glPopMatrix();
-	}
+				LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
+				const U32 kern_length = 4;
+				F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
+				F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
 
-	unbindDeferredShader(gDeferredSoftenProgram);
+				// sample symmetrically with the middle sample falling exactly on 0.0
+				F32 x = 0.f;
 
-	bindDeferredShader(gDeferredLightProgram);
+				LLVector3 gauss[32]; // xweight, yweight, offset
 
-	std::list<LLVector4> fullscreen_lights;
-	std::list<LLVector4> light_colors;
+				for (U32 i = 0; i < kern_length; i++)
+				{
+					gauss[i].mV[0] = llgaussian(x, go.mV[0]);
+					gauss[i].mV[1] = llgaussian(x, go.mV[1]);
+					gauss[i].mV[2] = x;
+					x += 1.f;
+				}
 
-	F32 v[24];
-	glVertexPointer(3, GL_FLOAT, 0, v);
-	{
-		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-		for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
-		{
-			LLDrawable* drawablep = *iter;
+				gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
+				gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
+				gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
+				gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
+				gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
 			
-			LLVOVolume* volume = drawablep->getVOVolume();
-			if (!volume)
-			{
-				continue;
+				{
+					LLGLDisable blend(GL_BLEND);
+					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+					stop_glerror();
+					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+					stop_glerror();
+				}
+				
+				mDeferredLight[1].flush();
+				unbindDeferredShader(gDeferredBlurLightProgram);
+
+				bindDeferredShader(gDeferredBlurLightProgram, 1);
+				mDeferredLight[0].bindTarget();
+
+				gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
+
+				{
+					LLGLDisable blend(GL_BLEND);
+					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+					stop_glerror();
+					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+					stop_glerror();
+				}
+				mDeferredLight[0].flush();
+				unbindDeferredShader(gDeferredBlurLightProgram);
 			}
 
-			LLVector3 center = drawablep->getPositionAgent();
-			F32* c = center.mV;
-			F32 s = volume->getLightRadius()*1.5f;
+			stop_glerror();
+			glPopMatrix();
+			stop_glerror();
+			glMatrixMode(GL_MODELVIEW);
+			stop_glerror();
+			glPopMatrix();
+			stop_glerror();
+		}
+
+		//copy depth and stencil from deferred screen
+		//mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+		//					0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+
+		if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+		{
+			mDeferredLight[1].bindTarget();
+			mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
+		}
+		else
+		{
+			mScreen.bindTarget();
+			mScreen.clear(GL_COLOR_BUFFER_BIT);
+		}
 
-			if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
+		if (gSavedSettings.getBOOL("RenderDeferredAtmospheric"))
+		{ //apply sunlight contribution 
+			LLFastTimer ftm(FTM_ATMOSPHERICS);
+			bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]);	
 			{
-				continue;
+				LLGLDepthTest depth(GL_FALSE);
+				LLGLDisable blend(GL_BLEND);
+				LLGLDisable test(GL_ALPHA_TEST);
+
+				//full screen blit
+				glPushMatrix();
+				glLoadIdentity();
+				glMatrixMode(GL_PROJECTION);
+				glPushMatrix();
+				glLoadIdentity();
+
+				glVertexPointer(2, GL_FLOAT, 0, vert);
+				
+				glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+				
+				glPopMatrix();
+				glMatrixMode(GL_MODELVIEW);
+				glPopMatrix();
 			}
 
-			sVisibleLightCount++;
-			glh::vec3f tc(c);
-			mat.mult_matrix_vec(tc);
+			unbindDeferredShader(gDeferredSoftenProgram);
+		}
+
+		{ //render sky
+			LLGLDisable blend(GL_BLEND);
+			LLGLDisable stencil(GL_STENCIL_TEST);
+			gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+			U32 render_mask = mRenderTypeMask;
+			mRenderTypeMask =	mRenderTypeMask & 
+								((1 << LLPipeline::RENDER_TYPE_SKY) |
+								(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
+								(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+								
 			
-			LLColor3 col = volume->getLightColor();
-			col *= volume->getLightIntensity();
-
-			//vertex positions are encoded so the 3 bits of their vertex index 
-			//correspond to their axis facing, with bit position 3,2,1 matching
-			//axis facing x,y,z, bit set meaning positive facing, bit clear 
-			//meaning negative facing
-			v[0] = c[0]-s; v[1]  = c[1]-s; v[2]  = c[2]-s;  // 0 - 0000 
-			v[3] = c[0]-s; v[4]  = c[1]-s; v[5]  = c[2]+s;  // 1 - 0001
-			v[6] = c[0]-s; v[7]  = c[1]+s; v[8]  = c[2]-s;  // 2 - 0010
-			v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s;  // 3 - 0011
-																							   
-			v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
-			v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
-			v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
-			v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
-
-			if (LLViewerCamera::getInstance()->getOrigin().mV[0] > c[0] + s + 0.2f ||
-				LLViewerCamera::getInstance()->getOrigin().mV[0] < c[0] - s - 0.2f ||
-				LLViewerCamera::getInstance()->getOrigin().mV[1] > c[1] + s + 0.2f ||
-				LLViewerCamera::getInstance()->getOrigin().mV[1] < c[1] - s - 0.2f ||
-				LLViewerCamera::getInstance()->getOrigin().mV[2] > c[2] + s + 0.2f ||
-				LLViewerCamera::getInstance()->getOrigin().mV[2] < c[2] - s - 0.2f)
-			{ //draw box if camera is outside box
-				glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
-				glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
-				glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
-					GL_UNSIGNED_BYTE, get_box_fan_indices(LLViewerCamera::getInstance(), center));
+			renderGeomPostDeferred(*LLViewerCamera::getInstance());
+			mRenderTypeMask = render_mask;
+		}
+
+		BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
+		BOOL render_fullscreen = gSavedSettings.getBOOL("RenderDeferredFullscreenLights");
+		
+
+		if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+		{
+			mDeferredLight[1].flush();
+			mDeferredLight[2].bindTarget();
+			mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT);
+		}
+
+		if (render_local || render_fullscreen)
+		{
+			gGL.setSceneBlendType(LLRender::BT_ADD);
+			std::list<LLVector4> fullscreen_lights;
+			LLDrawable::drawable_list_t spot_lights;
+			LLDrawable::drawable_list_t fullscreen_spot_lights;
+
+			for (U32 i = 0; i < 2; i++)
+			{
+				mTargetShadowSpotLight[i] = NULL;
 			}
-			else
-			{	
-				fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
-				light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+
+			std::list<LLVector4> light_colors;
+
+			F32 v[24];
+			glVertexPointer(3, GL_FLOAT, 0, v);
+			BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
+
+			{
+				bindDeferredShader(gDeferredLightProgram);
+				LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+				for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
+				{
+					LLDrawable* drawablep = *iter;
+					
+					LLVOVolume* volume = drawablep->getVOVolume();
+					if (!volume)
+					{
+						continue;
+					}
+
+					LLVector3 center = drawablep->getPositionAgent();
+					F32* c = center.mV;
+					F32 s = volume->getLightRadius()*1.5f;
+
+					LLColor3 col = volume->getLightColor();
+					col *= volume->getLightIntensity();
+
+					if (col.magVecSquared() < 0.001f)
+					{
+						continue;
+					}
+
+					if (s <= 0.001f)
+					{
+						continue;
+					}
+
+					if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
+					{
+						continue;
+					}
+
+					sVisibleLightCount++;
+
+					glh::vec3f tc(c);
+					mat.mult_matrix_vec(tc);
+					
+					//vertex positions are encoded so the 3 bits of their vertex index 
+					//correspond to their axis facing, with bit position 3,2,1 matching
+					//axis facing x,y,z, bit set meaning positive facing, bit clear 
+					//meaning negative facing
+					v[0] = c[0]-s; v[1]  = c[1]-s; v[2]  = c[2]-s;  // 0 - 0000 
+					v[3] = c[0]-s; v[4]  = c[1]-s; v[5]  = c[2]+s;  // 1 - 0001
+					v[6] = c[0]-s; v[7]  = c[1]+s; v[8]  = c[2]-s;  // 2 - 0010
+					v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s;  // 3 - 0011
+																									   
+					v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+					v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+					v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+					v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+					if (LLViewerCamera::getInstance()->getOrigin().mV[0] > c[0] + s + 0.2f ||
+						LLViewerCamera::getInstance()->getOrigin().mV[0] < c[0] - s - 0.2f ||
+						LLViewerCamera::getInstance()->getOrigin().mV[1] > c[1] + s + 0.2f ||
+						LLViewerCamera::getInstance()->getOrigin().mV[1] < c[1] - s - 0.2f ||
+						LLViewerCamera::getInstance()->getOrigin().mV[2] > c[2] + s + 0.2f ||
+						LLViewerCamera::getInstance()->getOrigin().mV[2] < c[2] - s - 0.2f)
+					{ //draw box if camera is outside box
+						if (render_local)
+						{
+							if (volume->getLightTexture())
+							{
+								drawablep->getVOVolume()->updateSpotLightPriority();
+								spot_lights.push_back(drawablep);
+								continue;
+							}
+							
+							LLFastTimer ftm(FTM_LOCAL_LIGHTS);
+							glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+							glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+							glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+								GL_UNSIGNED_BYTE, get_box_fan_indices(LLViewerCamera::getInstance(), center));
+							stop_glerror();
+						}
+					}
+					else if (render_fullscreen)
+					{	
+						if (volume->getLightTexture())
+						{
+							drawablep->getVOVolume()->updateSpotLightPriority();
+							fullscreen_spot_lights.push_back(drawablep);
+							continue;
+						}
+
+						fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
+						light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+					}
+				}
+				unbindDeferredShader(gDeferredLightProgram);
 			}
-		}
-	}
 
-	unbindDeferredShader(gDeferredLightProgram);
+			if (!spot_lights.empty())
+			{
+				LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+				bindDeferredShader(gDeferredSpotLightProgram);
 
-	if (!fullscreen_lights.empty())
-	{
-		bindDeferredShader(gDeferredMultiLightProgram);
-		LLGLDepthTest depth(GL_FALSE);
+				gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
 
-		//full screen blit
-		glPushMatrix();
-		glLoadIdentity();
-		glMatrixMode(GL_PROJECTION);
-		glPushMatrix();
-		glLoadIdentity();
+				for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
+				{
+					LLFastTimer ftm(FTM_PROJECTORS);
+					LLDrawable* drawablep = *iter;
 
-		U32 count = 0;
+					LLVOVolume* volume = drawablep->getVOVolume();
 
-		LLVector4 light[16];
-		LLVector4 col[16];
+					LLVector3 center = drawablep->getPositionAgent();
+					F32* c = center.mV;
+					F32 s = volume->getLightRadius()*1.5f;
 
-		glVertexPointer(2, GL_FLOAT, 0, vert);
+					sVisibleLightCount++;
 
-		while (!fullscreen_lights.empty())
-		{
-			light[count] = fullscreen_lights.front();
-			fullscreen_lights.pop_front();
-			col[count] = light_colors.front();
-			light_colors.pop_front();
+					glh::vec3f tc(c);
+					mat.mult_matrix_vec(tc);
+					
+					setupSpotLight(gDeferredSpotLightProgram, drawablep);
+					
+					LLColor3 col = volume->getLightColor();
+					col *= volume->getLightIntensity();
+
+					//vertex positions are encoded so the 3 bits of their vertex index 
+					//correspond to their axis facing, with bit position 3,2,1 matching
+					//axis facing x,y,z, bit set meaning positive facing, bit clear 
+					//meaning negative facing
+					v[0] = c[0]-s; v[1]  = c[1]-s; v[2]  = c[2]-s;  // 0 - 0000 
+					v[3] = c[0]-s; v[4]  = c[1]-s; v[5]  = c[2]+s;  // 1 - 0001
+					v[6] = c[0]-s; v[7]  = c[1]+s; v[8]  = c[2]-s;  // 2 - 0010
+					v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s;  // 3 - 0011
+																									   
+					v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+					v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+					v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+					v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+					glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+					glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+							GL_UNSIGNED_BYTE, get_box_fan_indices(LLViewerCamera::getInstance(), center));
+				}
+				gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+				unbindDeferredShader(gDeferredSpotLightProgram);
+			}
 
-			count++;
-			if (count == 16 || fullscreen_lights.empty())
 			{
-				gDeferredMultiLightProgram.uniform1i("light_count", count);
-				gDeferredMultiLightProgram.uniform4fv("light[0]", count, (GLfloat*) light);
-				gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
-				gDeferredMultiLightProgram.uniform4fv("light_col[0]", count, (GLfloat*) col);
-				gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
-				count = 0;
-				glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+				bindDeferredShader(gDeferredMultiLightProgram);
+			
+				LLGLDepthTest depth(GL_FALSE);
+
+				//full screen blit
+				glPushMatrix();
+				glLoadIdentity();
+				glMatrixMode(GL_PROJECTION);
+				glPushMatrix();
+				glLoadIdentity();
+
+				U32 count = 0;
+
+				const U32 max_count = 8;
+				LLVector4 light[max_count];
+				LLVector4 col[max_count];
+
+				glVertexPointer(2, GL_FLOAT, 0, vert);
+
+				F32 far_z = 0.f;
+
+				while (!fullscreen_lights.empty())
+				{
+					LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
+					light[count] = fullscreen_lights.front();
+					fullscreen_lights.pop_front();
+					col[count] = light_colors.front();
+					light_colors.pop_front();
+
+					far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
+
+					count++;
+					if (count == max_count || fullscreen_lights.empty())
+					{
+						gDeferredMultiLightProgram.uniform1i("light_count", count);
+						gDeferredMultiLightProgram.uniform4fv("light[0]", count, (GLfloat*) light);
+						gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
+						gDeferredMultiLightProgram.uniform4fv("light_col[0]", count, (GLfloat*) col);
+						gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
+						gDeferredMultiLightProgram.uniform1f("far_z", far_z);
+						far_z = 0.f;
+						count = 0;
+						glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+					}
+				}
+				
+				unbindDeferredShader(gDeferredMultiLightProgram);
+
+				bindDeferredShader(gDeferredMultiSpotLightProgram);
+
+				gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+				for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
+				{
+					LLFastTimer ftm(FTM_PROJECTORS);
+					LLDrawable* drawablep = *iter;
+					
+					LLVOVolume* volume = drawablep->getVOVolume();
+
+					LLVector3 center = drawablep->getPositionAgent();
+					F32* c = center.mV;
+					F32 s = volume->getLightRadius()*1.5f;
+
+					sVisibleLightCount++;
+
+					glh::vec3f tc(c);
+					mat.mult_matrix_vec(tc);
+					
+					setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
+
+					LLColor3 col = volume->getLightColor();
+					col *= volume->getLightIntensity();
+
+					glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+					glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+				}
+
+				gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+				unbindDeferredShader(gDeferredMultiSpotLightProgram);
+
+				glPopMatrix();
+				glMatrixMode(GL_MODELVIEW);
+				glPopMatrix();
 			}
 		}
+
+		gGL.setColorMask(true, true);
+
+		if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+		{
+			mDeferredLight[2].flush();
+
+			mScreen.bindTarget();
+			mScreen.clear(GL_COLOR_BUFFER_BIT);
 		
-		
-		glPopMatrix();
-		glMatrixMode(GL_MODELVIEW);
-		glPopMatrix();
+			gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+			{ //mix various light maps (local, sun, gi)
+				LLFastTimer ftm(FTM_POST);
+				LLGLDisable blend(GL_BLEND);
+				LLGLDisable test(GL_ALPHA_TEST);
+				LLGLDepthTest depth(GL_FALSE);
+				LLGLDisable stencil(GL_STENCIL_TEST);
+			
+				bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]);
+
+				gDeferredPostProgram.bind();
+
+				LLVertexBuffer::unbind();
+
+				glVertexPointer(2, GL_FLOAT, 0, vert);
+				glColor3f(1,1,1);
 
-		unbindDeferredShader(gDeferredMultiLightProgram);
+				glPushMatrix();
+				glLoadIdentity();
+				glMatrixMode(GL_PROJECTION);
+				glPushMatrix();
+				glLoadIdentity();
+
+				glDrawArrays(GL_TRIANGLES, 0, 3);
+
+				glPopMatrix();
+				glMatrixMode(GL_MODELVIEW);
+				glPopMatrix();
+
+				unbindDeferredShader(gDeferredPostProgram);
+			}
+		}
 	}
-	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
-	{ //render non-deferred geometry
+	{ //render non-deferred geometry (alpha, fullbright, glow)
 		LLGLDisable blend(GL_BLEND);
 		LLGLDisable stencil(GL_STENCIL_TEST);
 
 		U32 render_mask = mRenderTypeMask;
 		mRenderTypeMask =	mRenderTypeMask & 
-							((1 << LLPipeline::RENDER_TYPE_SKY) |
-							(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
-							(1 << LLPipeline::RENDER_TYPE_WL_SKY) |
-							(1 << LLPipeline::RENDER_TYPE_ALPHA) |
-							(1 << LLPipeline::RENDER_TYPE_AVATAR) |
-							(1 << LLPipeline::RENDER_TYPE_WATER) |
+							((1 << LLPipeline::RENDER_TYPE_ALPHA) |
 							(1 << LLPipeline::RENDER_TYPE_FULLBRIGHT) |
 							(1 << LLPipeline::RENDER_TYPE_VOLUME) |
 							(1 << LLPipeline::RENDER_TYPE_GLOW) |
-							(1 << LLPipeline::RENDER_TYPE_BUMP));
+							(1 << LLPipeline::RENDER_TYPE_BUMP) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_GLOW) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_GRASS) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_INVISIBLE) |
+							(1 << LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY) |
+							(1 << LLPipeline::RENDER_TYPE_AVATAR));
 		
 		renderGeomPostDeferred(*LLViewerCamera::getInstance());
 		mRenderTypeMask = render_mask;
@@ -5803,6 +6909,136 @@ void LLPipeline::renderDeferredLighting()
 						
 }
 
+void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
+{
+	//construct frustum
+	LLVOVolume* volume = drawablep->getVOVolume();
+	LLVector3 params = volume->getSpotLightParams();
+
+	F32 fov = params.mV[0];
+	F32 focus = params.mV[1];
+
+	LLVector3 pos = drawablep->getPositionAgent();
+	LLQuaternion quat = volume->getRenderRotation();
+	LLVector3 scale = volume->getScale();
+	
+	//get near clip plane
+	LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+	at_axis *= quat;
+
+	LLVector3 np = pos+at_axis;
+	at_axis.normVec();
+
+	//get origin that has given fov for plane np, at_axis, and given scale
+	F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+	LLVector3 origin = np - at_axis*dist;
+
+	//matrix from volume space to agent space
+	LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
+
+	glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
+	glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
+
+	glh::matrix4f screen_to_light = light_to_screen.inverse();
+
+	F32 s = volume->getLightRadius()*1.5f;
+	F32 near_clip = dist;
+	F32 width = scale.mV[VX];
+	F32 height = scale.mV[VY];
+	F32 far_clip = s+dist-scale.mV[VZ];
+
+	F32 fovy = fov * RAD_TO_DEG;
+	F32 aspect = width/height;
+
+	glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+				0.f, 0.5f, 0.f, 0.5f,
+				0.f, 0.f, 0.5f, 0.5f,
+				0.f, 0.f, 0.f, 1.f);
+
+	glh::vec3f p1(0, 0, -(near_clip+0.01f));
+	glh::vec3f p2(0, 0, -(near_clip+1.f));
+
+	glh::vec3f screen_origin(0, 0, 0);
+
+	light_to_screen.mult_matrix_vec(p1);
+	light_to_screen.mult_matrix_vec(p2);
+	light_to_screen.mult_matrix_vec(screen_origin);
+
+	glh::vec3f n = p2-p1;
+	n.normalize();
+	
+	F32 proj_range = far_clip - near_clip;
+	glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
+	screen_to_light = trans * light_proj * screen_to_light;
+	shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m);
+	shader.uniform1f("proj_near", near_clip);
+	shader.uniform3fv("proj_p", 1, p1.v);
+	shader.uniform3fv("proj_n", 1, n.v);
+	shader.uniform3fv("proj_origin", 1, screen_origin.v);
+	shader.uniform1f("proj_range", proj_range);
+	shader.uniform1f("proj_ambiance", params.mV[2]);
+	S32 s_idx = -1;
+
+	for (U32 i = 0; i < 2; i++)
+	{
+		if (mShadowSpotLight[i] == drawablep)
+		{
+			s_idx = i;
+		}
+	}
+
+	shader.uniform1i("proj_shadow_idx", s_idx);
+
+	if (s_idx >= 0)
+	{
+		shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]);
+	}
+	else
+	{
+		shader.uniform1f("shadow_fade", 1.f);
+	}
+
+	{
+		LLDrawable* potential = drawablep;
+		//determine if this is a good light for casting shadows
+		F32 m_pri = volume->getSpotLightPriority();
+
+		for (U32 i = 0; i < 2; i++)
+		{
+			F32 pri = 0.f;
+
+			if (mTargetShadowSpotLight[i].notNull())
+			{
+				pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();			
+			}
+
+			if (m_pri > pri)
+			{
+				LLDrawable* temp = mTargetShadowSpotLight[i];
+				mTargetShadowSpotLight[i] = potential;
+				potential = temp;
+				m_pri = pri;
+			}
+		}
+	}
+
+	LLViewerTexture* img = volume->getLightTexture();
+
+	S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+	if (channel > -1 && img)
+	{
+		gGL.getTexUnit(channel)->bind(img);
+
+		F32 lod_range = logf(img->getWidth())/logf(2.f);
+
+		shader.uniform1f("proj_focus", focus);
+		shader.uniform1f("proj_lod", lod_range);
+		shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
+	}
+}
+
 void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
 {
 	stop_glerror();
@@ -5812,14 +7048,43 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
 	shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
 	shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
 	shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
+	shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
+
 	for (U32 i = 0; i < 4; i++)
+	{
+		if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1)
+		{
+			glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+		}
+	}
+
+	for (U32 i = 4; i < 6; i++)
 	{
 		if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1)
 		{
 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
 		}
 	}
+
 	shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+	shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
 
 	S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 	if (channel > -1)
@@ -5833,6 +7098,8 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(0)->activate();
 	shader.unbind();
+
+	LLGLState::checkTextureChannels();
 }
 
 inline float sgn(float a)
@@ -5866,6 +7133,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 		camera.setFar(camera.getFar()*0.87654321f);
 		LLPipeline::sReflectionRender = TRUE;
 		S32 occlusion = LLPipeline::sUseOcclusion;
+
+		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
 		LLPipeline::sUseOcclusion = llmin(occlusion, 1);
 		
 		U32 type_mask = gPipeline.mRenderTypeMask;
@@ -5900,22 +7170,15 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			water_clip = 1;
 		}
 
-
-
 		if (!LLViewerCamera::getInstance()->cameraUnderWater())
 		{	//generate planar reflection map
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 			glClearColor(0,0,0,0);
-			gGL.setColorMask(true, true);
 			mWaterRef.bindTarget();
 			mWaterRef.getViewport(gGLViewport);
-			mWaterRef.clear();
-			gGL.setColorMask(true, false);
-
+			
 			stop_glerror();
 
-			LLVector3 origin = camera.getOrigin();
-
 			glPushMatrix();
 
 			mat.set_scale(glh::vec3f(1,1,-1));
@@ -5930,25 +7193,21 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
 			LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
 
-			glCullFace(GL_FRONT);
+			glh::matrix4f inv_mat = mat.inverse();
 
-			//initial sky pass (no user clip plane)
-			{ //mask out everything but the sky
-				U32 tmp = mRenderTypeMask;
-				mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
-									(1 << LLPipeline::RENDER_TYPE_WL_SKY));
-				static LLCullResult result;
-				updateCull(camera, result);
-				stateSort(camera, result);
-				mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
-									(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
-									(1 << LLPipeline::RENDER_TYPE_WL_SKY));
-				renderGeom(camera, TRUE);
-				mRenderTypeMask = tmp;
-			}
+			glh::vec3f origin(0,0,0);
+			inv_mat.mult_matrix_vec(origin);
 
+			camera.setOrigin(origin.v);
+
+			glCullFace(GL_FRONT);
+
+			
+			static LLCullResult ref_result;
+			U32 ref_mask = 0;
 			if (LLDrawPoolWater::sNeedsDistortionUpdate)
 			{
+				U32 mask = mRenderTypeMask;
 				mRenderTypeMask &=	~((1<<LLPipeline::RENDER_TYPE_WATER) |
 									  (1<<LLPipeline::RENDER_TYPE_GROUND) |
 									  (1<<LLPipeline::RENDER_TYPE_SKY) |
@@ -5971,24 +7230,60 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 						}
 					}
 
-					LLSpatialPartition::sFreezeState = TRUE;
-					LLPipeline::sSkipUpdate = TRUE;
 					LLGLUserClipPlane clip_plane(plane, mat, projection);
-					static LLCullResult result;
-					updateCull(camera, result, 1);
-					stateSort(camera, result);
+					LLGLDisable cull(GL_CULL_FACE);
+					updateCull(camera, ref_result, 1);
+					stateSort(camera, ref_result);
+					gGL.setColorMask(true, true);
+					mWaterRef.clear();
+					gGL.setColorMask(true, false);
+
+				}
+				else
+				{
+					gGL.setColorMask(true, true);
+					mWaterRef.clear();
+					gGL.setColorMask(true, false);
+				}
+
+				ref_mask = mRenderTypeMask;
+				mRenderTypeMask = mask;
+			}
+
+			//initial sky pass (no user clip plane)
+			{ //mask out everything but the sky
+				U32 tmp = mRenderTypeMask;
+				mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
+									(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+				static LLCullResult result;
+				updateCull(camera, result);
+				stateSort(camera, result);
+				mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
+									(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
+									(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+				renderGeom(camera, TRUE);
+				mRenderTypeMask = tmp;
+			}
+
+
+			if (LLDrawPoolWater::sNeedsDistortionUpdate)
+			{
+				mRenderTypeMask = ref_mask;
+				if (gSavedSettings.getBOOL("RenderWaterReflections"))
+				{
+					gPipeline.grabReferences(ref_result);
+					LLGLUserClipPlane clip_plane(plane, mat, projection);
 					renderGeom(camera);
-					LLSpatialPartition::sFreezeState = FALSE;
-					LLPipeline::sSkipUpdate = FALSE;
 				}
 			}	
 			glCullFace(GL_BACK);
 			glPopMatrix();
 			mWaterRef.flush();
-
 			glh_set_current_modelview(current);
 		}
 
+		camera.setOrigin(camera_in.getOrigin());
+
 		//render distortion map
 		static BOOL last_update = TRUE;
 		if (last_update)
@@ -6012,12 +7307,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 			LLColor4& col = LLDrawPoolWater::sWaterFogColor;
 			glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
-			gGL.setColorMask(true, true);
 			mWaterDis.bindTarget();
 			mWaterDis.getViewport(gGLViewport);
-			mWaterDis.clear();
-			gGL.setColorMask(true, false);
-
+			
 			if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
 			{
 				//clip out geometry on the same side of water as the camera
@@ -6026,6 +7318,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 				static LLCullResult result;
 				updateCull(camera, result, water_clip);
 				stateSort(camera, result);
+
+				gGL.setColorMask(true, true);
+				mWaterDis.clear();
+				gGL.setColorMask(true, false);
+
 				renderGeom(camera);
 			}
 
@@ -6078,7 +7375,6 @@ glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
 	
 	dirN = dir;
 	dirN.normVec();
-	
 
 	ret.m[ 0] = lftN[0];
 	ret.m[ 1] = upN[0];
@@ -6133,10 +7429,484 @@ static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows");
 static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow");
 static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow");
 
-void LLPipeline::generateSunShadow(LLCamera& camera)
+void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion)
+{
+	LLFastTimer t(FTM_SHADOW_RENDER);
+
+	//clip out geometry on the same side of water as the camera
+	S32 occlude = LLPipeline::sUseOcclusion;
+	if (!use_occlusion)
+	{
+		LLPipeline::sUseOcclusion = 0;
+	}
+	LLPipeline::sShadowRender = TRUE;
+	
+	U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY };
+	LLGLEnable cull(GL_CULL_FACE);
+
+	if (use_shader)
+	{
+		gDeferredShadowProgram.bind();
+	}
+
+	updateCull(shadow_cam, result);
+	stateSort(shadow_cam, result);
+	
+	//generate shadow map
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadMatrixf(proj.m);
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glLoadMatrixf(view.m);
+
+	stop_glerror();
+	gGLLastMatrix = NULL;
+
+	{
+		LLGLDepthTest depth(GL_TRUE);
+		glClear(GL_DEPTH_BUFFER_BIT);
+	}
+
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			
+	glColor4f(1,1,1,1);
+	
+	stop_glerror();
+
+	gGL.setColorMask(false, false);
+	
+	//glCullFace(GL_FRONT);
+
+	{
+		LLFastTimer ftm(FTM_SHADOW_SIMPLE);
+		LLGLDisable test(GL_ALPHA_TEST);
+		gGL.getTexUnit(0)->disable();
+		for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
+		{
+			renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
+		}
+		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+	}
+	
+	if (use_shader)
+	{
+		gDeferredShadowProgram.unbind();
+		renderGeomShadow(shadow_cam);
+		gDeferredShadowProgram.bind();
+	}
+	else
+	{
+		renderGeomShadow(shadow_cam);
+	}
+
+	{
+		LLFastTimer ftm(FTM_SHADOW_ALPHA);
+		LLGLEnable test(GL_ALPHA_TEST);
+		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
+		renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE);
+		glColor4f(1,1,1,1);
+		renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+	}
+
+	//glCullFace(GL_BACK);
+
+	gGLLastMatrix = NULL;
+	glLoadMatrixd(gGLModelView);
+	doOcclusion(shadow_cam);
+
+	if (use_shader)
+	{
+		gDeferredShadowProgram.unbind();
+	}
+	
+	gGL.setColorMask(true, true);
+			
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+	gGLLastMatrix = NULL;
+
+	LLPipeline::sUseOcclusion = occlude;
+	LLPipeline::sShadowRender = FALSE;
+}
+
+
+BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
 {
+	//get point cloud of intersection of frust and min, max
+
+	//get set of planes
+	std::vector<LLPlane> ps;
+	
+	if (getVisibleExtents(camera, min, max))
+	{
+		return FALSE;
+	}
+
+	ps.push_back(LLPlane(min, LLVector3(-1,0,0)));
+	ps.push_back(LLPlane(min, LLVector3(0,-1,0)));
+	ps.push_back(LLPlane(min, LLVector3(0,0,-1)));
+	ps.push_back(LLPlane(max, LLVector3(1,0,0)));
+	ps.push_back(LLPlane(max, LLVector3(0,1,0)));
+	ps.push_back(LLPlane(max, LLVector3(0,0,1)));
 
-	if (!sRenderDeferred)
+	/*if (!light_dir.isExactlyZero())
+	{
+		LLPlane ucp;
+		LLPlane mcp;
+
+		F32 maxd = -1.f;
+		F32 mind = 1.f;
+
+		for (U32 i = 0; i < ps.size(); ++i)
+		{  //pick the plane most aligned to lightDir for user clip plane
+			LLVector3 n(ps[i].mV);
+			F32 da = n*light_dir;
+			if (da > maxd)
+			{
+				maxd = da;
+				ucp = ps[i];
+			}
+
+			if (da < mind)
+			{
+				mind = da;
+				mcp = ps[i];
+			}
+		}
+			
+		camera.setUserClipPlane(ucp);
+
+		ps.clear();
+		ps.push_back(ucp);
+		ps.push_back(mcp);
+	}*/
+	
+	for (U32 i = 0; i < 6; i++)
+	{
+		ps.push_back(camera.getAgentPlane(i));
+	}
+
+	//get set of points where planes intersect and points are not above any plane
+	fp.clear();
+	
+	for (U32 i = 0; i < ps.size(); ++i)
+	{
+		for (U32 j = 0; j < ps.size(); ++j)
+		{
+			for (U32 k = 0; k < ps.size(); ++k)
+			{
+				if (i == j ||
+					i == k ||
+					k == j)
+				{
+					continue;
+				}
+
+				LLVector3 n1,n2,n3;
+				F32 d1,d2,d3;
+
+				n1.setVec(ps[i].mV);
+				n2.setVec(ps[j].mV);
+				n3.setVec(ps[k].mV);
+
+				d1 = ps[i].mV[3];
+				d2 = ps[j].mV[3];
+				d3 = ps[k].mV[3];
+			
+				//get point of intersection of 3 planes "p"
+				LLVector3 p = (-d1*(n2%n3)-d2*(n3%n1)-d3*(n1%n2))/(n1*(n2%n3));
+				
+				if (llround(p*n1+d1, 0.0001f) == 0.f &&
+					llround(p*n2+d2, 0.0001f) == 0.f &&
+					llround(p*n3+d3, 0.0001f) == 0.f)
+				{ //point is on all three planes
+					BOOL found = TRUE;
+					for (U32 l = 0; l < ps.size() && found; ++l)
+					{
+						if (llround(ps[l].dist(p), 0.0001f) > 0.0f)
+						{ //point is above some plane, not contained
+							found = FALSE;	
+						}
+					}
+
+					if (found)
+					{
+						fp.push_back(p);
+					}
+				}
+			}
+		}
+	}
+	
+	if (fp.empty())
+	{
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<LLVector3>& vpc)
+{
+	if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3)
+	{
+		return;
+	}
+
+	LLVector3 up;
+
+	//LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV);
+
+	if (lightDir.mV[2] > 0.5f)
+	{
+		up = LLVector3(1,0,0);
+	}
+	else
+	{
+		up = LLVector3(0, 0, 1);
+	}
+
+	
+	F32 gi_range = gSavedSettings.getF32("RenderGIRange");
+
+	U32 res = mGIMap.getWidth();
+
+	F32 atten = llmax(gSavedSettings.getF32("RenderGIAttenuation"), 0.001f);
+
+	//set radius to range at which distance attenuation of incoming photons is near 0
+
+	F32 lrad = sqrtf(1.f/(atten*0.01f));
+
+	F32 lrange = lrad+gi_range*0.5f;
+
+	LLVector3 pad(lrange,lrange,lrange);
+
+	glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up);
+
+	LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f);
+
+	glh::vec3f scp(cp.mV);
+	view.mult_matrix_vec(scp);
+	cp.setVec(scp.v);
+
+	F32 pix_width = lrange/(res*0.5f);
+
+	//move cp to the nearest pix_width
+	for (U32 i = 0; i < 3; i++)
+	{
+		cp.mV[i] = llround(cp.mV[i], pix_width);
+	}
+	
+	LLVector3 min = cp-pad;
+	LLVector3 max = cp+pad;
+	
+	//set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point
+	mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res;
+	mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res;
+	mGILightRadius = lrad/lrange*0.5f;
+
+	glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0],
+								min.mV[1], max.mV[1],
+								-max.mV[2], -min.mV[2]);
+
+	LLCamera sun_cam = camera;
+
+	glh::matrix4f eye_view = glh_get_current_modelview();
+	
+	//get eye space to camera space matrix
+	mGIMatrix = view*eye_view.inverse();
+	mGINormalMatrix = mGIMatrix.inverse().transpose();
+	mGIInvProj = proj.inverse();
+	mGIMatrixProj = proj*mGIMatrix;
+
+	//translate and scale to [0,1]
+	glh::matrix4f trans(.5f, 0.f, 0.f, .5f,
+						0.f, 0.5f, 0.f, 0.5f,
+						0.f, 0.f, 0.5f, 0.5f,
+						0.f, 0.f, 0.f, 1.f);
+
+	mGIMatrixProj = trans*mGIMatrixProj;
+
+	glh_set_current_modelview(view);
+	glh_set_current_projection(proj);
+
+	LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE);
+
+	sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+	static LLCullResult result;
+
+	U32 type_mask = mRenderTypeMask;
+
+	mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
+								   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
+								   (1<<LLPipeline::RENDER_TYPE_BUMP) |
+								   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
+								   (1<<LLPipeline::RENDER_TYPE_TREE) | 
+								   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
+								   (1<<LLPipeline::RENDER_TYPE_WATER) |
+								   (1<<LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW) |
+								   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
+								   (1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
+									(1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
+									(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
+									(1 << LLPipeline::RENDER_TYPE_PASS_SHINY));
+
+
+	
+	S32 occlude = LLPipeline::sUseOcclusion;
+	//LLPipeline::sUseOcclusion = 0;
+	LLPipeline::sShadowRender = TRUE;
+	
+	//only render large objects into GI map
+	sMinRenderSize = gSavedSettings.getF32("RenderGIMinRenderSize");
+	
+	LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE;
+	mGIMap.bindTarget();
+	
+	F64 last_modelview[16];
+	F64 last_projection[16];
+	for (U32 i = 0; i < 16; i++)
+	{
+		last_modelview[i] = gGLLastModelView[i];
+		last_projection[i] = gGLLastProjection[i];
+		gGLLastModelView[i] = mGIModelview.m[i];
+		gGLLastProjection[i] = mGIProjection.m[i];
+	}
+
+	sun_cam.setOrigin(0.f, 0.f, 0.f);
+	updateCull(sun_cam, result);
+	stateSort(sun_cam, result);
+	
+	for (U32 i = 0; i < 16; i++)
+	{
+		gGLLastModelView[i] = last_modelview[i];
+		gGLLastProjection[i] = last_projection[i];
+	}
+
+	mGIProjection = proj;
+	mGIModelview = view;
+
+	LLGLEnable cull(GL_CULL_FACE);
+
+	//generate GI map
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadMatrixf(proj.m);
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glLoadMatrixf(view.m);
+
+	stop_glerror();
+	gGLLastMatrix = NULL;
+
+	mGIMap.clear();
+
+	{
+		//LLGLEnable enable(GL_DEPTH_CLAMP_NV);
+		renderGeomDeferred(camera);
+	}
+
+	mGIMap.flush();
+	
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+	gGLLastMatrix = NULL;
+
+	LLPipeline::sUseOcclusion = occlude;
+	LLPipeline::sShadowRender = FALSE;
+	sMinRenderSize = 0.f;
+
+	mRenderTypeMask = type_mask;
+
+}
+
+void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
+{
+	if (obj && obj->getVolume())
+	{
+		for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter)
+		{
+			renderHighlight(*iter, fade);
+		}
+
+		LLDrawable* drawable = obj->mDrawable;
+		if (drawable)
+		{
+			for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+			{
+				LLFace* face = drawable->getFace(i);
+				if (face)
+				{
+					face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade));
+				}
+			}
+		}
+	}
+}
+
+void LLPipeline::generateHighlight(LLCamera& camera)
+{
+	//render highlighted object as white into offscreen render target
+	
+	if (mHighlightObject.notNull())
+	{
+		mHighlightSet.insert(HighlightItem(mHighlightObject));
+	}
+	
+	if (!mHighlightSet.empty())
+	{
+		F32 transition = gFrameIntervalSeconds/gSavedSettings.getF32("RenderHighlightFadeTime");
+
+		LLGLDisable test(GL_ALPHA_TEST);
+		LLGLDepthTest depth(GL_FALSE);
+		mHighlight.bindTarget();
+		disableLights();
+		gGL.setColorMask(true, true);
+		mHighlight.clear();
+
+		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+		for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
+		{
+			std::set<HighlightItem>::iterator cur_iter = iter++;
+
+			if (cur_iter->mItem.isNull())
+			{
+				mHighlightSet.erase(cur_iter);
+				continue;
+			}
+
+			if (cur_iter->mItem == mHighlightObject)
+			{
+				cur_iter->incrFade(transition); 
+			}
+			else
+			{
+				cur_iter->incrFade(-transition);
+				if (cur_iter->mFade <= 0.f)
+				{
+					mHighlightSet.erase(cur_iter);
+					continue;
+				}
+			}
+
+			renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade);
+		}
+
+		mHighlight.flush();
+		gGL.setColorMask(true, false);
+	}
+}
+
+
+void LLPipeline::generateSunShadow(LLCamera& camera)
+{
+	if (!sRenderDeferred || !gSavedSettings.getBOOL("RenderDeferredShadow"))
 	{
 		return;
 	}
@@ -6148,99 +7918,174 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	{
 		if (clear)
 		{
-			clear = FALSE;
-			for (U32 i = 0; i < 4; i++)
-			{
-				mSunShadow[i].bindTarget();
-				mSunShadow[i].clear();
-				mSunShadow[i].flush();
-			}
+			clear = FALSE;
+			for (U32 i = 0; i < 6; i++)
+			{
+				mShadow[i].bindTarget();
+				mShadow[i].clear();
+				mShadow[i].flush();
+			}
+		}
+		return;
+	}
+	clear = TRUE;
+
+	F64 last_modelview[16];
+	F64 last_projection[16];
+	for (U32 i = 0; i < 16; i++)
+	{ //store last_modelview of world camera
+		last_modelview[i] = gGLLastModelView[i];
+		last_projection[i] = gGLLastProjection[i];
+	}
+
+	U32 type_mask = mRenderTypeMask;
+	mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
+								   (1<<LLPipeline::RENDER_TYPE_ALPHA) |
+								   (1<<LLPipeline::RENDER_TYPE_GRASS) |
+								   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
+								   (1<<LLPipeline::RENDER_TYPE_BUMP) |
+								   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
+								   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
+								   (1<<LLPipeline::RENDER_TYPE_TREE) | 
+								   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
+								   (1<<LLPipeline::RENDER_TYPE_WATER) |
+								   (1<<LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW) |
+								   (1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
+								   (1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
+								   (1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
+								   (1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
+								   (1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY));
+
+	gGL.setColorMask(false, false);
+
+	//get sun view matrix
+	
+	//store current projection/modelview matrix
+	glh::matrix4f saved_proj = glh_get_current_projection();
+	glh::matrix4f saved_view = glh_get_current_modelview();
+	glh::matrix4f inv_view = saved_view.inverse();
+
+	glh::matrix4f view[6];
+	glh::matrix4f proj[6];
+	
+	//clip contains parallel split distances for 3 splits
+	LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes");
+
+	//F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold");
+
+	//far clip on last split is minimum of camera view distance and 128
+	mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
+
+	clip = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes");
+	mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
+
+	//currently used for amount to extrude frusta corners for constructing shadow frusta
+	LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
+	//F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
+
+	LLVector3 lightDir = -mSunDir;
+	lightDir.normVec();
+
+	glh::vec3f light_dir(lightDir.mV);
+
+	//create light space camera matrix
+	
+	LLVector3 at = lightDir;
+
+	LLVector3 up = camera.getAtAxis();
+
+	if (fabsf(up*lightDir) > 0.75f)
+	{
+		up = camera.getUpAxis();
+	}
+
+	/*LLVector3 left = up%at;
+	up = at%left;*/
+
+	up.normVec();
+	at.normVec();
+	
+	
+	F32 near_clip = 0.f;
+	{
+		//get visible point cloud
+		std::vector<LLVector3> fp;
+
+		LLVector3 min,max;
+		getVisiblePointCloud(camera,min,max,fp);
+
+		if (fp.empty())
+		{
+			mRenderTypeMask = type_mask;
+			return;
+		}
+
+		generateGI(camera, lightDir, fp);
+
+		//get good split distances for frustum
+		for (U32 i = 0; i < fp.size(); ++i)
+		{
+			glh::vec3f v(fp[i].mV);
+			saved_view.mult_matrix_vec(v);
+			fp[i].setVec(v.v);
+		}
+
+		min = fp[0];
+		max = fp[0];
+
+		//get camera space bounding box
+		for (U32 i = 1; i < fp.size(); ++i)
+		{
+			update_min_max(min, max, fp[i]);
 		}
-		return;
-	}
-	clear = TRUE;
 
-	gGL.setColorMask(false, false);
+		near_clip = -max.mV[2];
+		F32 far_clip = -min.mV[2]*2.f;
 
-	//get sun view matrix
-	
-	F32 range = 128.f;
+		far_clip = llmin(far_clip, 128.f);
+		far_clip = llmin(far_clip, camera.getFar());
 
-	//store current projection/modelview matrix
-	glh::matrix4f saved_proj = glh_get_current_projection();
-	glh::matrix4f saved_view = glh_get_current_modelview();
-	glh::matrix4f inv_view = saved_view.inverse();
+		F32 range = far_clip-near_clip;
 
-	glh::matrix4f view[4];
-	glh::matrix4f proj[4];
-	LLVector3 up;
+		LLVector3 split_exp = gSavedSettings.getVector3("RenderShadowSplitExponent");
 
-	//clip contains parallel split distances for 3 splits
-	LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes");
+		F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) );
+		
+		da = powf(da, split_exp.mV[2]);
 
-	//far clip on last split is minimum of camera view distance and 128
-	mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
 
-	const LLPickInfo& pick_info = gViewerWindow->getLastPick();
+		F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da;
 
-	if (!pick_info.mPosGlobal.isExactlyZero())
-	{ //squish nearest frustum based on alt-zoom (tighten up nearest frustum when focusing on tiny object
-		F32 focus_dist = (F32) (pick_info.mPosGlobal + LLVector3d(pick_info.mObjectOffset) - gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin())).magVec();
-		mSunClipPlanes.mV[0] = llclamp(focus_dist*focus_dist, 2.f, mSunClipPlanes.mV[0]);
-	}
-		
-	// convenience array of 4 near clip plane distances
-	F32 dist[] = { 0.1f, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
 
-	//currently used for amount to extrude frusta corners for constructing shadow frusta
-	LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
-	F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
+		for (U32 i = 0; i < 4; ++i)
+		{
+			F32 x = (F32)(i+1)/4.f;
+			x = powf(x, sxp);
+			mSunClipPlanes.mV[i] = near_clip+range*x;
+		}
+	}
 
+	// convenience array of 4 near clip plane distances
+	F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
+	
 	for (S32 j = 0; j < 4; j++)
 	{
+		if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+		{
+			mShadowFrustPoints[j].clear();
+		}
+
+		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j;
+
 		//restore render matrices
 		glh_set_current_modelview(saved_view);
 		glh_set_current_projection(saved_proj);
 
-		//get center of far clip plane (for point of interest later)
-		LLVector3 center = camera.getOrigin() + camera.getAtAxis() * range;
-
 		LLVector3 eye = camera.getOrigin();
 
 		//camera used for shadow cull/render
 		LLCamera shadow_cam;
 		
-	    // perspective shadow map
-		glh::vec3f p[16];		//point cloud to be contained by shadow projection (light camera space)
-		glh::vec3f wp[16];		//point cloud to be contained by shadow projection (world space)
-		
-		LLVector3 lightDir = -mSunDir;
-		glh::vec3f light_dir(lightDir.mV);
-
-		//create light space camera matrix
-		LLVector3 at;
-		F32 dl = camera.getLeftAxis() * lightDir;
-		F32 du = camera.getUpAxis() * lightDir;
-
-		//choose an at axis such that up will be most aligned with lightDir
-		if (dl*dl < du*du)
-		{
-			at = lightDir%camera.getLeftAxis();
-		}
-		else
-		{
-			at = lightDir%camera.getUpAxis();
-		}
-
-		if (at * camera.getAtAxis() < 0)
-		{
-			at = -at;
-		}
-		
-		LLVector3 left = lightDir%at;
-		up = left%lightDir;
-		up.normVec();
-
 		//create world space camera frustum for this split
 		shadow_cam = camera;
 		shadow_cam.setFar(16.f);
@@ -6251,8 +8096,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
 		LLVector3 pn = shadow_cam.getAtAxis();
 		
-		LLVector3 frust_center;
-		
 		LLVector3 min, max;
 
 		//construct 8 corners of split frustum section
@@ -6263,21 +8106,19 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 			F32 dp = delta*pn;
 			frust[i] = eye + (delta*dist[j])/dp;
 			frust[i+4] = eye + (delta*dist[j+1])/dp;
-			frust_center += frust[i] + frust[i+4];
 		}
-
-		//get frustum center
-		frust_center /= 8.f;
 						
 		shadow_cam.calcAgentFrustumPlanes(frust);
-
+		shadow_cam.mFrustumCornerDist = 0.f;
 		
 		if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
 		{
 			mShadowCamera[j] = shadow_cam;
 		}
 
-		if (gPipeline.getVisibleExtents(shadow_cam, min, max))
+		std::vector<LLVector3> fp;
+
+		if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir))
 		{
 			//no possible shadow receivers
 			if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
@@ -6287,6 +8128,16 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 				mShadowCamera[j+4] = shadow_cam;
 			}
 
+			mShadow[j].bindTarget();
+			{
+				LLGLDepthTest depth(GL_TRUE);
+				mShadow[j].clear();
+			}
+			mShadow[j].flush();
+
+			mShadowError.mV[j] = 0.f;
+			mShadowFOV.mV[j] = 0.f;
+
 			continue;
 		}
 
@@ -6294,53 +8145,263 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		{
 			mShadowExtents[j][0] = min;
 			mShadowExtents[j][1] = max;
+			mShadowFrustPoints[j] = fp;
 		}
 				
-		view[j] = look(frust_center-lightDir*nearDist[j], lightDir, up);
-		F32 shadow_dist = nearDist[j];
 
-		for (U32 i = 0; i < 8; i++)
+		//find a good origin for shadow projection
+		LLVector3 origin;
+
+		//get a temporary view projection
+		view[j] = look(camera.getOrigin(), lightDir, -up);
+
+		std::vector<LLVector3> wpf;
+
+		for (U32 i = 0; i < fp.size(); i++)
 		{
-			//points in worldspace (wp) and light camera space (p)
-			//that must be included in shadow generation
-			wp[i] = glh::vec3f(frust[i].mV);
-			wp[i+8] = wp[i] - light_dir*shadow_dist;
-			view[j].mult_matrix_vec(wp[i], p[i]);
-			view[j].mult_matrix_vec(wp[i+8], p[i+8]);
+			glh::vec3f p = glh::vec3f(fp[i].mV);
+			view[j].mult_matrix_vec(p);
+			wpf.push_back(LLVector3(p.v));
 		}
-	
-		min = LLVector3(p[0].v);
-		max = LLVector3(p[0].v);
 
-		LLVector3 fmin = min;
-		LLVector3 fmax = max;
+		min = wpf[0];
+		max = wpf[0];
 
-		for (U32 i = 1; i < 16; i++)
-		{ //find camera space AABB of frustum in light camera space
-			update_min_max(min, max, LLVector3(p[i].v));
-			if (i < 8)
-			{
-				update_min_max(fmin, fmax, LLVector3(p[i].v));
+		for (U32 i = 0; i < fp.size(); ++i)
+		{ //get AABB in camera space
+			update_min_max(min, max, wpf[i]);
+		}
+
+		// Construct a perspective transform with perspective along y-axis that contains
+		// points in wpf
+		//Known:
+		// - far clip plane
+		// - near clip plane
+		// - points in frustum
+		//Find:
+		// - origin
+
+		//get some "interesting" points of reference
+		LLVector3 center = (min+max)*0.5f;
+		LLVector3 size = (max-min)*0.5f;
+		LLVector3 near_center = center;
+		near_center.mV[1] += size.mV[1]*2.f;
+		
+		
+		//put all points in wpf in quadrant 0, reletive to center of min/max
+		//get the best fit line using least squares
+		F32 bfm = 0.f;
+		F32 bfb = 0.f;
+
+		for (U32 i = 0; i < wpf.size(); ++i)
+		{
+			wpf[i] -= center;
+			wpf[i].mV[0] = fabsf(wpf[i].mV[0]);
+			wpf[i].mV[2] = fabsf(wpf[i].mV[2]);
+		}
+
+		if (!wpf.empty())
+		{ 
+			F32 sx = 0.f;
+			F32 sx2 = 0.f;
+			F32 sy = 0.f;
+			F32 sxy = 0.f;
+			
+			for (U32 i = 0; i < wpf.size(); ++i)
+			{		
+				sx += wpf[i].mV[0];
+				sx2 += wpf[i].mV[0]*wpf[i].mV[0];
+				sy += wpf[i].mV[1];
+				sxy += wpf[i].mV[0]*wpf[i].mV[1]; 
 			}
+
+			bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2);
+			bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2);
 		}
+		
+		{
+			// best fit line is y=bfm*x+bfb
+		
+			//find point that is furthest to the right of line
+			F32 off_x = -1.f;
+			LLVector3 lp;
+
+			for (U32 i = 0; i < wpf.size(); ++i)
+			{
+				//y = bfm*x+bfb
+				//x = (y-bfb)/bfm
+				F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+
+				lx = wpf[i].mV[0]-lx;
+				
+				if (off_x < lx)
+				{
+					off_x = lx;
+					lp = wpf[i];
+				}
+			}
+
+			//get line with slope bfm through lp
+			// bfb = y-bfm*x
+			bfb = lp.mV[1]-bfm*lp.mV[0];
+
+			//calculate error
+			mShadowError.mV[j] = 0.f;
+
+			for (U32 i = 0; i < wpf.size(); ++i)
+			{
+				F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+				mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx);
+			}
+
+			mShadowError.mV[j] /= wpf.size();
+			mShadowError.mV[j] /= size.mV[0];
+
+			if (mShadowError.mV[j] > gSavedSettings.getF32("RenderShadowErrorCutoff"))
+			{ //just use ortho projection
+				mShadowFOV.mV[j] = -1.f;
+				origin.clearVec();
+				proj[j] = gl_ortho(min.mV[0], max.mV[0],
+									min.mV[1], max.mV[1],
+									-max.mV[2], -min.mV[2]);
+			}
+			else
+			{
+				//origin is where line x = 0;
+				origin.setVec(0,bfb,0);
+
+				F32 fovz = 1.f;
+				F32 fovx = 1.f;
+				
+				LLVector3 zp;
+				LLVector3 xp;
 
-		//generate perspective matrix that contains frustum
-		//proj[j] = matrix_perspective(min, max);
-		proj[j] = gl_ortho(min.mV[0], max.mV[0],
+				for (U32 i = 0; i < wpf.size(); ++i)
+				{
+					LLVector3 atz = wpf[i]-origin;
+					atz.mV[0] = 0.f;
+					atz.normVec();
+					if (fovz > -atz.mV[1])
+					{
+						zp = wpf[i];
+						fovz = -atz.mV[1];
+					}
+					
+					LLVector3 atx = wpf[i]-origin;
+					atx.mV[2] = 0.f;
+					atx.normVec();
+					if (fovx > -atx.mV[1])
+					{
+						fovx = -atx.mV[1];
+						xp = wpf[i];
+					}
+				}
+
+				fovx = acos(fovx);
+				fovz = acos(fovz);
+
+				F32 cutoff = llmin(gSavedSettings.getF32("RenderShadowFOVCutoff"), 1.4f);
+				
+				mShadowFOV.mV[j] = fovx;
+				
+				if (fovx < cutoff && fovz > cutoff)
+				{
+					//x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff
+					F32 d = zp.mV[2]/tan(cutoff);
+					F32 ny = zp.mV[1] + fabsf(d);
+
+					origin.mV[1] = ny;
+
+					fovz = 1.f;
+					fovx = 1.f;
+
+					for (U32 i = 0; i < wpf.size(); ++i)
+					{
+						LLVector3 atz = wpf[i]-origin;
+						atz.mV[0] = 0.f;
+						atz.normVec();
+						fovz = llmin(fovz, -atz.mV[1]);
+
+						LLVector3 atx = wpf[i]-origin;
+						atx.mV[2] = 0.f;
+						atx.normVec();
+						fovx = llmin(fovx, -atx.mV[1]);
+					}
+
+					fovx = acos(fovx);
+					fovz = acos(fovz);
+
+					if (fovx > cutoff || llround(fovz, 0.01f) > cutoff)
+					{
+					//	llerrs << "WTF?" << llendl;
+					}
+
+					mShadowFOV.mV[j] = cutoff;
+				}
+
+				
+				origin += center;
+			
+				F32 ynear = -(max.mV[1]-origin.mV[1]);
+				F32 yfar = -(min.mV[1]-origin.mV[1]);
+				
+				if (ynear < 0.1f) //keep a sensible near clip plane
+				{
+					F32 diff = 0.1f-ynear;
+					origin.mV[1] += diff;
+					ynear += diff;
+					yfar += diff;
+				}
+								
+				if (fovx > cutoff)
+				{ //just use ortho projection
+					origin.clearVec();
+					mShadowError.mV[j] = -1.f;
+					proj[j] = gl_ortho(min.mV[0], max.mV[0],
 							min.mV[1], max.mV[1],
 							-max.mV[2], -min.mV[2]);
-						
+				}
+				else
+				{
+					//get perspective projection
+					view[j] = view[j].inverse();
+
+					glh::vec3f origin_agent(origin.mV);
+					
+					//translate view to origin
+					view[j].mult_matrix_vec(origin_agent);
+
+					eye = LLVector3(origin_agent.v);
+
+					if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+					{
+						mShadowFrustOrigin[j] = eye;
+					}
+				
+					view[j] = look(LLVector3(origin_agent.v), lightDir, -up);
+
+					F32 fx = 1.f/tanf(fovx);
+					F32 fz = 1.f/tanf(fovz);
+
+					proj[j] = glh::matrix4f(-fx, 0, 0, 0,
+											0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar),
+											0, 0, -fz, 0,
+											0, -1.f, 0, 0);
+				}
+			}
+		}
+
 		shadow_cam.setFar(128.f);
 		shadow_cam.setOriginAndLookAt(eye, up, center);
 
+		shadow_cam.setOrigin(0,0,0);
+
 		glh_set_current_modelview(view[j]);
 		glh_set_current_projection(proj[j]);
 
 		LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
 
-		proj[j] = gl_ortho(fmin.mV[0], fmax.mV[0],
-						   fmin.mV[1], fmax.mV[1],
-						   -fmax.mV[2], -fmin.mV[2]);
+		shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
 
 		//translate and scale to from [-1, 1] to [0, 1]
 		glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
@@ -6351,113 +8412,168 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		glh_set_current_modelview(view[j]);
 		glh_set_current_projection(proj[j]);
 
+		for (U32 i = 0; i < 16; i++)
+		{
+			gGLLastModelView[i] = mShadowModelview[j].m[i];
+			gGLLastProjection[i] = mShadowProjection[j].m[i];
+		}
+
+		mShadowModelview[j] = view[j];
+		mShadowProjection[j] = proj[j];
+
+	
 		mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
 		
-		U32 type_mask = mRenderTypeMask;
-		mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
-									   (1<<LLPipeline::RENDER_TYPE_ALPHA) |
-									   (1<<LLPipeline::RENDER_TYPE_GRASS) |
-									   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-									   (1<<LLPipeline::RENDER_TYPE_BUMP) |
-									   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
-									   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
-									   (1<<LLPipeline::RENDER_TYPE_TREE) | 
-									   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
-									   0);
-
-		//clip out geometry on the same side of water as the camera
-		static LLCullResult result;
-		S32 occlude = LLPipeline::sUseOcclusion;
-		LLPipeline::sUseOcclusion = 1;
-		LLPipeline::sShadowRender = TRUE;
-		//hack to prevent LOD updates from using sun camera origin
-		shadow_cam.setOrigin(camera.getOrigin());
-		updateCull(shadow_cam, result);
-		stateSort(shadow_cam, result);
-		
+		stop_glerror();
+
+		mShadow[j].bindTarget();
+		mShadow[j].getViewport(gGLViewport);
+
+		{
+			static LLCullResult result[4];
+
+			//LLGLEnable enable(GL_DEPTH_CLAMP_NV);
+			renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE);
+		}
+
+		mShadow[j].flush();
+ 
 		if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
 		{
 			LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
 			mShadowCamera[j+4] = shadow_cam;
 		}
+	}
+
+	
+
+	F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
+
+	//update shadow targets
+	for (U32 i = 0; i < 2; i++)
+	{ //for each current shadow
+		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
+
+		if (mShadowSpotLight[i].notNull() && 
+			(mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
+			mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
+		{ //keep this spotlight
+			mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
+		}
+		else
+		{ //fade out this light
+			mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
+			
+			if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
+			{ //faded out, grab one of the pending spots (whichever one isn't already taken)
+				if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
+				{
+					mShadowSpotLight[i] = mTargetShadowSpotLight[0];
+				}
+				else
+				{
+					mShadowSpotLight[i] = mTargetShadowSpotLight[1];
+				}
+			}
+		}
+	}
 
-		LLFastTimer t(FTM_SHADOW_RENDER);
+	for (S32 i = 0; i < 2; i++)
+	{
+		glh_set_current_modelview(saved_view);
+		glh_set_current_projection(saved_proj);
 
-		stop_glerror();
+		if (mShadowSpotLight[i].isNull())
+		{
+			continue;
+		}
 
-		mSunShadow[j].bindTarget();
-		mSunShadow[j].getViewport(gGLViewport);
+		LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
 
+		if (!volume)
 		{
-			LLGLDepthTest depth(GL_TRUE);
-			mSunShadow[j].clear();
+			mShadowSpotLight[i] = NULL;
+			continue;
 		}
 
-		U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP };
-		LLGLEnable cull(GL_CULL_FACE);
+		LLDrawable* drawable = mShadowSpotLight[i];
 
-		//generate sun shadow map
-		glMatrixMode(GL_PROJECTION);
-		glPushMatrix();
-		glLoadMatrixf(proj[j].m);
-		glMatrixMode(GL_MODELVIEW);
-		glPushMatrix();
-		glLoadMatrixf(view[j].m);
+		LLVector3 params = volume->getSpotLightParams();
+		F32 fov = params.mV[0];
 
-		stop_glerror();
-		gGLLastMatrix = NULL;
+		//get agent->light space matrix (modelview)
+		LLVector3 center = drawable->getPositionAgent();
+		LLQuaternion quat = volume->getRenderRotation();
 
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-				
-		glColor4f(1,1,1,1);
+		//get near clip plane
+		LLVector3 scale = volume->getScale();
+		LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+		at_axis *= quat;
+
+		LLVector3 np = center+at_axis;
+		at_axis.normVec();
+
+		//get origin that has given fov for plane np, at_axis, and given scale
+		F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+		LLVector3 origin = np - at_axis*dist;
+
+		LLMatrix4 mat(quat, LLVector4(origin, 1.f));
+
+		view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
+
+		view[i+4] = view[i+4].inverse();
+
+		//get perspective matrix
+		F32 near_clip = dist+0.01f;
+		F32 width = scale.mV[VX];
+		F32 height = scale.mV[VY];
+		F32 far_clip = dist+volume->getLightRadius()*1.5f;
+
+		F32 fovy = fov * RAD_TO_DEG;
+		F32 aspect = width/height;
 		
-		glCullFace(GL_FRONT);
+		proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
 
-		stop_glerror();
+		//translate and scale to from [-1, 1] to [0, 1]
+		glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+						0.f, 0.5f, 0.f, 0.5f,
+						0.f, 0.f, 0.5f, 0.5f,
+						0.f, 0.f, 0.f, 1.f);
 
-		gGL.setColorMask(false, false);
+		glh_set_current_modelview(view[i+4]);
+		glh_set_current_projection(proj[i+4]);
 
-		gDeferredShadowProgram.bind();
-		{
-			LLFastTimer ftm(FTM_SHADOW_SIMPLE);
-			LLGLDisable test(GL_ALPHA_TEST);
-			gGL.getTexUnit(0)->disable();
-			for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
-			{
-				renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
-			}
-			gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		}
+		mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
 		
+		for (U32 j = 0; j < 16; j++)
 		{
-			LLFastTimer ftm(FTM_SHADOW_ALPHA);
-			LLGLEnable test(GL_ALPHA_TEST);
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
-			renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE);
-			glColor4f(1,1,1,1);
-			renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+			gGLLastModelView[j] = mShadowModelview[i+4].m[j];
+			gGLLastProjection[j] = mShadowProjection[i+4].m[j];
 		}
-		
-		gDeferredShadowProgram.unbind();
 
-		renderGeomShadow(shadow_cam);
+		mShadowModelview[i+4] = view[i+4];
+		mShadowProjection[i+4] = proj[i+4];
 
-		gGL.setColorMask(true, true);
+		LLCamera shadow_cam = camera;
+		shadow_cam.setFar(far_clip);
+		shadow_cam.setOrigin(origin);
 
-		glCullFace(GL_BACK);
-		LLPipeline::sUseOcclusion = occlude;
-		LLPipeline::sShadowRender = FALSE;
-		mRenderTypeMask = type_mask;
-		
-		glMatrixMode(GL_PROJECTION);
-		glPopMatrix();
-		glMatrixMode(GL_MODELVIEW);
-		glPopMatrix();
-		gGLLastMatrix = NULL;
+		LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
 
-		mSunShadow[j].flush();
-	}
+		stop_glerror();
+
+		mShadow[i+4].bindTarget();
+		mShadow[i+4].getViewport(gGLViewport);
+
+		static LLCullResult result[2];
+
+		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
+
+		renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
+
+		mShadow[i+4].flush();
+ 	}
 
 	if (!gSavedSettings.getBOOL("CameraOffset"))
 	{
@@ -6474,6 +8590,14 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		glMatrixMode(GL_MODELVIEW);
 	}
 	gGL.setColorMask(true, false);
+
+	for (U32 i = 0; i < 16; i++)
+	{
+		gGLLastModelView[i] = last_modelview[i];
+		gGLLastProjection[i] = last_projection[i];
+	}
+
+	mRenderTypeMask = type_mask;
 }
 
 void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
@@ -6482,7 +8606,7 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu
 	{
 		LLSpatialGroup* group = *i;
 		if (!group->isDead() &&
-			(!sUseOcclusion || !group->isState(LLSpatialGroup::OCCLUDED)) &&
+			(!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
 			gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
 			group->mDrawMap.find(type) != group->mDrawMap.end())
 		{
@@ -6525,7 +8649,16 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 				(1<<LLPipeline::RENDER_TYPE_SIMPLE) |
 				(1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
 				(1<<LLPipeline::RENDER_TYPE_ALPHA) | 
-				(1<<LLPipeline::RENDER_TYPE_INVISIBLE);
+				(1<<LLPipeline::RENDER_TYPE_INVISIBLE) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_INVISIBLE) |
+				(1 << LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
 	}
 	
 	mask = mask & gPipeline.getRenderTypeMask();
@@ -6535,6 +8668,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	S32 occlusion = sUseOcclusion;
 	sUseOcclusion = 0;
 	sReflectionRender = sRenderDeferred ? FALSE : TRUE;
+	sShadowRender = TRUE;
 	sImpostorRender = TRUE;
 
 	markVisible(avatar->mDrawable, *LLViewerCamera::getInstance());
@@ -6611,20 +8745,23 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
 		resY != avatar->mImpostor.getHeight())
 	{
+		avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,TRUE);
+		
 		if (LLPipeline::sRenderDeferred)
 		{
-			avatar->mImpostor.allocate(resX,resY,GL_RGBA16F_ARB,TRUE,TRUE);
 			addDeferredAttachments(avatar->mImpostor);
 		}
-		else
-		{
-			avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,TRUE);
-		}
+		
 		gGL.getTexUnit(0)->bind(&avatar->mImpostor);
 		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	}
 
+	LLGLEnable stencil(GL_STENCIL_TEST);
+	glStencilMask(0xFFFFFFFF);
+	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
+	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
 	{
 		LLGLEnable scissor(GL_SCISSOR_TEST);
 		glScissor(0, 0, resX, resY);
@@ -6632,15 +8769,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		avatar->mImpostor.clear();
 	}
 	
-	LLGLEnable stencil(GL_STENCIL_TEST);
-
-	glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
-	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-
 	if (LLPipeline::sRenderDeferred)
 	{
 		stop_glerror();
 		renderGeomDeferred(camera);
+		renderGeomPostDeferred(camera);
 	}
 	else
 	{
@@ -6650,11 +8783,16 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 	glStencilFunc(GL_EQUAL, 1, 0xFFFFFF);
 
-	if (!sRenderDeferred || muted)
-	{
+	{ //create alpha mask based on stencil buffer (grey out if muted)
 		LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f;
 		LLVector3 up = camera.getUpAxis()*tdim.mV[1]*2.f;
 
+		if (LLPipeline::sRenderDeferred)
+		{
+			GLuint buff = GL_COLOR_ATTACHMENT0_EXT;
+			glDrawBuffersARB(1, &buff);
+		}
+
 		LLGLEnable blend(muted ? 0 : GL_BLEND);
 
 		if (muted)
@@ -6693,6 +8831,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	sUseOcclusion = occlusion;
 	sReflectionRender = FALSE;
 	sImpostorRender = FALSE;
+	sShadowRender = FALSE;
 	gPipeline.mRenderTypeMask = saved_mask;
 
 	glMatrixMode(GL_PROJECTION);
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 8f6867aa012..ce50a374050 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -150,6 +150,8 @@ class LLPipeline
 	void        markMoved(LLDrawable *drawablep, BOOL damped_motion = FALSE);
 	void        markShift(LLDrawable *drawablep);
 	void        markTextured(LLDrawable *drawablep);
+	void		markGLRebuild(LLGLUpdate* glu);
+	void		markRebuild(LLSpatialGroup* group, BOOL priority = FALSE);
 	void        markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE);
 		
 	//get the object between start and end that's closest to start.
@@ -200,10 +202,14 @@ class LLPipeline
 	void updateMove();
 	BOOL visibleObjectsInFrustum(LLCamera& camera);
 	BOOL getVisibleExtents(LLCamera& camera, LLVector3 &min, LLVector3& max);
+	BOOL getVisiblePointCloud(LLCamera& camera, LLVector3 &min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir = LLVector3(0,0,0));
 	void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0);  //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane
 	void createObjects(F32 max_dtime);
 	void createObject(LLViewerObject* vobj);
 	void updateGeom(F32 max_dtime);
+	void updateGL();
+	void rebuildPriorityGroups();
+	void rebuildGroups();
 
 	//calculate pixel area of given box from vantage point of given camera
 	static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera);
@@ -224,12 +230,21 @@ class LLPipeline
 	void renderGeomDeferred(LLCamera& camera);
 	void renderGeomPostDeferred(LLCamera& camera);
 	void renderGeomShadow(LLCamera& camera);
-	void bindDeferredShader(LLGLSLShader& shader, U32 light_index = 0);
+	void bindDeferredShader(LLGLSLShader& shader, U32 light_index = 0, LLRenderTarget* gi_source = NULL, LLRenderTarget* last_gi_post = NULL, U32 noise_map = 0xFFFFFFFF);
+	void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep);
+
 	void unbindDeferredShader(LLGLSLShader& shader);
 	void renderDeferredLighting();
 	
 	void generateWaterReflection(LLCamera& camera);
 	void generateSunShadow(LLCamera& camera);
+	void generateHighlight(LLCamera& camera);
+	void renderHighlight(const LLViewerObject* obj, F32 fade);
+	void setHighlightObject(LLDrawable* obj) { mHighlightObject = obj; }
+
+
+	void renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& camera, LLCullResult& result, BOOL use_shader = TRUE, BOOL use_occlusion = TRUE);
+	void generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<LLVector3>& vpc);
 	void renderHighlights();
 	void renderDebug();
 
@@ -324,23 +339,35 @@ class LLPipeline
 	enum LLRenderTypeMask
 	{
 		// Following are pool types (some are also object types)
-		RENDER_TYPE_SKY			= LLDrawPool::POOL_SKY,
-		RENDER_TYPE_WL_SKY		= LLDrawPool::POOL_WL_SKY,
-		RENDER_TYPE_GROUND		= LLDrawPool::POOL_GROUND,	
-		RENDER_TYPE_TERRAIN		= LLDrawPool::POOL_TERRAIN,
-		RENDER_TYPE_SIMPLE		= LLDrawPool::POOL_SIMPLE,
-		RENDER_TYPE_GRASS		= LLDrawPool::POOL_GRASS,
-		RENDER_TYPE_FULLBRIGHT	= LLDrawPool::POOL_FULLBRIGHT,
-		RENDER_TYPE_BUMP		= LLDrawPool::POOL_BUMP,
-		RENDER_TYPE_AVATAR		= LLDrawPool::POOL_AVATAR,
-		RENDER_TYPE_TREE		= LLDrawPool::POOL_TREE,
-		RENDER_TYPE_INVISIBLE	= LLDrawPool::POOL_INVISIBLE,
-		RENDER_TYPE_WATER		= LLDrawPool::POOL_WATER,
- 		RENDER_TYPE_ALPHA		= LLDrawPool::POOL_ALPHA,
-		RENDER_TYPE_GLOW		= LLDrawPool::POOL_GLOW,
-		
+		RENDER_TYPE_SKY							= LLDrawPool::POOL_SKY,
+		RENDER_TYPE_WL_SKY						= LLDrawPool::POOL_WL_SKY,
+		RENDER_TYPE_GROUND						= LLDrawPool::POOL_GROUND,	
+		RENDER_TYPE_TERRAIN						= LLDrawPool::POOL_TERRAIN,
+		RENDER_TYPE_SIMPLE						= LLDrawPool::POOL_SIMPLE,
+		RENDER_TYPE_GRASS						= LLDrawPool::POOL_GRASS,
+		RENDER_TYPE_FULLBRIGHT					= LLDrawPool::POOL_FULLBRIGHT,
+		RENDER_TYPE_BUMP						= LLDrawPool::POOL_BUMP,
+		RENDER_TYPE_AVATAR						= LLDrawPool::POOL_AVATAR,
+		RENDER_TYPE_TREE						= LLDrawPool::POOL_TREE,
+		RENDER_TYPE_INVISIBLE					= LLDrawPool::POOL_INVISIBLE,
+		RENDER_TYPE_WATER						= LLDrawPool::POOL_WATER,
+ 		RENDER_TYPE_ALPHA						= LLDrawPool::POOL_ALPHA,
+		RENDER_TYPE_GLOW						= LLDrawPool::POOL_GLOW,
+		RENDER_TYPE_PASS_SIMPLE 				= LLRenderPass::PASS_SIMPLE,
+		RENDER_TYPE_PASS_GRASS					= LLRenderPass::PASS_GRASS,
+		RENDER_TYPE_PASS_FULLBRIGHT				= LLRenderPass::PASS_FULLBRIGHT,
+		RENDER_TYPE_PASS_INVISIBLE				= LLRenderPass::PASS_INVISIBLE,
+		RENDER_TYPE_PASS_INVISI_SHINY			= LLRenderPass::PASS_INVISI_SHINY,
+		RENDER_TYPE_PASS_FULLBRIGHT_SHINY		= LLRenderPass::PASS_FULLBRIGHT_SHINY,
+		RENDER_TYPE_PASS_SHINY					= LLRenderPass::PASS_SHINY,
+		RENDER_TYPE_PASS_BUMP					= LLRenderPass::PASS_BUMP,
+		RENDER_TYPE_PASS_GLOW					= LLRenderPass::PASS_GLOW,
+		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
+		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,
+		RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK	= LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK,
+		RENDER_TYPE_PASS_ALPHA_SHADOW = LLRenderPass::PASS_ALPHA_SHADOW,
 		// Following are object types (only used in drawable mRenderType)
-		RENDER_TYPE_HUD = LLDrawPool::NUM_POOL_TYPES,
+		RENDER_TYPE_HUD = LLRenderPass::NUM_RENDER_TYPES,
 		RENDER_TYPE_VOLUME,
 		RENDER_TYPE_PARTICLES,
 		RENDER_TYPE_CLOUDS,
@@ -383,7 +410,8 @@ class LLPipeline
 		RENDER_DEBUG_SHADOW_FRUSTA		= 0x0040000,
 		RENDER_DEBUG_SCULPTED           = 0x0080000,
 		RENDER_DEBUG_AVATAR_VOLUME      = 0x0100000,
-		RENDER_DEBUG_AGENT_TARGET       = 0x0200000,
+		RENDER_DEBUG_BUILD_QUEUE		= 0x0200000,
+		RENDER_DEBUG_AGENT_TARGET       = 0x0400000,
 	};
 
 public:
@@ -423,7 +451,6 @@ class LLPipeline
 	static BOOL				sUseFBO;
 	static BOOL				sUseFarClip;
 	static BOOL				sShadowRender;
-	static BOOL				sSkipUpdate; //skip lod updates
 	static BOOL				sWaterReflections;
 	static BOOL				sDynamicLOD;
 	static BOOL				sPickAvatar;
@@ -437,19 +464,47 @@ class LLPipeline
 	static BOOL				sRenderAttachedParticles;
 	static BOOL				sRenderDeferred;
 	static S32				sVisibleLightCount;
+	static F32				sMinRenderSize;
 
 	//screen texture
 	LLRenderTarget			mScreen;
+	LLRenderTarget			mUIScreen;
 	LLRenderTarget			mDeferredScreen;
-	LLRenderTarget			mDeferredLight[2];
+	LLRenderTarget			mEdgeMap;
+	LLRenderTarget			mDeferredDepth;
+	LLRenderTarget			mDeferredLight[3];
 	LLMultisampleBuffer		mSampleBuffer;
+	LLRenderTarget			mGIMap;
+	LLRenderTarget			mGIMapPost[2];
+	LLRenderTarget			mLuminanceMap;
+	LLRenderTarget			mHighlight;
 
 	//sun shadow map
-	LLRenderTarget			mSunShadow[4];
+	LLRenderTarget			mShadow[6];
+	std::vector<LLVector3>	mShadowFrustPoints[4];
+	LLVector4				mShadowError;
+	LLVector4				mShadowFOV;
+	LLVector3				mShadowFrustOrigin[4];
 	LLCamera				mShadowCamera[8];
 	LLVector3				mShadowExtents[4][2];
-	glh::matrix4f			mSunShadowMatrix[4];
+	glh::matrix4f			mSunShadowMatrix[6];
+	glh::matrix4f			mShadowModelview[6];
+	glh::matrix4f			mShadowProjection[6];
+	glh::matrix4f			mGIMatrix;
+	glh::matrix4f			mGIMatrixProj;
+	glh::matrix4f			mGIModelview;
+	glh::matrix4f			mGIProjection;
+	glh::matrix4f			mGINormalMatrix;
+	glh::matrix4f			mGIInvProj;
+	LLVector2				mGIRange;
+	F32						mGILightRadius;
+	
+	LLPointer<LLDrawable>				mShadowSpotLight[2];
+	F32									mSpotLightFade[2];
+	LLPointer<LLDrawable>				mTargetShadowSpotLight[2];
+
 	LLVector4				mSunClipPlanes;
+	LLVector4				mSunOrthoClipPlanes;
 
 	LLVector2				mScreenScale;
 
@@ -464,6 +519,8 @@ class LLPipeline
 
 	//noise map
 	U32					mNoiseMap;
+	U32					mTrueNoiseMap;
+	U32					mLightFunc;
 
 	LLColor4				mSunDiffuse;
 	LLVector3				mSunDir;
@@ -524,12 +581,45 @@ class LLPipeline
 	//
 	LLDrawable::drawable_list_t 	mBuildQ1; // priority
 	LLDrawable::drawable_list_t 	mBuildQ2; // non-priority
+	LLSpatialGroup::sg_list_t		mGroupQ1; //priority
+	LLSpatialGroup::sg_vector_t		mGroupQ2; // non-priority
+
 	LLViewerObject::vobj_list_t		mCreateQ;
 		
 	LLDrawable::drawable_set_t		mActiveQ;
 	
 	LLDrawable::drawable_set_t		mRetexturedList;
 
+	class HighlightItem
+	{
+	public:
+		const LLPointer<LLDrawable> mItem;
+		mutable F32 mFade;
+
+		HighlightItem(LLDrawable* item)
+		: mItem(item), mFade(0)
+		{
+		}
+
+		bool operator<(const HighlightItem& rhs) const
+		{
+			return mItem < rhs.mItem;
+		}
+
+		bool operator==(const HighlightItem& rhs) const
+		{
+			return mItem == rhs.mItem;
+		}
+
+		void incrFade(F32 val) const
+		{
+			mFade = llclamp(mFade+val, 0.f, 1.f);
+		}
+	};
+
+	std::set<HighlightItem> mHighlightSet;
+	LLPointer<LLDrawable> mHighlightObject;
+
 	//////////////////////////////////////////////////
 	//
 	// Draw pools are responsible for storing all rendered data,
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 327dc07cbe9..46679c19d2b 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2124,29 +2124,50 @@
              name="colorswatch"
              tool_tip="Click to open Color Picker"
              width="40" />
-            <spinner
+         <texture_picker 
+            allow_no_texture="true" 
+            top_delta="0" 
+            can_apply_immediately="true"
+            default_image_name="Default" 
+            follows="left|top" 
+            height="48" 
+            label=""
+            left_delta="57" 
+            mouse_opaque="true" 
+            name="light texture control"
+            tool_tip="Click to choose a projection image (only has effect with deferred rendering enabled)" 
+            width="32" />
+          <spinner
              follows="left|top"
              height="19"
              initial_value="0.5"
              label="Intensity"
              label_width="70"
              layout="topleft"
-             left_pad="15"
+             left="10"
              name="Light Intensity"
-             top_pad="-50"
+             top_pad="3"
              width="128" />
-            <spinner
+          <spinner bottom_delta="0" decimal_digits="3" follows="left|top" height="16"
+ increment="0.1" initial_val="0.5" label="FOV" label_width="55"
+ left="144" max_val="3" min_val="0" mouse_opaque="true"
+ name="Light FOV" width="120" />
+          <spinner
              follows="left|top"
              height="19"
              initial_value="5"
              label="Radius"
              label_width="70"
              layout="topleft"
-             left_delta="0"
+             left="10"
              max_val="20"
              name="Light Radius"
              top_pad="3"
              width="128" />
+          <spinner bottom_delta="0" decimal_digits="3" follows="left|top" height="16"
+        increment="0.5" initial_val="0.5" label="Focus" label_width="55"
+        left="144" max_val="20" min_val="-20" mouse_opaque="true"
+        name="Light Focus" width="120" />
             <spinner
              follows="left|top"
              height="19"
@@ -2155,13 +2176,17 @@
              label="Falloff"
              label_width="70"
              layout="topleft"
-             left_delta="0"
+             left="10"
              max_val="2"
              name="Light Falloff"
              top_pad="3"
              width="128" />
+          <spinner bottom_delta="0" decimal_digits="3" follows="left|top" height="16"
+           increment="0.05" initial_val="1" label="Ambiance" label_width="55"
+           left="144" max_val="1" min_val="0" mouse_opaque="true"
+           name="Light Ambiance" width="120" />
         </panel>
-        <panel
+         <panel
          border="false"
          follows="left|top|right|bottom"
          height="367"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index ee15e6f29ca..13350c1bf3d 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2143,6 +2143,147 @@
         </menu>
         <menu_item_separator
          layout="topleft" />
+      <menu
+        create_jump_keys="true"
+        label="Render Metadata"
+        layout="topleft"
+        name="Render Metadata"
+        tear_off="true">
+        <menu_item_check
+         label="Bounding Boxes"
+         layout="topleft"
+         name="Bounding Boxes">
+        <menu_item_check.on_check
+         function="Advanced.CheckInfoDisplay"
+         parameter="bboxes" />
+        <menu_item_check.on_click
+         function="Advanced.ToggleInfoDisplay"
+         parameter="bboxes" />
+        </menu_item_check>
+        <menu_item_check
+         label="Octree"
+         layout="topleft"
+         name="Octree">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="octree" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="octree" />
+        </menu_item_check>
+        <menu_item_check
+         label="Shadow Frusta"
+         layout="topleft"
+         name="Shadow Frusta">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="shadow frusta" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="shadow frusta" />
+        </menu_item_check>
+        <menu_item_check
+         label="Occlusion"
+         layout="topleft"
+         name="Occlusion">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="occlusion" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="occlusion" />
+        </menu_item_check>
+        <menu_item_check
+         label="Render Batches"
+         layout="topleft"
+         name="Render Batches">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="render batches" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="render batches" />
+        </menu_item_check>
+        <menu_item_check
+         label="Texture Anim"
+         layout="topleft"
+         name="Texture Anim">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="texture anim" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="texture anim" />
+        </menu_item_check>
+        <menu_item_check
+         label="Texture Priority"
+         layout="topleft"
+         name="Texture Priority">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="texture priority" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="texture priority" />
+        </menu_item_check>
+        <menu_item_check
+         label="Texture Area"
+         layout="topleft"
+         name="Texture Area">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="texture area" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="texture area" />
+        </menu_item_check>
+        <menu_item_check
+         label="Face Area"
+         layout="topleft"
+         name="Face Area">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="face area" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="face area" />
+        </menu_item_check>
+        <menu_item_check
+         label="Lights"
+         layout="topleft"
+         name="Lights">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="lights" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="lights" />
+        </menu_item_check>
+        <menu_item_check
+         label="Collision Skeleton"
+         layout="topleft"
+         name="Collision Skeleton">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="collision skeleton" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="collision skeleton" />
+        </menu_item_check>
+        <menu_item_check
+         label="Raycast"
+         layout="topleft"
+         name="Raycast">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="raycast" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="raycast" />
+        </menu_item_check>
+      </menu>
+      <menu_item_separator
+         layout="topleft" />
         <menu
          create_jump_keys="true"
          label="Display Info"
@@ -2406,7 +2547,47 @@
                 <menu_item_check.on_enable
                  function="Advanced.EnableObjectObjectOcclusion" />
             </menu_item_check>
-            <menu_item_check
+          <menu_item_check
+             label="Framebuffer Objects"
+             layout="topleft"
+             name="Framebuffer Objects">
+            <menu_item_check.on_check
+             function="CheckControl"
+             parameter="RenderUseFBO" />
+            <menu_item_check.on_click
+             function="ToggleControl"
+             parameter="RenderUseFBO" />
+            <menu_item_check.on_enable
+                 function="Advanced.EnableRenderFBO" />
+           </menu_item_check>
+          <menu_item_check
+                       label="Deferred Rendering"
+                       layout="topleft"
+                       name="Deferred Rendering">
+            <menu_item_check.on_check
+             function="CheckControl"
+             parameter="RenderDeferred" />
+            <menu_item_check.on_click
+             function="ToggleControl"
+             parameter="RenderDeferred" />
+            <menu_item_check.on_enable
+                 function="Advanced.EnableRenderDeferred" />
+          </menu_item_check>
+          <menu_item_check
+                   label="Global Illumintation"
+                   layout="topleft"
+                   name="Global Illumination">
+            <menu_item_check.on_check
+             function="CheckControl"
+             parameter="RenderDeferredGI" />
+            <menu_item_check.on_click
+             function="ToggleControl"
+             parameter="RenderDeferredGI" />
+            <menu_item_check.on_enable
+                 function="Advanced.EnableRenderDeferredGI" />
+          </menu_item_check>
+
+          <menu_item_check
              label="Debug GL"
              layout="topleft"
              name="Debug GL">
@@ -2461,6 +2642,16 @@
                  function="Advanced.ToggleDisableTextures" />
             </menu_item_check>
             <menu_item_check
+             label="Texture Atlas"
+             layout="topleft"
+             name="Texture Atlas">
+              <menu_item_check.on_check
+               function="Advanced.CheckTextureAtlas"
+               parameter="TextureAtlas" />
+              <menu_item_check.on_click
+               function="Advanced.ToggleTextureAtlas" />
+            </menu_item_check>
+              <menu_item_check
              label="Render Attached Lights"
              layout="topleft"
              name="Render Attached Lights">
-- 
GitLab