diff --git a/autobuild.xml b/autobuild.xml
index 056fa8e050e574cb5f81177168089314f65f4eb1..b1478a46b24017b18aee5e26009cca3a3b24d54e 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -1612,9 +1612,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>38ea083fe1204ee106b4d44d9811af19</string>
+              <string>facee34b8bd57ad602157e65a5af1a49</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-openssl/rev/249044/arch/Darwin/installer/openssl-1.0.0g-darwin-20120207.tar.bz2</string>
+              <string>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/openssl-0.9.8q-darwin-20110211.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -1624,9 +1624,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-	      <string>7dc5191a3d95074a6ed3bd53f57420e5</string>
+              <string>3d40be8566fa4b9df9a38e2a0f9ea467</string>
               <key>url</key>
-		   <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-openssl/rev/249044/arch/Linux/installer/openssl-1.0.0g-linux-20120207.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-openssl/rev/226882/arch/Linux/installer/openssl-1.0.0d-linux-20110418.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -1636,9 +1636,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>ed6cbaf9860a03bc99ac301277f1452a</string>
+              <string>774c7f0a0312bee3054757a623e227bc</string>
               <key>url</key>
-              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-openssl/rev/249044/arch/CYGWIN/installer/openssl-1.0.0g-windows-20120207.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-openssl/rev/220986/arch/CYGWIN/installer/openssl-0.9.8q-windows-20110211.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2638,7 +2638,6 @@
                 <array>
                   <string>/build</string>
                   <string>"/cfg=Release|Win32"</string>
-                  <string>"/CL_ADD=/m:1"</string>
                 </array>
               </map>
               <key>configure</key>
diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl
index 35a67204ec60fc1fa13817e0921c96b79d246b01..69d3d01efe485d3a4c677d1c6e730f0ea573b1e8 100755
--- a/indra/llmath/llvector4a.inl
+++ b/indra/llmath/llvector4a.inl
@@ -409,6 +409,26 @@ inline void LLVector4a::normalize3fast()
 	mQ = _mm_mul_ps( mQ, approxRsqrt );
 }
 
+inline void LLVector4a::normalize3fast_checked(LLVector4a* d)
+{
+	if (!isFinite3())
+	{
+		*this = d ? *d : LLVector4a(0,1,0,1);
+		return;
+	}
+
+	LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
+
+	if (lenSqrd.getF32ptr()[0] <= FLT_EPSILON)
+	{
+		*this = d ? *d : LLVector4a(0,1,0,1);
+		return;
+	}
+
+	const LLQuad approxRsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
+	mQ = _mm_mul_ps( mQ, approxRsqrt );
+}
+
 // Return true if this vector is normalized with respect to x,y,z up to tolerance
 inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const
 {
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 0c329c69b23fa6be4e98174d5235671de092641d..de960e5d951c8866d2b36ecd35efa158cc3c5222 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -94,8 +94,6 @@ const S32 SCULPT_MIN_AREA_DETAIL = 1;
 
 extern BOOL gDebugGL;
 
-bool less_than_max_mag(const LLVector4a& vec);
-
 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
 {    
 	LLVector3 test = (pt2-pt1)%(pt3-pt2);
@@ -138,6 +136,82 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent
 	return true;
 }
 
+// Finds tangent vec based on three vertices with texture coordinates.
+// Fills in dummy values if the triangle has degenerate texture coordinates.
+void calc_tangent_from_triangle(
+	LLVector4a&			normal,
+	LLVector4a&			tangent_out,
+	const LLVector4a& v1,
+	const LLVector2&  w1,
+	const LLVector4a& v2,
+	const LLVector2&  w2,
+	const LLVector4a& v3,
+	const LLVector2&  w3)
+{
+	const F32* v1ptr = v1.getF32ptr();
+	const F32* v2ptr = v2.getF32ptr();
+	const F32* v3ptr = v3.getF32ptr();
+
+	float x1 = v2ptr[0] - v1ptr[0];
+	float x2 = v3ptr[0] - v1ptr[0];
+	float y1 = v2ptr[1] - v1ptr[1];
+	float y2 = v3ptr[1] - v1ptr[1];
+	float z1 = v2ptr[2] - v1ptr[2];
+	float z2 = v3ptr[2] - v1ptr[2];
+
+	float s1 = w2.mV[0] - w1.mV[0];
+	float s2 = w3.mV[0] - w1.mV[0];
+	float t1 = w2.mV[1] - w1.mV[1];
+	float t2 = w3.mV[1] - w1.mV[1];
+
+	F32 rd = s1*t2-s2*t1;
+
+	float r = ((rd*rd) > FLT_EPSILON) ? 1.0F / rd : 1024.f; //some made up large ratio for division by zero
+
+	llassert(llfinite(r));
+	llassert(!llisnan(r));
+
+	LLVector4a sdir(
+		(t2 * x1 - t1 * x2) * r,
+		(t2 * y1 - t1 * y2) * r,
+		(t2 * z1 - t1 * z2) * r);
+
+	LLVector4a tdir(
+		(s1 * x2 - s2 * x1) * r,
+		(s1 * y2 - s2 * y1) * r,
+		(s1 * z2 - s2 * z1) * r);
+
+	LLVector4a	n = normal;
+	LLVector4a	t = sdir;
+
+	LLVector4a ncrosst;
+	ncrosst.setCross3(n,t);
+
+	// Gram-Schmidt orthogonalize
+	n.mul(n.dot3(t).getF32());
+
+	LLVector4a tsubn;
+	tsubn.setSub(t,n);
+
+	if (tsubn.dot3(tsubn).getF32() > F_APPROXIMATELY_ZERO)
+	{
+		tsubn.normalize3fast_checked();
+
+		// Calculate handedness
+		F32 handedness = ncrosst.dot3(tdir).getF32() < 0.f ? -1.f : 1.f;
+
+		tsubn.getF32ptr()[3] = handedness;
+
+		tangent_out = tsubn;
+	}
+	else
+	{
+		// degenerate, make up a value
+		//
+		tangent_out.set(0,0,1,1);
+	}
+
+}
 
 
 // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
@@ -991,7 +1065,6 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai
 			{
 				mOpen = FALSE;
 				mProfile.push_back(mProfile[0]);
-				llassert(mProfile[0].isFinite3());
 				mTotal++;
 			}
 		}
@@ -1019,7 +1092,7 @@ BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detai
 			addFace(mTotal-2, 2,0.5,LL_FACE_PROFILE_END, TRUE);
 		}
 	}
-
+	
 	return TRUE;
 }
 
@@ -1357,7 +1430,7 @@ void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 en
 		qang.setQuat   (ang,path_axis);
 		LLMatrix3 tmp(twist*qang);
 		pt->mRot.loadu(tmp);
-		
+
 		t+=step;
 	}
 
@@ -1383,7 +1456,7 @@ void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 en
 	qang.setQuat   (ang,path_axis);
 	LLMatrix3 tmp(twist*qang);
 	pt->mRot.loadu(tmp);
-	
+
 	mTotal = mPath.size();
 }
 
@@ -1987,7 +2060,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mHullIndices = NULL;
 	mNumHullPoints = 0;
 	mNumHullIndices = 0;
-	
+
 	// set defaults
 	if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
 	{
@@ -2733,7 +2806,7 @@ inline LLVector4a sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
 	value.set(r,g,b);
 	value.mul(1.f/255.f);
 	value.sub(sub);
-	
+
 	return value;
 }
 
@@ -2836,7 +2909,7 @@ void LLVolume::sculptGeneratePlaceholder()
 			F32 v = (F32)t/(sizeT-1);
 
 			const F32 RADIUS = (F32) 0.3;
-			
+					
 			F32* p = pt.getF32ptr();
 
 			p[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS);
@@ -4541,7 +4614,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 
 		if (src.mNormals)
 		{
-			LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
+		LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
 		}
 
 		if(src.mTexCoords)
@@ -4751,13 +4824,27 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
 		}
 	}
 
+
+	if (angle_cutoff > 1.f && !mNormals)
+	{
+		ll_aligned_free_16(new_face.mNormals);
+		new_face.mNormals = NULL;
+	}
+
+	if (!mTexCoords)
+	{
+		ll_aligned_free_16(new_face.mTexCoords);
+		new_face.mTexCoords = NULL;
+	}
+
 	// Only swap data if we've actually optimized the mesh
 	//
 	if (new_face.mNumVertices <= mNumVertices)
 	{
-		llassert(new_face.mNumIndices == mNumIndices);
+	llassert(new_face.mNumIndices == mNumIndices);
 		swapData(new_face);
 	}
+
 }
 
 class LLVCacheTriangleData;
@@ -4827,29 +4914,29 @@ F64 find_vertex_score(LLVCacheVertexData& data)
 	if (data.mActiveTriangles >= 0)
 	{ 
 		score = 0.0;
-		
-		S32 cache_idx = data.mCacheTag;
 
-		if (cache_idx < 0)
-		{
-			//not in cache
+	S32 cache_idx = data.mCacheTag;
+
+	if (cache_idx < 0)
+	{
+		//not in cache
+	}
+	else
+	{
+		if (cache_idx < 3)
+		{ //vertex was in the last triangle
+			score = FindVertexScore_LastTriScore;
 		}
 		else
-		{
-			if (cache_idx < 3)
-			{ //vertex was in the last triangle
-				score = FindVertexScore_LastTriScore;
-			}
-			else
-			{ //more points for being higher in the cache
+		{ //more points for being higher in the cache
 				score = 1.0-((cache_idx-3)*FindVertexScore_Scaler);
 				score = pow(score, FindVertexScore_CacheDecayPower);
-			}
 		}
+	}
 
-		//bonus points for having low valence
+	//bonus points for having low valence
 		F64 valence_boost = pow((F64)data.mActiveTriangles, -FindVertexScore_ValenceBoostPower);
-		score += FindVertexScore_ValenceBoostScale * valence_boost;
+	score += FindVertexScore_ValenceBoostScale * valence_boost;
 	}
 
 	return score;
@@ -5429,9 +5516,6 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 		mCenter->mul(0.5f); 
 	}
 
-	llassert(less_than_max_mag(mExtents[0]));
-	llassert(less_than_max_mag(mExtents[1]));
-
 	if (!partial_build)
 	{
 		resizeIndices(grid_size*grid_size*6);
@@ -5572,9 +5656,9 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 			++src;
 			++pos;
 		}
-	}
-	else
-	{
+		}
+		else
+		{
 
 		min_uv.set((*p)[0]+0.5f,
 				   0.5f - (*p)[1]);
@@ -5589,9 +5673,9 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 			llassert(src->isFinite3());
 			update_min_max(min,max,*src);
 			update_min_max(min_uv, max_uv, *tc);
-		
-			*pos = *src;
 
+			*pos = *src;
+		
 			llassert(pos->isFinite3());
 		
 			++p;
@@ -5619,7 +5703,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 		*tc++ = cuv;
 		num_vertices++;
 	}
-	
+		
 	LL_CHECK_MEMORY
 		
 	if (partial_build)
@@ -5760,7 +5844,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 				const F32* p2V = p2.getF32ptr();
 				const F32* paV = pa.getF32ptr();
 				const F32* pbV = pb.getF32ptr();
-				
+
 				// Use area of triangle to determine backfacing
 				F32 area_1a2, area_1ba, area_21b, area_2ab;
 				area_1a2 =  (p1V[0]*paV[1] - paV[0]*p1V[1]) +
@@ -5941,7 +6025,7 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
 	ll_aligned_free(mPositions);
 	//DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
 	ll_aligned_free_16(mTangents);
-	
+
 	mTangents = NULL;
 
 	if (num_verts)
@@ -5993,15 +6077,15 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
 		mNormals = mPositions+new_verts;
 		mTexCoords = (LLVector2*) (mNormals+new_verts);
 
-		//positions
+	//positions
 		LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
-		
-		//normals
-		LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
 	
-		//tex coords
+	//normals
+		LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
+
+	//tex coords
 		LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tc_size);
-	
+
 	//just clear tangents
 	ll_aligned_free_16(mTangents);
 	mTangents = NULL;
@@ -6265,7 +6349,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 				i = mBeginS + s + max_s*t;
 			}
 
-			llassert(less_than_max_mag(mesh[i]));
 			mesh[i].store4a((F32*)(pos+cur_vertex));
 			tc[cur_vertex].set(ss,tt);
 		
@@ -6273,7 +6356,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 			if (test && s > 0)
 			{
-				llassert(less_than_max_mag(mesh[i]));
 				mesh[i].store4a((F32*)(pos+cur_vertex));
 				tc[cur_vertex].set(ss,tt);
 				cur_vertex++;
@@ -6294,16 +6376,13 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 			i = mBeginS + s + max_s*t;
 			ss = profile[mBeginS + s][2] - begin_stex;
 
-			llassert(less_than_max_mag(mesh[i]));
 			mesh[i].store4a((F32*)(pos+cur_vertex));
 			tc[cur_vertex].set(ss,tt);
-						
+			
 			cur_vertex++;
 		}
-	}
-	
+	}	
 	LL_CHECK_MEMORY
-
 	
 	mCenter->clear();
 
@@ -6459,7 +6538,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 		LLQuad& vector1 = *((LLQuad*) &v1);
 		LLQuad& vector2 = *((LLQuad*) &v2);
-
+		
 		LLQuad& amQ = *((LLQuad*) &a);
 		LLQuad& bmQ = *((LLQuad*) &b);
 
@@ -6482,7 +6561,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		llassert(v1.isFinite3());
 
 		v1.store4a((F32*) output);
-
+		
 		
 		output++;
 		idx += 3;
@@ -6500,20 +6579,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		LLVector4a* n0p = norm+idx[0];
 		LLVector4a* n1p = norm+idx[1];
 		LLVector4a* n2p = norm+idx[2];
-
+		
 		idx += 3;
 
 		LLVector4a n0,n1,n2;
 		n0.load4a((F32*) n0p);
 		n1.load4a((F32*) n1p);
 		n2.load4a((F32*) n2p);
-
+		
 		n0.add(c);
 		n1.add(c);
 		n2.add(c);
-		
+
 		llassert(c.isFinite3());
-		
+
 		//even out quad contributions
 		switch (i%2+1)
 		{
@@ -6758,7 +6837,7 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe
 			tangent[a].set(0,0,1,1);
 		}
     }
-
+    
 	ll_aligned_free_16(tan1);
 }
 
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 00de61a8cc9a03a0ad5bbbc1b524d9b63b030759..acfb3c085afce5d70c2d44558966ea0949c8ecc3 100755
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -73,7 +73,6 @@ std::ofstream gFailLog;
 #define APIENTRY
 #endif
 
-
 void APIENTRY gl_debug_callback(GLenum source,
                                 GLenum type,
                                 GLuint id,
@@ -84,24 +83,24 @@ void APIENTRY gl_debug_callback(GLenum source,
 {
 	if (gGLDebugLoggingEnabled)
 	{
-		if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
-		{
-			llwarns << "----- GL ERROR --------" << llendl;
-		}
-		else
-		{
-			llwarns << "----- GL WARNING -------" << llendl;
-		}
-		llwarns << "Type: " << std::hex << type << llendl;
-		llwarns << "ID: " << std::hex << id << llendl;
-		llwarns << "Severity: " << std::hex << severity << llendl;
-		llwarns << "Message: " << message << llendl;
-		llwarns << "-----------------------" << llendl;
-		if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
-		{
-			llerrs << "Halting on GL Error" << llendl;
-		}
+	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+	{
+		llwarns << "----- GL ERROR --------" << llendl;
+	}
+	else
+	{
+		llwarns << "----- GL WARNING -------" << llendl;
 	}
+	llwarns << "Type: " << std::hex << type << llendl;
+	llwarns << "ID: " << std::hex << id << llendl;
+	llwarns << "Severity: " << std::hex << severity << llendl;
+	llwarns << "Message: " << message << llendl;
+	llwarns << "-----------------------" << llendl;
+	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
+	{
+		llerrs << "Halting on GL Error" << llendl;
+	}
+}
 }
 #endif
 
@@ -653,7 +652,8 @@ bool LLGLManager::initGL()
 		}
 #if LL_DARWIN
 		else if ((mGLRenderer.find("9400M") != std::string::npos)
-			  || (mGLRenderer.find("9600M") != std::string::npos))
+			  || (mGLRenderer.find("9600M") != std::string::npos)
+			  || (mGLRenderer.find("9800M") != std::string::npos))
 		{
 			mIsMobileGF = TRUE;
 		}
@@ -751,7 +751,7 @@ bool LLGLManager::initGL()
 #if LL_WINDOWS
 	if (mHasDebugOutput && gDebugGL)
 	{ //setup debug output callback
-		glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
+		//glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
 		glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
 		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
 	}
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index dfb73de6f311378eff3050caed52621dd88b9e26..35620bb6568963985a8546aad582b9af2a1bfe92 100755
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -375,6 +375,11 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes,
 	// Create program
 	mProgramObject = glCreateProgramObjectARB();
 	
+#if LL_DARWIN
+    // work-around missing mix(vec3,vec3,bvec3)
+    mDefines["OLD_SELECT"] = "1";
+#endif
+	
 	//compile new source
 	vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
 	for ( ; fileIter != mShaderFiles.end(); fileIter++ )
@@ -1190,7 +1195,7 @@ GLint LLGLSLShader::getAttribLocation(U32 attrib)
 void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v)
 {
 	GLint location = getUniformLocation(uniform);
-
+				
 	if (location >= 0)
 	{
 		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
@@ -1223,7 +1228,7 @@ void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint
 void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v)
 {
 	GLint location = getUniformLocation(uniform);
-
+				
 	if (location >= 0)
 	{
 		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
@@ -1239,7 +1244,7 @@ void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v)
 void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y)
 {
 	GLint location = getUniformLocation(uniform);
-
+				
 	if (location >= 0)
 	{
 		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
@@ -1256,7 +1261,7 @@ void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLf
 void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z)
 {
 	GLint location = getUniformLocation(uniform);
-
+				
 	if (location >= 0)
 	{
 		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
@@ -1288,7 +1293,7 @@ void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, co
 void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
 {
 	GLint location = getUniformLocation(uniform);
-
+				
 	if (location >= 0)
 	{
 		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
@@ -1304,7 +1309,7 @@ void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, co
 void LLGLSLShader::uniform3fv(const LLStaticHashedString& uniform, U32 count, const GLfloat* v)
 {
 	GLint location = getUniformLocation(uniform);
-
+				
 	if (location >= 0)
 	{
 		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 3393d352de07252e101f54d606c05cb94f263087..aa94110f4d01f01652180148409a60588ad5a4cc 100755
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1872,33 +1872,33 @@ void LLRender::flush()
 		//store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
 		U32 count = mCount;
 
-		if (mMode == LLRender::QUADS && !sGLCoreProfile)
-		{
-			if (mCount%4 != 0)
+			if (mMode == LLRender::QUADS && !sGLCoreProfile)
 			{
+				if (mCount%4 != 0)
+				{
 				count -= (mCount % 4);
 				llwarns << "Incomplete quad requested." << llendl;
+				}
 			}
-		}
-
-		if (mMode == LLRender::TRIANGLES)
-		{
-			if (mCount%3 != 0)
+			
+			if (mMode == LLRender::TRIANGLES)
 			{
+				if (mCount%3 != 0)
+				{
 				count -= (mCount % 3);
 				llwarns << "Incomplete triangle requested." << llendl;
+				}
 			}
-		}
-
-		if (mMode == LLRender::LINES)
-		{
-			if (mCount%2 != 0)
+			
+			if (mMode == LLRender::LINES)
 			{
+				if (mCount%2 != 0)
+				{
 				count -= (mCount % 2);
 				llwarns << "Incomplete line requested." << llendl;
 			}
 		}
-		
+
 		mCount = 0;
 
 		if (mBuffer->useVBOs() && !mBuffer->isLocked())
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 33a852bedf74bc0efccb4228ab2f35164a5d9122..d7f141bd92de197a8b4664e9d9b5b89259929684 100755
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -79,7 +79,7 @@ LLRenderTarget::~LLRenderTarget()
 	release();
 }
 
-void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
+void LLRenderTarget::resize(U32 resx, U32 resy)
 { 
 	//for accounting, get the number of pixels added/subtracted
 	S32 pix_diff = (resx*resy)-(mResX*mResY);
@@ -87,10 +87,12 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
 	mResX = resx;
 	mResY = resy;
 
+	llassert(mInternalFormat.size() == mTex.size());
+
 	for (U32 i = 0; i < mTex.size(); ++i)
 	{ //resize color attachments
 		gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
-		LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+		LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
 		sBytesAllocated += pix_diff*4;
 	}
 
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 740e25d40debf22a4c5252229b7c3afdba446775..6dc84d978da0b9869e12b2d3987a1017c37e4dff 100755
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -79,7 +79,7 @@ class LLRenderTarget
 	// CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined
 	// DO NOT use for screen space buffers or for scratch space for an image that might be uploaded
 	// DO use for render targets that resize often and aren't likely to ruin someone's day if they break
-	void resize(U32 resx, U32 resy, U32 color_fmt);
+	void resize(U32 resx, U32 resy);
 
 	//add color buffer attachment
 	//limit of 4 color attachments per render target
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index d1afd2ed28dd048e460834ef201228dfbd3580b9..d230574752d9aed6ef373aabb5c1b2f908772799 100755
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -1137,7 +1137,8 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("lightMap");
 	mReservedUniforms.push_back("bloomMap");
 	mReservedUniforms.push_back("projectionMap");
-	
+	mReservedUniforms.push_back("norm_mat");
+
 	mReservedUniforms.push_back("global_gamma");
 	mReservedUniforms.push_back("texture_gamma");
 	
@@ -1183,7 +1184,7 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("alpha_ramp");
 
 	mReservedUniforms.push_back("origin");
-
+	mReservedUniforms.push_back("display_gamma");
 	llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
 
 	std::set<std::string> dupe_check;
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index ba781036eb82f23cc3b7d2e1cb0d24de29bf0d9f..51c27fc8b66f7a5a4141a25c2a89e10f2f80d01e 100755
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -167,7 +167,8 @@ class LLShaderMgr
 		DEFERRED_LIGHT,
 		DEFERRED_BLOOM,
 		DEFERRED_PROJECTION,
-		
+		DEFERRED_NORM_MATRIX,
+
 		GLOBAL_GAMMA,
 		TEXTURE_GAMMA,
 		
@@ -213,9 +214,8 @@ class LLShaderMgr
 		TERRAIN_ALPHARAMP,
 		
 		SHINY_ORIGIN,
-
+DISPLAY_GAMMA,
 		END_RESERVED_UNIFORMS
-
 	} eGLSLReservedUniforms;
 
 	// singleton pattern implementation
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 83ea6fabbb271ff55ae99935d9dbfa3943c71221..f168b3af141ad15fdde920132628d626e33a7cbb 100755
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -954,15 +954,15 @@ S32 LLVertexBuffer::determineUsage(S32 usage)
 	{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
 		if (ret_usage != GL_DYNAMIC_COPY_ARB)
 		{
-			if (sDisableVBOMapping)
-			{ //always use stream draw if VBO mapping is disabled
-				ret_usage = GL_STREAM_DRAW_ARB;
-			}
-			else
-			{
-				ret_usage = GL_DYNAMIC_DRAW_ARB;
-			}
+		if (sDisableVBOMapping)
+		{ //always use stream draw if VBO mapping is disabled
+			ret_usage = GL_STREAM_DRAW_ARB;
 		}
+		else
+		{
+			ret_usage = GL_DYNAMIC_DRAW_ARB;
+		}
+	}
 	}
 	
 	return ret_usage;
@@ -1119,7 +1119,7 @@ void LLVertexBuffer::genBuffer(U32 size)
 	{
 		mMappedData = sDynamicCopyVBOPool.allocate(mGLBuffer, mSize);
 	}
-
+	
 	
 	sGLCount++;
 }
@@ -1333,7 +1333,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 		//actually allocate space for the vertex buffer if using VBO mapping
 		flush();
 
-		if (gGLManager.mHasVertexArrayObject && useVBOs() && (sUseVAO))
+		if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
 		{
 #if GL_ARB_vertex_array_object
 			mGLArray = getVAOName();
@@ -1489,18 +1489,21 @@ bool LLVertexBuffer::useVBOs() const
 
 //----------------------------------------------------------------------------
 
-bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end)
+bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
 {
+	S32 end = index+count;
+	S32 region_end = region.mIndex+region.mCount;
+	
 	if (end < region.mIndex ||
-		start > region.mEnd)
+		index > region_end)
 	{ //gap exists, do not merge
 		return false;
 	}
 
-	region.mEnd = llmax(end, region.mEnd);
-	region.mIndex = llmin(start, region.mIndex);
-	region.mCount = region.mEnd-region.mIndex;
-
+	S32 new_end = llmax(end, region_end);
+	S32 new_index = llmin(index, region.mIndex);
+	region.mIndex = new_index;
+	region.mCount = new_end-new_index;
 	return true;
 }
 
@@ -1510,6 +1513,7 @@ static LLFastTimer::DeclareTimer FTM_VBO_MAP_BUFFER("VBO Map");
 // Map for data access
 volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
 {
+	bindGLBuffer(true);
 	if (mFinal)
 	{
 		llerrs << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << llendl;
@@ -1530,23 +1534,23 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 
 			bool mapped = false;
 			//see if range is already mapped
-			S32 start_index = mOffsets[type]+index*sTypeSize[type];
-			S32 end_index = start_index+count*sTypeSize[type];
-
-			for (std::vector<MappedRegion>::iterator iter = mMappedVertexRegions.begin(), end = mMappedVertexRegions.end(); iter != end; ++iter)
+			for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 			{
-				MappedRegion& region = *iter;
-				if (expand_region(region, index, end_index))
+				MappedRegion& region = mMappedVertexRegions[i];
+				if (region.mType == type)
 				{
-					mapped = true;
-					break;
+					if (expand_region(region, index, count))
+					{
+						mapped = true;
+						break;
+					}
 				}
 			}
 
 			if (!mapped)
 			{
 				//not already mapped, map new region
-				MappedRegion region(mMappable && map_range ? -1 : start_index, end_index-start_index);
+				MappedRegion region(type, mMappable && map_range ? -1 : index, count);
 				mMappedVertexRegions.push_back(region);
 			}
 		}
@@ -1570,7 +1574,6 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 			{
 				volatile U8* src = NULL;
 				waitFence();
-				bindGLBuffer();
 				if (gGLManager.mHasMapBufferRange)
 				{
 					if (map_range)
@@ -1691,6 +1694,7 @@ static LLFastTimer::DeclareTimer FTM_VBO_MAP_INDEX("IBO Map");
 
 volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 {
+	bindGLIndices(true);
 	if (mFinal)
 	{
 		llerrs << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << llendl;
@@ -1709,14 +1713,12 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 				count = mNumIndices-index;
 			}
 
-			S32 end = index+count;
-
 			bool mapped = false;
 			//see if range is already mapped
 			for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
 			{
 				MappedRegion& region = mMappedIndexRegions[i];
-				if (expand_region(region, index, end))
+				if (expand_region(region, index, count))
 				{
 					mapped = true;
 					break;
@@ -1726,7 +1728,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 			if (!mapped)
 			{
 				//not already mapped, map new region
-				MappedRegion region(mMappable && map_range ? -1 : index, count);
+				MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count);
 				mMappedIndexRegions.push_back(region);
 			}
 		}
@@ -1742,23 +1744,23 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 			sMappedCount++;
 			stop_glerror();	
 
+			if (gDebugGL && useVBOs())
+			{
+				GLint elem = 0;
+				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
+
+				if (elem != mGLIndices)
+				{
+					llerrs << "Wrong index buffer bound!" << llendl;
+				}
+			}
+
 			if(!mMappable)
 			{
 				map_range = false;
 			}
 			else
 			{
-				bindGLIndices();
-				if (gDebugGL && useVBOs())
-				{
-					GLint elem = 0;
-					glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
-
-					if (elem != mGLIndices)
-					{
-						llerrs << "Wrong index buffer bound!" << llendl;
-					}
-				}
 				volatile U8* src = NULL;
 				waitFence();
 				if (gGLManager.mHasMapBufferRange)
@@ -1871,10 +1873,8 @@ void LLVertexBuffer::unmapBuffer()
 
 	if (mMappedData && mVertexLocked)
 	{
-		llassert(mUsage != GL_DYNAMIC_COPY_ARB);
-		
 		LLFastTimer t(FTM_VBO_UNMAP);
-		bindGLBuffer();
+		bindGLBuffer(true);
 		updated_all = mIndexLocked; //both vertex and index buffers done updating
 
 		if(!mMappable)
@@ -1885,8 +1885,8 @@ void LLVertexBuffer::unmapBuffer()
 				for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 				{
 					const MappedRegion& region = mMappedVertexRegions[i];
-					S32 offset = region.mIndex;
-					S32 length = region.mCount;
+					S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
+					S32 length = sTypeSize[region.mType]*region.mCount;
 					glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset);
 					stop_glerror();
 				}
@@ -1910,8 +1910,8 @@ void LLVertexBuffer::unmapBuffer()
 					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 					{
 						const MappedRegion& region = mMappedVertexRegions[i];
-						S32 offset = region.mIndex;
-						S32 length = region.mCount;
+						S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
+						S32 length = sTypeSize[region.mType]*region.mCount;
 						if (gGLManager.mHasMapBufferRange)
 						{
 							LLFastTimer t(FTM_VBO_FLUSH_RANGE);
@@ -2131,6 +2131,7 @@ bool LLVertexBuffer::bindGLArray()
 	if (mGLArray && sGLRenderArray != mGLArray)
 	{
 		{
+			LLFastTimer t(FTM_BIND_GL_ARRAY);
 #if GL_ARB_vertex_array_object
 			glBindVertexArray(mGLArray);
 #endif
@@ -2165,7 +2166,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 		sVBOActive = true;
 
 		llassert(!mGLArray || sGLRenderArray == mGLArray);
-		
+
 		ret = true;
 	}
 
@@ -2245,7 +2246,38 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 
 			if ((data_mask & required_mask) != required_mask)
 			{
-				llwarns << "Shader consumption mismatches data provision." << llendl;
+				
+				U32 unsatisfied_mask = (required_mask & ~data_mask);
+				U32 i = 0;
+
+				while (i < TYPE_MAX)
+				{
+                    U32 unsatisfied_flag = unsatisfied_mask & (1 << i);
+					switch (unsatisfied_flag)
+					{
+						case MAP_VERTEX: llinfos << "Missing vert pos" << llendl; break;
+						case MAP_NORMAL: llinfos << "Missing normals" << llendl; break;
+						case MAP_TEXCOORD0: llinfos << "Missing TC 0" << llendl; break;
+						case MAP_TEXCOORD1: llinfos << "Missing TC 1" << llendl; break;
+						case MAP_TEXCOORD2: llinfos << "Missing TC 2" << llendl; break;
+						case MAP_TEXCOORD3: llinfos << "Missing TC 3" << llendl; break;
+						case MAP_COLOR: llinfos << "Missing vert color" << llendl; break;
+						case MAP_EMISSIVE: llinfos << "Missing emissive" << llendl; break;
+						case MAP_TANGENT: llinfos << "Missing tangent" << llendl; break;
+						case MAP_WEIGHT: llinfos << "Missing weight" << llendl; break;
+						case MAP_WEIGHT4: llinfos << "Missing weightx4" << llendl; break;
+						case MAP_CLOTHWEIGHT: llinfos << "Missing clothweight" << llendl; break;
+						case MAP_TEXTURE_INDEX: llinfos << "Missing tex index" << llendl; break;
+						default: llinfos << "Missing who effin knows: " << unsatisfied_flag << llendl;
+					}					
+				}
+
+            if (unsatisfied_mask & (1 << TYPE_INDEX))
+            {
+               llinfos << "Missing indices" << llendl;
+            }
+
+				llerrs << "Shader consumption mismatches data provision." << llendl;
 			}
 		}
 	}
@@ -2512,8 +2544,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 	llglassertok();
 }
 
-LLVertexBuffer::MappedRegion::MappedRegion(S32 index, S32 count)
-: mIndex(index), mCount(count)
+LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
+: mType(type), mIndex(index), mCount(count)
 { 
 	mEnd = mIndex+mCount;	
 }	
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index b7597cf60e72b73c7759c6a3acb057b340c4cd1b..de58207c23e38206a060f6e9517a030e5233b326 100755
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -104,11 +104,12 @@ class LLVertexBuffer : public LLRefCount
 	class MappedRegion
 	{
 	public:
+		S32 mType;
 		S32 mIndex;
 		S32 mCount;
 		S32 mEnd;
 		
-		MappedRegion(S32 index, S32 count);
+		MappedRegion(S32 type, S32 index, S32 count);
 	};
 
 	LLVertexBuffer(const LLVertexBuffer& rhs)
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 4f2c1d15f6df48073057472403968720cb96e72b..5b3413147c957b8ea5c1233ea0409dfa13288fc0 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.6.6
+3.6.7
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 31c69f6b3ef9f4294c17caf4339ddb631f537e70..eeed12499d831aa3eb89be5396364a235ab2307e 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8842,6 +8842,18 @@
     </array>
   </map>
 
+  <key>RenderSpecularPrecision</key>
+  <map>
+    <key>Comment</key>
+    <string>Force 32-bit floating point LUT</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>0</real>
+  </map>
+  
   <key>RenderSpecularResX</key>
   <map>
     <key>Comment</key>
@@ -9132,6 +9144,17 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
+  <key>RenderDeferredDisplayGamma</key>
+  <map>
+    <key>Comment</key>
+    <string>Gamma ramp exponent for final correction before display gamma.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>2.2</real>
+  </map>
     <key>RenderGLCoreProfile</key>
     <map>
       <key>Comment</key>
@@ -9892,6 +9915,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>RenderWaterMaterials</key>
+    <map>
+      <key>Comment</key>
+      <string>Water planar reflections include materials rendering.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RenderWaterMipNormal</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 4b428cb904b16968c20966b20abb0a057ef80fed..e5f7366b707264dc9d7feebc657458c7d9a504f4 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -35,6 +35,26 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
+uniform float display_gamma;
+uniform vec4 gamma;
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform float haze_horizon;
+uniform float haze_density;
+uniform float cloud_shadow;
+uniform float density_multiplier;
+uniform float distance_multiplier;
+uniform float max_y;
+uniform vec4 glow;
+uniform float scene_light_strength;
+uniform mat3 env_mat;
+uniform mat3 ssao_effect_mat;
+
+uniform vec3 sun_dir;
+
 #if HAS_SHADOW
 uniform sampler2DShadow shadowMap0;
 uniform sampler2DShadow shadowMap1;
@@ -53,15 +73,8 @@ uniform float shadow_bias;
 uniform sampler2D diffuseMap;
 #endif
 
-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_pointlight_col;
-VARYING vec3 vary_pointlight_col_linear;
 VARYING vec2 vary_texcoord0;
 VARYING vec3 vary_norm;
 
@@ -69,12 +82,73 @@ VARYING vec3 vary_norm;
 VARYING vec4 vertex_color;
 #endif
 
+vec3 vary_PositionEye;
+vec3 vary_SunlitColor;
+vec3 vary_AmblitColor;
+vec3 vary_AdditiveColor;
+vec3 vary_AtmosAttenuation;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
 uniform vec4 light_position[8];
 uniform vec3 light_direction[8];
 uniform vec3 light_attenuation[8]; 
 uniform vec3 light_diffuse[8];
 
-uniform vec2 screen_res;
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
+vec3 decode_normal (vec2 enc)
+{
+    vec2 fenc = enc*4-2;
+    float f = dot(fenc,fenc);
+    float g = sqrt(1-f/4);
+    vec3 n;
+    n.xy = fenc*g;
+    n.z = 1-f/2;
+    return n;
+}
 
 vec3 calcDirectionalLight(vec3 n, vec3 l)
 {
@@ -83,7 +157,7 @@ vec3 calcDirectionalLight(vec3 n, vec3 l)
 	return vec3(a,a,a);
 }
 
-float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
 {
 	//get light vector
 	vec3 lv = lp.xyz-v;
@@ -91,19 +165,20 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa
 	//get distance
 	float d = length(lv);
 	
-	float da = 0.0;
+	float da = 1.0;
 
-	//if (d > 0.0 && la > 0.0 && fa > 0.0)
+	vec3 col = vec3(0);
+
+	if (d > 0.0 && la > 0.0 && fa > 0.0)
 	{
 		//normalize light vector
-		lv /= d;
+		lv = normalize(lv);
 	
 		//distance attenuation
-		float dist = d*la;
-		da = clamp(1.0-(dist+fa-1.0)/fa, 0.0, 1.0);
-		da *= da;
-		da *= 2.0;
-	
+		float dist = d/la;
+		float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
+		dist_atten *= dist_atten;
+		dist_atten *= 2.0;
 
 		// spotlight coefficient.
 		float spot = max(dot(-ln, lv), is_pointlight);
@@ -111,9 +186,15 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa
 
 		//angular attenuation
 		da *= max(dot(n, lv), 0.0);		
+
+		float lit = max(da * dist_atten,0.0);
+
+		col = light_col * lit * diffuse;
+
+		// no spec for alpha shader...
 	}
 
-	return da;	
+	return max(col, vec3(0.0,0.0,0.0));
 }
 
 #if HAS_SHADOW
@@ -136,40 +217,254 @@ float pcfShadow(sampler2DShadow shadowMap, vec4 stc)
 }
 #endif
 
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
 
-void main() 
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
 {
-#ifdef USE_INDEXED_TEX
-	vec4 diff = diffuseLookup(vary_texcoord0.xy);
-#else
-	vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
-#endif
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
 
-#ifdef USE_VERTEX_COLOR
-	float vertex_color_alpha = vertex_color.a;	
-#else
-	float vertex_color_alpha = 1.0;
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
 #endif
 
-	float alpha = vertex_color_alpha*diff.a;
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
 
-	vec4 gamma_diff = diff;
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
 
-	diff.rgb = pow(diff.rgb, vec3(2.2f, 2.2f, 2.2f));
+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);
+	
+	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 + vec4(haze_density * 0.25)) * (density_multiplier * max_y);
+		//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);
+	blue_weight = blue_density / temp1;
+	haze_weight = vec4(haze_density) / 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;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z * distance_multiplier);
+
+	//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 * 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) + tmpAmbient)
+	  + (haze_horizon * haze_weight) * (sunlight*(1.-cloud_shadow) * 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 / vec3(scene_light_strength, scene_light_strength, scene_light_strength));
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	return (light * vec3(scene_light_strength, scene_light_strength, scene_light_strength));
+}
+
+vec3 atmosAmbient(vec3 light)
+{
+	return getAmblitColor() + (light * vec3(0.5f, 0.5f, 0.5f));
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return getSunlitColor() * vec3(lightIntensity, lightIntensity, lightIntensity);
+}
+
+vec3 scaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+    vec3 zeroes = vec3(0.0f, 0.0f, 0.0f);
+    vec3 ones   = vec3(1.0f, 1.0f, 1.0f);
+
+	light = ones - clamp(light, zeroes, ones);
+	light = ones - pow(light, gamma.xxx);
+
+	return light;
+}
+
+vec3 fullbrightAtmosTransport(vec3 light) {
+	float brightness = dot(light.rgb, vec3(0.33333));
+
+	return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness);
+}
+
+vec3 fullbrightScaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	return light;
+}
+
+void main() 
+{
 	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
 	frag *= screen_res;
 	
 	vec4 pos = vec4(vary_position, 1.0);
 	
+	float shadow = 1.0;
 
 #if HAS_SHADOW
-	float shadow = 0.0;
 	vec4 spos = pos;
 		
 	if (spos.z > -shadow_clip.w)
 	{	
+		shadow = 0.0;
+
 		vec4 lpos;
 		
 		vec4 near_split = shadow_clip*-0.75;
@@ -230,30 +525,81 @@ void main()
 	}
 #endif
 
-	vec3 normal = vary_norm; 
-	
-	vec3 l = light_position[0].xyz;
-	vec3 dlight = calcDirectionalLight(normal, l);
-	dlight = dlight * vary_directional.rgb * vary_pointlight_col;
+#ifdef USE_INDEXED_TEX
+	vec4 diff = diffuseLookup(vary_texcoord0.xy);
+#else
+	vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
+#endif
 
-#if HAS_SHADOW
-	vec4 col = vec4(vary_ambient + dlight * shadow, vertex_color_alpha);
+#ifdef FOR_IMPOSTOR
+	vec4 color;
+	color.rgb = diff.rgb;
+
+#ifdef USE_VERTEX_COLOR
+	float final_alpha = diff.a * vertex_color.a;
+	diff.rgb *= vertex_color.rgb;
 #else
-	vec4 col = vec4(vary_ambient + dlight, vertex_color_alpha);
+	float final_alpha = diff.a;
 #endif
+	
+	// Insure we don't pollute depth with invis pixels in impostor rendering
+	//
+	if (final_alpha < 0.01)
+	{
+		discard;
+	}
+#else
+	
+#ifdef USE_VERTEX_COLOR
+	float final_alpha = diff.a * vertex_color.a;
+	diff.rgb *= vertex_color.rgb;
+#else
+	float final_alpha = diff.a;
+#endif
+
+
+	vec4 gamma_diff = diff;	
+	diff.rgb = srgb_to_linear(diff.rgb);
+
+	vec3 norm = vary_norm; 
+
+	calcAtmospherics(pos.xyz, 1.0);
+
+	vec2 abnormal	= encode_normal(norm.xyz);
+		 norm.xyz   = decode_normal(abnormal.xy);
+
+	float da = dot(norm.xyz, sun_dir.xyz);
+
+    float final_da = da;
+          final_da = min(final_da, shadow);
+          final_da = max(final_da, 0.0f);
+		  final_da = min(final_da, 1.0f);
+		  final_da = pow(final_da, 1.0/1.3);
+
+	vec4 color = vec4(0,0,0,0);
 
-	vec4 color = gamma_diff * col;
+	color.rgb = atmosAmbient(color.rgb);
+	color.a   = final_alpha;
+
+	float ambient = abs(da);
+	ambient *= 0.5;
+	ambient *= ambient;
+	ambient = (1.0-ambient);
+
+	color.rgb *= ambient;
+	color.rgb += atmosAffectDirectionalLight(final_da);
+	color.rgb *= gamma_diff.rgb;
+
+	//color.rgb = mix(diff.rgb, color.rgb, final_alpha);
 	
 	color.rgb = atmosLighting(color.rgb);
-
 	color.rgb = scaleSoftClip(color.rgb);
 
-	//convert to linear space
-	color.rgb = pow(color.rgb, vec3(2.2));
-	col = vec4(0,0,0,0);
+	vec4 light = vec4(0,0,0,0);
 
+	color.rgb = srgb_to_linear(color.rgb);
 	
-   #define LIGHT_LOOP(i) col.rgb += light_diffuse[i].rgb * calcPointLightOrSpotLight(pos.xyz, normal, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z);
+   #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, diff.rgb, pos.xyz, norm, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z);
 
 	LIGHT_LOOP(1)
 	LIGHT_LOOP(2)
@@ -263,10 +609,19 @@ void main()
 	LIGHT_LOOP(6)
 	LIGHT_LOOP(7)
 
-	color.rgb += diff.rgb * vary_pointlight_col_linear * col.rgb;
+	// keep it linear
+	//
+	color.rgb += light.rgb;
 
-	//convert to gamma space
-	color.rgb = pow(color.rgb, vec3(1.0/2.2));
+	// straight to display gamma, we're post-deferred
+	//
+	color.rgb = linear_to_srgb(color.rgb);
+
+#ifdef WATER_FOG
+	color = applyWaterFogDeferred(pos.xyz, color);
+#endif
+
+#endif
 
 	frag_color = color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index cc63baa42256ffa05663b7c1b98055657ddfe99a..b40785bbd77849518e090dc9a1ffb62a30dc4fb8 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -55,33 +55,18 @@ mat4 getSkinnedTransform();
 #endif
 #endif
 
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
-void calcAtmospherics(vec3 inPositionEye);
-
-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_pointlight_col;
-VARYING vec3 vary_pointlight_col_linear;
 
 #ifdef USE_VERTEX_COLOR
 VARYING vec4 vertex_color;
 #endif
 
 VARYING vec2 vary_texcoord0;
-
 VARYING vec3 vary_norm;
 
 uniform float near_clip;
 
-uniform vec3 sun_dir;
-
 void main()
 {
 	vec4 pos;
@@ -134,42 +119,8 @@ void main()
 	vary_norm = norm;
 	vary_position = pos.xyz;
 
-	calcAtmospherics(pos.xyz);
-
-#ifndef USE_VERTEX_COLOR
-	vec4 diffuse_color = vec4(1,1,1,1);
-#endif
-	//vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.));
-	vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a);
-	
-	vec3 diff = diffuse_color.rgb;
-
-	
-
-	vary_pointlight_col = diff;
-	vary_pointlight_col_linear = pow(diff, vec3(2.2));
-
-	
-	col.rgb = vec3(0,0,0);
-
-	// Add windlight lights
-	col.rgb = atmosAmbient(col.rgb);
-	
-	float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
-	ambient *= 0.5;
-	ambient *= ambient;
-	ambient = (1.0-ambient);
-
-	col.rgb *= ambient;
-
-	vary_ambient = col.rgb*diff.rgb;
-
-	vary_directional.rgb = atmosAffectDirectionalLight(1.0f);
-	
-	col.rgb = col.rgb*diff.rgb;
-	
 #ifdef USE_VERTEX_COLOR
-	vertex_color = col;
+	vertex_color = diffuse_color;
 #endif
 	
 #ifdef HAS_SKIN
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
index 59d109b886a6f8a4d9d3c7019e3f5c9353c8428d..8525e13333eaa9fff6c2fd5d90b3655d2ef93b34 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
@@ -50,7 +50,7 @@ void main()
 	{
 		discard;
 	}
-
+	
 	frag_data[0] = vec4(col.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0);
 	vec3 nvn = normalize(vary_normal);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index dc1dead656120b9132133828001af2e5601c638e..f22b16965c471a07f49bbf671a75e1ef7e20a173 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -35,29 +35,143 @@ out vec4 frag_color;
 uniform sampler2D diffuseMap;
 #endif
 
+VARYING vec3 vary_position;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
-vec3 fullbrightAtmosTransport(vec3 light);
-vec3 fullbrightScaleSoftClip(vec3 light);
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+vec3 fullbrightAtmosTransportDeferred(vec3 light)
+{
+	return light;
+}
+
+vec3 fullbrightScaleSoftClipDeferred(vec3 light)
+{
+	//soft clip effect:
+	return light;
+}
+
+#ifdef HAS_ALPHA_MASK
+uniform float minimum_alpha;
+#endif
+
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
 
 void main() 
 {
 #if HAS_DIFFUSE_LOOKUP
-	vec4 color = diffuseLookup(vary_texcoord0.xy)*vertex_color;
+	vec4 color = diffuseLookup(vary_texcoord0.xy);
 #else
-	vec4 color = texture2D(diffuseMap, vary_texcoord0.xy)*vertex_color;
+	vec4 color = texture2D(diffuseMap, vary_texcoord0.xy);
 #endif
 
-	color.rgb = pow(color.rgb,vec3(2.2f,2.2f,2.2f));
-	
-	color.rgb = fullbrightAtmosTransport(color.rgb);
+	float final_alpha = color.a * vertex_color.a;
 
-	color.rgb = fullbrightScaleSoftClip(color.rgb);
+#ifdef HAS_ALPHA_MASK
+	if (color.a < minimum_alpha)
+	{
+		discard;
+	}
+#endif
+
+	color.rgb *= vertex_color.rgb;
+	color.rgb = srgb_to_linear(color.rgb);
+	color.rgb = fullbrightAtmosTransportDeferred(color.rgb);
+	color.rgb = fullbrightScaleSoftClipDeferred(color.rgb);
+	
+	color.rgb = linear_to_srgb(color.rgb);
 
-	color.rgb = pow(color.rgb, vec3(1.0/2.2));
+#ifdef WATER_FOG
+	vec3 pos = vary_position;
+	vec4 fogged = applyWaterFogDeferred(pos, vec4(color.rgb, final_alpha));
+	color.rgb = fogged.rgb;
+	color.a   = fogged.a;
+#else
+	color.a   = final_alpha;
+#endif
 
-	frag_color = color;
+	frag_color.rgb = color.rgb;
+	frag_color.a   = color.a;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index 3f09a153754d8c24333fed5465fb7ca6f17a880d..8e899e3e0f32df89f36b81531d979ced9b57f534 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -40,6 +40,9 @@ vec3 atmosAffectDirectionalLight(float lightIntensity);
 vec3 scaleDownLight(vec3 light);
 vec3 scaleUpLight(vec3 light);
 
+#ifdef WATER_FOG
+VARYING vec3 vary_position;
+#endif
 
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
@@ -53,7 +56,11 @@ void main()
 	passTextureIndex();
 
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-	
+
+#ifdef WATER_FOG
+	vary_position = pos.xyz;
+#endif
+
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	calcAtmospherics(pos.xyz);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
index bc0719cb82de9a8537dc4963fbb4b74175dca768..f8fdde43f9fe80a960de67e7b49d9503914c176d 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
@@ -38,6 +38,42 @@ uniform sampler2D specularMap;
 
 VARYING vec2 vary_texcoord0;
 
+vec3 decode_normal (vec2 enc)
+{
+    vec2 fenc = enc*4-2;
+    float f = dot(fenc,fenc);
+    float g = sqrt(1-f/4);
+    vec3 n;
+    n.xy = fenc*g;
+    n.z = 1-f/2;
+    return n;
+}
+
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 void main() 
 {
 	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
@@ -47,7 +83,12 @@ void main()
 		discard;
 	}
 
-	frag_data[0] = vec4(col.rgb, col.a * 0.005);
-	frag_data[1] = texture2D(specularMap, vary_texcoord0.xy);
-	frag_data[2] = vec4(texture2D(normalMap, vary_texcoord0.xy).xyz, 0.0);
+	vec4 norm = texture2D(normalMap,   vary_texcoord0.xy);
+	vec4 spec = texture2D(specularMap, vary_texcoord0.xy);
+
+	col.rgb = linear_to_srgb(col.rgb);
+
+	frag_data[0] = vec4(col.rgb, 0.0);
+	frag_data[1] = spec;
+	frag_data[2] = vec4(norm.xy,0,0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index 27bb43110b1ebaae4e93ea188ed904c6e423b8df..07d28ed4cdd2df2ea7ec7f8376fb0c3209640471 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -29,6 +29,44 @@
 #define DIFFUSE_ALPHA_MODE_EMISSIVE 3
 
 uniform float emissive_brightness;
+uniform float display_gamma;
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
 
 #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
 
@@ -114,6 +152,52 @@ uniform vec3 light_direction[8];
 uniform vec3 light_attenuation[8]; 
 uniform vec3 light_diffuse[8];
 
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 vec3 calcDirectionalLight(vec3 n, vec3 l)
 {
 	float a = max(dot(n,l),0.0);
@@ -133,14 +217,14 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spe
 
 	vec3 col = vec3(0,0,0);
 
-	//if (d > 0.0 && la > 0.0 && fa > 0.0)
+	if (d > 0.0 && la > 0.0 && fa > 0.0)
 	{
 		//normalize light vector
-		lv /= d;
+		lv = normalize(lv);
 	
 		//distance attenuation
-		float dist = d*la;
-		float dist_atten = clamp(1.0-(dist-1.0+fa)/fa, 0.0, 1.0);
+		float dist = d/la;
+		float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
 		dist_atten *= dist_atten;
 		dist_atten *= 2.0;
 
@@ -199,10 +283,13 @@ vec4 getPosition_d(vec2 pos_screen, float depth)
 	return pos;
 }
 
+#ifndef WATER_FOG
 vec3 getPositionEye()
 {
 	return vary_PositionEye;
 }
+#endif
+
 vec3 getSunlitColor()
 {
 	return vary_SunlitColor;
@@ -458,8 +545,8 @@ void main()
 #endif
 
 #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
-	vec3 old_diffcol = diffcol.rgb;
-	diffcol.rgb = pow(diffcol.rgb, vec3(2.2));
+	vec3 gamma_diff = diffcol.rgb;
+	diffcol.rgb = srgb_to_linear(diffcol.rgb);
 #endif
 
 #if HAS_SPECULAR_MAP
@@ -485,6 +572,9 @@ void main()
     norm.xyz = tnorm;
     norm.xyz = normalize(norm.xyz);
 
+	vec2 abnormal	= encode_normal(norm.xyz);
+		 norm.xyz   = decode_normal(abnormal.xy);
+
 	vec4 final_color = diffcol;
 	
 #if (DIFFUSE_ALPHA_MODE != DIFFUSE_ALPHA_MODE_EMISSIVE)
@@ -588,22 +678,26 @@ void main()
 	vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
 
 	float da =dot(norm.xyz, sun_dir.xyz);
+
     float final_da = da;
           final_da = min(final_da, shadow);
-          final_da = max(final_da, diffuse.a);
+          //final_da = max(final_da, diffuse.a);
           final_da = max(final_da, 0.0f);
+		  final_da = min(final_da, 1.0f);
+		  final_da = pow(final_da, 1.0/1.3);
 
 	col.rgb = atmosAmbient(col);
 	
-	float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
+	float ambient = min(abs(da), 1.0);
 	ambient *= 0.5;
 	ambient *= ambient;
 	ambient = (1.0-ambient);
 
 	col.rgb *= ambient;
 
-	col.rgb = col.rgb + atmosAffectDirectionalLight(pow(final_da, 1.0/1.3));
-	col.rgb *= old_diffcol.rgb;
+	col.rgb = col.rgb + atmosAffectDirectionalLight(final_da);
+
+	col.rgb *= gamma_diff.rgb;
 	
 
 	float glare = 0.0;
@@ -626,7 +720,8 @@ void main()
 		col += spec_contrib;
 	}
 
-	col = mix(col.rgb, old_diffcol.rgb, diffuse.a);
+
+	col = mix(col.rgb, diffcol.rgb, diffuse.a);
 
 	if (envIntensity > 0.0)
 	{
@@ -644,16 +739,20 @@ void main()
 		glare += cur_glare;
 	}
 
-	col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a);
-	col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
+	//col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a);
+	//col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col),  diffuse.a);
+
+	col = atmosLighting(col);
+	col = scaleSoftClip(col);
 
 	//convert to linear space before adding local lights
-	col = pow(col, vec3(2.2));
+	col = srgb_to_linear(col);
 
-			
 	vec3 npos = normalize(-pos.xyz);
+			
+	vec3 light = vec3(0,0,0);
 
- #define LIGHT_LOOP(i) col.rgb = col.rgb + calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, final_specular, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare);
+ #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, final_specular, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare);
 
 		LIGHT_LOOP(1)
 		LIGHT_LOOP(2)
@@ -663,13 +762,22 @@ void main()
 		LIGHT_LOOP(6)
 		LIGHT_LOOP(7)
 
+	col.rgb += light.rgb;
+
+	glare = min(glare, 1.0);
+	float al = max(diffcol.a,glare)*vertex_color.a;
 
 	//convert to gamma space for display on screen
-	col.rgb = pow(col.rgb, vec3(1.0/2.2));
+	col.rgb = linear_to_srgb(col.rgb);
+
+#ifdef WATER_FOG
+	vec4 temp = applyWaterFogDeferred(pos, vec4(col.rgb, al));
+	col.rgb = temp.rgb;
+	al = temp.a;
+#endif
 
 	frag_color.rgb = col.rgb;
-	glare = min(glare, 1.0);
-	frag_color.a = max(diffcol.a,glare)*vertex_color.a;
+	frag_color.a   = al;
 
 #else
 	frag_data[0] = final_color;
@@ -677,3 +785,4 @@ void main()
 	frag_data[2] = final_normal; // XY = Normal.  Z = Env. intensity.
 #endif
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
index b25032866ba5b7d8a63832a18647f1a9502e36cb..393d1e69da76417d2f2b63f170ac1fff80a13c5f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
@@ -142,3 +142,4 @@ vary_normal  = n;
 #endif
 #endif
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 5a08980fec09cb17b666394cda899b90a3faff6c..236567219bf404a660b1faa188a3aa1c90d1fc74 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -36,6 +36,7 @@ uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
 uniform sampler2DRect normalMap;
 uniform samplerCube environmentMap;
+uniform sampler2D noiseMap;
 uniform sampler2D lightFunc;
 
 
@@ -98,6 +99,8 @@ void main()
 	norm = normalize(norm);
 	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);
 
@@ -105,47 +108,56 @@ void main()
 	for (int i = 0; i < LIGHT_COUNT; ++i)
 	{
 		vec3 lv = light[i].xyz-pos;
-		float d = length(lv);
-		float dist = d * light[i].w;
+		float dist = length(lv);
+		dist /= light[i].w;
 		if (dist <= 1.0)
 		{
-			float da = dot(norm, lv);
+		float da = dot(norm, lv);
 			if (da > 0.0)
-			{
-				lv /= d;
-				da = dot(norm, lv);
+		{
+			lv = normalize(lv);
+			da = dot(norm, lv);
 			
-				float fa = light_col[i].a+1.0;
-				float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
-				dist_atten *= dist_atten;
-				dist_atten *= 2.0;
+			float fa = light_col[i].a+1.0;
+			float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
+			dist_atten *= dist_atten;
+			dist_atten *= 2.0;
 			
-				float lit = da * dist_atten;
+			dist_atten *= noise;
+
+			float lit = da * dist_atten;
 						
-				vec3 col = light_col[i].rgb*lit*diff;
+			vec3 col = light_col[i].rgb*lit*diff;
 			
-				if (spec.a > 0.0)
-				{
-					lit = min(da*6.0, 1.0) * dist_atten;
-					//vec3 ref = dot(pos+lv, norm);
-					vec3 h = normalize(lv+npos);
-					float nh = dot(norm, h);
-					float nv = dot(norm, npos);
-					float vh = dot(npos, h);
-					float sa = nh;
-					float fres = pow(1 - dot(h, npos), 5)*0.4+0.5;
-
-					float gtdenom = 2 * nh;
-					float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
+			//vec3 col = vec3(dist2, light_col[i].a, lit);
+			
+			if (spec.a > 0.0)
+			{
+				lit = min(da*6.0, 1.0) * dist_atten;
+				//vec3 ref = dot(pos+lv, norm);
+				vec3 h = normalize(lv+npos);
+				float nh = dot(norm, h);
+				float nv = dot(norm, npos);
+				float vh = dot(npos, h);
+				float sa = nh;
+				float fres = pow(1 - dot(h, npos), 5)*0.4+0.5;
+
+				float gtdenom = 2 * nh;
+				float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
 								
+				if (nh > 0.0)
+				{
 					float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da);
-					col += max(lit*scol*light_col[i].rgb*spec.rgb, vec3(0.0));
+					col += lit*scol*light_col[i].rgb*spec.rgb;
+					//col += spec.rgb;
 				}
-			
-				out_col += col;
 			}
+			
+			out_col += col;
 		}
 	}
+	}
+	
 	
 	frag_color.rgb = out_col;
 	frag_color.a = 0.0;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
index 7b0982324230c93e6c765f7070a4c9fbb145c099..2e5a2c273eba17ffe675ff74b37b315b6b68ad6a 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
@@ -84,16 +84,48 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
 
-vec4 correctWithGamma(vec4 col)
+vec3 linear_to_srgb(vec3 cl)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
 }
 
+
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
-	ret = correctWithGamma(ret);
+	ret.rgb = srgb_to_linear(ret.rgb);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -109,7 +141,7 @@ vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
-	ret = correctWithGamma(ret);
+	ret.rgb = srgb_to_linear(ret.rgb);
 	
 	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
 	
@@ -127,7 +159,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
 vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
-	ret = correctWithGamma(ret);
+	ret.rgb = srgb_to_linear(ret.rgb);
 	
 	vec2 dist = tc-vec2(0.5);
 	
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index b331258952ca43e451199fe928bf5e1863843e8c..73b9767a7166ee8008e1fb28ff0da51b05ea0cf6 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -93,52 +93,64 @@ void main()
 	
 	vec3 pos = getPosition(frag.xy).xyz;
 	vec3 lv = trans_center.xyz-pos;
-	float d = length(lv);
+	float dist = length(lv);
+	dist /= size;
+	if (dist > 1.0)
+	{
+		discard;
+	}
 	
-	float dist = d*size;
-
-	vec3 col = vec3(0.0);
-	if (dist <= 1.0)
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
+	norm = decode_normal(norm.xy); // unpack norm
+	float da = dot(norm, lv);
+	if (da < 0.0)
 	{
-		vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-		norm = decode_normal(norm.xy); // unpack norm
-			
-		norm = normalize(norm);
-		lv = normalize(lv);
-		float da = max(dot(norm, lv), 0.0);
+		discard;
+	}
+	
+	norm = normalize(norm);
+	lv = normalize(lv);
+	da = dot(norm, lv);
 	
 		//float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	
-		col = texture2DRect(diffuseRect, frag.xy).rgb;
-		float fa = falloff+1.0;
-		float dist_atten = clamp(1.0-(dist-1.0+fa)/fa, 0.0, 1.0);
-		dist_atten *= dist_atten;
-		dist_atten *= 2.0;
+	vec3 col = texture2DRect(diffuseRect, frag.xy).rgb;
+	float fa = falloff+1.0;
+	float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
+	dist_atten *= dist_atten;
+	dist_atten *= 2.0;
 	
 		float lit = da * dist_atten;
 
-		col = color.rgb*lit*col;
+	col = color.rgb*lit*col;
 
-		vec4 spec = texture2DRect(specularRect, frag.xy);
-		if (spec.a > 0.0)
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+	if (spec.a > 0.0)
+	{
+		lit = min(da*6.0, 1.0) * dist_atten;
+
+		vec3 npos = -normalize(pos);
+		vec3 h = normalize(lv+npos);
+		float nh = dot(norm, h);
+		float nv = dot(norm, npos);
+		float vh = dot(npos, h);
+		float sa = nh;
+		float fres = pow(1 - dot(h, npos), 5) * 0.4+0.5;
+		float gtdenom = 2 * nh;
+		float gt = max(0,(min(gtdenom * nv / vh, gtdenom * da / vh)));
+
+		if (nh > 0.0)
 		{
-			lit = min(da*6.0, 1.0) * dist_atten;
-
-			vec3 npos = -normalize(pos);
-			vec3 h = normalize(lv+npos);
-			float nh = dot(norm, h);
-			float nv = dot(norm, npos);
-			float vh = dot(npos, h);
-			float sa = nh;
-			float fres = pow(1 - dot(h, npos), 5) * 0.4+0.5;
-			float gtdenom = 2 * nh;
-			float gt = max(0,(min(gtdenom * nv / vh, gtdenom * da / vh)));
-
 			float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da);
-			col += max(lit*scol*color.rgb*spec.rgb, vec3(0.0));
+			col += lit*scol*color.rgb*spec.rgb;
 		}
 	}
 	
+	if (dot(col, col) <= 0.0)
+	{
+		discard;
+	}
+		
 	frag_color.rgb = col;	
 	frag_color.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
index 6f2cfae6d2381e416712c2564ab96125dbf0edc8..4e2f98aa29bb6e4fb4dc5255af184a5fcd41b9d6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
@@ -36,11 +36,32 @@ uniform sampler2DRect diffuseRect;
 uniform vec2 screen_res;
 VARYING vec2 vary_fragcoord;
 
-uniform float texture_gamma;
+uniform float display_gamma;
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 
 void main() 
 {
 	vec4 diff = texture2DRect(diffuseRect, vary_fragcoord);
-	frag_color = pow(diff, vec4(texture_gamma, texture_gamma, texture_gamma, 1.0f));
+	diff.rgb = linear_to_srgb(diff.rgb);
+	frag_color = diff;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 26b1041cd5a4e9bd8976c69529363ab55c5eef26..760d52a9ce47de62351be9eb7905bd54fe591538 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -79,6 +79,43 @@ vec3 vary_AtmosAttenuation;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+
 vec3 decode_normal (vec2 enc)
 {
     vec2 fenc = enc*4-2;
@@ -154,6 +191,53 @@ void setAtmosAttenuation(vec3 v)
 	vary_AtmosAttenuation = v;
 }
 
+
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 
 	vec3 P = inPositionEye;
@@ -308,13 +392,16 @@ void main()
 	float envIntensity = norm.z;
 	norm.xyz = decode_normal(norm.xy); // unpack norm
 		
-	float da = max(dot(norm.xyz, sun_dir.xyz), 0.0);
-	da = pow(da, 1.0/1.3);
+	float da = dot(norm.xyz, sun_dir.xyz);
+
+	float final_da = max(0.0,da);
+          final_da = min(final_da, 1.0f);
+	      final_da = pow(final_da, 1.0/1.3);
 
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
 
 	//convert to gamma space
-	diffuse.rgb = pow(diffuse.rgb, vec3(1.0/2.2));
+	diffuse.rgb = linear_to_srgb(diffuse.rgb);
 
 	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
 	vec3 col;
@@ -330,7 +417,7 @@ void main()
 
 		col.rgb *= ambient;
 
-		col += atmosAffectDirectionalLight(max(min(da, 1.0), 0.0));
+		col += atmosAffectDirectionalLight(final_da);	
 	
 		col *= diffuse.rgb;
 	
@@ -370,13 +457,19 @@ void main()
 			col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
 		}
 
-		col = pow(col, vec3(2.2));
+		#ifdef WATER_FOG
+			vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom));
+			col = fogged.rgb;
+			bloom = fogged.a;
+		#endif
+
+		col = srgb_to_linear(col);
 
 		//col = vec3(1,0,1);
 		//col.g = envIntensity;
 	}
 
-	frag_color.rgb = col;
-
+	frag_color.rgb = col.rgb;
 	frag_color.a = bloom;
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
index e9e6ba993511af3fb1d7cef4bd18574cf21f16ac..8d8a6c9dde2bee4074dae24eb82daf56f27360ad 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -85,9 +85,46 @@ vec3 decode_normal (vec2 enc)
     return n;
 }
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec4 correctWithGamma(vec4 col)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	return vec4(srgb_to_linear(col.rgb), col.a);
 }
 
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl b/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..587f3d5a944587f4166b94b9a68eefff0464d6d5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl
@@ -0,0 +1,46 @@
+/** 
+ * @file srgb.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+	return mix(high_range, low_range, lte);
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+	return mix(high_range, low_range, lt);
+
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl b/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..6cc1e6e798d64c31268cac2f4c24a61f7f19cf6c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl
@@ -0,0 +1,54 @@
+/** 
+ * @file srgb.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+	return result;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..78f841c73314ece6b65658efcf9701700339ea87
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl
@@ -0,0 +1,157 @@
+/**
+ * @file underWaterF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+ 
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_data[3];
+#else
+#define frag_data gl_FragData
+#endif
+
+uniform sampler2D diffuseMap;
+uniform sampler2D bumpMap;   
+uniform sampler2D screenTex;
+uniform sampler2D refTex;
+uniform sampler2D screenDepth;
+
+uniform vec4 fogCol;
+uniform vec3 lightDir;
+uniform vec3 specular;
+uniform float lightExp;
+uniform vec2 fbScale;
+uniform float refScale;
+uniform float znear;
+uniform float zfar;
+uniform float kd;
+uniform vec4 waterPlane;
+uniform vec3 eyeVec;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+uniform vec2 screenRes;
+
+//bigWave is (refCoord.w, view.w);
+VARYING vec4 refCoord;
+VARYING vec4 littleWave;
+VARYING vec4 view;
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
+vec4 applyWaterFog(vec4 color, vec3 viewVec)
+{
+	//normalize view vector
+	vec3 view = normalize(viewVec);
+	float es = -view.z;
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	//get object depth
+	float depth = length(viewVec);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	//return vec4(1.0, 0.0, 1.0, 1.0);
+	return color * D + kc * L;
+	//depth /= 10.0;
+	//return vec4(depth,depth,depth,0.0);
+}
+
+void main() 
+{
+	vec4 color;
+	    
+	//get detail normals
+	vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0;
+	vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0;
+	vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0;    
+	vec3 wavef = normalize(wave1+wave2+wave3);
+	
+	//figure out distortion vector (ripply)   
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	distort = distort+wavef.xy*refScale;
+		
+	vec4 fb = texture2D(screenTex, distort);
+
+	frag_data[0] = vec4(linear_to_srgb(fb.rgb), 1.0); // diffuse
+	frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec
+	frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, displace
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
index 8de8ba1dd8a183ef1651e3d288f0ce5028482f5a..e7a3bb2001ff0bcb341ecbd9624d6834893d9b1f 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -53,11 +53,12 @@ uniform vec3 specular;
 uniform float lightExp;
 uniform float refScale;
 uniform float kd;
+uniform vec2 screenRes;
 uniform vec3 normScale;
 uniform float fresnelScale;
 uniform float fresnelOffset;
 uniform float blurMultiplier;
-uniform mat3 normal_matrix;
+uniform mat4 norm_mat; //region space to screen space
 
 //bigWave is (refCoord.w, view.w);
 VARYING vec4 refCoord;
@@ -65,6 +66,43 @@ VARYING vec4 littleWave;
 VARYING vec4 view;
 VARYING vec4 vary_position;
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -119,7 +157,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;
@@ -129,13 +167,14 @@ void main()
 	vec2 refvec4 = distort+refdistort4/dmod;
 	float dweight = min(dist2*blurMultiplier, 1.0);
 	vec4 baseCol = texture2D(refTex, refvec4);
+
 	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);
@@ -146,24 +185,17 @@ void main()
 	// Note we actually want to use just df1, but multiplying by 0.999999 gets around an nvidia compiler bug
 	color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999);
 	
-	float shadow = 1.0;
 	vec4 pos = vary_position;
 	
-	//vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
-	vec4 spos = pos;
-		
-	//spec *= shadow;
-	//color.rgb += spec * specular;
+	color.rgb += spec * specular;
 	
 	color.rgb = atmosTransport(color.rgb);
 	color.rgb = scaleSoftClip(color.rgb);
-	//color.a = spec * sunAngle2;
+	color.a   = spec * sunAngle2;
 
-	//wavef.z *= 0.1f;
-	//wavef = normalize(wavef);
-	vec3 screenspacewavef = normal_matrix*wavef;
+	vec3 screenspacewavef = normalize((norm_mat*vec4(wavef, 1.0)).xyz);
 	
-	frag_data[0] = vec4(color.rgb, 0.5); // diffuse
-	frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec
-	frag_data[2] = vec4(encode_normal(screenspacewavef), 0.0, 0.0); // normalxyz, displace
+	frag_data[0] = vec4(color.rgb, color); // diffuse
+	frag_data[1] = vec4(0);		// speccolor, spec
+	frag_data[2] = vec4(encode_normal(screenspacewavef.xyz*0.5+0.5), 0.05, 0);// normalxy, 0, 0
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
index ece34dcc4edd96efb98617a203386be6517789d5..9734acf005a372378eff057667cb4bfea6033210 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
@@ -85,7 +85,7 @@ void main()
 	pos.w = 1.0;
 	pos = modelview_matrix*pos;
 	
-	calcAtmospherics(view.xyz);
+	calcAtmospherics(pos.xyz);
 		
 	//pass wave parameters to pixel shader
 	vec2 bigWave =  (v.xy) * vec2(0.04,0.04)  + d1 * time * 0.055;
diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl
index 6523a06d22b6259945e24251c7c8b73fecfba192..f8efd7cb4ae2bbc881def496a9cf58ef08a0ba0b 100644
--- a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl
@@ -31,8 +31,6 @@ out vec4 frag_color;
 
 uniform sampler2D depthMap;
 
-uniform float delta;
-
 VARYING vec2 tc0;
 VARYING vec2 tc1;
 VARYING vec2 tc2;
diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
index 0e5dc0818363afffa65038762f0ca726ce3d7069..942c5888e753e2d406a1d0e993f1f4a822aa693c 100644
--- a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
@@ -33,8 +33,6 @@ out vec4 frag_color;
 
 uniform sampler2DRect depthMap;
 
-uniform float delta;
-
 VARYING vec2 tc0;
 VARYING vec2 tc1;
 VARYING vec2 tc2;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
index eaaa7b208d78773f996106c197687705d936d3fe..cad5b9ff043b63d417eb5870a2f1fab88782d9f3 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
@@ -41,13 +41,13 @@ void default_lighting()
 {
 	vec4 color = diffuseLookup(vary_texcoord0.xy);
 	
+	color *= vertex_color;
+
 	if (color.a < minimum_alpha)
 	{
 		discard;
 	}
 
-	color.rgb *= vertex_color.rgb;
-
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
index 62ca3f1ff162843c13b12f3fd98d1ae86622bc74..c20e00163c64ed1649d48fabb88a269baabb7e99 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -69,6 +69,43 @@ uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -88,10 +125,9 @@ vec3 decode_normal (vec2 enc)
 
 vec4 correctWithGamma(vec4 col)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	return vec4(srgb_to_linear(col.rgb), col.a);
 }
 
-
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
@@ -298,14 +334,12 @@ void main()
 			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
 			
 			vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+			stc /= stc.w;
 
 			if (stc.z > 0.0)
 			{
-				stc.xy /= stc.w;
+				float fatten = clamp(envIntensity*envIntensity+envIntensity*0.25, 0.25, 1.0);
 
-				float fatten = clamp(envIntensity*envIntensity+envIntensity*0.5, 0.25, 1.0);
-				
-				//stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
 				stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
 								
 				if (stc.x < 1.0 &&
@@ -313,7 +347,7 @@ void main()
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod-envIntensity*proj_lod).rgb*shadow*spec.rgb;										
+					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod).rgb*shadow*spec.rgb;										
 				}
 			}
 		}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 6e05091b57073ffc620a78c50036050a37af2345..1022c23f7b536c81adb6e3409eb925bf003008a1 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -78,6 +78,43 @@ vec3 vary_AtmosAttenuation;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -246,6 +283,52 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
 }
 
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 vec3 atmosLighting(vec3 light)
 {
 	light *= getAtmosAttenuation().r;
@@ -326,7 +409,7 @@ void main()
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
 
 	//convert to gamma space
-	diffuse.rgb = pow(diffuse.rgb, vec3(1.0/2.2));
+	diffuse.rgb = linear_to_srgb(diffuse.rgb);
 	
 	vec3 col;
 	float bloom = 0.0;
@@ -392,7 +475,13 @@ void main()
 			col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
 		}
 
-		col = pow(col, vec3(2.2));
+		#ifdef WATER_FOG
+			vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom));
+			col = fogged.rgb;
+			bloom = fogged.a;
+		#endif
+
+		col = srgb_to_linear(col);
 
 		//col = vec3(1,0,1);
 		//col.g = envIntensity;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
index 4bad439952138b1e5aa897a301ec2c7e14b686c9..7689b72d202a72ad343b4f1895ca0deb8d454c6b 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -86,9 +86,46 @@ vec3 decode_normal (vec2 enc)
     return n;
 }
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec4 correctWithGamma(vec4 col)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	return vec4(srgb_to_linear(col.rgb), col.a);
 }
 
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
@@ -316,7 +353,7 @@ void main()
 			}
 		}
 	}
-
+	
 	//not sure why, but this line prevents MATBUG-194
 	col = max(col, vec3(0.0));
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 14c09a23932fa3d27beb59d9348e2d8b0c85e32f..9682f3822738e6c79a87d042dea694f6d4f7298f 100755
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -132,10 +132,16 @@ void LLDrawable::destroy()
 		sNumZombieDrawables--;
 	}
 
+	// Attempt to catch violations of this in debug,
+	// knowing that some false alarms may result
+	//
+	llassert(!LLSpatialGroup::sNoDelete);
+
+	/* cannot be guaranteed and causes crashes on false alarms
 	if (LLSpatialGroup::sNoDelete)
 	{
 		llerrs << "Illegal deletion of LLDrawable!" << llendl;
-	}
+	}*/
 
 	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
 	mFaces.clear();
@@ -254,7 +260,7 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
 	return count;
 }
 
-static LLFastTimer::DeclareTimer FTM_ALLOCATE_FACE("Allocate Face");
+static LLFastTimer::DeclareTimer FTM_ALLOCATE_FACE("Allocate Face", true);
 
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
@@ -527,6 +533,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
 		}
 		updatePartition();
 	}
+
+	llassert(isAvatar() || isRoot() || mParent->isStatic());
 }
 
 // Returns "distance" between target destination and resulting xfrom
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 2f6e895cb7a6915be88b700c83f5ea0dd01563f3..1cd4d8743791f30b53b9e732b2f321d02eddf3c8 100755
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -93,15 +93,35 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 
 	if (pass == 0)
 	{
+		if (LLPipeline::sImpostorRender)
+		{
+			simple_shader = &gDeferredAlphaImpostorProgram;
+			fullbright_shader = &gDeferredFullbrightProgram;
+		}
+		else if (LLPipeline::sUnderWaterRender)
+		{
+			simple_shader = &gDeferredAlphaWaterProgram;
+			fullbright_shader = &gDeferredFullbrightWaterProgram;
+		}
+		else
+		{
 		simple_shader = &gDeferredAlphaProgram;
-		fullbright_shader = &gObjectFullbrightProgram;
+			fullbright_shader = &gDeferredFullbrightProgram;
+		}
+		
+		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+
 		fullbright_shader->bind();
 		fullbright_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); 
+		fullbright_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 		fullbright_shader->unbind();
+
 		//prime simple shader (loads shadow relevant uniforms)
 		gPipeline.bindDeferredShader(*simple_shader);
+
+		simple_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 	}
-	else
+	else if (!LLPipeline::sImpostorRender)
 	{
 		//update depth buffer sampler
 		gPipeline.mScreen.flush();
@@ -113,6 +133,23 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 		gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f);
 	}
 
+
+    if (LLPipeline::sRenderDeferred)
+    {
+		emissive_shader = &gDeferredEmissiveProgram;
+    }
+    else
+    {
+		if (LLPipeline::sUnderWaterRender)
+		{
+			emissive_shader = &gObjectEmissiveWaterProgram;
+		}
+		else
+		{
+			emissive_shader = &gObjectEmissiveProgram;
+		}
+    }
+
 	deferred_render = TRUE;
 	if (mVertexShaderLevel > 0)
 	{
@@ -124,7 +161,7 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
 { 
-	if (pass == 1)
+	if (pass == 1 && !LLPipeline::sImpostorRender)
 	{
 		gPipeline.mDeferredDepth.flush();
 		gPipeline.mScreen.bindTarget();
@@ -144,7 +181,13 @@ void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_ALPHA);
 	
-	if (LLPipeline::sUnderWaterRender)
+	if (LLPipeline::sImpostorRender)
+	{
+		simple_shader = &gObjectSimpleImpostorProgram;
+		fullbright_shader = &gObjectFullbrightProgram;
+		emissive_shader = &gObjectEmissiveProgram;
+	}
+	else if (LLPipeline::sUnderWaterRender)
 	{
 		simple_shader = &gObjectSimpleWaterProgram;
 		fullbright_shader = &gObjectFullbrightWaterProgram;
@@ -192,8 +235,13 @@ void LLDrawPoolAlpha::render(S32 pass)
 		gGL.setColorMask(true, true);
 	}
 	
-	LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy || 
-				(deferred_render && pass == 1) ? GL_TRUE : GL_FALSE);
+	bool write_depth = LLDrawPoolWater::sSkipScreenCopy
+						 || (deferred_render && pass == 1)
+						 // we want depth written so that rendered alpha will
+						 // contribute to the alpha mask used for impostors
+						 || LLPipeline::sImpostorRenderAlphaDepthPass;
+
+	LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
 
 	if (deferred_render && pass == 1)
 	{
@@ -239,11 +287,11 @@ void LLDrawPoolAlpha::render(S32 pass)
 
 	if (mVertexShaderLevel > 0)
 	{
-		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
+		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass);
 	}
 	else
 	{
-		renderAlpha(getVertexDataMask());
+		renderAlpha(getVertexDataMask(), pass);
 	}
 
 	gGL.setColorMask(true, false);
@@ -315,7 +363,7 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 	}
 }
 
-void LLDrawPoolAlpha::renderAlpha(U32 mask)
+void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 {
 	BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
@@ -331,15 +379,10 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 		if (group->mSpatialPartition->mRenderByGroup &&
 		    !group->isDead())
 		{
-			static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group");
-			LLFastTimer t(FTM_RENDER_ALPHA_GROUP_LOOP);
-
-			bool draw_glow_for_this_partition = mVertexShaderLevel > 0; // no shaders = no glow.
-
-			bool disable_cull = group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_PARTICLE ||
-				group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE;
-
-			LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0);
+			bool draw_glow_for_this_partition = mVertexShaderLevel > 0 && // no shaders = no glow.
+				// All particle systems seem to come off the wire with texture entries which claim that they glow.  This is probably a bug in the data.  Suppress.
+				group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_PARTICLE &&
+				group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD_PARTICLE;
 
 			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
 
@@ -353,11 +396,28 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					continue;
 				}
 
+				// Fix for bug - NORSPEC-271
+				// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+				// We don't want the nearly invisible objects to cause of DoF effects
+				if(pass == 1 && !LLPipeline::sImpostorRender)
+				{
+					LLFace*	face = params.mFace;
+					if(face)
+					{
+						const LLTextureEntry* tep = face->getTextureEntry();
+						if(tep)
+						{
+							if(tep->getColor().mV[3] < 0.1f)
+								continue;
+						}
+					}
+				}
+
 				LLRenderPass::applyModelMatrix(params);
 				
 				LLMaterial* mat = NULL;
 
-				if (deferred_render && !LLPipeline::sUnderWaterRender)
+				if (deferred_render)
 				{
 					mat = params.mMaterial;
 				}
@@ -401,6 +461,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					llassert(mask < LLMaterial::SHADER_COUNT);
 					target_shader = &(gDeferredMaterialProgram[mask]);
 
+					if (LLPipeline::sUnderWaterRender)
+					{
+						target_shader = &(gDeferredMaterialWaterProgram[mask]);
+					}
+
 					if (current_shader != target_shader)
 					{
 						gPipeline.bindDeferredShader(*target_shader);
@@ -510,8 +575,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					LLFastTimer t(FTM_RENDER_ALPHA_PUSH);
 					gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
 					params.mVertexBuffer->setBuffer(mask);
-					params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
-					gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+				params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+				gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
 				}
 				
 				// If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow).  Interleaving these state-changing calls could be expensive, but glow must be drawn Z-sorted with alpha.
@@ -531,6 +596,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					// do the actual drawing, again
 					params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 					gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+
+					// restore our alpha blend mode
+					gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
+					current_shader->bind();
 				}
 			
 				if (tex_setup)
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index 43122218edadba815be0945cf5911beeb18fd27d..d064a3a324b7522c97b395d86c4e48b125292ec4 100755
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -63,7 +63,7 @@ class LLDrawPoolAlpha: public LLRenderPass
 	/*virtual*/ void prerender();
 
 	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	void renderAlpha(U32 mask);
+	void renderAlpha(U32 mask, S32 pass);
 	void renderAlphaHighlight(U32 mask);
 		
 	static BOOL sShowDebugAlpha;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index f3f0b3cce2de66682e117587f1c0e77d86bae514..5c4cb71e57ee27d89ff6df6ee7f6341dc2632899 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -49,6 +49,7 @@
 #include "llappviewer.h"
 #include "llrendersphere.h"
 #include "llviewerpartsim.h"
+#include "llviewercontrol.h" // for gSavedSettings
 
 static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
 static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
@@ -688,12 +689,10 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 	}
 
 	sVertexProgram = &gDeferredImpostorProgram;
-
 	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
 	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-
-	sVertexProgram->bind();
+	gPipeline.bindDeferredShader(*sVertexProgram);
 	sVertexProgram->setMinimumAlpha(0.01f);
 }
 
@@ -703,8 +702,9 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	gGL.getTexUnit(0)->activate();
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+   sVertexProgram = NULL;
+   sDiffuseChannel = 0;
 }
 
 void LLDrawPoolAvatar::beginDeferredRigid()
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 08a36bddf181fe7b18666eb18f239218c356fdef..d1b508065036b0d7ea5fd7f12193d5f08198b242 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -72,6 +72,12 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 	};
 	
 	mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		mShader = &(gDeferredMaterialWaterProgram[shader_idx[pass]]);
+	}
+
 	mShader->bind();
 
 	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
@@ -215,3 +221,4 @@ void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture,
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
 	}
 }
+
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 2cf9d833c60520d3f8d0f016c23a1d2394eaabb0..8926f64c64f30ec445c85de0a2b6f97d0601d67f 100755
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -37,6 +37,7 @@
 #include "llviewershadermgr.h"
 #include "llrender.h"
 
+#define GE_FORCE_WORKAROUND LL_DARWIN
 
 static LLGLSLShader* simple_shader = NULL;
 static LLGLSLShader* fullbright_shader = NULL;
@@ -111,7 +112,14 @@ void LLDrawPoolGlow::render(S32 pass)
 	
 	LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
 	shader->bind();
-	shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
+	if (LLPipeline::sRenderDeferred)
+	{
+		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+	}
+	else
+	{
+		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
+	}	
 
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
@@ -148,7 +156,11 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_SIMPLE);
 
-	if (LLPipeline::sUnderWaterRender)
+	if (LLPipeline::sImpostorRender)
+	{
+		simple_shader = &gObjectSimpleImpostorProgram;
+	}
+	else if (LLPipeline::sUnderWaterRender)
 	{
 		simple_shader = &gObjectSimpleWaterProgram;
 	}
@@ -536,7 +548,15 @@ void LLDrawPoolFullbright::prerender()
 
 void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass)
 {
-	gDeferredFullbrightProgram.bind();
+	if (LLPipeline::sUnderWaterRender)
+	{
+		gDeferredFullbrightWaterProgram.bind();
+	}
+	else
+	{
+		gDeferredFullbrightProgram.bind();
+	}
+	
 }
 
 void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
@@ -550,7 +570,14 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 
 void LLDrawPoolFullbright::endPostDeferredPass(S32 pass)
 {
-	gDeferredFullbrightProgram.unbind();
+	if (LLPipeline::sUnderWaterRender)
+	{
+		gDeferredFullbrightWaterProgram.unbind();
+	}
+	else
+	{
+		gDeferredFullbrightProgram.unbind();
+	}
 	LLRenderPass::endRenderPass(pass);
 }
 
@@ -625,15 +652,35 @@ S32 LLDrawPoolFullbright::getNumPasses()
 
 void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass)
 {
-	gObjectFullbrightAlphaMaskProgram.bind();
+	
 	if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
 	{
+		gObjectFullbrightAlphaMaskProgram.bind();
 		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
 	} 
 	else 
-	{
+	{	
+
+// Work-around until we can figure out why the right shader causes
+// the GeForce driver to go tango uniform on OS X 10.6.8 only
+//
+#if GE_FORCE_WORKAROUND
+		gObjectFullbrightAlphaMaskProgram.bind();
 		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+#else
+		if (LLPipeline::sUnderWaterRender)
+		{
+			gDeferredFullbrightAlphaMaskWaterProgram.bind();
+			gDeferredFullbrightAlphaMaskWaterProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
+		else
+		{
+			gDeferredFullbrightAlphaMaskProgram.bind();
+			gDeferredFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
+#endif
 	}
+
 }
 
 void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
@@ -646,7 +693,30 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
 
 void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass)
 {
-	gObjectFullbrightAlphaMaskProgram.unbind();
+	if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+	{
+		gObjectFullbrightAlphaMaskProgram.unbind();
+	}
+	else
+	{
+
+// Work-around until we can figure out why the right shader causes
+// the GeForce driver to go tango uniform on OS X 10.6.8 only
+//
+#if GE_FORCE_WORKAROUND		
+		gObjectFullbrightAlphaMaskProgram.unbind();
+#else
+		if (LLPipeline::sUnderWaterRender)
+		{
+			gDeferredFullbrightAlphaMaskWaterProgram.unbind();
+		}
+		else
+		{
+			gDeferredFullbrightAlphaMaskProgram.unbind();
+		}
+#endif
+
+	}
 	LLRenderPass::endRenderPass(pass);
 }
 
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index 7f7d9f65c60c048a26d02438e278dd21893f190f..ef8bdc33048e2bc217277ee894203bd8d80b3a9b 100755
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -155,3 +155,4 @@ void LLDrawPoolSky::renderSkyCubeFace(U8 side)
 void LLDrawPoolSky::endRenderPass( S32 pass )
 {
 }
+
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 0d79631182e9c0f2149ae85a01008e14de99c2be..32a9365abae70ef895ba2441d29b6a6c858db2f0 100755
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -522,14 +522,21 @@ void LLDrawPoolWater::shade()
 
 	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
 	
+	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
+	{
 	if (deferred_render)
 	{
-		shader = &gDeferredWaterProgram;
+			shader = &gDeferredUnderWaterProgram;
 	}
-	else if (eyedepth < 0.f && LLPipeline::sWaterReflections)
+		else
 	{
 		shader = &gUnderWaterProgram;
 	}
+	}
+	else if (deferred_render)
+	{
+		shader = &gDeferredWaterProgram;
+	}
 	else
 	{
 		shader = &gWaterProgram;
@@ -597,9 +604,15 @@ void LLDrawPoolWater::shade()
 		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
 	}
 
+	F32 screenRes[] = 
+	{
+		1.f/gGLViewport[2],
+		1.f/gGLViewport[3]
+	};
+	shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
 	stop_glerror();
 	
-	S32 diffTex = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
 	stop_glerror();
 	
 	light_dir.normVec();
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index ead013d6c602652649415dc47b282b21926f7630..bf24a37e34ade8b146f6bedc4a4e57f7bd5525f9 100755
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1940,7 +1940,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			
 			LLMatrix4a mat_vert;
 			mat_vert.loadu(mat_vert_in);
-								
+
 			F32* dst = (F32*) vert.get();
 			F32* end_f32 = dst+mGeomCount*4;
 
@@ -1951,7 +1951,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 
 			LLVector4a res0; //,res1,res2,res3;
-			
+
 			LLVector4a texIdx;
 
 			S32 index = mTextureIndex < 255 ? mTextureIndex : 0;
@@ -2002,14 +2002,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}*/
 
 				while (src < end)
-				{
+				{	
 					mat_vert.affineTransform(*src++, res0);
 					tmp.setSelectWithMask(mask, texIdx, res0);
 					tmp.store4a((F32*) dst);
 					dst += 4;
 				}
 			}
-			
+
 			{
 				//LLFastTimer t(FTM_FACE_POSITION_PAD);
 				while (dst < end_f32)
@@ -2035,7 +2035,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			LLVector4a* end = src+num_vertices;
 			
 			while (src < end)
-			{
+			{	
 				LLVector4a normal;
 				mat_normal.rotate(*src++, normal);
 				normal.store4a(normals);
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 763634a3ab53708a66f81458cda06e1fde7d1455..66b5f137401f38379169f7f8ba4d70e4f7b23e5f 100755
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -194,8 +194,7 @@ class LLFace
 
 	void		setSize(S32 numVertices, S32 num_indices = 0, bool align = false);
 	
-	BOOL		genVolumeBBoxes(const LLVolume &volume, S32 f,
-								   const LLMatrix4& mat, BOOL global_volume = FALSE);
+	BOOL		genVolumeBBoxes(const LLVolume &volume, S32 f,const LLMatrix4& mat, BOOL global_volume = FALSE);
 	
 	void		init(LLDrawable* drawablep, LLViewerObject* objp);
 	void		destroy();
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 14923eec3c8c10880ca269c71966d94f3ec807b0..7b25291da7df632bda40d86d9f18768c2d859ed0 100755
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1328,7 +1328,7 @@ void LLFloaterTools::getMediaState()
 		getChildView("media_tex")->setEnabled(bool_has_media && editable);
 		getChildView("edit_media")->setEnabled(bool_has_media && LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo && editable );
 		getChildView("delete_media")->setEnabled(bool_has_media && editable );
-		getChildView("add_media")->setEnabled(( ! bool_has_media ) && editable );
+		getChildView("add_media")->setEnabled(editable);
 			// TODO: display a list of all media on the face - use 'identical' flag
 	}
 	else // not all face has media but at least one does.
@@ -1358,7 +1358,7 @@ void LLFloaterTools::getMediaState()
 		getChildView("media_tex")->setEnabled(TRUE);
 		getChildView("edit_media")->setEnabled(LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo);
 		getChildView("delete_media")->setEnabled(TRUE);
-		getChildView("add_media")->setEnabled(FALSE );
+		getChildView("add_media")->setEnabled(editable);
 	}
 	media_info->setText(media_title);
 	
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index ad9958546cb39a0fc75f4f038487bc3106d1c93b..14d3d4e7a8cfaaa513c70e277d45a81d01418403 100644
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -52,10 +52,12 @@
 #define MATERIALS_CAP_MATERIAL_ID_FIELD           "MaterialID"
 #define SIM_FEATURE_MAX_MATERIALS_PER_TRANSACTION "MaxMaterialsPerTransaction"
 
-#define MATERIALS_DEFAULT_MAX_ENTRIES             50
+#define MATERIALS_GET_MAX_ENTRIES                 50
 #define MATERIALS_GET_TIMEOUT                     (60.f * 20)
+#define MATERIALS_POST_MAX_ENTRIES                50
 #define MATERIALS_POST_TIMEOUT                    (60.f * 5)
 #define MATERIALS_PUT_THROTTLE_SECS               1.f
+#define MATERIALS_PUT_MAX_ENTRIES                 50
 
 /**
  * LLMaterialsResponder helper class
@@ -543,11 +545,9 @@ void LLMaterialMgr::onIdle(void*)
 		instancep->processGetAllQueue();
 	}
 
-	static LLFrameTimer mPutTimer;
-	if ( (!instancep->mPutQueue.empty()) && (mPutTimer.hasExpired()) )
+	if (!instancep->mPutQueue.empty())
 	{
 		instancep->processPutQueue();
-		mPutTimer.resetWithExpiry(MATERIALS_PUT_THROTTLE_SECS);
 	}
 }
 
@@ -564,14 +564,14 @@ void LLMaterialMgr::processGetQueue()
 			continue;
 		}
 
-		const LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
+		LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
 		if (!regionp)
 		{
 			LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL;
 			mGetQueue.erase(itRegionQueue);
 			continue;
 		}
-		else if (!regionp->capabilitiesReceived())
+		else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled())
 		{
 			continue;
 		}
@@ -594,8 +594,8 @@ void LLMaterialMgr::processGetQueue()
 		LLSD materialsData = LLSD::emptyArray();
 
 		material_queue_t& materials = itRegionQueue->second;
-		U32 max_entries = getMaxEntries(regionp);
-		material_queue_t::iterator loopMaterial = materials.begin();		
+		U32 max_entries = regionp->getMaxMaterialsPerTransaction();
+		material_queue_t::iterator loopMaterial = materials.begin();
 		while ( (materials.end() != loopMaterial) && (materialsData.size() < max_entries) )
 		{
 			material_queue_t::iterator itMaterial = loopMaterial++;
@@ -628,6 +628,7 @@ void LLMaterialMgr::processGetQueue()
 		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials." 
 			<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
 		LLHTTPClient::post(capURL, postData, materialsResponder);
+		regionp->resetMaterialsCapThrottle();
 	}
 }
 
@@ -646,7 +647,7 @@ void LLMaterialMgr::processGetAllQueue()
 			clearGetQueues(region_id);		// Invalidates region_id
 			continue;
 		}
-		else if (!regionp->capabilitiesReceived())
+		else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled())
 		{
 			continue;
 		}
@@ -663,6 +664,7 @@ void LLMaterialMgr::processGetAllQueue()
 		LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL;
 		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion));
 		LLHTTPClient::get(capURL, materialsResponder);
+		regionp->resetMaterialsCapThrottle();
 		mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
 		mGetAllQueue.erase(itRegion);	// Invalidates region_id
 	}
@@ -670,7 +672,7 @@ void LLMaterialMgr::processGetAllQueue()
 
 void LLMaterialMgr::processPutQueue()
 {
-	typedef std::map<const LLViewerRegion*, LLSD> regionput_request_map;
+	typedef std::map<LLViewerRegion*, LLSD> regionput_request_map;
 	regionput_request_map requests;
 
 	put_queue_t::iterator loopQueue = mPutQueue.begin();
@@ -687,46 +689,47 @@ void LLMaterialMgr::processPutQueue()
 		}
 		else
 		{
-			const LLViewerRegion* regionp = objectp->getRegion();
+			LLViewerRegion* regionp = objectp->getRegion();
 			if ( !regionp )
-			{
+		{
 				LL_WARNS("Materials") << "Object region is NULL" << LL_ENDL;
 				mPutQueue.erase(itQueue);
-			}
-			else if ( regionp->capabilitiesReceived())
+		}
+			else if ( regionp->capabilitiesReceived() && !regionp->materialsCapThrottled())
 			{
-				LLSD& facesData = requests[regionp];
+		LLSD& facesData = requests[regionp];
 
-				facematerial_map_t& face_map = itQueue->second;
-				U32 max_entries = getMaxEntries(regionp);
-				facematerial_map_t::iterator itFace = face_map.begin();
+		facematerial_map_t& face_map = itQueue->second;
+				U32 max_entries = regionp->getMaxMaterialsPerTransaction();
+		facematerial_map_t::iterator itFace = face_map.begin();
 				while ( (face_map.end() != itFace) && (facesData.size() < max_entries) )
-				{
-					LLSD faceData = LLSD::emptyMap();
-					faceData[MATERIALS_CAP_FACE_FIELD] = static_cast<LLSD::Integer>(itFace->first);
-					faceData[MATERIALS_CAP_OBJECT_ID_FIELD] = static_cast<LLSD::Integer>(objectp->getLocalID());
-					if (!itFace->second.isNull())
-					{
-						faceData[MATERIALS_CAP_MATERIAL_FIELD] = itFace->second.asLLSD();
-					}
-					facesData.append(faceData);
-					face_map.erase(itFace++);
-				}
-				if (face_map.empty())
-				{
-					mPutQueue.erase(itQueue);
-				}
+		{
+			LLSD faceData = LLSD::emptyMap();
+			faceData[MATERIALS_CAP_FACE_FIELD] = static_cast<LLSD::Integer>(itFace->first);
+			faceData[MATERIALS_CAP_OBJECT_ID_FIELD] = static_cast<LLSD::Integer>(objectp->getLocalID());
+			if (!itFace->second.isNull())
+			{
+				faceData[MATERIALS_CAP_MATERIAL_FIELD] = itFace->second.asLLSD();
 			}
+			facesData.append(faceData);
+			face_map.erase(itFace++);
+		}
+		if (face_map.empty())
+		{
+			mPutQueue.erase(itQueue);
+		}
+	}
 		}
 	}
 
 	for (regionput_request_map::const_iterator itRequest = requests.begin(); itRequest != requests.end(); ++itRequest)
 	{
-		std::string capURL = itRequest->first->getCapability(MATERIALS_CAPABILITY_NAME);
+		LLViewerRegion* regionp = itRequest->first;
+		std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
 		if (capURL.empty())
 		{
 			LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
-				<< "' is not defined on region '" << itRequest->first->getName() << "'" << LL_ENDL;
+				<< "' is not defined on region '" << regionp->getName() << "'" << LL_ENDL;
 			continue;
 		}
 
@@ -749,6 +752,7 @@ void LLMaterialMgr::processPutQueue()
 			LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
 			LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2));
 			LLHTTPClient::put(capURL, putData, materialsResponder);
+			regionp->resetMaterialsCapThrottle();
 		}
 		else
 		{
@@ -783,20 +787,3 @@ void LLMaterialMgr::onRegionRemoved(LLViewerRegion* regionp)
 	// Put doesn't need clearing: objects that can't be found will clean up in processPutQueue()
 }
 
-U32 LLMaterialMgr::getMaxEntries(const LLViewerRegion* regionp)
-{
-	LLSD sim_features;
-	regionp->getSimulatorFeatures(sim_features);
-	U32 max_entries;
-	if (   sim_features.has( SIM_FEATURE_MAX_MATERIALS_PER_TRANSACTION )
-		&& sim_features[ SIM_FEATURE_MAX_MATERIALS_PER_TRANSACTION ].isInteger())
-	{
-		max_entries = sim_features[ SIM_FEATURE_MAX_MATERIALS_PER_TRANSACTION ].asInteger();
-	}
-	else
-	{
-		max_entries = MATERIALS_DEFAULT_MAX_ENTRIES;
-	}
-	return max_entries;
-}
-
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 834ad9e14ca8f771fea383d238a655a459c5c955..b68488122580c63c1481ca47860b25da128bc549 100755
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -255,7 +255,26 @@ class LLPanelFace : public LLPanel
 					// Determine correct alpha mode for current diffuse texture
 					// (i.e. does it have an alpha channel that makes alpha mode useful)
 					//
-					U8 default_alpha_mode = (_panel->isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
+					// _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329)
+					// need to get per-face answer to this question for sane alpha mode retention on updates.
+					//					
+					bool is_alpha_face = object->isImageAlphaBlended(face);
+
+					// need to keep this original answer for valid comparisons in logic below
+					//
+					U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+					
+					U8 default_alpha_mode = original_default_alpha_mode;
+
+					if (!current_material.isNull())
+					{
+						default_alpha_mode = current_material->getDiffuseAlphaMode();
+					}
+
+					// Insure we don't inherit the default of blend by accident...
+					// this will be stomped by a legit request to change the alpha mode by the apply() below
+					//
+					new_material->setDiffuseAlphaMode(default_alpha_mode);
 
 					// Do "It"!
 					//
@@ -265,7 +284,13 @@ class LLPanelFace : public LLPanel
 					LLUUID	new_normal_map_id		= new_material->getNormalID();
 					LLUUID	new_spec_map_id		= new_material->getSpecularID();
 
-					bool is_default_blend_mode		= (new_alpha_mode == default_alpha_mode);
+					if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
+					{
+						new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+						new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
+					}
+
+					bool is_default_blend_mode		= (new_alpha_mode == original_default_alpha_mode);
 					bool is_need_material			= !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
 
 					if (!is_need_material)
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 02d363d7952eb3d99e74feedeef75014b4162dec..a1d60b5b16907350eec4501817bb8f9211123240 100755
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -710,9 +710,19 @@ void LLPanelVolume::onLightCancelColor(const LLSD& data)
 void LLPanelVolume::onLightCancelTexture(const LLSD& data)
 {
 	LLTextureCtrl* LightTextureCtrl = getChild<LLTextureCtrl>("light texture control");
+
 	if (LightTextureCtrl)
 	{
-		LightTextureCtrl->setImageAssetID(mLightSavedTexture);
+		LightTextureCtrl->setImageAssetID(LLUUID::null);
+	}
+
+	LLVOVolume *volobjp = (LLVOVolume *) mObject.get();
+	if(volobjp)
+	{
+		// Cancel the light texture as requested
+		// NORSPEC-292
+		//
+		volobjp->setLightTextureID(LLUUID::null);
 	}
 }
 
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 4676f7b251327f250d4a38e73d259559637732d9..4300cafb6bae86c5b7c37923ea7c0b7b8f9b5ec1 100755
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -133,6 +133,7 @@ class LLFloaterTexturePicker : public LLFloater
 	PermissionMask 	getFilterPermMask();
 	void updateFilterPermMask();
 	void commitIfImmediateSet();
+	void commitCancel();
 	
 	void onFilterEdit(const std::string& search_string );
 	
@@ -706,6 +707,14 @@ void LLFloaterTexturePicker::commitIfImmediateSet()
 	}
 }
 
+void LLFloaterTexturePicker::commitCancel()
+{
+	if (!mNoCopyTextureSelected && mOwner && mCanApply)
+	{
+		mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CANCEL);
+	}
+}
+
 // static
 void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
 {
@@ -733,7 +742,7 @@ void LLFloaterTexturePicker::onBtnNone(void* userdata)
 {
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 	self->setImageID( LLUUID::null );
-	self->commitIfImmediateSet();
+	self->commitCancel();
 }
 
 /*
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index aae84709d84e568d8a69f3b692d16f8ed7f27253..bbebeea3e0e22a5bd2d6e5de5e912224a1681baa 100755
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -225,13 +225,13 @@ void display_stats()
 }
 
 static LLFastTimer::DeclareTimer FTM_PICK("Picking");
-static LLFastTimer::DeclareTimer FTM_RENDER("Render");
+static LLFastTimer::DeclareTimer FTM_RENDER("Render", true);
 static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky");
 static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures");
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images");
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class");
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Image Update Bump");
-static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List", true);
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List");
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete");
 static LLFastTimer::DeclareTimer FTM_RESIZE_WINDOW("Resize Window");
 static LLFastTimer::DeclareTimer FTM_HUD_UPDATE("HUD Update");
@@ -675,7 +675,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
 		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
-		LLPipeline::sUnderWaterRender = FALSE;
 		stop_glerror();
 
 		LLGLState::checkStates();
@@ -891,7 +890,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		{
 			gGL.setColorMask(true, true);
 					
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			if (LLPipeline::sRenderDeferred)
 			{
 				gPipeline.mDeferredScreen.bindTarget();
 				glClearColor(1,0,1,1);
@@ -940,7 +939,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 
 			gGL.setColorMask(true, false);
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			if (LLPipeline::sRenderDeferred)
 			{
 				gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
 			}
@@ -977,7 +976,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		
 		if (to_texture)
 		{
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			if (LLPipeline::sRenderDeferred)
 			{
 				gPipeline.mDeferredScreen.flush();
 				if(LLRenderTarget::sUseFBO)
@@ -1003,7 +1002,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			}
 		}
 
-		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		if (LLPipeline::sRenderDeferred)
 		{
 			gPipeline.renderDeferredLighting();
 		}
@@ -1624,3 +1623,4 @@ void display_cleanup()
 {
 	gDisconnectedImagep = NULL;
 }
+
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index e92cc39ba7de7685093f2e19e2aec1f1bcf23819..7151a0d6ed1f76fed2c335d87c07cf6d3e4ef068 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -1724,7 +1724,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				// keep local flags and overwrite remote-controlled flags
 				mFlags = (mFlags & FLAGS_LOCAL) | flags;
 
-				// ...new objects that should come in selected need to be added to the selected list
+					// ...new objects that should come in selected need to be added to the selected list
 				mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
 			}
 			break;
@@ -4412,12 +4412,10 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
 
 void LLViewerObject::refreshMaterials()
 {
-	setChanged(ALL_CHANGED);
+	setChanged(TEXTURE);
 	if (mDrawable.notNull())
 	{
 		gPipeline.markTextured(mDrawable);
-		gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL);
-		dirtySpatialGroup(TRUE);
 	}
 }
 
@@ -4521,6 +4519,30 @@ LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const
 }
 
 
+bool LLViewerObject::isImageAlphaBlended(const U8 te) const
+{
+	LLViewerTexture* image = getTEImage(te);
+	LLGLenum format = image ? image->getPrimaryFormat() : GL_RGB;
+	switch (format)
+	{
+		case GL_RGBA:
+		case GL_ALPHA:
+		{
+			return true;
+		}
+		break;
+
+		case GL_RGB: break;
+		default:
+		{
+			llwarns << "Unexpected tex format in LLViewerObject::isImageAlphaBlended...returning no alpha." << llendl;
+		}
+		break;
+	}
+
+	return false;
+}
+
 LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const
 {
 	//	llassert(mTEImages);
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 05bc7f68a21a40ed8077e9b890a553fc261a90a8..b035473c747e138df6d866a6126a626303c41809 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -112,6 +112,14 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 protected:
 	~LLViewerObject(); // use unref()
 
+	// TomY: Provide for a list of extra parameter structures, mapped by structure name
+	struct ExtraParameter
+	{
+		BOOL in_use;
+		LLNetworkData *data;
+	};
+	std::map<U16, ExtraParameter*> mExtraParameterList;
+
 public:
 	typedef std::list<LLPointer<LLViewerObject> > child_list_t;
 	typedef std::list<LLPointer<LLViewerObject> > vobj_list_t;
@@ -331,6 +339,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	LLViewerTexture		*getTENormalMap(const U8 te) const;
 	LLViewerTexture		*getTESpecularMap(const U8 te) const;
 	
+	bool 						isImageAlphaBlended(const U8 te) const;
+
 	void fitFaceTexture(const U8 face);
 	void sendTEUpdate() const;			// Sends packed representation of all texture entry information
 	
@@ -553,8 +563,6 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	std::vector<LLVector3> mUnselectedChildrenPositions ;
 
 private:
-	// TomY: Provide for a list of extra parameter structures, mapped by structure name
-	struct ExtraParameter;
 	ExtraParameter* createNewParameterEntry(U16 param_type);
 	ExtraParameter* getExtraParameterEntry(U16 param_type) const;
 	ExtraParameter* getExtraParameterEntryCreate(U16 param_type);
@@ -794,14 +802,6 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	LLUUID mAttachmentItemID; // ItemID of the associated object is in user inventory.
 	EObjectUpdateType	mLastUpdateType;
 	BOOL	mLastUpdateCached;
-
-	// TomY: Provide for a list of extra parameter structures, mapped by structure name
-	struct ExtraParameter
-	{
-		BOOL in_use;
-		LLNetworkData *data;
-	};
-	std::map<U16, ExtraParameter*> mExtraParameterList;
 };
 
 ///////////////////
@@ -847,7 +847,7 @@ class LLAlphaObject : public LLViewerObject
 								LLStrider<LLVector4a>& verticesp,
 								LLStrider<LLVector3>& normalsp, 
 								LLStrider<LLVector2>& texcoordsp,
-								LLStrider<LLColor4U>& colorsp,
+								LLStrider<LLColor4U>& colorsp, 
 								LLStrider<LLColor4U>& emissivep,
 								LLStrider<U16>& indicesp) = 0;
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index b91dde4113bc4c91389f92b720c7a15e0ab4f2b8..e6fc82f761730dc76c4e8c04d20583c5c3aed408 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -44,7 +44,6 @@
 
 #include "llagent.h"
 #include "llagentcamera.h"
-#include "llavatarrenderinfoaccountant.h"
 #include "llcallingcard.h"
 #include "llcaphttpsender.h"
 #include "llcapabilitylistener.h"
@@ -301,16 +300,12 @@ class BaseCapabilitiesCompleteTracker :  public LLHTTPClient::Responder
 		
 		if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )
 		{
-			llinfos << "BaseCapabilitiesCompleteTracker " << "sim " << regionp->getName()
-				<< " sent duplicate seed caps that differs in size - most likely content. " 
-				<< (S32) regionp->getRegionImpl()->mCapabilities.size() << " vs " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size()
-				<< llendl;			
+			llinfos<<"BaseCapabilitiesCompleteTracker "<<"Sim sent duplicate seed caps that differs in size - most likely content."<<llendl;			
 			//todo#add cap debug versus original check?
-			/*
-			CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin();
+			/*CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin();
 			while (iter!=regionp->getRegionImpl()->mCapabilities.end() )
 			{
-				llinfos << "BaseCapabilitiesCompleteTracker Original " << iter->first << " is " << iter->second << llendl;
+				llinfos<<"BaseCapabilitiesCompleteTracker Original "<<iter->first<<" "<< iter->second<<llendl;
 				++iter;
 			}
 			*/
@@ -398,9 +393,6 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mImpl->mObjectPartition.push_back(new LLBridgePartition());	//PARTITION_BRIDGE
 	mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE
 	mImpl->mObjectPartition.push_back(NULL);						//PARTITION_NONE
-
-	mRenderInfoRequestTimer.resetWithExpiry(0.f);		// Set timer to be expired
-	setCapabilitiesReceivedCallback(boost::bind(&LLAvatarRenderInfoAccountant::expireRenderInfoReportTimer, _1));
 }
 
 
@@ -1585,7 +1577,6 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("AgentState");
 	capabilityNames.append("AttachmentResources");
 	capabilityNames.append("AvatarPickerSearch");
-	capabilityNames.append("AvatarRenderInfo");
 	capabilityNames.append("CharacterProperties");
 	capabilityNames.append("ChatSessionRequest");
 	capabilityNames.append("CopyInventoryFromNotecard");
@@ -1953,3 +1944,47 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const
 			 mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean());
 }
 
+void LLViewerRegion::resetMaterialsCapThrottle()
+{
+	F32 requests_per_sec = 	1.0f; // original default;
+	if (   mSimulatorFeatures.has("RenderMaterialsCapability")
+		&& mSimulatorFeatures["RenderMaterialsCapability"].isReal() )
+	{
+		requests_per_sec = mSimulatorFeatures["RenderMaterialsCapability"].asReal();
+		if ( requests_per_sec == 0.0f )
+		{
+			requests_per_sec = 1.0f;
+			LL_WARNS("Materials")
+				<< "region '" << getName()
+				<< "' returned zero for RenderMaterialsCapability; using default "
+				<< requests_per_sec << " per second"
+				<< LL_ENDL;
+		}
+		LL_DEBUGS("Materials") << "region '" << getName()
+							   << "' RenderMaterialsCapability " << requests_per_sec
+							   << LL_ENDL;
+	}
+	else
+	{
+		LL_DEBUGS("Materials")
+			<< "region '" << getName()
+			<< "' did not return RenderMaterialsCapability, using default "
+			<< requests_per_sec << " per second"
+			<< LL_ENDL;
+	}
+	
+	mMaterialsCapThrottleTimer.resetWithExpiry( 1.0f / requests_per_sec );
+}
+
+U32 LLViewerRegion::getMaxMaterialsPerTransaction() const
+{
+	U32 max_entries = 50; // original hard coded default
+	if (   mSimulatorFeatures.has( "MaxMaterialsPerTransaction" )
+		&& mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].isInteger())
+	{
+		max_entries = mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].asInteger();
+	}
+	return max_entries;
+}
+
+
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index e2cc95f232c9eca02d156476934d32a98bc19a37..8f8bfa23c17468abb9ac9f205b967242453980a8 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -43,6 +43,7 @@
 #include "llcapabilityprovider.h"
 #include "m4math.h"					// LLMatrix4
 #include "llhttpclient.h"
+#include "llframetimer.h"
 
 // Surface id's
 #define LAND  1
@@ -343,6 +344,11 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	const LLViewerRegionImpl * getRegionImpl() const { return mImpl; }
 	LLViewerRegionImpl * getRegionImplNC() { return mImpl; }
 	
+	// implements the materials capability throttle
+	bool materialsCapThrottled() const { return !mMaterialsCapThrottleTimer.hasExpired(); }
+	void resetMaterialsCapThrottle();
+	
+	U32 getMaxMaterialsPerTransaction() const;
 public:
 	struct CompareDistance
 	{
@@ -437,7 +443,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	
 	LLSD mSimulatorFeatures;
 
-	LLFrameTimer	mRenderInfoRequestTimer;
+	// the materials capability throttle
+	LLFrameTimer mMaterialsCapThrottleTimer;
+LLFrameTimer	mRenderInfoRequestTimer;
 };
 
 inline BOOL LLViewerRegion::getRegionProtocol(U64 protocol) const
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index dfe4147d94f74945a6a351baffec4fc6dab02acb..0e099b8299275c22411c4f2079529a4342d6b6c2 100755
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -90,6 +90,7 @@ LLGLSLShader	gAlphaMaskProgram;
 
 //object shaders
 LLGLSLShader		gObjectSimpleProgram;
+LLGLSLShader		gObjectSimpleImpostorProgram;
 LLGLSLShader		gObjectPreviewProgram;
 LLGLSLShader		gObjectSimpleWaterProgram;
 LLGLSLShader		gObjectSimpleAlphaMaskProgram;
@@ -175,6 +176,7 @@ LLGLSLShader			gPostNightVisionProgram;
 // Deferred rendering shaders
 LLGLSLShader			gDeferredImpostorProgram;
 LLGLSLShader			gDeferredWaterProgram;
+LLGLSLShader			gDeferredUnderWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
 LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
@@ -196,14 +198,20 @@ LLGLSLShader			gDeferredMultiSpotLightProgram;
 LLGLSLShader			gDeferredSunProgram;
 LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
+LLGLSLShader			gDeferredSoftenWaterProgram;
 LLGLSLShader			gDeferredShadowProgram;
 LLGLSLShader			gDeferredShadowCubeProgram;
 LLGLSLShader			gDeferredShadowAlphaMaskProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
 LLGLSLShader			gDeferredAttachmentShadowProgram;
 LLGLSLShader			gDeferredAlphaProgram;
+LLGLSLShader			gDeferredAlphaImpostorProgram;
+LLGLSLShader			gDeferredAlphaWaterProgram;
 LLGLSLShader			gDeferredAvatarEyesProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
+LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
+LLGLSLShader			gDeferredFullbrightWaterProgram;
+LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
 LLGLSLShader			gDeferredEmissiveProgram;
 LLGLSLShader			gDeferredPostProgram;
 LLGLSLShader			gDeferredCoFProgram;
@@ -221,6 +229,7 @@ LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
+LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mVertexShaderLevel(SHADER_COUNT, 0),
@@ -236,6 +245,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gWaterProgram);
 	mShaderList.push_back(&gAvatarEyeballProgram); 
 	mShaderList.push_back(&gObjectSimpleProgram);
+	mShaderList.push_back(&gObjectSimpleImpostorProgram);
 	mShaderList.push_back(&gObjectPreviewProgram);
 	mShaderList.push_back(&gImpostorProgram);
 	mShaderList.push_back(&gObjectFullbrightNoColorProgram);
@@ -286,6 +296,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
+	mShaderList.push_back(&gDeferredSoftenWaterProgram);
 	mShaderList.push_back(&gDeferredMaterialProgram[1]);
 	mShaderList.push_back(&gDeferredMaterialProgram[5]);
 	mShaderList.push_back(&gDeferredMaterialProgram[9]);
@@ -294,15 +305,30 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT]);	
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[1]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[5]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[9]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[13]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT]);	
 	mShaderList.push_back(&gDeferredAlphaProgram);
+	mShaderList.push_back(&gDeferredAlphaProgram);
+	mShaderList.push_back(&gDeferredAlphaImpostorProgram);
+	mShaderList.push_back(&gDeferredAlphaWaterProgram);
 	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
+	mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram);
+	mShaderList.push_back(&gDeferredFullbrightWaterProgram);
+	mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram);	
 	mShaderList.push_back(&gDeferredFullbrightShinyProgram);
 	mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
 	mShaderList.push_back(&gDeferredSkinnedFullbrightProgram);
 	mShaderList.push_back(&gDeferredEmissiveProgram);
 	mShaderList.push_back(&gDeferredAvatarEyesProgram);
 	mShaderList.push_back(&gDeferredWaterProgram);
+	mShaderList.push_back(&gDeferredUnderWaterProgram);	
 	mShaderList.push_back(&gDeferredAvatarAlphaProgram);
 	mShaderList.push_back(&gDeferredWLSkyProgram);
 	mShaderList.push_back(&gDeferredWLCloudProgram);
@@ -671,6 +697,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gObjectFullbrightNoColorProgram.unload();
 	gObjectFullbrightNoColorWaterProgram.unload();
 	gObjectSimpleProgram.unload();
+	gObjectSimpleImpostorProgram.unload();
 	gObjectPreviewProgram.unload();
 	gImpostorProgram.unload();
 	gObjectSimpleAlphaMaskProgram.unload();
@@ -1087,6 +1114,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSunProgram.unload();
 		gDeferredBlurLightProgram.unload();
 		gDeferredSoftenProgram.unload();
+		gDeferredSoftenWaterProgram.unload();
 		gDeferredShadowProgram.unload();
 		gDeferredShadowCubeProgram.unload();
 		gDeferredShadowAlphaMaskProgram.unload();
@@ -1095,7 +1123,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarProgram.unload();
 		gDeferredAvatarAlphaProgram.unload();
 		gDeferredAlphaProgram.unload();
+		gDeferredAlphaWaterProgram.unload();
 		gDeferredFullbrightProgram.unload();
+		gDeferredFullbrightAlphaMaskProgram.unload();
+		gDeferredFullbrightWaterProgram.unload();
+		gDeferredFullbrightAlphaMaskWaterProgram.unload();
 		gDeferredEmissiveProgram.unload();
 		gDeferredAvatarEyesProgram.unload();
 		gDeferredPostProgram.unload();		
@@ -1104,6 +1136,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredPostGammaCorrectProgram.unload();
 		gFXAAProgram.unload();
 		gDeferredWaterProgram.unload();
+		gDeferredUnderWaterProgram.unload();
 		gDeferredWLSkyProgram.unload();
 		gDeferredWLCloudProgram.unload();
 		gDeferredStarProgram.unload();
@@ -1115,6 +1148,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 		{
 			gDeferredMaterialProgram[i].unload();
+			gDeferredMaterialWaterProgram[i].unload();
 		}
 		return TRUE;
 	}
@@ -1199,11 +1233,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	if (success)
 	{
 		gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader";
-		gDeferredSkinnedAlphaProgram.mFeatures.atmosphericHelpers = true;
 		gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true;
 		gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = false;
 		gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = false;
 		gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true;
@@ -1213,8 +1243,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredSkinnedAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		gDeferredSkinnedAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1");
-		gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredSkinnedAlphaProgram.addPermutation("HAS_SKIN", "1");
+		gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredSkinnedAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
 		success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL);
 		
@@ -1242,6 +1272,15 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 
+	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+
 	for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 	{
 		if (success)
@@ -1268,6 +1307,34 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 			success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
 		}
+
+		if (success)
+		{
+			gDeferredMaterialWaterProgram[i].mName = llformat("Deferred Underwater Material Shader %d", i);
+
+			U32 alpha_mode = i & 0x3;
+
+			gDeferredMaterialWaterProgram[i].mShaderFiles.clear();
+			gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredMaterialWaterProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			gDeferredMaterialWaterProgram[i].mShaderGroup = LLGLSLShader::SG_WATER;
+
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_NORMAL_MAP", i & 0x8? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SPECULAR_MAP", i & 0x4 ? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+			bool has_skin = i & 0x10;
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN",has_skin ? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1");
+
+			if (has_skin)
+			{
+				gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true;
+			}
+
+			success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);//&mWLUniforms);
+		}
 	}
 
 	gDeferredMaterialProgram[1].mFeatures.hasLighting = true;
@@ -1279,6 +1346,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 
+	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 
 	
 	if (success)
@@ -1324,8 +1399,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 	for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; i++)
 	{
-		if (success)
-		{
+	if (success)
+	{
 			gDeferredMultiLightProgram[i].mName = llformat("Deferred MultiLight Shader %d", i);
 			gDeferredMultiLightProgram[i].mShaderFiles.clear();
 			gDeferredMultiLightProgram[i].mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB));
@@ -1399,11 +1474,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	if (success)
 	{
 		gDeferredAlphaProgram.mName = "Deferred Alpha Shader";
-		gDeferredAlphaProgram.mFeatures.atmosphericHelpers = true;
+
 		gDeferredAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredAlphaProgram.mFeatures.hasAtmospherics = true;
 		gDeferredAlphaProgram.mFeatures.hasLighting = false;
 		gDeferredAlphaProgram.mFeatures.isAlphaLighting = true;
 		gDeferredAlphaProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
@@ -1420,8 +1492,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredAlphaProgram.addPermutation("USE_INDEXED_TEX", "1");
-		gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+		gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
 		success = gDeferredAlphaProgram.createShader(NULL, NULL);
@@ -1431,6 +1503,72 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAlphaProgram.mFeatures.hasLighting = true;
 	}
 
+	if (success)
+	{
+		gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Shader";
+
+		gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = false;
+		gDeferredAlphaImpostorProgram.mFeatures.hasLighting = false;
+		gDeferredAlphaImpostorProgram.mFeatures.isAlphaLighting = true;
+		gDeferredAlphaImpostorProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+		if (mVertexShaderLevel[SHADER_DEFERRED] < 1)
+		{
+			gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		}
+		else
+		{ //shave off some texture units for shadow maps
+			gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+		}
+
+		gDeferredAlphaImpostorProgram.mShaderFiles.clear();
+		gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAlphaImpostorProgram.addPermutation("USE_INDEXED_TEX", "1");
+		gDeferredAlphaImpostorProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+		gDeferredAlphaImpostorProgram.addPermutation("USE_VERTEX_COLOR", "1");
+		gDeferredAlphaImpostorProgram.addPermutation("FOR_IMPOSTOR", "1");
+
+		gDeferredAlphaImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+
+		success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL);
+
+		// Hack
+		gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true;
+		gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true;
+	}
+
+	if (success)
+	{
+		gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader";
+		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = false;
+		gDeferredAlphaWaterProgram.mFeatures.hasLighting = false;
+		gDeferredAlphaWaterProgram.mFeatures.isAlphaLighting = true;
+		gDeferredAlphaWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+		if (mVertexShaderLevel[SHADER_DEFERRED] < 1)
+		{
+			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		}
+		else
+		{ //shave off some texture units for shadow maps
+			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+		}
+		gDeferredAlphaWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		gDeferredAlphaWaterProgram.mShaderFiles.clear();
+		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAlphaWaterProgram.addPermutation("USE_INDEXED_TEX", "1");
+		gDeferredAlphaWaterProgram.addPermutation("WATER_FOG", "1");
+		gDeferredAlphaWaterProgram.addPermutation("USE_VERTEX_COLOR", "1");
+		gDeferredAlphaWaterProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+		gDeferredAlphaWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+
+		success = gDeferredAlphaWaterProgram.createShader(NULL, NULL);
+
+		// Hack
+		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = true;
+		gDeferredAlphaWaterProgram.mFeatures.hasLighting = true;
+	}
+
 	if (success)
 	{
 		gDeferredAvatarEyesProgram.mName = "Deferred Avatar Eyes Shader";
@@ -1459,6 +1597,54 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredFullbrightProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredFullbrightAlphaMaskProgram.mName = "Deferred Fullbright Alpha Masking Shader";
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.clear();
+		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK","1");
+		gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredFullbrightWaterProgram.mName = "Deferred Fullbright Underwater Shader";
+		gDeferredFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightWaterProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightWaterProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		gDeferredFullbrightWaterProgram.mShaderFiles.clear();
+		gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1");
+		success = gDeferredFullbrightWaterProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader";
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.clear();
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1");
+		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1");
+		success = gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredFullbrightShinyProgram.mName = "Deferred FullbrightShiny Shader";
@@ -1531,6 +1717,20 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredWaterProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		// load water shader
+		gDeferredUnderWaterProgram.mName = "Deferred Under Water Shader";
+		gDeferredUnderWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredUnderWaterProgram.mFeatures.hasGamma = true;
+		gDeferredUnderWaterProgram.mFeatures.hasTransport = true;
+		gDeferredUnderWaterProgram.mShaderFiles.clear();
+		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/underWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredUnderWaterProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredSoftenProgram.mName = "Deferred Soften Shader";
@@ -1548,6 +1748,25 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredSoftenProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredSoftenWaterProgram.mName = "Deferred Soften Underwater Shader";
+		gDeferredSoftenWaterProgram.mShaderFiles.clear();
+		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+		gDeferredSoftenWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredSoftenWaterProgram.addPermutation("WATER_FOG", "1");
+		gDeferredSoftenWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+
+		if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+		{ //if using SSAO, take screen space light map into account as if shadows are enabled
+			gDeferredSoftenWaterProgram.mShaderLevel = llmax(gDeferredSoftenWaterProgram.mShaderLevel, 2);
+		}
+
+		success = gDeferredSoftenWaterProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredShadowProgram.mName = "Deferred Shadow Shader";
@@ -1630,12 +1849,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	if (success)
 	{
 		gDeferredAvatarAlphaProgram.mName = "Avatar Alpha Shader";
-		gDeferredAvatarAlphaProgram.mFeatures.atmosphericHelpers = true;
 		gDeferredAvatarAlphaProgram.mFeatures.hasSkinning = true;
 		gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true;
 		gDeferredAvatarAlphaProgram.mFeatures.hasLighting = false;
 		gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true;
 		gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true;
@@ -1774,6 +1989,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightNoColorProgram.unload();
 		gObjectFullbrightNoColorWaterProgram.unload();
 		gObjectSimpleProgram.unload();
+		gObjectSimpleImpostorProgram.unload();
 		gObjectPreviewProgram.unload();
 		gImpostorProgram.unload();
 		gObjectSimpleAlphaMaskProgram.unload();
@@ -2194,6 +2410,27 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectSimpleProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gObjectSimpleImpostorProgram.mName = "Simple Impostor Shader";
+		gObjectSimpleImpostorProgram.mFeatures.calculatesLighting = true;
+		gObjectSimpleImpostorProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectSimpleImpostorProgram.mFeatures.hasGamma = true;
+		gObjectSimpleImpostorProgram.mFeatures.hasAtmospherics = true;
+		gObjectSimpleImpostorProgram.mFeatures.hasLighting = true;
+		gObjectSimpleImpostorProgram.mFeatures.mIndexedTextureChannels = 0;
+		// force alpha mask version of lighting so we can weed out
+		// transparent pixels from impostor temp buffer
+		//
+		gObjectSimpleImpostorProgram.mFeatures.hasAlphaMask = true; 
+		gObjectSimpleImpostorProgram.mShaderFiles.clear();
+		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectSimpleImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		
+		success = gObjectSimpleImpostorProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gObjectSimpleWaterProgram.mName = "Simple Water Shader";
@@ -3128,3 +3365,4 @@ LLViewerShaderMgr::shader_iter LLViewerShaderMgr::endShaders() const
 {
 	return mShaderList.end();
 }
+
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index a685ce591416f3758edc8ed81df782058d56ec2c..3d89f8d20a5326fbe9bead016eecc558fe205afa 100755
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -77,8 +77,6 @@ class LLViewerShaderMgr: public LLShaderMgr
 		SHADER_COUNT
 	};
 
-	
-
 	// simple model of forward iterator
 	// http://www.sgi.com/tech/stl/ForwardIterator.html
 	class shader_iter
@@ -130,6 +128,23 @@ class LLViewerShaderMgr: public LLShaderMgr
 	/* virtual */ void updateShaderUniforms(LLGLSLShader * shader);
 
 private:
+	
+	std::vector<std::string> mShinyUniforms;
+
+	//water parameters
+	std::vector<std::string> mWaterUniforms;
+
+	std::vector<std::string> mWLUniforms;
+
+	//terrain parameters
+	std::vector<std::string> mTerrainUniforms;
+
+	//glow parameters
+	std::vector<std::string> mGlowUniforms;
+
+	std::vector<std::string> mGlowExtractUniforms;
+
+	std::vector<std::string> mAvatarUniforms;
 
 	// the list of shaders we need to propagate parameters to.
 	std::vector<LLGLSLShader *> mShaderList;
@@ -176,6 +191,7 @@ extern LLGLSLShader			gOneTextureNoColorProgram;
 
 //object shaders
 extern LLGLSLShader			gObjectSimpleProgram;
+extern LLGLSLShader			gObjectSimpleImpostorProgram;
 extern LLGLSLShader			gObjectPreviewProgram;
 extern LLGLSLShader			gObjectSimpleAlphaMaskProgram;
 extern LLGLSLShader			gObjectSimpleWaterProgram;
@@ -264,6 +280,7 @@ extern LLGLSLShader			gPostNightVisionProgram;
 // Deferred rendering shaders
 extern LLGLSLShader			gDeferredImpostorProgram;
 extern LLGLSLShader			gDeferredWaterProgram;
+extern LLGLSLShader			gDeferredUnderWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
 extern LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
@@ -284,6 +301,7 @@ extern LLGLSLShader			gDeferredSunProgram;
 extern LLGLSLShader			gDeferredBlurLightProgram;
 extern LLGLSLShader			gDeferredAvatarProgram;
 extern LLGLSLShader			gDeferredSoftenProgram;
+extern LLGLSLShader			gDeferredSoftenWaterProgram;
 extern LLGLSLShader			gDeferredShadowProgram;
 extern LLGLSLShader			gDeferredShadowCubeProgram;
 extern LLGLSLShader			gDeferredShadowAlphaMaskProgram;
@@ -296,7 +314,12 @@ extern LLGLSLShader			gDeferredPostGammaCorrectProgram;
 extern LLGLSLShader			gDeferredAvatarShadowProgram;
 extern LLGLSLShader			gDeferredAttachmentShadowProgram;
 extern LLGLSLShader			gDeferredAlphaProgram;
+extern LLGLSLShader			gDeferredAlphaImpostorProgram;
 extern LLGLSLShader			gDeferredFullbrightProgram;
+extern LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
+extern LLGLSLShader			gDeferredAlphaWaterProgram;
+extern LLGLSLShader			gDeferredFullbrightWaterProgram;
+extern LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
 extern LLGLSLShader			gDeferredEmissiveProgram;
 extern LLGLSLShader			gDeferredAvatarEyesProgram;
 extern LLGLSLShader			gDeferredAvatarAlphaProgram;
@@ -310,5 +333,5 @@ extern LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
-
+extern LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 #endif
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index fc43abf844820a2e8bd5488329eb21747ce2390e..2efe4665fa393fc0bea784a5fa525cf82e5f9fac 100755
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -566,12 +566,12 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 	}
 	else
 	{
-		if((mImageList.insert(image)).second != true) 
-		{
+	if((mImageList.insert(image)).second != true) 
+	{
 			llwarns << "Error happens when insert image " << image->getID()  << " into mImageList!" << llendl ;
-		}
-		image->setInImageList(TRUE) ;
 	}
+	image->setInImageList(TRUE) ;
+}
 }
 
 void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
@@ -585,30 +585,30 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 	{
 		count = mImageList.erase(image) ;
 		if(count != 1) 
-		{
-			llwarns << "Image  " << image->getID() 
+	{
+			llinfos << "Image  " << image->getID() 
 				<< " had mInImageList set but mImageList.erase() returned " << count
 				<< llendl;
 		}
 	}
 	else
 	{	// Something is wrong, image is expected in list or callers should check first
-		llwarns << "Calling removeImageFromList() for " << image->getID() 
+		llinfos << "Calling removeImageFromList() for " << image->getID() 
 			<< " but doesn't have mInImageList set"
 			<< " ref count is " << image->getNumRefs()
 			<< llendl;
 		uuid_map_t::iterator iter = mUUIDMap.find(image->getID());
 		if(iter == mUUIDMap.end())
 		{
-			llwarns << "Image  " << image->getID() << " is also not in mUUIDMap!" << llendl ;
+			llinfos << "Image  " << image->getID() << " is also not in mUUIDMap!" << llendl ;
 		}
 		else if (iter->second != image)
 		{
-			llwarns << "Image  " << image->getID() << " was in mUUIDMap but with different pointer" << llendl ;
-		}
+			llinfos << "Image  " << image->getID() << " was in mUUIDMap but with different pointer" << llendl ;
+	}
 		else
-		{
-			llwarns << "Image  " << image->getID() << " was in mUUIDMap with same pointer" << llendl ;
+	{
+			llinfos << "Image  " << image->getID() << " was in mUUIDMap with same pointer" << llendl ;
 		}
 		count = mImageList.erase(image) ;
 		if(count != 0) 
@@ -618,7 +618,7 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 				<< llendl;
 		}
 	}
-
+      
 	image->setInImageList(FALSE) ;
 }
 
@@ -626,15 +626,15 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image)
 {
 	if (!new_image)
 	{
-		llwarning("No image to add to image list", 0);
 		return;
 	}
+	llassert(new_image);
 	LLUUID image_id = new_image->getID();
 	
 	LLViewerFetchedTexture *image = findImage(image_id);
 	if (image)
 	{
-		llwarns << "Image with ID " << image_id << " already in list" << llendl;
+		llinfos << "Image with ID " << image_id << " already in list" << llendl;
 	}
 	sNumImages++;
 	
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e3bd2b86211f3381158dfc66e2c0a2fad284a7ad..183799af24ae222c3b31726bd2f954fe47cc3e3f 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1035,7 +1035,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 				}
 			}
 		}
-		
+
 		static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback");
 
 		bool cache_in_vram = use_transform_feedback && gTransformPositionProgram.mProgramObject &&
@@ -4426,7 +4426,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	U32 spec_count = 0;
 	U32 normspec_count = 0;
 
-	
+
 	U32 useage = group->mSpatialPartition->mBufferUsage;
 
 	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
@@ -5004,7 +5004,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		}
 		else
 		{
-			pAvatarVO->mAttachmentGeometryBytes += group->mGeometryBytes;
+		pAvatarVO->mAttachmentGeometryBytes += group->mGeometryBytes;
 		}
 		if (pAvatarVO->mAttachmentSurfaceArea < 0.f)
 		{	// First time through value is -1
@@ -5012,10 +5012,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		}
 		else
 		{
-			pAvatarVO->mAttachmentSurfaceArea += group->mSurfaceArea;
-		}
+		pAvatarVO->mAttachmentSurfaceArea += group->mSurfaceArea;
 	}
 }
+}
 
 static LLFastTimer::DeclareTimer FTM_REBUILD_MESH_FLUSH("Flush Mesh");
 
@@ -5033,7 +5033,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 
 		const U32 MAX_BUFFER_COUNT = 4096;
 		LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT];
-
+		
 		U32 buffer_count = 0;
 
 		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
@@ -5044,7 +5044,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 			{
 				LLVOVolume* vobj = drawablep->getVOVolume();
 				vobj->preRebuild();
-				
+
 				if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
 				{
 					vobj->updateRelativeXform(true);
@@ -5090,17 +5090,17 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 		{
 			LLFastTimer t(FTM_REBUILD_MESH_FLUSH);
 			for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter)
-			{
-				(*iter)->flush();
-			}
-		
-			// don't forget alpha
-			if(group != NULL && 
-			   !group->mVertexBuffer.isNull() && 
-			   group->mVertexBuffer->isLocked())
-			{
-				group->mVertexBuffer->flush();
-			}
+		{
+			(*iter)->flush();
+		}
+
+		// don't forget alpha
+		if(group != NULL && 
+		   !group->mVertexBuffer.isNull() && 
+		   group->mVertexBuffer->isLocked())
+		{
+			group->mVertexBuffer->flush();
+		}
 		}
 
 		//if not all buffers are unmapped
@@ -5297,7 +5297,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
 				{
 					texture_list[texture_count++] = tex;
 				}
-				
+
 				if (can_batch_texture(facep))
 				{ //populate texture_list with any textures that can be batched
 				  //move i to the next unbatchable face
@@ -5503,18 +5503,23 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFac
 			}
 
 			bool use_legacy_bump = te->getBumpmap() && (te->getBumpmap() < 18) && (!mat || mat->getNormalID().isNull());
+			bool opaque = te->getColor().mV[3] >= 0.999f;
 
 			if (mat && LLPipeline::sRenderDeferred && !hud_group)
 			{
 				bool material_pass = false;
 
-				if (fullbright)
+				// do NOT use 'fullbright' for this logic or you risk sending
+				// things without normals down the materials pipeline and will
+				// render poorly if not crash NORSPEC-240,314
+				//
+				if (te->getFullbright())
 				{
 					if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
 					{
-						if (te->getColor().mV[3] >= 0.999f)
+						if (opaque)
 						{
-							material_pass = true;
+							registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
 						}
 						else
 						{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e00d22023aa38c8d87345887a2d6fa21be850e4f..8e8114d667c0ca265e70ef272ce7386a24432b48 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -387,6 +387,7 @@ BOOL	LLPipeline::sWaterReflections = FALSE;
 BOOL	LLPipeline::sRenderGlow = FALSE;
 BOOL	LLPipeline::sReflectionRender = FALSE;
 BOOL	LLPipeline::sImpostorRender = FALSE;
+BOOL	LLPipeline::sImpostorRenderAlphaDepthPass = FALSE;
 BOOL	LLPipeline::sUnderWaterRender = FALSE;
 BOOL	LLPipeline::sTextureBindTest = FALSE;
 BOOL	LLPipeline::sRenderFrameTest = FALSE;
@@ -802,14 +803,22 @@ void LLPipeline::resizeScreenTexture()
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
 		GLuint resY = gViewerWindow->getWorldViewHeightRaw();
 	
+		if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight()))
+		{
+			releaseScreenBuffers();
 		if (!allocateScreenBuffer(resX,resY))
-		{ //FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled
+			{
+#if PROBABLE_FALSE_DISABLES_OF_ALM_HERE
+				//FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled
 			//NOTE: if the session closes successfully after this call, deferred rendering will be 
 			// disabled on future sessions
 			if (LLPipeline::sRenderDeferred)
 			{
 				gSavedSettings.setBOOL("RenderDeferred", FALSE);
 				LLPipeline::refreshCachedSettings();
+
+				}
+#endif
 			}
 		}
 	}
@@ -1201,6 +1210,7 @@ void LLPipeline::releaseGLBuffers()
 
 	mWaterRef.release();
 	mWaterDis.release();
+	mHighlight.release();
 	
 	for (U32 i = 0; i < 3; i++)
 	{
@@ -1231,12 +1241,12 @@ void LLPipeline::releaseScreenBuffers()
 	mDeferredScreen.release();
 	mDeferredDepth.release();
 	mDeferredLight.release();
-	
-	mHighlight.release();
+	mOcclusionDepth.release();
 		
 	for (U32 i = 0; i < 6; i++)
 	{
 		mShadow[i].release();
+		mShadowOcclusion[i].release();
 	}
 }
 
@@ -1248,14 +1258,31 @@ void LLPipeline::createGLBuffers()
 
 	updateRenderDeferred();
 
+	bool materials_in_water = false;
+
+#if MATERIALS_IN_REFLECTIONS
+	materials_in_water = gSavedSettings.getS32("RenderWaterMaterials");
+#endif
+
 	if (LLPipeline::sWaterReflections)
 	{ //water reflection texture
 		U32 res = (U32) llmax(gSavedSettings.getS32("RenderWaterRefResolution"), 512);
 			
+		// Set up SRGB targets if we're doing deferred-path reflection rendering
+		//
+		if (LLPipeline::sRenderDeferred && materials_in_water)
+		{
+			mWaterRef.allocate(res,res,GL_SRGB8_ALPHA8,TRUE,FALSE);
+			//always use FBO for mWaterDis so it can be used for avatar texture bakes
+			mWaterDis.allocate(res,res,GL_SRGB8_ALPHA8,TRUE,FALSE,LLTexUnit::TT_TEXTURE, true);
+		}
+		else
+		{
 		mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
 		//always use FBO for mWaterDis so it can be used for avatar texture bakes
 		mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE,LLTexUnit::TT_TEXTURE, true);
 	}
+	}
 
 	mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
 
@@ -2464,7 +2491,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	if (to_texture)
 	{
-		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		if (LLPipeline::sRenderDeferred)
 		{
 			mOcclusionDepth.bindTarget();
 		}
@@ -2609,7 +2636,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	if (to_texture)
 	{
-		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		if (LLPipeline::sRenderDeferred)
 		{
 			mOcclusionDepth.flush();
 		}
@@ -8326,6 +8353,13 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n
 	shader.uniform2f(LLShaderMgr::DEFERRED_PROJ_SHADOW_RES, mShadow[4].getWidth(), mShadow[4].getHeight());
 	shader.uniform1f(LLShaderMgr::DEFERRED_DEPTH_CUTOFF, RenderEdgeDepthCutoff);
 	shader.uniform1f(LLShaderMgr::DEFERRED_NORM_CUTOFF, RenderEdgeNormCutoff);
+	
+
+	if (shader.getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0)
+	{
+		glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
+		shader.uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m);
+	}
 }
 
 LLColor3 pow3f(LLColor3 v, F32 f)
@@ -8447,7 +8481,7 @@ void LLPipeline::renderDeferredLighting()
 				}
 
 				gDeferredSunProgram.uniform3fv(sOffset, slice, offset);
-								
+				
 				{
 					LLGLDisable blend(GL_BLEND);
 					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
@@ -8539,7 +8573,7 @@ void LLPipeline::renderDeferredLighting()
 		if (RenderDeferredAtmospheric)
 		{ //apply sunlight contribution 
 			LLFastTimer ftm(FTM_ATMOSPHERICS);
-			bindDeferredShader(gDeferredSoftenProgram);	
+			bindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);	
 			{
 				LLGLDepthTest depth(GL_FALSE);
 				LLGLDisable blend(GL_BLEND);
@@ -8561,7 +8595,7 @@ void LLPipeline::renderDeferredLighting()
 				gGL.popMatrix();
 			}
 
-			unbindDeferredShader(gDeferredSoftenProgram);
+			unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);
 		}
 
 		{ //render non-deferred geometry (fullbright, alpha, etc)
@@ -8677,7 +8711,7 @@ void LLPipeline::renderDeferredLighting()
 							
 							LLFastTimer ftm(FTM_LOCAL_LIGHTS);
 							gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
-							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, 1.f/s);
+							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
 							gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
 							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
 							gGL.syncMatrices();
@@ -8698,7 +8732,7 @@ void LLPipeline::renderDeferredLighting()
 						glh::vec3f tc(c);
 						mat.mult_matrix_vec(tc);
 					
-						fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], 1.f/s));
+						fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s));
 						light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
 					}
 				}
@@ -8783,7 +8817,7 @@ void LLPipeline::renderDeferredLighting()
 					col[count].mV[1] = powf(col[count].mV[1], 2.2f);
 					col[count].mV[2] = powf(col[count].mV[2], 2.2f);*/
 					
-					far_z = llmin(light[count].mV[2]-1.f/light[count].mV[3], far_z);
+					far_z = llmin(light[count].mV[2]-light[count].mV[3], far_z);
 					//col[count] = pow4fsrgb(col[count], 2.2f);
 					count++;
 					if (count == max_count || fullscreen_lights.empty())
@@ -8796,13 +8830,12 @@ void LLPipeline::renderDeferredLighting()
 						gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
 						far_z = 0.f;
 						count = 0; 
-						mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+      mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 						mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+						unbindDeferredShader(gDeferredMultiLightProgram[idx]);
 					}
 				}
 				
-				unbindDeferredShader(gDeferredMultiLightProgram[0]);
-
 				bindDeferredShader(gDeferredMultiSpotLightProgram);
 
 				gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
@@ -8883,9 +8916,9 @@ void LLPipeline::renderDeferredLighting()
 		
 		gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mScreen.getWidth(), mScreen.getHeight());
 		
-		F32 gamma = 1.0/2.2;
+		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
 
-		gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, gamma);
+		gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 		
 		gGL.begin(LLRender::TRIANGLE_STRIP);
 		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
@@ -8964,146 +8997,677 @@ void LLPipeline::renderDeferredLighting()
 						
 }
 
-void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
+void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target)
 {
-	//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));
+	if (!sCull)
+	{
+		return;
+	}
 
-	glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
-	glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
+	{
+		LLFastTimer ftm(FTM_RENDER_DEFERRED);
 
-	glh::matrix4f screen_to_light = light_to_screen.inverse();
+		LLViewerCamera* camera = LLViewerCamera::getInstance();
 
-	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];
+		{
+			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);	
+		}
 
-	F32 fovy = fov * RAD_TO_DEG;
-	F32 aspect = width/height;
+		LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
 
-	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);
+		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+		{
+			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+		}
 
-	glh::vec3f p1(0, 0, -(near_clip+0.01f));
-	glh::vec3f p2(0, 0, -(near_clip+1.f));
+		//ati doesn't seem to love actually using the stencil buffer on FBO's
+		LLGLDisable stencil(GL_STENCIL_TEST);
+		//glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
+		//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 
-	glh::vec3f screen_origin(0, 0, 0);
+		gGL.setColorMask(true, true);
+		
+		//draw a cube around every light
+		LLVertexBuffer::unbind();
 
-	light_to_screen.mult_matrix_vec(p1);
-	light_to_screen.mult_matrix_vec(p2);
-	light_to_screen.mult_matrix_vec(screen_origin);
+		LLGLEnable cull(GL_CULL_FACE);
+		LLGLEnable blend(GL_BLEND);
 
-	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(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m);
-	shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip);
-	shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v);
-	shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v);
-	shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v);
-	shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range);
-	shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]);
-	S32 s_idx = -1;
+		glh::matrix4f mat = glh_copy_matrix(gGLModelView);
 
-	for (U32 i = 0; i < 2; i++)
-	{
-		if (mShadowSpotLight[i] == drawablep)
+		LLStrider<LLVector3> vert; 
+		mDeferredVB->getVertexStrider(vert);
+		
+		vert[0].set(-1,1,0);
+		vert[1].set(-1,-3,0);
+		vert[2].set(3,1,0);
+		
 		{
-			s_idx = i;
+			setupHWLights(NULL); //to set mSunDir;
+			LLVector4 dir(mSunDir, 0.f);
+			glh::vec4f tc(dir.mV);
+			mat.mult_matrix_vec(tc);
+			mTransformedSunDir.set(tc.v);
 		}
-	}
-
-	shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx);
-
-	if (s_idx >= 0)
-	{
-		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]);
-	}
-	else
-	{
-		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f);
-	}
 
-	{
-		LLDrawable* potential = drawablep;
-		//determine if this is a good light for casting shadows
-		F32 m_pri = volume->getSpotLightPriority();
+		gGL.pushMatrix();
+		gGL.loadIdentity();
+		gGL.matrixMode(LLRender::MM_PROJECTION);
+		gGL.pushMatrix();
+		gGL.loadIdentity();
 
-		for (U32 i = 0; i < 2; i++)
+		if (RenderDeferredSSAO || RenderShadowDetail > 0)
 		{
-			F32 pri = 0.f;
+			mDeferredLight.bindTarget();
+			{ //paint shadow/SSAO light map (direct lighting lightmap)
+				LLFastTimer ftm(FTM_SUN_SHADOW);
+				bindDeferredShader(gDeferredSunProgram);
+				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				glClearColor(1,1,1,1);
+				mDeferredLight.clear(GL_COLOR_BUFFER_BIT);
+				glClearColor(0,0,0,0);
 
-			if (mTargetShadowSpotLight[i].notNull())
-			{
-				pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();			
-			}
+				glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
 
-			if (m_pri > pri)
-			{
-				LLDrawable* temp = mTargetShadowSpotLight[i];
-				mTargetShadowSpotLight[i] = potential;
-				potential = temp;
-				m_pri = pri;
+				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];
+					}
+				}
+
+				gDeferredSunProgram.uniform3fv(LLShaderMgr::DEFERRED_SHADOW_OFFSET, slice, offset);
+				gDeferredSunProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mDeferredLight.getWidth(), mDeferredLight.getHeight());
+				
+				{
+					LLGLDisable blend(GL_BLEND);
+					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+					stop_glerror();
+					mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+					stop_glerror();
+				}
+				
+				unbindDeferredShader(gDeferredSunProgram);
 			}
+			mDeferredLight.flush();
 		}
-	}
+				
+		stop_glerror();
+		gGL.popMatrix();
+		stop_glerror();
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		stop_glerror();
+		gGL.popMatrix();
+		stop_glerror();
 
-	LLViewerTexture* img = volume->getLightTexture();
+		target->bindTarget();
 
-	if (img == NULL)
-	{
-		img = LLViewerFetchedTexture::sWhiteImagep;
-	}
+		//clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
+		glClearColor(0,0,0,0);
+		target->clear(GL_COLOR_BUFFER_BIT);
+		
+		if (RenderDeferredAtmospheric)
+		{ //apply sunlight contribution 
+			LLFastTimer ftm(FTM_ATMOSPHERICS);
+			bindDeferredShader(gDeferredSoftenProgram);	
+			{
+				LLGLDepthTest depth(GL_FALSE);
+				LLGLDisable blend(GL_BLEND);
+				LLGLDisable test(GL_ALPHA_TEST);
 
-	S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+				//full screen blit
+				gGL.pushMatrix();
+				gGL.loadIdentity();
+				gGL.matrixMode(LLRender::MM_PROJECTION);
+				gGL.pushMatrix();
+				gGL.loadIdentity();
 
-	if (channel > -1)
-	{
-		if (img)
-		{
-			gGL.getTexUnit(channel)->bind(img);
+				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				
+				mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
 
-			F32 lod_range = logf(img->getWidth())/logf(2.f);
+				gGL.popMatrix();
+				gGL.matrixMode(LLRender::MM_MODELVIEW);
+				gGL.popMatrix();
+			}
 
-			shader.uniform1f(LLShaderMgr::PROJECTOR_FOCUS, focus);
-			shader.uniform1f(LLShaderMgr::PROJECTOR_LOD, lod_range);
-			shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIENT_LOD, llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
+			unbindDeferredShader(gDeferredSoftenProgram);
 		}
-	}
-		
-}
 
-void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
+		{ //render non-deferred geometry (fullbright, alpha, etc)
+			LLGLDisable blend(GL_BLEND);
+			LLGLDisable stencil(GL_STENCIL_TEST);
+			gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+			gPipeline.pushRenderTypeMask();
+			
+			gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+										LLPipeline::RENDER_TYPE_CLOUDS,
+										LLPipeline::RENDER_TYPE_WL_SKY,
+										LLPipeline::END_RENDER_TYPES);
+								
+			
+			renderGeomPostDeferred(*LLViewerCamera::getInstance(), false);
+			gPipeline.popRenderTypeMask();
+		}
+
+		BOOL render_local = RenderLocalLights;
+				
+		if (render_local)
+		{
+			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;
+			}
+
+			std::list<LLVector4> light_colors;
+
+			LLVertexBuffer::unbind();
+
+			{
+				bindDeferredShader(gDeferredLightProgram);
+				
+				if (mCubeVB.isNull())
+				{
+					mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB);
+				}
+
+				mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				
+				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;
+					}
+
+					if (volume->isAttachment())
+					{
+						if (!sRenderAttachedLights)
+						{
+							continue;
+						}
+					}
+
+
+					LLVector4a center;
+					center.load3(drawablep->getPositionAgent().mV);
+					const F32* c = center.getF32ptr();
+					F32 s = volume->getLightRadius()*1.5f;
+
+					LLColor3 col = volume->getLightColor();
+					
+					if (col.magVecSquared() < 0.001f)
+					{
+						continue;
+					}
+
+					if (s <= 0.001f)
+					{
+						continue;
+					}
+
+					LLVector4a sa;
+					sa.splat(s);
+					if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
+					{
+						continue;
+					}
+
+					sVisibleLightCount++;
+										
+					if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
+						camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
+						camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
+						camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
+						camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
+						camera->getOrigin().mV[2] < c[2] - s - 0.2f)
+					{ //draw box if camera is outside box
+						if (render_local)
+						{
+							if (volume->isLightSpotlight())
+							{
+								drawablep->getVOVolume()->updateSpotLightPriority();
+								spot_lights.push_back(drawablep);
+								continue;
+							}
+							
+							/*col.mV[0] = powf(col.mV[0], 2.2f);
+							col.mV[1] = powf(col.mV[1], 2.2f);
+							col.mV[2] = powf(col.mV[2], 2.2f);*/
+							
+							LLFastTimer ftm(FTM_LOCAL_LIGHTS);
+							gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
+							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
+							gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+							gGL.syncMatrices();
+							
+							mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center));
+							stop_glerror();
+						}
+					}
+					else
+					{	
+						if (volume->isLightSpotlight())
+						{
+							drawablep->getVOVolume()->updateSpotLightPriority();
+							fullscreen_spot_lights.push_back(drawablep);
+							continue;
+						}
+
+						glh::vec3f tc(c);
+						mat.mult_matrix_vec(tc);
+					
+						fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s));
+						light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+					}
+				}
+				unbindDeferredShader(gDeferredLightProgram);
+			}
+
+			if (!spot_lights.empty())
+			{
+				LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+				bindDeferredShader(gDeferredSpotLightProgram);
+
+				mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+				gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+				for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
+				{
+					LLFastTimer ftm(FTM_PROJECTORS);
+					LLDrawable* drawablep = *iter;
+
+					LLVOVolume* volume = drawablep->getVOVolume();
+
+					LLVector4a center;
+					center.load3(drawablep->getPositionAgent().mV);
+					const F32* c = center.getF32ptr();
+					F32 s = volume->getLightRadius()*1.5f;
+
+					sVisibleLightCount++;
+
+					setupSpotLight(gDeferredSpotLightProgram, drawablep);
+					
+					LLColor3 col = volume->getLightColor();
+					/*col.mV[0] = powf(col.mV[0], 2.2f);
+					col.mV[1] = powf(col.mV[1], 2.2f);
+					col.mV[2] = powf(col.mV[2], 2.2f);*/
+					
+					gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
+					gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
+					gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+					gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+					gGL.syncMatrices();
+										
+					mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center));
+				}
+				gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+				unbindDeferredShader(gDeferredSpotLightProgram);
+			}
+
+			//reset mDeferredVB to fullscreen triangle
+			mDeferredVB->getVertexStrider(vert);
+			vert[0].set(-1,1,0);
+			vert[1].set(-1,-3,0);
+			vert[2].set(3,1,0);
+
+			{
+				LLGLDepthTest depth(GL_FALSE);
+
+				//full screen blit
+				gGL.pushMatrix();
+				gGL.loadIdentity();
+				gGL.matrixMode(LLRender::MM_PROJECTION);
+				gGL.pushMatrix();
+				gGL.loadIdentity();
+
+				U32 count = 0;
+
+				const U32 max_count = LL_DEFERRED_MULTI_LIGHT_COUNT;
+				LLVector4 light[max_count];
+				LLVector4 col[max_count];
+
+				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();
+					
+					/*col[count].mV[0] = powf(col[count].mV[0], 2.2f);
+					col[count].mV[1] = powf(col[count].mV[1], 2.2f);
+					col[count].mV[2] = powf(col[count].mV[2], 2.2f);*/
+					
+					far_z = llmin(light[count].mV[2]-light[count].mV[3], far_z);
+					//col[count] = pow4fsrgb(col[count], 2.2f);
+					count++;
+					if (count == max_count || fullscreen_lights.empty())
+					{
+						U32 idx = count-1;
+						bindDeferredShader(gDeferredMultiLightProgram[idx]);
+						gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
+						gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
+						far_z = 0.f;
+						count = 0; 
+						mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+						mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+					}
+				}
+				
+				unbindDeferredShader(gDeferredMultiLightProgram[0]);
+
+				bindDeferredShader(gDeferredMultiSpotLightProgram);
+
+				gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+				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.mV[0] = powf(col.mV[0], 2.2f);
+					col.mV[1] = powf(col.mV[1], 2.2f);
+					col.mV[2] = powf(col.mV[2], 2.2f);*/
+					
+					gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
+					gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
+					gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+					gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+					mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+				}
+
+				gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+				unbindDeferredShader(gDeferredMultiSpotLightProgram);
+
+				gGL.popMatrix();
+				gGL.matrixMode(LLRender::MM_MODELVIEW);
+				gGL.popMatrix();
+			}
+		}
+
+		gGL.setColorMask(true, true);
+	}
+
+	/*target->flush();
+
+	//gamma correct lighting
+	gGL.matrixMode(LLRender::MM_PROJECTION);
+	gGL.pushMatrix();
+	gGL.loadIdentity();
+	gGL.matrixMode(LLRender::MM_MODELVIEW);
+	gGL.pushMatrix();
+	gGL.loadIdentity();
+
+	{
+		LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+
+		LLVector2 tc1(0,0);
+		LLVector2 tc2((F32) target->getWidth()*2,
+				  (F32) target->getHeight()*2);
+
+		target->bindTarget();
+		// Apply gamma correction to the frame here.
+		gDeferredPostGammaCorrectProgram.bind();
+		//mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+		S32 channel = 0;
+		channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, target->getUsage());
+		if (channel > -1)
+		{
+			target->bindTexture(0,channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		}
+		
+		gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, target->getWidth(), target->getHeight());
+		
+		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+
+		gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
+		
+		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);
+		
+		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+		gGL.vertex2f(3,-1);
+		
+		gGL.end();
+		
+		gGL.getTexUnit(channel)->unbind(target->getUsage());
+		gDeferredPostGammaCorrectProgram.unbind();
+		target->flush();
+	}
+
+	gGL.matrixMode(LLRender::MM_PROJECTION);
+	gGL.popMatrix();
+	gGL.matrixMode(LLRender::MM_MODELVIEW);
+	gGL.popMatrix();	
+
+	target->bindTarget();*/
+
+	{ //render non-deferred geometry (alpha, fullbright, glow)
+		LLGLDisable blend(GL_BLEND);
+		LLGLDisable stencil(GL_STENCIL_TEST);
+
+		pushRenderTypeMask();
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+						 LLPipeline::RENDER_TYPE_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_VOLUME,
+						 LLPipeline::RENDER_TYPE_GLOW,
+						 LLPipeline::RENDER_TYPE_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_GLOW,
+						 LLPipeline::RENDER_TYPE_PASS_GRASS,
+						 LLPipeline::RENDER_TYPE_PASS_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+						 LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+						 LLPipeline::RENDER_TYPE_AVATAR,
+						 LLPipeline::RENDER_TYPE_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK,
+						 END_RENDER_TYPES);
+		
+		renderGeomPostDeferred(*LLViewerCamera::getInstance());
+		popRenderTypeMask();
+	}
+
+	//target->flush();				
+}
+
+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(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m);
+	shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip);
+	shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v);
+	shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v);
+	shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v);
+	shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range);
+	shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]);
+	S32 s_idx = -1;
+
+	for (U32 i = 0; i < 2; i++)
+	{
+		if (mShadowSpotLight[i] == drawablep)
+		{
+			s_idx = i;
+		}
+	}
+
+	shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx);
+
+	if (s_idx >= 0)
+	{
+		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]);
+	}
+	else
+	{
+		shader.uniform1f(LLShaderMgr::PROJECTOR_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();
+
+	if (img == NULL)
+	{
+		img = LLViewerFetchedTexture::sWhiteImagep;
+	}
+
+	S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+	if (channel > -1)
+	{
+		if (img)
+		{
+			gGL.getTexUnit(channel)->bind(img);
+
+			F32 lod_range = logf(img->getWidth())/logf(2.f);
+
+			shader.uniform1f(LLShaderMgr::PROJECTOR_FOCUS, focus);
+			shader.uniform1f(LLShaderMgr::PROJECTOR_LOD, lod_range);
+			shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIENT_LOD, llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
+		}
+	}
+		
+}
+
+void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
 {
 	stop_glerror();
 	shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, mDeferredScreen.getUsage());
@@ -9210,16 +9774,23 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			water_clip = 1;
 		}
 
-		S32 occlusion = LLPipeline::sUseOcclusion;
-		LLPipeline::sUseOcclusion = 0;
+		bool materials_in_water = false;
+
+#if MATERIALS_IN_REFLECTIONS
+		materials_in_water = gSavedSettings.getS32("RenderWaterMaterials");
+#endif
 
 		if (!LLViewerCamera::getInstance()->cameraUnderWater())
 		{	//generate planar reflection map
 
 			//disable occlusion culling for reflection map for now
+			S32 occlusion = LLPipeline::sUseOcclusion;
+			LLPipeline::sUseOcclusion = 0;
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 			glClearColor(0,0,0,0);
+
 			mWaterRef.bindTarget();
+
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0;
 			gGL.setColorMask(true, true);
 			mWaterRef.clear();
@@ -9268,11 +9839,27 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					updateCull(camera, result);
 					stateSort(camera, result);
 
+					if (LLPipeline::sRenderDeferred && materials_in_water)
+					{
+						mWaterRef.flush();
+
+						gPipeline.grabReferences(result);
+						gPipeline.mDeferredScreen.bindTarget();
+						gGL.setColorMask(true, true);						
+						glClearColor(0,0,0,0);
+						gPipeline.mDeferredScreen.clear();
+
+						renderGeomDeferred(camera);						
+					}
+					else
+					{
 					renderGeom(camera, TRUE);
+					}					
 
 					gPipeline.popRenderTypeMask();
 				}
 
+				gGL.setColorMask(true, false);
 				gPipeline.pushRenderTypeMask();
 
 				clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
@@ -9310,9 +9897,23 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					{
 						gPipeline.grabReferences(ref_result);
 						LLGLUserClipPlane clip_plane(plane, mat, projection);
+
+						if (LLPipeline::sRenderDeferred && materials_in_water)
+						{							
+							renderGeomDeferred(camera);
+						}
+						else
+						{
 						renderGeom(camera);
 					}
 				}	
+				}	
+
+				if (LLPipeline::sRenderDeferred && materials_in_water)
+				{
+					gPipeline.mDeferredScreen.flush();
+					renderDeferredLightingToRT(&mWaterRef);
+				}
 
 				gPipeline.popRenderTypeMask();
 			}	
@@ -9320,6 +9921,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			gGL.popMatrix();
 			mWaterRef.flush();
 			glh_set_current_modelview(current);
+			LLPipeline::sUseOcclusion = occlusion;
 		}
 
 		camera.setOrigin(camera_in.getOrigin());
@@ -9368,15 +9970,33 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 				mWaterDis.clear();
 				gGL.setColorMask(true, false);
 
+				
+				if (LLPipeline::sRenderDeferred && materials_in_water)
+				{										
+					mWaterDis.flush();
+					gPipeline.mDeferredScreen.bindTarget();
+					gGL.setColorMask(true, true);
+					glClearColor(0,0,0,0);
+					gPipeline.mDeferredScreen.clear();
+					gPipeline.grabReferences(result);
+					renderGeomDeferred(camera);					
+				}
+				else
+				{
 				renderGeom(camera);
+				}
 
+				if (LLPipeline::sRenderDeferred && materials_in_water)
+				{
+					gPipeline.mDeferredScreen.flush();
+					renderDeferredLightingToRT(&mWaterDis);
+				}
 			}
 
-			LLPipeline::sUnderWaterRender = FALSE;
 			mWaterDis.flush();
+			LLPipeline::sUnderWaterRender = FALSE;
+			
 		}
-
-		LLPipeline::sUseOcclusion = occlusion;
 		last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
 
 		LLPipeline::sReflectionRender = FALSE;
@@ -10701,23 +11321,29 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	}
 	else
 	{
-		andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
-						LLPipeline::RENDER_TYPE_AVATAR,
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+			LLPipeline::RENDER_TYPE_FULLBRIGHT,
+			LLPipeline::RENDER_TYPE_VOLUME,
+			LLPipeline::RENDER_TYPE_GLOW,
 						LLPipeline::RENDER_TYPE_BUMP,
-						LLPipeline::RENDER_TYPE_GRASS,
-						LLPipeline::RENDER_TYPE_SIMPLE,
-						LLPipeline::RENDER_TYPE_FULLBRIGHT,
-						LLPipeline::RENDER_TYPE_ALPHA, 
-						LLPipeline::RENDER_TYPE_INVISIBLE,
 						LLPipeline::RENDER_TYPE_PASS_SIMPLE,
 						LLPipeline::RENDER_TYPE_PASS_ALPHA,
 						LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+			LLPipeline::RENDER_TYPE_PASS_BUMP,
+			LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
 						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
 						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
 						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+			LLPipeline::RENDER_TYPE_PASS_GLOW,
+			LLPipeline::RENDER_TYPE_PASS_GRASS,
 						LLPipeline::RENDER_TYPE_PASS_SHINY,
 						LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
 						LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+			LLPipeline::RENDER_TYPE_AVATAR,
+			LLPipeline::RENDER_TYPE_ALPHA_MASK,
+			LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK,
+			LLPipeline::RENDER_TYPE_INVISIBLE,
+			LLPipeline::RENDER_TYPE_SIMPLE,
 						END_RENDER_TYPES);
 	}
 	
@@ -10818,22 +11444,26 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		if (!avatar->mImpostor.isComplete())
 		{
 			LLFastTimer t(FTM_IMPOSTOR_ALLOCATE);
-			avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+			
 
 			if (LLPipeline::sRenderDeferred)
 			{
+				avatar->mImpostor.allocate(resX,resY,GL_SRGB8_ALPHA8,TRUE,FALSE);
 				addDeferredAttachments(avatar->mImpostor);
 			}
+			else
+			{
+				avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+			}
 		
 			gGL.getTexUnit(0)->bind(&avatar->mImpostor);
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		}
-		else if(resX != avatar->mImpostor.getWidth() ||
-			resY != avatar->mImpostor.getHeight())
+		else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight())
 		{
 			LLFastTimer t(FTM_IMPOSTOR_RESIZE);
-			avatar->mImpostor.resize(resX,resY,GL_RGBA);
+			avatar->mImpostor.resize(resX,resY);
 		}
 
 		avatar->mImpostor.bindTarget();
@@ -10850,7 +11480,23 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	{
 		avatar->mImpostor.clear();
 		renderGeomDeferred(camera);
+
+		renderGeomPostDeferred(camera);		
+
+		// Shameless hack time: render it all again,
+		// this time writing the depth
+		// values we need to generate the alpha mask below
+		// while preserving the alpha-sorted color rendering
+		// from the previous pass
+		//
+		sImpostorRenderAlphaDepthPass = true;
+		// depth-only here...
+		//
+		gGL.setColorMask(false,false);
 		renderGeomPostDeferred(camera);
+
+		sImpostorRenderAlphaDepthPass = false;
+
 	}
 	else
 	{
@@ -10858,12 +11504,28 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		glScissor(0, 0, resX, resY);
 		avatar->mImpostor.clear();
 		renderGeom(camera);
+
+		// Shameless hack time: render it all again,
+		// this time writing the depth
+		// values we need to generate the alpha mask below
+		// while preserving the alpha-sorted color rendering
+		// from the previous pass
+		//
+		sImpostorRenderAlphaDepthPass = true;
+
+		// depth-only here...
+		//
+		gGL.setColorMask(false,false);
+		renderGeom(camera);
+
+		sImpostorRenderAlphaDepthPass = false;
 	}
-	
+
 	LLDrawPoolAvatar::sMinimumAlpha = old_alpha;
-		
+
 	{ //create alpha mask based on depth buffer (grey out if muted)
 		LLFastTimer t(FTM_IMPOSTOR_BACKGROUND);
+
 		if (LLPipeline::sRenderDeferred)
 		{
 			GLuint buff = GL_COLOR_ATTACHMENT0;
@@ -10875,7 +11537,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		if (visually_muted)
 		{
 			gGL.setColorMask(true, true);
-
 		}
 		else
 		{
@@ -10894,7 +11555,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		gGL.pushMatrix();
 		gGL.loadIdentity();
 
-		static const F32 clip_plane = 0.999f;
+		static const F32 clip_plane = 0.99999f;
 
 		if (LLGLSLShader::sNoFixedFunction)
 		{
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index f0bebbe20d869d1421ad8411375d3ec2ffe45da1..9aeb2d4978cdc3afa9a6a3a7afd3f109c78152fc 100755
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -295,6 +295,7 @@ class LLPipeline
 
 	void unbindDeferredShader(LLGLSLShader& shader);
 	void renderDeferredLighting();
+	void renderDeferredLightingToRT(LLRenderTarget* target);
 	
 	void generateWaterReflection(LLCamera& camera);
 	void generateSunShadow(LLCamera& camera);
@@ -594,6 +595,7 @@ class LLPipeline
 	static BOOL				sPickAvatar;
 	static BOOL				sReflectionRender;
 	static BOOL				sImpostorRender;
+	static BOOL				sImpostorRenderAlphaDepthPass;
 	static BOOL				sUnderWaterRender;
 	static BOOL				sRenderGlow;
 	static BOOL				sTextureBindTest;
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
index 5ac2ec2b206bbccc4f9e302334dd49c0826e6370..426c0c491554501f57c83ea423603a4605eb8dbc 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -663,7 +663,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="bumpyOffsetU"
              width="265" />
             <spinner
@@ -674,7 +674,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="bumpyOffsetV"
              width="265" />
             <spinner
@@ -726,7 +726,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="shinyOffsetU"
              width="265" />
             <spinner
@@ -737,7 +737,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="shinyOffsetV"
              width="265" />
             <check_box