diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index e725bdd9fae7d2fa4b6ffbfcbaf38edcffd6b937..46cabfadcddad0cf5eb2eb391c31620dd3fc34c9 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -38,17 +38,28 @@ class LLMutex ;
 
 inline void* ll_aligned_malloc( size_t size, int align )
 {
+#if defined(LL_WINDOWS)
+	return _aligned_malloc(size, align);
+#else
 	void* mem = malloc( size + (align - 1) + sizeof(void*) );
 	char* aligned = ((char*)mem) + sizeof(void*);
 	aligned += align - ((uintptr_t)aligned & (align - 1));
 
 	((void**)aligned)[-1] = mem;
 	return aligned;
+#endif
 }
 
 inline void ll_aligned_free( void* ptr )
 {
-	free( ((void**)ptr)[-1] );
+#if defined(LL_WINDOWS)
+	_aligned_free(ptr);
+#else
+	if (ptr)
+	{
+		free( ((void**)ptr)[-1] );
+	}
+#endif
 }
 
 #if !LL_USE_TCMALLOC
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 02c8d2b86f090f5150bdd8574338ceb3d0d1f6f6..f989e8ed17c9b405be22ad37de8b5df9561d55fc 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -5180,6 +5180,7 @@ LLVolumeFace::LLVolumeFace() :
 	mNumS(0),
 	mNumT(0),
 	mNumVertices(0),
+	mNumAllocatedVertices(0),
 	mNumIndices(0),
 	mPositions(NULL),
 	mNormals(NULL),
@@ -5187,7 +5188,8 @@ LLVolumeFace::LLVolumeFace() :
 	mTexCoords(NULL),
 	mIndices(NULL),
 	mWeights(NULL),
-	mOctree(NULL)
+	mOctree(NULL),
+	mOptimized(FALSE)
 {
 	mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*3);
 	mExtents[0].splat(-0.5f);
@@ -5203,6 +5205,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
 	mNumS(0),
 	mNumT(0),
 	mNumVertices(0),
+	mNumAllocatedVertices(0),
 	mNumIndices(0),
 	mPositions(NULL),
 	mNormals(NULL),
@@ -5257,12 +5260,6 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 		{
 			LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
 		}
-		else
-		{
-			ll_aligned_free_16(mTexCoords) ;
-			mTexCoords = NULL ;
-		}
-
 
 		if (src.mBinormals)
 		{
@@ -5294,6 +5291,8 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 		LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size);
 	}
 	
+	mOptimized = src.mOptimized;
+
 	//delete 
 	return *this;
 }
@@ -5310,10 +5309,11 @@ void LLVolumeFace::freeData()
 {
 	ll_aligned_free_16(mPositions);
 	mPositions = NULL;
-	ll_aligned_free_16( mNormals);
+
+	//normals and texture coordinates are part of the same buffer as mPositions, do not free them separately
 	mNormals = NULL;
-	ll_aligned_free_16(mTexCoords);
 	mTexCoords = NULL;
+
 	ll_aligned_free_16(mIndices);
 	mIndices = NULL;
 	ll_aligned_free_16(mBinormals);
@@ -5495,18 +5495,6 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
 	llassert(new_face.mNumIndices == mNumIndices);
 	llassert(new_face.mNumVertices <= mNumVertices);
 
-	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;
-	}
-
 	swapData(new_face);
 }
 
@@ -5517,14 +5505,14 @@ class LLVCacheVertexData
 public:
 	S32 mIdx;
 	S32 mCacheTag;
-	F32 mScore;
+	F64 mScore;
 	U32 mActiveTriangles;
 	std::vector<LLVCacheTriangleData*> mTriangles;
 
 	LLVCacheVertexData()
 	{
 		mCacheTag = -1;
-		mScore = 0.f;
+		mScore = 0.0;
 		mActiveTriangles = 0;
 		mIdx = -1;
 	}
@@ -5534,13 +5522,13 @@ class LLVCacheTriangleData
 {
 public:
 	bool mActive;
-	F32 mScore;
+	F64 mScore;
 	LLVCacheVertexData* mVertex[3];
 
 	LLVCacheTriangleData()
 	{
 		mActive = true;
-		mScore = 0.f;
+		mScore = 0.0;
 		mVertex[0] = mVertex[1] = mVertex[2] = NULL;
 	}
 
@@ -5551,7 +5539,7 @@ class LLVCacheTriangleData
 		{
 			if (mVertex[i])
 			{
-				llassert_always(mVertex[i]->mActiveTriangles > 0);
+				llassert(mVertex[i]->mActiveTriangles > 0);
 				mVertex[i]->mActiveTriangles--;
 			}
 		}
@@ -5563,44 +5551,44 @@ class LLVCacheTriangleData
 	}
 };
 
-const F32 FindVertexScore_CacheDecayPower = 1.5f;
-const F32 FindVertexScore_LastTriScore = 0.75f;
-const F32 FindVertexScore_ValenceBoostScale = 2.0f;
-const F32 FindVertexScore_ValenceBoostPower = 0.5f;
+const F64 FindVertexScore_CacheDecayPower = 1.5;
+const F64 FindVertexScore_LastTriScore = 0.75;
+const F64 FindVertexScore_ValenceBoostScale = 2.0;
+const F64 FindVertexScore_ValenceBoostPower = 0.5;
 const U32 MaxSizeVertexCache = 32;
+const F64 FindVertexScore_Scaler = 1.0/(MaxSizeVertexCache-3);
 
-F32 find_vertex_score(LLVCacheVertexData& data)
+F64 find_vertex_score(LLVCacheVertexData& data)
 {
-	if (data.mActiveTriangles == 0)
-	{ //no triangle references this vertex
-		return -1.f;
-	}
+	F64 score = -1.0;
 
-	F32 score = 0.f;
-
-	S32 cache_idx = data.mCacheTag;
+	if (data.mActiveTriangles >= 0)
+	{ 
+		score = 0.0;
+		
+		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;
+		if (cache_idx < 0)
+		{
+			//not in cache
 		}
 		else
-		{ //more points for being higher in the cache
-			F32 scaler = 1.f/(MaxSizeVertexCache-3);
-			score = 1.f-((cache_idx-3)*scaler);
-			score = powf(score, FindVertexScore_CacheDecayPower);
+		{
+			if (cache_idx < 3)
+			{ //vertex was in the last triangle
+				score = FindVertexScore_LastTriScore;
+			}
+			else
+			{ //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
-	F32 valence_boost = powf((F32)data.mActiveTriangles, -FindVertexScore_ValenceBoostPower);
-	score += FindVertexScore_ValenceBoostScale * valence_boost;
+		//bonus points for having low valence
+		F64 valence_boost = pow((F64)data.mActiveTriangles, -FindVertexScore_ValenceBoostPower);
+		score += FindVertexScore_ValenceBoostScale * valence_boost;
+	}
 
 	return score;
 }
@@ -5707,32 +5695,44 @@ class LLVCacheLRU
 
 	void updateScores()
 	{
-		for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
-		{ //trailing 3 vertices aren't actually in the cache for scoring purposes
-			if (mCache[i])
+		LLVCacheVertexData** data_iter = mCache+MaxSizeVertexCache;
+		LLVCacheVertexData** end_data = mCache+MaxSizeVertexCache+3;
+
+		while(data_iter != end_data)
+		{
+			LLVCacheVertexData* data = *data_iter++;
+			//trailing 3 vertices aren't actually in the cache for scoring purposes
+			if (data)
 			{
-				mCache[i]->mCacheTag = -1;
+				data->mCacheTag = -1;
 			}
 		}
 
-		for (U32 i = 0; i < MaxSizeVertexCache; ++i)
+		data_iter = mCache;
+		end_data = mCache+MaxSizeVertexCache;
+
+		while (data_iter != end_data)
 		{ //update scores of vertices in cache
-			if (mCache[i])
+			LLVCacheVertexData* data = *data_iter++;
+			if (data)
 			{
-				mCache[i]->mScore = find_vertex_score(*(mCache[i]));
-				llassert_always(mCache[i]->mCacheTag == i);
+				data->mScore = find_vertex_score(*data);
 			}
 		}
 
 		mBestTriangle = NULL;
 		//update triangle scores
-		for (U32 i = 0; i < MaxSizeVertexCache+3; ++i)
+		data_iter = mCache;
+		end_data = mCache+MaxSizeVertexCache+3;
+
+		while (data_iter != end_data)
 		{
-			if (mCache[i])
+			LLVCacheVertexData* data = *data_iter++;
+			if (data)
 			{
-				for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j)
+				for (std::vector<LLVCacheTriangleData*>::iterator iter = data->mTriangles.begin(), end_iter = data->mTriangles.end(); iter != end_iter; ++iter)
 				{
-					LLVCacheTriangleData* tri = mCache[i]->mTriangles[j];
+					LLVCacheTriangleData* tri = *iter;
 					if (tri->mActive)
 					{
 						tri->mScore = tri->mVertex[0]->mScore;
@@ -5749,13 +5749,17 @@ class LLVCacheLRU
 		}
 
 		//knock trailing 3 vertices off the cache
-		for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
+		data_iter = mCache+MaxSizeVertexCache;
+		end_data = mCache+MaxSizeVertexCache+3;
+		while (data_iter != end_data)
 		{
-			if (mCache[i])
+			LLVCacheVertexData* data = *data_iter;
+			if (data)
 			{
-				llassert_always(mCache[i]->mCacheTag == -1);
-				mCache[i] = NULL;
+				llassert(data->mCacheTag == -1);
+				*data_iter = NULL;
 			}
+			++data_iter;
 		}
 	}
 };
@@ -5765,6 +5769,9 @@ void LLVolumeFace::cacheOptimize()
 { //optimize for vertex cache according to Forsyth method: 
   // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
 	
+	llassert(!mOptimized);
+	mOptimized = TRUE;
+
 	LLVCacheLRU cache;
 	
 	if (mNumVertices < 3)
@@ -5810,12 +5817,14 @@ void LLVolumeFace::cacheOptimize()
 
 	for (U32 i = 0; i < mNumVertices; i++)
 	{ //initialize score values (no cache -- might try a fifo cache here)
-		vertex_data[i].mScore = find_vertex_score(vertex_data[i]);
-		vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size();
+		LLVCacheVertexData& data = vertex_data[i];
 
-		for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j)
+		data.mScore = find_vertex_score(data);
+		data.mActiveTriangles = data.mTriangles.size();
+
+		for (U32 j = 0; j < data.mActiveTriangles; ++j)
 		{
-			vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore;
+			data.mTriangles[j]->mScore += data.mScore;
 		}
 	}
 
@@ -5885,10 +5894,10 @@ void LLVolumeFace::cacheOptimize()
 	
 	//allocate space for new buffer
 	S32 num_verts = mNumVertices;
-	LLVector4a* pos = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
-	LLVector4a* norm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
 	S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
-	LLVector2* tc = (LLVector2*) ll_aligned_malloc_16(size);
+	LLVector4a* pos = (LLVector4a*) ll_aligned_malloc(sizeof(LLVector4a)*2*num_verts+size, 64);
+	LLVector4a* norm = pos + num_verts;
+	LLVector2* tc = (LLVector2*) (norm + num_verts);
 
 	LLVector4a* wght = NULL;
 	if (mWeights)
@@ -5936,9 +5945,8 @@ void LLVolumeFace::cacheOptimize()
 		mIndices[i] = new_idx[mIndices[i]];
 	}
 	
-	ll_aligned_free_16(mPositions);
-	ll_aligned_free_16(mNormals);
-	ll_aligned_free_16(mTexCoords);
+	ll_aligned_free(mPositions);
+	// DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
 	ll_aligned_free_16(mWeights);
 	ll_aligned_free_16(mBinormals);
 
@@ -6655,24 +6663,22 @@ void LLVolumeFace::createBinormals()
 
 void LLVolumeFace::resizeVertices(S32 num_verts)
 {
-	ll_aligned_free_16(mPositions);
-	ll_aligned_free_16(mNormals);
+	ll_aligned_free(mPositions);
+	//DO NOT free mNormals and mTexCoords as they are part of mPositions buffer
 	ll_aligned_free_16(mBinormals);
-	ll_aligned_free_16(mTexCoords);
-
+	
 	mBinormals = NULL;
 
 	if (num_verts)
 	{
-		mPositions = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
-		ll_assert_aligned(mPositions, 16);
-		mNormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
-		ll_assert_aligned(mNormals, 16);
-
 		//pad texture coordinate block end to allow for QWORD reads
 		S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
-		mTexCoords = (LLVector2*) ll_aligned_malloc_16(size);
-		ll_assert_aligned(mTexCoords, 16);
+
+		mPositions = (LLVector4a*) ll_aligned_malloc(sizeof(LLVector4a)*2*num_verts+size, 64);
+		mNormals = mPositions+num_verts;
+		mTexCoords = (LLVector2*) (mNormals+num_verts);
+
+		ll_assert_aligned(mPositions, 64);
 	}
 	else
 	{
@@ -6682,6 +6688,7 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
 	}
 
 	mNumVertices = num_verts;
+	mNumAllocatedVertices = num_verts;
 }
 
 void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
@@ -6692,27 +6699,43 @@ void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
 void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc)
 {
 	S32 new_verts = mNumVertices+1;
-	S32 new_size = new_verts*16;
-	S32 old_size = mNumVertices*16;
 
-	//positions
-	mPositions = (LLVector4a*) ll_aligned_realloc_16(mPositions, new_size, old_size);
-	ll_assert_aligned(mPositions,16);
+	if (new_verts > mNumAllocatedVertices)
+	{ 
+		//double buffer size on expansion
+		new_verts *= 2;
+
+		S32 new_tc_size = ((new_verts*8)+0xF) & ~0xF;
+		S32 old_tc_size = ((mNumVertices*8)+0xF) & ~0xF;
+
+		S32 old_vsize = mNumVertices*16;
+		
+		S32 new_size = new_verts*16*2+new_tc_size;
+
+		LLVector4a* old_buf = mPositions;
+
+		mPositions = (LLVector4a*) ll_aligned_malloc(new_size, 64);
+		mNormals = mPositions+new_verts;
+		mTexCoords = (LLVector2*) (mNormals+new_verts);
+
+		//positions
+		LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
+		
+		//normals
+		LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
 	
-	//normals
-	mNormals = (LLVector4a*) ll_aligned_realloc_16(mNormals, new_size, old_size);
-	ll_assert_aligned(mNormals,16);
-
-	//tex coords
-	new_size = ((new_verts*8)+0xF) & ~0xF;
-	old_size = ((mNumVertices*8)+0xF) & ~0xF;
-	mTexCoords = (LLVector2*) ll_aligned_realloc_16(mTexCoords, new_size, old_size);
-	ll_assert_aligned(mTexCoords,16);
+		//tex coords
+		LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tc_size);
 	
+		//just clear binormals
+		ll_aligned_free_16(mBinormals);
 
-	//just clear binormals
-	ll_aligned_free_16(mBinormals);
-	mBinormals = NULL;
+		ll_aligned_free(old_buf);
+
+		mNumAllocatedVertices = new_verts;
+
+		mBinormals = NULL;
+	}
 
 	mPositions[mNumVertices] = pos;
 	mNormals[mNumVertices] = norm;
@@ -6801,13 +6824,23 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
 		llerrs << "Cannot append empty face." << llendl;
 	}
 
+	U32 old_vsize = mNumVertices*16;
+	U32 new_vsize = new_count * 16;
+	U32 old_tcsize = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF;
+	U32 new_tcsize = (new_count*sizeof(LLVector2)+0xF) & ~0xF;
+	U32 new_size = new_vsize * 2 + new_tcsize;
+
 	//allocate new buffer space
-	mPositions = (LLVector4a*) ll_aligned_realloc_16(mPositions, new_count*sizeof(LLVector4a), mNumVertices*sizeof(LLVector4a));
-	ll_assert_aligned(mPositions, 16);
-	mNormals = (LLVector4a*) ll_aligned_realloc_16(mNormals, new_count*sizeof(LLVector4a), mNumVertices*sizeof(LLVector4a));
-	ll_assert_aligned(mNormals, 16);
-	mTexCoords = (LLVector2*) ll_aligned_realloc_16(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF, (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF);
-	ll_assert_aligned(mTexCoords, 16);
+	LLVector4a* old_buf = mPositions;
+	mPositions = (LLVector4a*) ll_aligned_malloc(new_size, 64);
+	mNormals = mPositions + new_count;
+	mTexCoords = (LLVector2*) (mNormals+new_count);
+
+	mNumAllocatedVertices = new_count;
+
+	LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) old_buf, old_vsize);
+	LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) (old_buf+mNumVertices), old_vsize);
+	LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) (old_buf+mNumVertices*2), old_tcsize);
 	
 	mNumVertices = new_count;
 
@@ -6903,12 +6936,15 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 	LLVector4a* pos = (LLVector4a*) mPositions;
 	LLVector4a* norm = (LLVector4a*) mNormals;
 	LLVector2* tc = (LLVector2*) mTexCoords;
-	S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
+	F32 begin_stex = floorf(profile[mBeginS].mV[2]);
 	S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
 
 	S32 cur_vertex = 0;
+	S32 end_t = mBeginT+mNumT;
+	bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2;
+
 	// Copy the vertices into the array
-	for (t = mBeginT; t < mBeginT + mNumT; t++)
+	for (t = mBeginT; t < end_t; t++)
 	{
 		tt = path_data[t].mTexT;
 		for (s = 0; s < num_s; s++)
@@ -6959,9 +6995,8 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 			norm[cur_vertex].clear();
 			cur_vertex++;
 
-			if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
+			if (test && s > 0)
 			{
-
 				pos[cur_vertex].load3(mesh[i].mPos.mV);
 				tc[cur_vertex] = LLVector2(ss,tt);
 			
@@ -7076,30 +7111,38 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 	}
 
 	//generate normals 
-	for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle
+	U32 count = mNumIndices/3;
+
+	for (U32 i = 0; i < count; i++) //for each triangle
 	{
 		const U16* idx = &(mIndices[i*3]);
 		
-
-		LLVector4a* v[] = 
-		{	pos+idx[0], pos+idx[1], pos+idx[2] };
+		LLVector4a& v0 = *(pos+idx[0]);
+		LLVector4a& v1 = *(pos+idx[1]);
+		LLVector4a& v2 = *(pos+idx[2]);
 		
-		LLVector4a* n[] = 
-		{	norm+idx[0], norm+idx[1], norm+idx[2] };
+		LLVector4a& n0 = *(norm+idx[0]);
+		LLVector4a& n1 = *(norm+idx[1]);
+		LLVector4a& n2 = *(norm+idx[2]);
 		
 		//calculate triangle normal
 		LLVector4a a, b, c;
 		
-		a.setSub(*v[0], *v[1]);
-		b.setSub(*v[0], *v[2]);
+		a.setSub(v0, v1);
+		b.setSub(v0, v2);
 		c.setCross3(a,b);
 
-		n[0]->add(c);
-		n[1]->add(c);
-		n[2]->add(c);
+		n0.add(c);
+		n1.add(c);
+		n2.add(c);
 		
 		//even out quad contributions
-		n[i%2+1]->add(c);
+		switch (i%2+1)
+		{
+			case 0: n0.add(c); break;
+			case 1: n1.add(c); break;
+			case 2: n2.add(c); break;
+		};
 	}
 	
 	// adjust normals based on wrapping and stitching
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index c845556557bf54ce19fba3737271b003190b6e68..1d3b0fe52fefa8e5bcce557198ee04518999297a 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -912,6 +912,7 @@ class LLVolumeFace
 	LLVector2   mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
 
 	S32 mNumVertices;
+	S32 mNumAllocatedVertices;
 	S32 mNumIndices;
 
 	LLVector4a* mPositions;
@@ -933,6 +934,9 @@ class LLVolumeFace
 
 	LLOctreeNode<LLVolumeTriangle>* mOctree;
 
+	//whether or not face has been cache optimized
+	BOOL mOptimized;
+
 private:
 	BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
 	BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 9d06dd6904eab697c177460a4cb3503be7fa7249..58bd346c15a5cbc0b3f78b654e567b8d7437ca60 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -59,6 +59,7 @@ BOOL gDebugGL = FALSE;
 BOOL gClothRipple = FALSE;
 BOOL gHeadlessClient = FALSE;
 BOOL gGLActive = FALSE;
+BOOL gGLDebugLoggingEnabled = TRUE;
 
 static const std::string HEADLESS_VENDOR_STRING("Linden Lab");
 static const std::string HEADLESS_RENDERER_STRING("Headless");
@@ -72,6 +73,7 @@ std::ofstream gFailLog;
 #define APIENTRY
 #endif
 
+
 void APIENTRY gl_debug_callback(GLenum source,
                                 GLenum type,
                                 GLuint id,
@@ -80,22 +82,25 @@ void APIENTRY gl_debug_callback(GLenum source,
                                 const GLchar* message,
                                 GLvoid* userParam)
 {
-	if (severity == GL_DEBUG_SEVERITY_HIGH_ARB)
-	{
-		llwarns << "----- GL ERROR --------" << llendl;
-	}
-	else
+	if (gGLDebugLoggingEnabled)
 	{
-		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
@@ -253,6 +258,7 @@ PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL;
 PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL;
 PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL;
 PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL;
+PFNGLBINDBUFFERBASEPROC glBindBufferBase = NULL;
 
 //GL_ARB_debug_output
 PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
@@ -735,7 +741,7 @@ bool LLGLManager::initGL()
 #if LL_WINDOWS
 	if (mHasDebugOutput && gDebugGL)
 	{ //setup debug output callback
-		//glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
+		glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
 		glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
 		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
 	}
@@ -1224,6 +1230,7 @@ void LLGLManager::initExtensions()
 		glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback");
 		glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings");
 		glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange");
+		glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferBase");
 	}
 	if (mHasDebugOutput)
 	{
@@ -1471,7 +1478,7 @@ void do_assert_glerror()
 
 void assert_glerror()
 {
-	if (!gGLActive)
+/*	if (!gGLActive)
 	{
 		//llwarns << "GL used while not active!" << llendl;
 
@@ -1480,8 +1487,13 @@ void assert_glerror()
 			//ll_fail("GL used while not active");
 		}
 	}
+*/
 
-	if (gDebugGL) 
+	if (!gDebugGL) 
+	{
+		//funny looking if for branch prediction -- gDebugGL is almost always false and assert_glerror is called often
+	}
+	else
 	{
 		do_assert_glerror();
 	}
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 509de51f4dfc4261ab7c22cf47cb817288dbd189..a92ed428da033f01fb7e7d62469cd827add5140b 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -533,6 +533,7 @@ extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
 extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
 extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
 extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+extern PFNGLBINDBUFFERBASEPROC glBindBufferBase;
 
 
 #elif LL_WINDOWS
@@ -771,6 +772,7 @@ extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
 extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
 extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
 extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+extern PFNGLBINDBUFFERBASEPROC glBindBufferBase;
 
 //GL_ARB_debug_output
 extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index a4d7872ec25e0091152a4da7de8e60f2df09e5ed..ef2648ae986d54147f5c1a5130590a7ceda52e8d 100755
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -709,9 +709,12 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 
 					mMipLevels = wpo2(llmax(w, h));
 
-					//use legacy mipmap generation mode
-					glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE);
-					
+					if (!gGLManager.mHasFramebufferObject)
+					{
+						//use legacy mipmap generation mode
+						glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE);
+					}
+										
 					LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
 								 w, h, 
 								 mFormatPrimary, mFormatType,
@@ -726,6 +729,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 						glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
 						stop_glerror();
 					}
+
+					if (gGLManager.mHasFramebufferObject)
+					{
+						glGenerateMipmap(mTarget);
+					}
 				}
 			}
 			else
@@ -1057,6 +1065,16 @@ void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 n
 {
 	bool empty = true;
 
+	if (LLRender::sGLCoreProfile)
+	{
+		switch (format)
+		{
+			case GL_LUMINANCE8: format = GL_RGB8; break;
+			case GL_LUMINANCE8_ALPHA8:
+			case GL_ALPHA8: format = GL_RGBA8; break;
+		}
+	}
+
 	dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format);
 	
 	if (iter != sDeadTextureList[type].end())
@@ -1084,6 +1102,16 @@ void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip
 {
 	if (gGLManager.mInited)
 	{
+		if (LLRender::sGLCoreProfile)
+		{
+			switch (format)
+			{
+				case GL_LUMINANCE8: format = GL_RGB8; break;
+				case GL_LUMINANCE8_ALPHA8:
+				case GL_ALPHA8: format = GL_RGBA8; break;
+			}
+		}
+
 		if (format == 0 ||  type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1)
 		{ //unknown internal format or unknown number of mip levels, not safe to reuse
 			glDeleteTextures(numTextures, textures);
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index a12e9caf4c97b49470a256a03d33dfa0e20daf00..14962fe58ed6107887d4e70758214f7f6c9a5c67 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -225,26 +225,15 @@ void LLTexUnit::disable(void)
 bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 {
 	stop_glerror();
-	if (mIndex < 0) return false;
-
+	if (mIndex >= 0)
+	{
 	gGL.flush();
 
 	LLImageGL* gl_tex = NULL ;
-	if (texture == NULL || !(gl_tex = texture->getGLTexture()))
+		if (texture != NULL && (gl_tex = texture->getGLTexture()))
 	{
-		llwarns << "NULL LLTexUnit::bind texture" << llendl;
-		return false;
-	}
-
-	if (!gl_tex->getTexName()) //if texture does not exist
+			if (gl_tex->getTexName()) //if texture exists
 	{
-		//if deleted, will re-generate it immediately
-		texture->forceImmediateUpdate() ;
-
-		gl_tex->forceUpdateBindStats() ;
-		return texture->bindDefaultImage(mIndex);
-	}
-
 	//in audit, replace the selected texture by the default one.
 	if ((mCurrTexture != gl_tex->getTexName()) || forceBind)
 	{
@@ -265,6 +254,27 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 			setTextureFilteringOption(gl_tex->mFilterOption);
 		}
 	}
+			}
+			else
+			{
+				//if deleted, will re-generate it immediately
+				texture->forceImmediateUpdate() ;
+
+				gl_tex->forceUpdateBindStats() ;
+				return texture->bindDefaultImage(mIndex);
+			}
+		}
+		else
+		{
+			llwarns << "NULL LLTexUnit::bind texture" << llendl;
+			return false;
+		}
+	}
+	else
+	{ // mIndex < 0
+		return false;
+	}
+
 	return true;
 }
 
@@ -1060,6 +1070,16 @@ LLRender::~LLRender()
 
 void LLRender::init()
 {
+	if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
+	{ //bind a dummy vertex array object so we're core profile compliant
+#ifdef GL_ARB_vertex_array_object
+		U32 ret;
+		glGenVertexArrays(1, &ret);
+		glBindVertexArray(ret);
+#endif
+	}
+
+
 	llassert_always(mBuffer.isNull()) ;
 	stop_glerror();
 	mBuffer = new LLVertexBuffer(immediate_mask, 0);
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index b6a9a6b653a28c37b69929713fe65046913815c5..825f80a6dc54d5316d0b5768667f11cf5353747a 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -974,7 +974,9 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("texture_matrix1");
 	mReservedUniforms.push_back("texture_matrix2");
 	mReservedUniforms.push_back("texture_matrix3");
-	llassert(mReservedUniforms.size() == LLShaderMgr::TEXTURE_MATRIX3+1);
+	mReservedUniforms.push_back("object_plane_s");
+	mReservedUniforms.push_back("object_plane_t");
+	llassert(mReservedUniforms.size() == LLShaderMgr::OBJECT_PLANE_T+1);
 
 	mReservedUniforms.push_back("viewport");
 
@@ -1116,6 +1118,48 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("bloomMap");
 	mReservedUniforms.push_back("projectionMap");
 
+	mReservedUniforms.push_back("matrixPalette");
+	
+	
+	mReservedUniforms.reserve(12);
+	mReservedUniforms.push_back("screenTex");
+	mReservedUniforms.push_back("screenDepth");
+	mReservedUniforms.push_back("refTex");
+	mReservedUniforms.push_back("eyeVec");
+	mReservedUniforms.push_back("time");
+	mReservedUniforms.push_back("d1");
+	mReservedUniforms.push_back("d2");
+	mReservedUniforms.push_back("lightDir");
+	mReservedUniforms.push_back("specular");
+	mReservedUniforms.push_back("lightExp");
+	mReservedUniforms.push_back("waterFogColor");
+	mReservedUniforms.push_back("waterFogDensity");
+	mReservedUniforms.push_back("waterFogKS");
+	mReservedUniforms.push_back("refScale");
+	mReservedUniforms.push_back("waterHeight");
+	mReservedUniforms.push_back("waterPlane");
+	mReservedUniforms.push_back("normScale");
+	mReservedUniforms.push_back("fresnelScale");
+	mReservedUniforms.push_back("fresnelOffset");
+	mReservedUniforms.push_back("blurMultiplier");
+	mReservedUniforms.push_back("sunAngle");
+	mReservedUniforms.push_back("scaledAngle");
+	mReservedUniforms.push_back("sunAngle2");
+	
+	mReservedUniforms.push_back("camPosLocal");
+
+	mReservedUniforms.push_back("gWindDir");
+	mReservedUniforms.push_back("gSinWaveParams");
+	mReservedUniforms.push_back("gGravity");
+
+	mReservedUniforms.push_back("detail_0");
+	mReservedUniforms.push_back("detail_1");
+	mReservedUniforms.push_back("detail_2");
+	mReservedUniforms.push_back("detail_3");
+	mReservedUniforms.push_back("alpha_ramp");
+
+	mReservedUniforms.push_back("origin");
+
 	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 7a16b7c20fd6585b042476ce5d29173af3ab3567..77e90372e052bc1dc81a9a870935b76284e93278 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -47,6 +47,8 @@ class LLShaderMgr
 		TEXTURE_MATRIX1,
 		TEXTURE_MATRIX2,
 		TEXTURE_MATRIX3,
+		OBJECT_PLANE_S,
+		OBJECT_PLANE_T,
 		VIEWPORT,
 		LIGHT_POSITION,
 		LIGHT_DIRECTION,
@@ -164,7 +166,49 @@ class LLShaderMgr
 		DEFERRED_LIGHT,
 		DEFERRED_BLOOM,
 		DEFERRED_PROJECTION,
+		
+		AVATAR_MATRIX,
+
+		WATER_SCREENTEX,
+		WATER_SCREENDEPTH,
+		WATER_REFTEX,
+		WATER_EYEVEC,
+		WATER_TIME,
+		WATER_WAVE_DIR1,
+		WATER_WAVE_DIR2,
+		WATER_LIGHT_DIR,
+		WATER_SPECULAR,
+		WATER_SPECULAR_EXP,
+		WATER_FOGCOLOR,
+		WATER_FOGDENSITY,
+		WATER_FOGKS,
+		WATER_REFSCALE,
+		WATER_WATERHEIGHT,
+		WATER_WATERPLANE,
+		WATER_NORM_SCALE,
+		WATER_FRESNEL_SCALE,
+		WATER_FRESNEL_OFFSET,
+		WATER_BLUR_MULTIPLIER,
+		WATER_SUN_ANGLE,
+		WATER_SCALED_ANGLE,
+		WATER_SUN_ANGLE2,
+		
+		WL_CAMPOSLOCAL,
+
+		AVATAR_WIND,
+		AVATAR_SINWAVE,
+		AVATAR_GRAVITY,
+
+		TERRAIN_DETAIL0,
+		TERRAIN_DETAIL1,
+		TERRAIN_DETAIL2,
+		TERRAIN_DETAIL3,
+		TERRAIN_ALPHARAMP,
+		
+		SHINY_ORIGIN,
+
 		END_RESERVED_UNIFORMS
+
 	} eGLSLReservedUniforms;
 
 	// singleton pattern implementation
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index dfbd8cd4eed705dfaacba315bb56114ff03a1593..1d257d84153a82f20530add01e0598edd1e49365 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -85,6 +85,7 @@ const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
 //static
 LLVBOPool LLVertexBuffer::sStreamVBOPool(GL_STREAM_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
 LLVBOPool LLVertexBuffer::sDynamicVBOPool(GL_DYNAMIC_DRAW_ARB, GL_ARRAY_BUFFER_ARB);
+LLVBOPool LLVertexBuffer::sDynamicCopyVBOPool(GL_DYNAMIC_COPY_ARB, GL_ARRAY_BUFFER_ARB);
 LLVBOPool LLVertexBuffer::sStreamIBOPool(GL_STREAM_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
 LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_BUFFER_ARB);
 
@@ -199,7 +200,10 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 		if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
 		{
 			glBufferDataARB(mType, size, 0, mUsage);
-			ret = (U8*) ll_aligned_malloc_16(size);
+			if (mUsage != GL_DYNAMIC_COPY_ARB)
+			{ //data will be provided by application
+				ret = (U8*) ll_aligned_malloc(size, 64);
+			}
 		}
 		else
 		{ //always use a true hint of static draw when allocating non-client-backed buffers
@@ -252,7 +256,7 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
 	llassert(vbo_block_size(size) == size);
 
 	deleteBuffer(name);
-	ll_aligned_free_16((U8*) buffer);
+	ll_aligned_free((U8*) buffer);
 
 	if (mType == GL_ARRAY_BUFFER_ARB)
 	{
@@ -393,6 +397,7 @@ void LLVertexBuffer::seedPools()
 {
 	sStreamVBOPool.seedPool();
 	sDynamicVBOPool.seedPool();
+	sDynamicCopyVBOPool.seedPool();
 	sStreamIBOPool.seedPool();
 	sDynamicIBOPool.seedPool();
 }
@@ -875,6 +880,7 @@ void LLVertexBuffer::cleanupClass()
 	sDynamicIBOPool.cleanup();
 	sStreamVBOPool.cleanup();
 	sDynamicVBOPool.cleanup();
+	sDynamicCopyVBOPool.cleanup();
 
 	if(sPrivatePoolp)
 	{
@@ -911,13 +917,16 @@ S32 LLVertexBuffer::determineUsage(S32 usage)
 	
 	if (ret_usage && ret_usage != GL_STREAM_DRAW_ARB)
 	{ //only stream_draw and dynamic_draw are supported when using VBOs, dynamic draw is the default
-		if (sDisableVBOMapping)
-		{ //always use stream draw if VBO mapping is disabled
-			ret_usage = GL_STREAM_DRAW_ARB;
-		}
-		else
+		if (ret_usage != GL_DYNAMIC_COPY_ARB)
 		{
-			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;
+			}
 		}
 	}
 	
@@ -1067,10 +1076,15 @@ void LLVertexBuffer::genBuffer(U32 size)
 	{
 		mMappedData = sStreamVBOPool.allocate(mGLBuffer, mSize);
 	}
-	else
+	else if (mUsage == GL_DYNAMIC_DRAW_ARB)
 	{
 		mMappedData = sDynamicVBOPool.allocate(mGLBuffer, mSize);
 	}
+	else
+	{
+		mMappedData = sDynamicCopyVBOPool.allocate(mGLBuffer, mSize);
+	}
+
 	
 	sGLCount++;
 }
@@ -1284,7 +1298,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() && (LLRender::sGLCoreProfile || sUseVAO))
+		if (gGLManager.mHasVertexArrayObject && useVBOs() && (sUseVAO))
 		{
 #if GL_ARB_vertex_array_object
 			mGLArray = getVAOName();
@@ -1440,21 +1454,18 @@ bool LLVertexBuffer::useVBOs() const
 
 //----------------------------------------------------------------------------
 
-bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count)
+bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end)
 {
-	S32 end = index+count;
-	S32 region_end = region.mIndex+region.mCount;
-	
 	if (end < region.mIndex ||
-		index > region_end)
+		start > region.mEnd)
 	{ //gap exists, do not merge
 		return false;
 	}
 
-	S32 new_end = llmax(end, region_end);
-	S32 new_index = llmin(index, region.mIndex);
-	region.mIndex = new_index;
-	region.mCount = new_end-new_index;
+	region.mEnd = llmax(end, region.mEnd);
+	region.mIndex = llmin(start, region.mIndex);
+	region.mCount = region.mEnd-region.mIndex;
+
 	return true;
 }
 
@@ -1464,7 +1475,6 @@ 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;
@@ -1485,23 +1495,23 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 
 			bool mapped = false;
 			//see if range is already mapped
-			for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+			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)
 			{
-				MappedRegion& region = mMappedVertexRegions[i];
-				if (region.mType == type)
+				MappedRegion& region = *iter;
+				if (expand_region(region, index, end_index))
 				{
-					if (expand_region(region, index, count))
-					{
-						mapped = true;
-						break;
-					}
+					mapped = true;
+					break;
 				}
 			}
 
 			if (!mapped)
 			{
 				//not already mapped, map new region
-				MappedRegion region(type, mMappable && map_range ? -1 : index, count);
+				MappedRegion region(mMappable && map_range ? -1 : start_index, end_index-start_index);
 				mMappedVertexRegions.push_back(region);
 			}
 		}
@@ -1525,6 +1535,7 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo
 			{
 				volatile U8* src = NULL;
 				waitFence();
+				bindGLBuffer();
 				if (gGLManager.mHasMapBufferRange)
 				{
 					if (map_range)
@@ -1643,7 +1654,6 @@ 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;
@@ -1662,12 +1672,14 @@ 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, count))
+				if (expand_region(region, index, end))
 				{
 					mapped = true;
 					break;
@@ -1677,7 +1689,7 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range
 			if (!mapped)
 			{
 				//not already mapped, map new region
-				MappedRegion region(TYPE_INDEX, mMappable && map_range ? -1 : index, count);
+				MappedRegion region(mMappable && map_range ? -1 : index, count);
 				mMappedIndexRegions.push_back(region);
 			}
 		}
@@ -1693,23 +1705,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)
@@ -1820,8 +1832,10 @@ void LLVertexBuffer::unmapBuffer()
 
 	if (mMappedData && mVertexLocked)
 	{
+		llassert(mUsage != GL_DYNAMIC_COPY_ARB);
+		
 		LLFastTimer t(FTM_VBO_UNMAP);
-		bindGLBuffer(true);
+		bindGLBuffer();
 		updated_all = mIndexLocked; //both vertex and index buffers done updating
 
 		if(!mMappable)
@@ -1832,8 +1846,8 @@ void LLVertexBuffer::unmapBuffer()
 				for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 				{
 					const MappedRegion& region = mMappedVertexRegions[i];
-					S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
-					S32 length = sTypeSize[region.mType]*region.mCount;
+					S32 offset = region.mIndex;
+					S32 length = region.mCount;
 					glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, length, (U8*) mMappedData+offset);
 					stop_glerror();
 				}
@@ -1857,8 +1871,8 @@ void LLVertexBuffer::unmapBuffer()
 					for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 					{
 						const MappedRegion& region = mMappedVertexRegions[i];
-						S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
-						S32 length = sTypeSize[region.mType]*region.mCount;
+						S32 offset = region.mIndex;
+						S32 length = region.mCount;
 						if (gGLManager.mHasMapBufferRange)
 						{
 							LLFastTimer t(FTM_VBO_FLUSH_RANGE);
@@ -2067,7 +2081,6 @@ bool LLVertexBuffer::bindGLArray()
 	if (mGLArray && sGLRenderArray != mGLArray)
 	{
 		{
-			LLFastTimer t(FTM_BIND_GL_ARRAY);
 #if GL_ARB_vertex_array_object
 			glBindVertexArray(mGLArray);
 #endif
@@ -2094,22 +2107,15 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind)
 
 	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
 	{
-		LLFastTimer t(FTM_BIND_GL_BUFFER);
-		/*if (sMapped)
-		{
-			llerrs << "VBO bound while another VBO mapped!" << llendl;
-		}*/
+		//LLFastTimer t(FTM_BIND_GL_BUFFER); <-- this timer is showing up as a hotspot (irony)
+		
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
 		sGLRenderBuffer = mGLBuffer;
 		sBindCount++;
 		sVBOActive = true;
 
-		if (mGLArray)
-		{
-			llassert(sGLRenderArray == mGLArray);
-			//mCachedRenderBuffer = mGLBuffer;
-		}
-
+		llassert(!mGLArray || sGLRenderArray == mGLArray);
+		
 		ret = true;
 	}
 
@@ -2444,11 +2450,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 	llglassertok();
 }
 
-LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
-: mType(type), mIndex(index), mCount(count)
+LLVertexBuffer::MappedRegion::MappedRegion(S32 index, S32 count)
+: mIndex(index), mCount(count)
 { 
-	llassert(mType == LLVertexBuffer::TYPE_INDEX || 
-			mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
+	mEnd = mIndex+mCount;	
 }	
 
 
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 11fa4ab6a0da3b7862298801072572cf9dd0b3dd..52559d35054ddfab95785ad07e87c36917b63718 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -104,11 +104,11 @@ class LLVertexBuffer : public LLRefCount
 	class MappedRegion
 	{
 	public:
-		S32 mType;
 		S32 mIndex;
 		S32 mCount;
+		S32 mEnd;
 		
-		MappedRegion(S32 type, S32 index, S32 count);
+		MappedRegion(S32 index, S32 count);
 	};
 
 	LLVertexBuffer(const LLVertexBuffer& rhs)
@@ -125,9 +125,10 @@ class LLVertexBuffer : public LLRefCount
 
 	static LLVBOPool sStreamVBOPool;
 	static LLVBOPool sDynamicVBOPool;
+	static LLVBOPool sDynamicCopyVBOPool;
 	static LLVBOPool sStreamIBOPool;
 	static LLVBOPool sDynamicIBOPool;
-
+	
 	static std::list<U32> sAvailableVAOName;
 	static U32 sCurVAOName;
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
deleted file mode 100644
index da1b234240007d2ecce4330ab4173a617f66687f..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
+++ /dev/null
@@ -1,190 +0,0 @@
-/** 
- * @file giF.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$
- */
- 
-#extension GL_ARB_texture_rectangle : enable
-
-#ifdef DEFINE_GL_FRAGCOLOR
-out vec4 frag_color;
-#else
-#define frag_color gl_FragColor
-#endif
-
-uniform sampler2DRect depthMap;
-uniform sampler2DRect normalMap;
-uniform sampler2D noiseMap;
-
-uniform sampler2D		diffuseGIMap;
-uniform sampler2D		normalGIMap;
-uniform sampler2D		depthGIMap;
-
-uniform sampler2D		lightFunc;
-
-// Inputs
-VARYING vec2 vary_fragcoord;
-
-uniform vec2 screen_res;
-
-uniform mat4 inv_proj;
-uniform mat4 gi_mat;  //gPipeline.mGIMatrix - eye space to sun space
-uniform mat4 gi_mat_proj; //gPipeline.mGIMatrixProj - eye space to projected sun space
-uniform mat4 gi_norm_mat; //gPipeline.mGINormalMatrix - eye space normal to sun space normal matrix
-uniform mat4 gi_inv_proj; //gPipeline.mGIInvProj - projected sun space to sun space
-uniform float gi_radius;
-uniform float gi_intensity;
-uniform int gi_samples;
-uniform vec2 gi_kern[25];
-uniform vec2 gi_scale;
-uniform vec3 gi_quad;
-uniform vec3 gi_spec;
-uniform float gi_direction_weight;
-uniform float gi_light_offset;
-
-vec4 getPosition(vec2 pos_screen)
-{
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
-	vec2 sc = pos_screen.xy*2.0;
-	sc /= screen_res;
-	sc -= vec2(1.0,1.0);
-	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
-	vec4 pos = inv_proj * ndc;
-	pos /= pos.w;
-	pos.w = 1.0;
-	return pos;
-}
-
-vec4 getGIPosition(vec2 gi_tc)
-{
-	float depth = texture2D(depthGIMap, gi_tc).a;
-	vec2 sc = gi_tc*2.0;
-	sc -= vec2(1.0, 1.0);
-	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
-	vec4 pos = gi_inv_proj*ndc;
-	pos.xyz /= pos.w;
-	pos.w = 1.0;
-	return pos;
-}
-
-vec3 giAmbient(vec3 pos, vec3 norm)
-{
-	vec4 gi_c = gi_mat_proj * vec4(pos, 1.0);
-	gi_c.xyz /= gi_c.w;
-
-	vec4 gi_pos = gi_mat*vec4(pos,1.0);
-	vec3 gi_norm = (gi_norm_mat*vec4(norm,1.0)).xyz;
-	gi_norm = normalize(gi_norm);
-	
-	vec2 tcx = gi_norm.xy;
-	vec2 tcy = gi_norm.yx;
-	
-	vec4 eye_pos = gi_mat*vec4(0,0,0,1.0);
-	
-	vec3 eye_dir = normalize(gi_pos.xyz-eye_pos.xyz/eye_pos.w);
-	
-	//vec3 eye_dir = vec3(0,0,-1);
-	//eye_dir = (gi_norm_mat*vec4(eye_dir, 1.0)).xyz;
-	//eye_dir = normalize(eye_dir);
-	
-	//float round_x = gi_scale.x;
-	//float round_y = gi_scale.y;
-	
-	vec3 debug = texture2D(normalGIMap, gi_c.xy).rgb*0.5+0.5;
-	debug.xz = vec2(0.0,0.0);
-	//debug = fract(debug);
-	
-	float round_x = 1.0/64.0;
-	float round_y = 1.0/64.0;
-	
-	//gi_c.x = floor(gi_c.x/round_x+0.5)*round_x;
-	//gi_c.y = floor(gi_c.y/round_y+0.5)*round_y;
-	
-	float fda = 0.0;
-	vec3 fdiff = vec3(0,0,0);
-	
-	vec3 rcol = vec3(0,0,0);
-	
-	float fsa = 0.0;
-	
-	for (int i = -1; i < 2; i+=2 )
-	{
-		for (int j = -1; j < 2; j+=2)
-		{
-			vec2 tc = vec2(i, j)*0.75;
-			vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0+tc*0.5).xyz;
-			//tc += gi_norm.xy*nz.z;
-			tc += nz.xy*2.0;
-			tc /= gi_samples;
-			tc += gi_c.xy;
-			
-			vec3 lnorm = -normalize(texture2D(normalGIMap, tc.xy).xyz*2.0-1.0);
-			vec3 lpos = getGIPosition(tc.xy).xyz;
-							
-			vec3 at = lpos-gi_pos.xyz;
-			float dist = dot(at,at);
-			float da = clamp(1.0/(gi_spec.x*dist), 0.0, 1.0);
-			
-			if (da > 0.0)
-			{
-				//add angular attenuation
-				vec3 ldir = at;
-				float ang_atten = clamp(dot(ldir, gi_norm), 0.0, 1.0);
-			
-				float ld = -dot(ldir, lnorm);
-				
-				if (ang_atten > 0.0 && ld < 0.0)
-				{
-					vec3 diff = texture2D(diffuseGIMap, tc.xy).xyz;
-					da = da*ang_atten;
-					fda += da;
-					fdiff += diff*da;
-				}
-			}
-		}
-	}
-
-	fdiff /= max(gi_spec.y*fda, gi_quad.z);
-	fdiff = clamp(fdiff, vec3(0), vec3(1));
-	
-	vec3 ret = fda*fdiff;
-	//ret = ret*ret*gi_quad.x+ret*gi_quad.y+gi_quad.z;			
-
-	//fda *= nz.z;
-	
-	//rcol.rgb *= gi_intensity;
-	//return rcol.rgb+vary_AmblitColor.rgb*0.25;
-	//return vec4(debug, 0.0);
-	//return vec4(fda*fdiff, 0.0);
-	return clamp(ret,vec3(0.0), vec3(1.0));
-	//return debug.xyz;
-}
-
-void main() 
-{
-	vec2 pos_screen = vary_fragcoord.xy;
-	vec4 pos = getPosition(pos_screen);
-	vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
-	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
-	
-	frag_color.xyz = giAmbient(pos, norm);
-}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
index 3427d6db57926257622b9055e16c61c2086aecff..1149aec30bff47ac9d073f86a3fa67470eb42e9d 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -53,13 +53,11 @@ 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 vec2 screen_res;
-uniform mat4 norm_mat; //region space to screen space
+uniform mat3 normal_matrix;
 
 //bigWave is (refCoord.w, view.w);
 VARYING vec4 refCoord;
@@ -157,7 +155,7 @@ void main()
 
 	//wavef.z *= 0.1f;
 	//wavef = normalize(wavef);
-	vec3 screenspacewavef = (norm_mat*vec4(wavef, 1.0)).xyz;
+	vec3 screenspacewavef = normal_matrix*wavef;
 	
 	frag_data[0] = vec4(color.rgb, 0.5); // diffuse
 	frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec
diff --git a/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
index 0d8dab0a4191bd347c4ffb559118a2f578330373..485e48537cd1f89d8e0fa85df629ea89733878e1 100644
--- a/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/underWaterF.glsl
@@ -43,13 +43,11 @@ 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;
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
index 79bffab745cb2e17869a0bcf1cbec60d5704da7d..1fd7bdaa5c7a3ba780a9f888a14755fb355d20a0 100644
--- a/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterF.glsl
@@ -42,8 +42,6 @@ uniform vec3 lightDir;
 uniform vec3 specular;
 uniform float lightExp;
 uniform float refScale;
-uniform float kd;
-uniform vec2 screenRes;
 uniform vec3 normScale;
 uniform float fresnelScale;
 uniform float fresnelOffset;
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index b6fd7bc9c20d9b02a55a9379e9c616fb4999878a..f0eee24fef4a9906f43529640a750f917bc6c6b9 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -3062,6 +3062,30 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request)
 	sendReliableMessage();
 }
 
+// Send a message to the region to stop the NULL animation state
+// This will reset animation state overrides for the agent.
+void LLAgent::sendAnimationStateReset()
+{
+	if (gAgentID.isNull() || !mRegionp)
+	{
+		return;
+	}
+
+	LLMessageSystem* msg = gMessageSystem;
+	msg->newMessageFast(_PREHASH_AgentAnimation);
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, getID());
+	msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+
+	msg->nextBlockFast(_PREHASH_AnimationList);
+	msg->addUUIDFast(_PREHASH_AnimID, LLUUID::null );
+	msg->addBOOLFast(_PREHASH_StartAnim, FALSE);
+
+	msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
+	msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
+	sendReliableMessage();
+}
+
 void LLAgent::sendWalkRun(bool running)
 {
 	LLMessageSystem* msgsys = gMessageSystem;
@@ -4140,6 +4164,8 @@ void LLAgent::stopCurrentAnimations()
 	// avatar, propagating this change back to the server.
 	if (isAgentAvatarValid())
 	{
+		LLDynamicArray<LLUUID> anim_ids;
+
 		for ( LLVOAvatar::AnimIterator anim_it =
 			      gAgentAvatarp->mPlayingAnimations.begin();
 		      anim_it != gAgentAvatarp->mPlayingAnimations.end();
@@ -4157,10 +4183,15 @@ void LLAgent::stopCurrentAnimations()
 				// stop this animation locally
 				gAgentAvatarp->stopMotion(anim_it->first, TRUE);
 				// ...and tell the server to tell everyone.
-				sendAnimationRequest(anim_it->first, ANIM_REQUEST_STOP);
+				anim_ids.push_back(anim_it->first);
 			}
 		}
 
+		sendAnimationRequests(anim_ids, ANIM_REQUEST_STOP);
+
+		// Tell the region to clear any animation state overrides.
+		sendAnimationStateReset();
+
 		// re-assert at least the default standing animation, because
 		// viewers get confused by avs with no associated anims.
 		sendAnimationRequest(ANIM_AGENT_STAND,
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 99904e118c15033dd01ebd22bc0a1ef1efe79ca2..bec9352f5feb566f49b5ac257be9217a54f0c1a4 100644
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -431,6 +431,8 @@ class LLAgent : public LLOldEvents::LLObservable
 	void			onAnimStop(const LLUUID& id);
 	void			sendAnimationRequests(LLDynamicArray<LLUUID> &anim_ids, EAnimRequest request);
 	void			sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request);
+	void			sendAnimationStateReset();
+
 	void			endAnimationUpdateUI();
 	void			unpauseAnimation() { mPauseRequest = NULL; }
 	BOOL			getCustomAnim() const { return mCustomAnim; }
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 7331b938108e70cf89350ef647b146333257182f..9bbaede68dd8ca0a465c51cdb0e93c59865f6a59 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -537,7 +537,7 @@ static void settings_to_globals()
 	LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
 	
 	LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile");
-
+	LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
 	LLImageGL::sGlobalUseAnisotropic	= gSavedSettings.getBOOL("RenderAnisotropic");
 	LLImageGL::sCompressTextures		= gSavedSettings.getBOOL("RenderCompressTextures");
 	LLVOVolume::sLODFactor				= gSavedSettings.getF32("RenderVolumeLODFactor");
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 119b8d24d044c232e22f3d25e3e1d4867bd4775c..d29181a3cef4c35940f7badb8e626c4c14de51ac 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -254,7 +254,7 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep)
 	return count;
 }
 
-static LLFastTimer::DeclareTimer FTM_ALLOCATE_FACE("Allocate Face", true);
+static LLFastTimer::DeclareTimer FTM_ALLOCATE_FACE("Allocate Face");
 
 LLFace*	LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep)
 {
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 94dd927d26ce1a53dcdcdb85def8bf99b2f29ff1..d8f293cc6272b891f823c06694062b7fe06be889 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -472,6 +472,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
 		{
 			params.mGroup->rebuildMesh();
 		}
+		
 		params.mVertexBuffer->setBuffer(mask);
 		params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 		gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 3cf96a905458bdc3d45c8f4e8ecc1418bfa64461..d5afa25c9c6d6c89217d5319186d3d41b8f7b4c4 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1505,8 +1505,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 				
 				stop_glerror();
 
-				static LLStaticHashedString sMatPalette("matrixPalette");
-				LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv(sMatPalette, 
+				LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv(LLViewerShaderMgr::AVATAR_MATRIX, 
 					skin->mJointNames.size(),
 					FALSE,
 					(GLfloat*) mat[0].mMatrix);
@@ -1548,6 +1547,8 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 				buff->setBuffer(data_mask);
 				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
 			}
+
+			gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES);
 		}
 	}
 }
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 4137084ebe185f68377b839c7181126c4a3800fa..7e9504647930c9d21bf161d1c07d9d73b243dfce 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -461,6 +461,8 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
 				}
 			}
 		}
+        // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0
+        // MAINT-755
 		cube_map->disable();
 		cube_map->restoreMatrix();
 	}
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 3805348b6bf42388e7410bf468e527815580b72c..cac862a10775bc228b61772e6920dc4f12a66386 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -49,9 +49,6 @@
 #include "llviewershadermgr.h"
 #include "llrender.h"
 
-static LLStaticHashedString sObjectPlaneS("object_plane_s");
-static LLStaticHashedString sObjectPlaneT("object_plane_t");
-
 const F32 DETAIL_SCALE = 1.f/16.f;
 int DebugDetailMap = 0;
 
@@ -355,8 +352,8 @@ void LLDrawPoolTerrain::renderFullShader()
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
 	llassert(shader);
 		
-	shader->uniform4fv(sObjectPlaneS, 1, tp0.mV);
-	shader->uniform4fv(sObjectPlaneT, 1, tp1.mV);
+	shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
+	shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
 
 	gGL.matrixMode(LLRender::MM_TEXTURE);
 	gGL.loadIdentity();
@@ -865,8 +862,8 @@ void LLDrawPoolTerrain::renderSimple()
 	
 	if (LLGLSLShader::sNoFixedFunction)
 	{
-		sShader->uniform4fv(sObjectPlaneS, 1, tp0.mV);
-		sShader->uniform4fv(sObjectPlaneT, 1, tp1.mV);
+		sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV);
+		sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV);
 	}
 	else
 	{
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index ffe438eb2736b7c42048755aeb2f0cb793932014..b6a4b0194c82d30a6a6631c4d348897634e5d05e 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -1,736 +1,719 @@
-/** 
- * @file lldrawpoolwater.cpp
- * @brief LLDrawPoolWater class implementation
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, 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$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llfeaturemanager.h"
-#include "lldrawpoolwater.h"
-
-#include "llviewercontrol.h"
-#include "lldir.h"
-#include "llerror.h"
-#include "m3math.h"
-#include "llrender.h"
-
-#include "llagent.h"		// for gAgent for getRegion for getWaterHeight
-#include "llcubemap.h"
-#include "lldrawable.h"
-#include "llface.h"
-#include "llsky.h"
-#include "llviewertexturelist.h"
-#include "llviewerregion.h"
-#include "llvosky.h"
-#include "llvowater.h"
-#include "llworld.h"
-#include "pipeline.h"
-#include "llviewershadermgr.h"
-#include "llwaterparammanager.h"
-
-const LLUUID TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004");
-const LLUUID OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055");
-
-static LLStaticHashedString sObjectPlaneS("object_plane_s");
-static LLStaticHashedString sObjectPlaneT("object_plane_t");
-static LLStaticHashedString sScreenRes("screenRes");
-static LLStaticHashedString sNormScale("normScale");
-static LLStaticHashedString sFresnelScale("fresnelScale");
-static LLStaticHashedString sFresnelOffset("fresnelOffset");
-static LLStaticHashedString sBlurMultiplier("blurMultiplier");
-static LLStaticHashedString sSunAngle("sunAngle");
-static LLStaticHashedString sScaledAngle("scaledAngle");
-static LLStaticHashedString sSunAngle2("sunAngle2");
-
-static float sTime;
-
-BOOL deferred_render = FALSE;
-
-BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
-BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
-BOOL LLDrawPoolWater::sNeedsDistortionUpdate = TRUE;
-LLColor4 LLDrawPoolWater::sWaterFogColor = LLColor4(0.2f, 0.5f, 0.5f, 0.f);
-F32 LLDrawPoolWater::sWaterFogEnd = 0.f;
-
-LLVector3 LLDrawPoolWater::sLightDir;
-
-LLDrawPoolWater::LLDrawPoolWater() :
-	LLFacePool(POOL_WATER)
-{
-	mHBTex[0] = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, LLViewerTexture::BOOST_UI);
-	gGL.getTexUnit(0)->bind(mHBTex[0]) ;
-	mHBTex[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
-
-	mHBTex[1] = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, LLViewerTexture::BOOST_UI);
-	gGL.getTexUnit(0)->bind(mHBTex[1]);
-	mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
-
-
-	mWaterImagep = LLViewerTextureManager::getFetchedTexture(TRANSPARENT_WATER_TEXTURE);
-	llassert(mWaterImagep);
-	mWaterImagep->setNoDelete();
-	mOpaqueWaterImagep = LLViewerTextureManager::getFetchedTexture(OPAQUE_WATER_TEXTURE);
-	llassert(mOpaqueWaterImagep);
-	mWaterNormp = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL);
-	mWaterNormp->setNoDelete();
-
-	restoreGL();
-}
-
-LLDrawPoolWater::~LLDrawPoolWater()
-{
-}
-
-//static
-void LLDrawPoolWater::restoreGL()
-{
-	
-}
-
-LLDrawPool *LLDrawPoolWater::instancePool()
-{
-	llerrs << "Should never be calling instancePool on a water pool!" << llendl;
-	return NULL;
-}
-
-
-void LLDrawPoolWater::prerender()
-{
-	mVertexShaderLevel = (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) ?
-		LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WATER) : 0;
-
-	// got rid of modulation by light color since it got a little too
-	// green at sunset and sl-57047 (underwater turns black at 8:00)
-	sWaterFogColor = LLWaterParamManager::instance().getFogColor();
-	sWaterFogColor.mV[3] = 0;
-
-}
-
-S32 LLDrawPoolWater::getNumPasses()
-{
-	if (LLViewerCamera::getInstance()->getOrigin().mV[2] < 1024.f)
-	{
-		return 1;
-	}
-
-	return 0;
-}
-
-void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
-{
-	beginRenderPass(pass);
-	deferred_render = TRUE;
-}
-
-void LLDrawPoolWater::endPostDeferredPass(S32 pass)
-{
-	endRenderPass(pass);
-	deferred_render = FALSE;
-}
-
-//===============================
-//DEFERRED IMPLEMENTATION
-//===============================
-void LLDrawPoolWater::renderDeferred(S32 pass)
-{
-	LLFastTimer t(FTM_RENDER_WATER);
-	deferred_render = TRUE;
-	shade();
-	deferred_render = FALSE;
-}
-
-//=========================================
-
-void LLDrawPoolWater::render(S32 pass)
-{
-	LLFastTimer ftm(FTM_RENDER_WATER);
-	if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1)
-	{
-		return;
-	}
-
-	//do a quick 'n dirty depth sort
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-			 iter != mDrawFace.end(); iter++)
-	{
-		LLFace* facep = *iter;
-		facep->mDistance = -facep->mCenterLocal.mV[2];
-	}
-
-	std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater());
-
-	// See if we are rendering water as opaque or not
-	if (!gSavedSettings.getBOOL("RenderTransparentWater"))
-	{
-		// render water for low end hardware
-		renderOpaqueLegacyWater();
-		return;
-	}
-
-	LLGLEnable blend(GL_BLEND);
-
-	if ((mVertexShaderLevel > 0) && !sSkipScreenCopy)
-	{
-		shade();
-		return;
-	}
-
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-	stop_glerror();
-
-	if (!gGLManager.mHasMultitexture)
-	{
-		// Ack!  No multitexture!  Bail!
-		return;
-	}
-
-	LLFace* refl_face = voskyp->getReflFace();
-
-	gPipeline.disableLights();
-	
-	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
-
-	LLGLDisable cullFace(GL_CULL_FACE);
-	
-	// Set up second pass first
-	mWaterImagep->addTextureStats(1024.f*1024.f);
-	gGL.getTexUnit(1)->activate();
-	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(1)->bind(mWaterImagep) ;
-
-	LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis();
-	F32 up_dot = camera_up * LLVector3::z_axis;
-
-	LLColor4 water_color;
-	if (LLViewerCamera::getInstance()->cameraUnderWater())
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
-	}
-	else
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
-	}
-
-	gGL.diffuseColor4fv(water_color.mV);
-
-	// Automatically generate texture coords for detail map
-	glEnable(GL_TEXTURE_GEN_S); //texture unit 1
-	glEnable(GL_TEXTURE_GEN_T); //texture unit 1
-	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-
-	// Slowly move over time.
-	F32 offset = fmod(gFrameTimeSeconds*2.f, 100.f);
-	F32 tp0[4] = {16.f/256.f, 0.0f, 0.0f, offset*0.01f};
-	F32 tp1[4] = {0.0f, 16.f/256.f, 0.0f, offset*0.01f};
-	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
-	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
-
-	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
-	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
-
-	gGL.getTexUnit(0)->activate();
-	
-	glClearStencil(1);
-	glClear(GL_STENCIL_BUFFER_BIT);
-	LLGLEnable gls_stencil(GL_STENCIL_TEST);
-	glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);
-	glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
-
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-		 iter != mDrawFace.end(); iter++)
-	{
-		LLFace *face = *iter;
-		if (voskyp->isReflFace(face))
-		{
-			continue;
-		}
-		gGL.getTexUnit(0)->bind(face->getTexture());
-		face->renderIndexed();
-	}
-
-	// Now, disable texture coord generation on texture state 1
-	gGL.getTexUnit(1)->activate();
-	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(1)->disable();
-	glDisable(GL_TEXTURE_GEN_S); //texture unit 1
-	glDisable(GL_TEXTURE_GEN_T); //texture unit 1
-
-	// Disable texture coordinate and color arrays
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-	stop_glerror();
-	
-	if (gSky.mVOSkyp->getCubeMap())
-	{
-		gSky.mVOSkyp->getCubeMap()->enable(0);
-		gSky.mVOSkyp->getCubeMap()->bind();
-
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.loadIdentity();
-		LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
-		LLMatrix4 camera_rot(camera_mat.getMat3());
-		camera_rot.invert();
-
-		gGL.loadMatrix((F32 *)camera_rot.mMatrix);
-
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-		LLOverrideFaceColor overrid(this, 1.f, 1.f, 1.f,  0.5f*up_dot);
-
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
-		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-			 iter != mDrawFace.end(); iter++)
-		{
-			LLFace *face = *iter;
-			if (voskyp->isReflFace(face))
-			{
-				//refl_face = face;
-				continue;
-			}
-
-			if (face->getGeomCount() > 0)
-			{					
-				face->renderIndexed();
-			}
-		}
-
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
-		gSky.mVOSkyp->getCubeMap()->disable();
-		
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.loadIdentity();
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-		
-	}
-
-	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
-    if (refl_face)
-	{
-		glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
-		renderReflection(refl_face);
-	}
-
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-}
-
-// for low end hardware
-void LLDrawPoolWater::renderOpaqueLegacyWater()
-{
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-	LLGLSLShader* shader = NULL;
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			shader = &gObjectSimpleNonIndexedTexGenWaterProgram;
-		}
-		else
-		{
-			shader = &gObjectSimpleNonIndexedTexGenProgram;
-		}
-
-		shader->bind();
-	}
-
-	stop_glerror();
-
-	// Depth sorting and write to depth buffer
-	// since this is opaque, we should see nothing
-	// behind the water.  No blending because
-	// of no transparency.  And no face culling so
-	// that the underside of the water is also opaque.
-	LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
-	LLGLDisable no_cull(GL_CULL_FACE);
-	LLGLDisable no_blend(GL_BLEND);
-
-	gPipeline.disableLights();
-
-	mOpaqueWaterImagep->addTextureStats(1024.f*1024.f);
-
-	// Activate the texture binding and bind one
-	// texture since all images will have the same texture
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(0)->bind(mOpaqueWaterImagep);
-
-	// Automatically generate texture coords for water texture
-	if (!shader)
-	{
-		glEnable(GL_TEXTURE_GEN_S); //texture unit 0
-		glEnable(GL_TEXTURE_GEN_T); //texture unit 0
-		glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-		glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	}
-
-	// Use the fact that we know all water faces are the same size
-	// to save some computation
-
-	// Slowly move texture coordinates over time so the watter appears
-	// to be moving.
-	F32 movement_period_secs = 50.f;
-
-	F32 offset = fmod(gFrameTimeSeconds, movement_period_secs);
-
-	if (movement_period_secs != 0)
-	{
-	 	offset /= movement_period_secs;
-	}
-	else
-	{
-		offset = 0;
-	}
-
-	F32 tp0[4] = { 16.f / 256.f, 0.0f, 0.0f, offset };
-	F32 tp1[4] = { 0.0f, 16.f / 256.f, 0.0f, offset };
-
-	if (!shader)
-	{
-		glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
-		glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
-	}
-	else
-	{
-		shader->uniform4fv(sObjectPlaneS, 1, tp0);
-		shader->uniform4fv(sObjectPlaneT, 1, tp1);
-	}
-
-	gGL.diffuseColor3f(1.f, 1.f, 1.f);
-
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-		 iter != mDrawFace.end(); iter++)
-	{
-		LLFace *face = *iter;
-		if (voskyp->isReflFace(face))
-		{
-			continue;
-		}
-
-		face->renderIndexed();
-	}
-
-	stop_glerror();
-
-	if (!shader)
-	{
-		// Reset the settings back to expected values
-		glDisable(GL_TEXTURE_GEN_S); //texture unit 0
-		glDisable(GL_TEXTURE_GEN_T); //texture unit 0
-	}
-
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-}
-
-
-void LLDrawPoolWater::renderReflection(LLFace* face)
-{
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-	if (!voskyp)
-	{
-		return;
-	}
-
-	if (!face->getGeomCount())
-	{
-		return;
-	}
-	
-	S8 dr = voskyp->getDrawRefl();
-	if (dr < 0)
-	{
-		return;
-	}
-
-	LLGLSNoFog noFog;
-
-	gGL.getTexUnit(0)->bind(mHBTex[dr]);
-
-	LLOverrideFaceColor override(this, face->getFaceColor().mV);
-	face->renderIndexed();
-}
-
-void LLDrawPoolWater::shade()
-{
-	if (!deferred_render)
-	{
-		gGL.setColorMask(true, true);
-	}
-
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-	if(voskyp == NULL) 
-	{
-		return;
-	}
-
-	LLGLDisable blend(GL_BLEND);
-
-	LLColor3 light_diffuse(0,0,0);
-	F32 light_exp = 0.0f;
-	LLVector3 light_dir;
-	LLColor3 light_color;
-
-	if (gSky.getSunDirection().mV[2] > LLSky::NIGHTTIME_ELEVATION_COS) 	 
-    { 	 
-        light_dir  = gSky.getSunDirection(); 	 
-        light_dir.normVec(); 	
-		light_color = gSky.getSunDiffuseColor();
-		if(gSky.mVOSkyp) {
-	        light_diffuse = gSky.mVOSkyp->getSun().getColorCached(); 	 
-			light_diffuse.normVec(); 	 
-		}
-        light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0); 	 
-        light_diffuse *= light_exp + 0.25f; 	 
-    } 	 
-    else  	 
-    { 	 
-        light_dir       = gSky.getMoonDirection(); 	 
-        light_dir.normVec(); 	 
-		light_color = gSky.getMoonDiffuseColor();
-        light_diffuse   = gSky.mVOSkyp->getMoon().getColorCached(); 	 
-        light_diffuse.normVec(); 	 
-        light_diffuse *= 0.5f; 	 
-        light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0); 	 
-    }
-
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= light_exp;
-	light_exp *= 256.f;
-	light_exp = light_exp > 32.f ? light_exp : 32.f;
-
-	LLGLSLShader* shader;
-
-	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
-	
-	if (deferred_render)
-	{
-		shader = &gDeferredWaterProgram;
-	}
-	else if (eyedepth < 0.f && LLPipeline::sWaterReflections)
-	{
-		shader = &gUnderWaterProgram;
-	}
-	else
-	{
-		shader = &gWaterProgram;
-	}
-
-	if (deferred_render)
-	{
-		gPipeline.bindDeferredShader(*shader);
-	}
-	else
-	{
-		shader->bind();
-	}
-
-	sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f;
-	
-	S32 reftex = shader->enableTexture(LLViewerShaderMgr::WATER_REFTEX);
-		
-	if (reftex > -1)
-	{
-		gGL.getTexUnit(reftex)->activate();
-		gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef);
-		gGL.getTexUnit(0)->activate();
-	}	
-
-	//bind normal map
-	S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-
-	LLWaterParamManager * param_mgr = &LLWaterParamManager::instance();
-
-	// change mWaterNormp if needed
-	if (mWaterNormp->getID() != param_mgr->getNormalMapID())
-	{
-		mWaterNormp = LLViewerTextureManager::getFetchedTexture(param_mgr->getNormalMapID());
-	}
-
-	mWaterNormp->addTextureStats(1024.f*1024.f);
-	gGL.getTexUnit(bumpTex)->bind(mWaterNormp) ;
-	if (gSavedSettings.getBOOL("RenderWaterMipNormal"))
-	{
-		mWaterNormp->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
-	}
-	else 
-	{
-		mWaterNormp->setFilteringOption(LLTexUnit::TFO_POINT);
-	}
-	
-	S32 screentex = shader->enableTexture(LLViewerShaderMgr::WATER_SCREENTEX);	
-		
-	if (screentex > -1)
-	{
-		shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
-		shader->uniform1f(LLViewerShaderMgr::WATER_FOGDENSITY, 
-			param_mgr->getFogDensity());
-		gPipeline.mWaterDis.bindTexture(0, screentex);
-	}
-	
-	stop_glerror();
-	
-	gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);	
-
-	if (mVertexShaderLevel == 1)
-	{
-		sWaterFogColor.mV[3] = param_mgr->mDensitySliderValue;
-		shader->uniform4fv(LLViewerShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
-	}
-
-	F32 screenRes[] = 
-	{
-		1.f/gGLViewport[2],
-		1.f/gGLViewport[3]
-	};
-	shader->uniform2fv(sScreenRes, 1, screenRes);
-	stop_glerror();
-	
-	S32 diffTex = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	stop_glerror();
-	
-	light_dir.normVec();
-	sLightDir = light_dir;
-	
-	light_diffuse *= 6.f;
-
-	//shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix);
-	shader->uniform1f(LLViewerShaderMgr::WATER_WATERHEIGHT, eyedepth);
-	shader->uniform1f(LLViewerShaderMgr::WATER_TIME, sTime);
-	shader->uniform3fv(LLViewerShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
-	shader->uniform3fv(LLViewerShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
-	shader->uniform1f(LLViewerShaderMgr::WATER_SPECULAR_EXP, light_exp);
-	shader->uniform2fv(LLViewerShaderMgr::WATER_WAVE_DIR1, 1, param_mgr->getWave1Dir().mV);
-	shader->uniform2fv(LLViewerShaderMgr::WATER_WAVE_DIR2, 1, param_mgr->getWave2Dir().mV);
-	shader->uniform3fv(LLViewerShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
-
-	shader->uniform3fv(sNormScale, 1, param_mgr->getNormalScale().mV);
-	shader->uniform1f(sFresnelScale, param_mgr->getFresnelScale());
-	shader->uniform1f(sFresnelOffset, param_mgr->getFresnelOffset());
-	shader->uniform1f(sBlurMultiplier, param_mgr->getBlurMultiplier());
-
-	F32 sunAngle = llmax(0.f, light_dir.mV[2]);
-	F32 scaledAngle = 1.f - sunAngle;
-
-	shader->uniform1f(sSunAngle, sunAngle);
-	shader->uniform1f(sScaledAngle, scaledAngle);
-	shader->uniform1f(sSunAngle2, 0.1f + 0.2f*sunAngle);
-
-	LLColor4 water_color;
-	LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis();
-	F32 up_dot = camera_up * LLVector3::z_axis;
-	if (LLViewerCamera::getInstance()->cameraUnderWater())
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
-		shader->uniform1f(LLViewerShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow());
-	}
-	else
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
-		shader->uniform1f(LLViewerShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove());
-	}
-
-	if (water_color.mV[3] > 0.9f)
-	{
-		water_color.mV[3] = 0.9f;
-	}
-
-	{
-		LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
-		LLGLDisable cullface(GL_CULL_FACE);
-		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-			iter != mDrawFace.end(); iter++)
-		{
-			LLFace *face = *iter;
-
-			if (voskyp->isReflFace(face))
-			{
-				continue;
-			}
-
-			LLVOWater* water = (LLVOWater*) face->getViewerObject();
-			gGL.getTexUnit(diffTex)->bind(face->getTexture());
-
-			sNeedsReflectionUpdate = TRUE;
-			
-			if (water->getUseTexture() || !water->getIsEdgePatch())
-			{
-				sNeedsDistortionUpdate = TRUE;
-				face->renderIndexed();
-			}
-			else if (gGLManager.mHasDepthClamp || deferred_render)
-			{
-				face->renderIndexed();
-			}
-			else
-			{
-				LLGLSquashToFarClip far_clip(glh_get_current_projection());
-				face->renderIndexed();
-			}
-		}
-	}
-	
-	shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
-	shader->disableTexture(LLViewerShaderMgr::WATER_SCREENTEX);	
-	shader->disableTexture(LLViewerShaderMgr::BUMP_MAP);
-	shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	shader->disableTexture(LLViewerShaderMgr::WATER_REFTEX);
-	shader->disableTexture(LLViewerShaderMgr::WATER_SCREENDEPTH);
-
-	if (deferred_render)
-	{
-		gPipeline.unbindDeferredShader(*shader);
-	}
-	else
-	{
-		shader->unbind();
-	}
-
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-	if (!deferred_render)
-	{
-		gGL.setColorMask(true, false);
-	}
-
-}
-
-LLViewerTexture *LLDrawPoolWater::getDebugTexture()
-{
-	return LLViewerFetchedTexture::sSmokeImagep;
-}
-
-LLColor3 LLDrawPoolWater::getDebugColor() const
-{
-	return LLColor3(0.f, 1.f, 1.f);
-}
+/** 
+ * @file lldrawpoolwater.cpp
+ * @brief LLDrawPoolWater class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llfeaturemanager.h"
+#include "lldrawpoolwater.h"
+
+#include "llviewercontrol.h"
+#include "lldir.h"
+#include "llerror.h"
+#include "m3math.h"
+#include "llrender.h"
+
+#include "llagent.h"		// for gAgent for getRegion for getWaterHeight
+#include "llcubemap.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llsky.h"
+#include "llviewertexturelist.h"
+#include "llviewerregion.h"
+#include "llvosky.h"
+#include "llvowater.h"
+#include "llworld.h"
+#include "pipeline.h"
+#include "llviewershadermgr.h"
+#include "llwaterparammanager.h"
+
+const LLUUID TRANSPARENT_WATER_TEXTURE("2bfd3884-7e27-69b9-ba3a-3e673f680004");
+const LLUUID OPAQUE_WATER_TEXTURE("43c32285-d658-1793-c123-bf86315de055");
+
+static float sTime;
+
+BOOL deferred_render = FALSE;
+
+BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE;
+BOOL LLDrawPoolWater::sNeedsReflectionUpdate = TRUE;
+BOOL LLDrawPoolWater::sNeedsDistortionUpdate = TRUE;
+LLColor4 LLDrawPoolWater::sWaterFogColor = LLColor4(0.2f, 0.5f, 0.5f, 0.f);
+F32 LLDrawPoolWater::sWaterFogEnd = 0.f;
+
+LLVector3 LLDrawPoolWater::sLightDir;
+
+LLDrawPoolWater::LLDrawPoolWater() :
+	LLFacePool(POOL_WATER)
+{
+	mHBTex[0] = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, LLViewerTexture::BOOST_UI);
+	gGL.getTexUnit(0)->bind(mHBTex[0]) ;
+	mHBTex[0]->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+	mHBTex[1] = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, LLViewerTexture::BOOST_UI);
+	gGL.getTexUnit(0)->bind(mHBTex[1]);
+	mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+
+	mWaterImagep = LLViewerTextureManager::getFetchedTexture(TRANSPARENT_WATER_TEXTURE);
+	llassert(mWaterImagep);
+	mWaterImagep->setNoDelete();
+	mOpaqueWaterImagep = LLViewerTextureManager::getFetchedTexture(OPAQUE_WATER_TEXTURE);
+	llassert(mOpaqueWaterImagep);
+	mWaterNormp = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL);
+	mWaterNormp->setNoDelete();
+
+	restoreGL();
+}
+
+LLDrawPoolWater::~LLDrawPoolWater()
+{
+}
+
+//static
+void LLDrawPoolWater::restoreGL()
+{
+	
+}
+
+LLDrawPool *LLDrawPoolWater::instancePool()
+{
+	llerrs << "Should never be calling instancePool on a water pool!" << llendl;
+	return NULL;
+}
+
+
+void LLDrawPoolWater::prerender()
+{
+	mVertexShaderLevel = (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) ?
+		LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WATER) : 0;
+
+	// got rid of modulation by light color since it got a little too
+	// green at sunset and sl-57047 (underwater turns black at 8:00)
+	sWaterFogColor = LLWaterParamManager::instance().getFogColor();
+	sWaterFogColor.mV[3] = 0;
+
+}
+
+S32 LLDrawPoolWater::getNumPasses()
+{
+	if (LLViewerCamera::getInstance()->getOrigin().mV[2] < 1024.f)
+	{
+		return 1;
+	}
+
+	return 0;
+}
+
+void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
+{
+	beginRenderPass(pass);
+	deferred_render = TRUE;
+}
+
+void LLDrawPoolWater::endPostDeferredPass(S32 pass)
+{
+	endRenderPass(pass);
+	deferred_render = FALSE;
+}
+
+//===============================
+//DEFERRED IMPLEMENTATION
+//===============================
+void LLDrawPoolWater::renderDeferred(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_WATER);
+	deferred_render = TRUE;
+	shade();
+	deferred_render = FALSE;
+}
+
+//=========================================
+
+void LLDrawPoolWater::render(S32 pass)
+{
+	LLFastTimer ftm(FTM_RENDER_WATER);
+	if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1)
+	{
+		return;
+	}
+
+	//do a quick 'n dirty depth sort
+	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+			 iter != mDrawFace.end(); iter++)
+	{
+		LLFace* facep = *iter;
+		facep->mDistance = -facep->mCenterLocal.mV[2];
+	}
+
+	std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater());
+
+	// See if we are rendering water as opaque or not
+	if (!gSavedSettings.getBOOL("RenderTransparentWater"))
+	{
+		// render water for low end hardware
+		renderOpaqueLegacyWater();
+		return;
+	}
+
+	LLGLEnable blend(GL_BLEND);
+
+	if ((mVertexShaderLevel > 0) && !sSkipScreenCopy)
+	{
+		shade();
+		return;
+	}
+
+	LLVOSky *voskyp = gSky.mVOSkyp;
+
+	stop_glerror();
+
+	if (!gGLManager.mHasMultitexture)
+	{
+		// Ack!  No multitexture!  Bail!
+		return;
+	}
+
+	LLFace* refl_face = voskyp->getReflFace();
+
+	gPipeline.disableLights();
+	
+	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+
+	LLGLDisable cullFace(GL_CULL_FACE);
+	
+	// Set up second pass first
+	mWaterImagep->addTextureStats(1024.f*1024.f);
+	gGL.getTexUnit(1)->activate();
+	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(1)->bind(mWaterImagep) ;
+
+	LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis();
+	F32 up_dot = camera_up * LLVector3::z_axis;
+
+	LLColor4 water_color;
+	if (LLViewerCamera::getInstance()->cameraUnderWater())
+	{
+		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
+	}
+	else
+	{
+		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
+	}
+
+	gGL.diffuseColor4fv(water_color.mV);
+
+	// Automatically generate texture coords for detail map
+	glEnable(GL_TEXTURE_GEN_S); //texture unit 1
+	glEnable(GL_TEXTURE_GEN_T); //texture unit 1
+	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+
+	// Slowly move over time.
+	F32 offset = fmod(gFrameTimeSeconds*2.f, 100.f);
+	F32 tp0[4] = {16.f/256.f, 0.0f, 0.0f, offset*0.01f};
+	F32 tp1[4] = {0.0f, 16.f/256.f, 0.0f, offset*0.01f};
+	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
+	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
+
+	gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
+	gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA);
+
+	gGL.getTexUnit(0)->activate();
+	
+	glClearStencil(1);
+	glClear(GL_STENCIL_BUFFER_BIT);
+	LLGLEnable gls_stencil(GL_STENCIL_TEST);
+	glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);
+	glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
+
+	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+		 iter != mDrawFace.end(); iter++)
+	{
+		LLFace *face = *iter;
+		if (voskyp->isReflFace(face))
+		{
+			continue;
+		}
+		gGL.getTexUnit(0)->bind(face->getTexture());
+		face->renderIndexed();
+	}
+
+	// Now, disable texture coord generation on texture state 1
+	gGL.getTexUnit(1)->activate();
+	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(1)->disable();
+	glDisable(GL_TEXTURE_GEN_S); //texture unit 1
+	glDisable(GL_TEXTURE_GEN_T); //texture unit 1
+
+	// Disable texture coordinate and color arrays
+	gGL.getTexUnit(0)->activate();
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+	stop_glerror();
+	
+	if (gSky.mVOSkyp->getCubeMap())
+	{
+		gSky.mVOSkyp->getCubeMap()->enable(0);
+		gSky.mVOSkyp->getCubeMap()->bind();
+
+		gGL.matrixMode(LLRender::MM_TEXTURE);
+		gGL.loadIdentity();
+		LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
+		LLMatrix4 camera_rot(camera_mat.getMat3());
+		camera_rot.invert();
+
+		gGL.loadMatrix((F32 *)camera_rot.mMatrix);
+
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		LLOverrideFaceColor overrid(this, 1.f, 1.f, 1.f,  0.5f*up_dot);
+
+		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+			 iter != mDrawFace.end(); iter++)
+		{
+			LLFace *face = *iter;
+			if (voskyp->isReflFace(face))
+			{
+				//refl_face = face;
+				continue;
+			}
+
+			if (face->getGeomCount() > 0)
+			{					
+				face->renderIndexed();
+			}
+		}
+
+		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+		gSky.mVOSkyp->getCubeMap()->disable();
+		
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+		gGL.matrixMode(LLRender::MM_TEXTURE);
+		gGL.loadIdentity();
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		
+	}
+
+	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+    if (refl_face)
+	{
+		glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
+		renderReflection(refl_face);
+	}
+
+	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+}
+
+// for low end hardware
+void LLDrawPoolWater::renderOpaqueLegacyWater()
+{
+	LLVOSky *voskyp = gSky.mVOSkyp;
+
+	LLGLSLShader* shader = NULL;
+	if (LLGLSLShader::sNoFixedFunction)
+	{
+		if (LLPipeline::sUnderWaterRender)
+		{
+			shader = &gObjectSimpleNonIndexedTexGenWaterProgram;
+		}
+		else
+		{
+			shader = &gObjectSimpleNonIndexedTexGenProgram;
+		}
+
+		shader->bind();
+	}
+
+	stop_glerror();
+
+	// Depth sorting and write to depth buffer
+	// since this is opaque, we should see nothing
+	// behind the water.  No blending because
+	// of no transparency.  And no face culling so
+	// that the underside of the water is also opaque.
+	LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
+	LLGLDisable no_cull(GL_CULL_FACE);
+	LLGLDisable no_blend(GL_BLEND);
+
+	gPipeline.disableLights();
+
+	mOpaqueWaterImagep->addTextureStats(1024.f*1024.f);
+
+	// Activate the texture binding and bind one
+	// texture since all images will have the same texture
+	gGL.getTexUnit(0)->activate();
+	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(0)->bind(mOpaqueWaterImagep);
+
+	// Automatically generate texture coords for water texture
+	if (!shader)
+	{
+		glEnable(GL_TEXTURE_GEN_S); //texture unit 0
+		glEnable(GL_TEXTURE_GEN_T); //texture unit 0
+		glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+		glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+	}
+
+	// Use the fact that we know all water faces are the same size
+	// to save some computation
+
+	// Slowly move texture coordinates over time so the watter appears
+	// to be moving.
+	F32 movement_period_secs = 50.f;
+
+	F32 offset = fmod(gFrameTimeSeconds, movement_period_secs);
+
+	if (movement_period_secs != 0)
+	{
+	 	offset /= movement_period_secs;
+	}
+	else
+	{
+		offset = 0;
+	}
+
+	F32 tp0[4] = { 16.f / 256.f, 0.0f, 0.0f, offset };
+	F32 tp1[4] = { 0.0f, 16.f / 256.f, 0.0f, offset };
+
+	if (!shader)
+	{
+		glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
+		glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
+	}
+	else
+	{
+		shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0);
+		shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1);
+	}
+
+	gGL.diffuseColor3f(1.f, 1.f, 1.f);
+
+	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+		 iter != mDrawFace.end(); iter++)
+	{
+		LLFace *face = *iter;
+		if (voskyp->isReflFace(face))
+		{
+			continue;
+		}
+
+		face->renderIndexed();
+	}
+
+	stop_glerror();
+
+	if (!shader)
+	{
+		// Reset the settings back to expected values
+		glDisable(GL_TEXTURE_GEN_S); //texture unit 0
+		glDisable(GL_TEXTURE_GEN_T); //texture unit 0
+	}
+
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+}
+
+
+void LLDrawPoolWater::renderReflection(LLFace* face)
+{
+	LLVOSky *voskyp = gSky.mVOSkyp;
+
+	if (!voskyp)
+	{
+		return;
+	}
+
+	if (!face->getGeomCount())
+	{
+		return;
+	}
+	
+	S8 dr = voskyp->getDrawRefl();
+	if (dr < 0)
+	{
+		return;
+	}
+
+	LLGLSNoFog noFog;
+
+	gGL.getTexUnit(0)->bind(mHBTex[dr]);
+
+	LLOverrideFaceColor override(this, face->getFaceColor().mV);
+	face->renderIndexed();
+}
+
+void LLDrawPoolWater::shade()
+{
+	if (!deferred_render)
+	{
+		gGL.setColorMask(true, true);
+	}
+
+	LLVOSky *voskyp = gSky.mVOSkyp;
+
+	if(voskyp == NULL) 
+	{
+		return;
+	}
+
+	LLGLDisable blend(GL_BLEND);
+
+	LLColor3 light_diffuse(0,0,0);
+	F32 light_exp = 0.0f;
+	LLVector3 light_dir;
+	LLColor3 light_color;
+
+	if (gSky.getSunDirection().mV[2] > LLSky::NIGHTTIME_ELEVATION_COS) 	 
+    { 	 
+        light_dir  = gSky.getSunDirection(); 	 
+        light_dir.normVec(); 	
+		light_color = gSky.getSunDiffuseColor();
+		if(gSky.mVOSkyp) {
+	        light_diffuse = gSky.mVOSkyp->getSun().getColorCached(); 	 
+			light_diffuse.normVec(); 	 
+		}
+        light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0); 	 
+        light_diffuse *= light_exp + 0.25f; 	 
+    } 	 
+    else  	 
+    { 	 
+        light_dir       = gSky.getMoonDirection(); 	 
+        light_dir.normVec(); 	 
+		light_color = gSky.getMoonDiffuseColor();
+        light_diffuse   = gSky.mVOSkyp->getMoon().getColorCached(); 	 
+        light_diffuse.normVec(); 	 
+        light_diffuse *= 0.5f; 	 
+        light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0); 	 
+    }
+
+	light_exp *= light_exp;
+	light_exp *= light_exp;
+	light_exp *= light_exp;
+	light_exp *= light_exp;
+	light_exp *= 256.f;
+	light_exp = light_exp > 32.f ? light_exp : 32.f;
+
+	LLGLSLShader* shader;
+
+	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
+	
+	if (deferred_render)
+	{
+		shader = &gDeferredWaterProgram;
+	}
+	else if (eyedepth < 0.f && LLPipeline::sWaterReflections)
+	{
+		shader = &gUnderWaterProgram;
+	}
+	else
+	{
+		shader = &gWaterProgram;
+	}
+
+	if (deferred_render)
+	{
+		gPipeline.bindDeferredShader(*shader);
+	}
+	else
+	{
+		shader->bind();
+	}
+
+	sTime = (F32)LLFrameTimer::getElapsedSeconds()*0.5f;
+	
+	S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX);
+		
+	if (reftex > -1)
+	{
+		gGL.getTexUnit(reftex)->activate();
+		gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef);
+		gGL.getTexUnit(0)->activate();
+	}	
+
+	//bind normal map
+	S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+
+	LLWaterParamManager * param_mgr = &LLWaterParamManager::instance();
+
+	// change mWaterNormp if needed
+	if (mWaterNormp->getID() != param_mgr->getNormalMapID())
+	{
+		mWaterNormp = LLViewerTextureManager::getFetchedTexture(param_mgr->getNormalMapID());
+	}
+
+	mWaterNormp->addTextureStats(1024.f*1024.f);
+	gGL.getTexUnit(bumpTex)->bind(mWaterNormp) ;
+	if (gSavedSettings.getBOOL("RenderWaterMipNormal"))
+	{
+		mWaterNormp->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+	}
+	else 
+	{
+		mWaterNormp->setFilteringOption(LLTexUnit::TFO_POINT);
+	}
+	
+	S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);	
+		
+	if (screentex > -1)
+	{
+		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
+		shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, 
+			param_mgr->getFogDensity());
+		gPipeline.mWaterDis.bindTexture(0, screentex);
+	}
+	
+	stop_glerror();
+	
+	gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);	
+
+	if (mVertexShaderLevel == 1)
+	{
+		sWaterFogColor.mV[3] = param_mgr->mDensitySliderValue;
+		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, sWaterFogColor.mV);
+	}
+
+	stop_glerror();
+	
+	S32 diffTex = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	stop_glerror();
+	
+	light_dir.normVec();
+	sLightDir = light_dir;
+	
+	light_diffuse *= 6.f;
+
+	//shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix);
+	shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth);
+	shader->uniform1f(LLShaderMgr::WATER_TIME, sTime);
+	shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+	shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV);
+	shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
+	shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, param_mgr->getWave1Dir().mV);
+	shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, param_mgr->getWave2Dir().mV);
+	shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV);
+
+	shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, param_mgr->getNormalScale().mV);
+	shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, param_mgr->getFresnelScale());
+	shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, param_mgr->getFresnelOffset());
+	shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, param_mgr->getBlurMultiplier());
+
+	F32 sunAngle = llmax(0.f, light_dir.mV[2]);
+	F32 scaledAngle = 1.f - sunAngle;
+
+	shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle);
+	shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle);
+	shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f*sunAngle);
+
+	LLColor4 water_color;
+	LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis();
+	F32 up_dot = camera_up * LLVector3::z_axis;
+	if (LLViewerCamera::getInstance()->cameraUnderWater())
+	{
+		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
+		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleBelow());
+	}
+	else
+	{
+		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
+		shader->uniform1f(LLShaderMgr::WATER_REFSCALE, param_mgr->getScaleAbove());
+	}
+
+	if (water_color.mV[3] > 0.9f)
+	{
+		water_color.mV[3] = 0.9f;
+	}
+
+	{
+		LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
+		LLGLDisable cullface(GL_CULL_FACE);
+		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+			iter != mDrawFace.end(); iter++)
+		{
+			LLFace *face = *iter;
+
+			if (voskyp->isReflFace(face))
+			{
+				continue;
+			}
+
+			LLVOWater* water = (LLVOWater*) face->getViewerObject();
+			gGL.getTexUnit(diffTex)->bind(face->getTexture());
+
+			sNeedsReflectionUpdate = TRUE;
+			
+			if (water->getUseTexture() || !water->getIsEdgePatch())
+			{
+				sNeedsDistortionUpdate = TRUE;
+				face->renderIndexed();
+			}
+			else if (gGLManager.mHasDepthClamp || deferred_render)
+			{
+				face->renderIndexed();
+			}
+			else
+			{
+				LLGLSquashToFarClip far_clip(glh_get_current_projection());
+				face->renderIndexed();
+			}
+		}
+	}
+	
+	shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+	shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);	
+	shader->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+	shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	shader->disableTexture(LLShaderMgr::WATER_REFTEX);
+	shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
+
+	if (deferred_render)
+	{
+		gPipeline.unbindDeferredShader(*shader);
+	}
+	else
+	{
+		shader->unbind();
+	}
+
+	gGL.getTexUnit(0)->activate();
+	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+	if (!deferred_render)
+	{
+		gGL.setColorMask(true, false);
+	}
+
+}
+
+LLViewerTexture *LLDrawPoolWater::getDebugTexture()
+{
+	return LLViewerFetchedTexture::sSmokeImagep;
+}
+
+LLColor3 LLDrawPoolWater::getDebugColor() const
+{
+	return LLColor3(0.f, 1.f, 1.f);
+}
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 3c7a49d5cefb6d34dd990711cb78d607224f0b5a..86e5f208121ce936c52f57793cdcb1c4fb4efd05 100755
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -51,7 +51,9 @@
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
 #include "llviewershadermgr.h"
+#include "llvoavatar.h"
 
+extern BOOL gGLDebugLoggingEnabled;
 
 #define LL_MAX_INDICES_COUNT 1000000
 
@@ -328,6 +330,12 @@ void LLFace::dirtyTexture()
 		if (vobj)
 		{
 			vobj->mLODChanged = TRUE;
+
+			LLVOAvatar* avatar = vobj->getAvatar();
+			if (avatar)
+			{ //avatar render cost may have changed
+				avatar->updateVisualComplexity();
+			}
 		}
 		gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE);
 	}		
@@ -1162,6 +1170,15 @@ static LLFastTimer::DeclareTimer FTM_FACE_GEOM_COLOR("Color");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_EMISSIVE("Emissive");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_WEIGHTS("Weights");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_BINORMAL("Binormal");
+
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK("Face Feedback");
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_POSITION("Feedback Position");
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_NORMAL("Feedback  Normal");
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_TEXTURE("Feedback  Texture");
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_COLOR("Feedback  Color");
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_EMISSIVE("Feedback  Emissive");
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_FEEDBACK_BINORMAL("Feedback Binormal");
+
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX("Index");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX_TAIL("Tail");
 static LLFastTimer::DeclareTimer FTM_FACE_POSITION_STORE("Pos");
@@ -1385,12 +1402,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 #ifdef GL_TRANSFORM_FEEDBACK_BUFFER
 	if (use_transform_feedback &&
+		mVertexBuffer->getUsage() == GL_DYNAMIC_COPY_ARB &&
 		gTransformPositionProgram.mProgramObject && //transform shaders are loaded
 		mVertexBuffer->useVBOs() && //target buffer is in VRAM
 		!rebuild_weights && //TODO: add support for weights
 		!volume.isUnique()) //source volume is NOT flexi
 	{ //use transform feedback to pack vertex buffer
-
+		//gGLDebugLoggingEnabled = TRUE;
+		LLFastTimer t(FTM_FACE_GEOM_FEEDBACK);
+		LLGLEnable discard(GL_RASTERIZER_DISCARD);
 		LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
 
 		if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices)
@@ -1407,7 +1427,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_pos)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_POSITION);
+			LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_POSITION);
 			gTransformPositionProgram.bind();
 
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount);
@@ -1420,7 +1440,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			vp[1] = 0;
 			vp[2] = 0;
 			vp[3] = 0;
-						
+			
 			gTransformPositionProgram.uniform1i(sTextureIndexIn, val);
 			glBeginTransformFeedback(GL_POINTS);
 			buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
@@ -1432,7 +1452,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_color)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_COLOR);
+			LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_COLOR);
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount);
@@ -1448,7 +1468,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_emissive)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_EMISSIVE);
+			LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_EMISSIVE);
 			gTransformColorProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount);
@@ -1469,7 +1489,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_normal)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_NORMAL);
+			LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_NORMAL);
 			gTransformNormalProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount);
@@ -1482,7 +1502,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_binormal)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_BINORMAL);
+			LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_BINORMAL);
 			gTransformBinormalProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_BINORMAL, mGeomIndex, mGeomCount);
@@ -1495,7 +1515,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_tcoord)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_TEXTURE);
+			LLFastTimer t(FTM_FACE_GEOM_FEEDBACK_TEXTURE);
 			gTransformTexCoordProgram.bind();
 			
 			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount);
@@ -1518,13 +1538,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 
 		glBindBufferARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
-
 		gGL.popMatrix();
 
 		if (cur_shader)
 		{
 			cur_shader->bind();
 		}
+		//gGLDebugLoggingEnabled = FALSE;
 	}
 	else
 #endif
@@ -1939,21 +1959,31 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (rebuild_pos)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_POSITION);
+			LLVector4a* src = vf.mPositions;
+			
+			//_mm_prefetch((char*)src, _MM_HINT_T0);
+
+			LLVector4a* end = src+num_vertices;
+			//LLVector4a* end_64 = end-4;
+
+			//LLFastTimer t(FTM_FACE_GEOM_POSITION);
 			llassert(num_vertices > 0);
 		
 			mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
 			
-
 			LLMatrix4a mat_vert;
 			mat_vert.loadu(mat_vert_in);
+								
+			F32* dst = (F32*) vert.get();
+			F32* end_f32 = dst+mGeomCount*4;
 
-			LLVector4a* src = vf.mPositions;
-			volatile F32* dst = (volatile F32*) vert.get();
-
-			volatile F32* end = dst+num_vertices*4;
-			LLVector4a res;
+			//_mm_prefetch((char*)dst, _MM_HINT_NTA);
+			//_mm_prefetch((char*)src, _MM_HINT_NTA);
+				
+			//_mm_prefetch((char*)dst, _MM_HINT_NTA);
 
+			LLVector4a res0; //,res1,res2,res3;
+			
 			LLVector4a texIdx;
 
 			S32 index = mTextureIndex < 255 ? mTextureIndex : 0;
@@ -1970,29 +2000,53 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 			texIdx.set(0,0,0,val);
 
+			LLVector4a tmp;
+
 			{
-				LLFastTimer t(FTM_FACE_POSITION_STORE);
-				LLVector4a tmp;
+				//LLFastTimer t2(FTM_FACE_POSITION_STORE);
 
-				do
-				{	
-					mat_vert.affineTransform(*src++, res);
-					tmp.setSelectWithMask(mask, texIdx, res);
+				/*if (num_vertices > 4)
+				{ //more than 64 bytes
+					while (src < end_64)
+					{	
+						_mm_prefetch((char*)src + 64, _MM_HINT_T0);
+						_mm_prefetch((char*)dst + 64, _MM_HINT_T0);
+
+						mat_vert.affineTransform(*src, res0);
+						tmp.setSelectWithMask(mask, texIdx, res0);
+						tmp.store4a((F32*) dst);
+
+						mat_vert.affineTransform(*(src+1), res1);
+						tmp.setSelectWithMask(mask, texIdx, res1);
+						tmp.store4a((F32*) dst+4);
+
+						mat_vert.affineTransform(*(src+2), res2);
+						tmp.setSelectWithMask(mask, texIdx, res2);
+						tmp.store4a((F32*) dst+8);
+
+						mat_vert.affineTransform(*(src+3), res3);
+						tmp.setSelectWithMask(mask, texIdx, res3);
+						tmp.store4a((F32*) dst+12);
+
+						dst += 16;
+						src += 4;
+					}
+				}*/
+
+				while (src < end)
+				{
+					mat_vert.affineTransform(*src++, res0);
+					tmp.setSelectWithMask(mask, texIdx, res0);
 					tmp.store4a((F32*) dst);
 					dst += 4;
 				}
-				while(dst < end);
 			}
-
+			
 			{
-				LLFastTimer t(FTM_FACE_POSITION_PAD);
-				S32 aligned_pad_vertices = mGeomCount - num_vertices;
-				res.set(res[0], res[1], res[2], 0.f);
-
-				while (aligned_pad_vertices > 0)
+				//LLFastTimer t(FTM_FACE_POSITION_PAD);
+				while (dst < end_f32)
 				{
-					--aligned_pad_vertices;
-					res.store4a((F32*) dst);
+					res0.store4a((F32*) dst);
 					dst += 4;
 				}
 			}
@@ -2006,15 +2060,17 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 		if (rebuild_normal)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_NORMAL);
+			//LLFastTimer t(FTM_FACE_GEOM_NORMAL);
 			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
 			F32* normals = (F32*) norm.get();
 	
-			for (S32 i = 0; i < num_vertices; i++)
-			{	
+			LLVector4a* src = vf.mNormals;
+			LLVector4a* end = src+num_vertices;
+			
+			while (src < end)
+			{
 				LLVector4a normal;
-				mat_normal.rotate(vf.mNormals[i], normal);
-				normal.normalize3fast();
+				mat_normal.rotate(*src++, normal);
 				normal.store4a(normals);
 				normals += 4;
 			}
@@ -2031,11 +2087,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range);
 			F32* binormals = (F32*) binorm.get();
 		
-			for (S32 i = 0; i < num_vertices; i++)
+			LLVector4a* src = vf.mBinormals;
+			LLVector4a* end = vf.mBinormals+num_vertices;
+
+			while (src < end)
 			{	
 				LLVector4a binormal;
-				mat_normal.rotate(vf.mBinormals[i], binormal);
-				binormal.normalize3fast();
+				mat_normal.rotate(*src++, binormal);
 				binormal.store4a(binormals);
 				binormals += 4;
 			}
diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 4dfb93f1bca3359ace15787dc845598b2a710266..e7a3f9b390ad4d4e1d6f6384454aa2cc3f01b1fd 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -345,7 +345,7 @@ BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	return TRUE;
 }
 
-static LLFastTimer::DeclareTimer FTM_RENDER_TIMER("Timers", true);
+static LLFastTimer::DeclareTimer FTM_RENDER_TIMER("Timers");
 
 static std::map<LLFastTimer::NamedTimer*, LLColor4> sTimerColors;
 
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 1223615079772e274ff703f6ea17e85964ca2c5f..306f29f7034ad143538ba50363f70429140cd46b 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -588,7 +588,7 @@ void LLMeshRepoThread::run()
 					if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit
 					{
 						mMutex->lock();
-						mLODReqQ.push(req) ; 
+						mLODReqQ.push(req); 
 						mMutex->unlock();
 					}
 				}
@@ -1200,8 +1200,7 @@ bool LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* dat
 			LLMutexLock lock(mHeaderMutex);
 			mMeshHeaderSize[mesh_id] = header_size;
 			mMeshHeader[mesh_id] = header;
-			}
-
+		}
 
 		LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time.
 
@@ -1919,7 +1918,7 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -1927,7 +1926,7 @@ void LLMeshLODResponder::completedRaw(U32 status, const std::string& reason,
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
 			llwarns << "Unhandled status " << status << llendl;
 		}
 		return;
@@ -1983,7 +1982,7 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -1991,7 +1990,7 @@ void LLMeshSkinInfoResponder::completedRaw(U32 status, const std::string& reason
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
 			llwarns << "Unhandled status " << status << llendl;
 		}
 		return;
@@ -2046,7 +2045,7 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -2054,7 +2053,7 @@ void LLMeshDecompositionResponder::completedRaw(U32 status, const std::string& r
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
 			llwarns << "Unhandled status " << status << llendl;
 		}
 		return;
@@ -2110,7 +2109,7 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re
 
 	if (data_size < mRequestedBytes)
 	{
-		if (status == 499 || status == 503)
+		if (status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE)
 		{ //timeout or service unavailable, try again
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -2118,7 +2117,7 @@ void LLMeshPhysicsShapeResponder::completedRaw(U32 status, const std::string& re
 		}
 		else
 		{
-			llassert(status == 499 || status == 503); //intentionally trigger a breakpoint
+			llassert(status == HTTP_INTERNAL_ERROR || status == HTTP_SERVICE_UNAVAILABLE); //intentionally trigger a breakpoint
 			llwarns << "Unhandled status " << status << llendl;
 		}
 		return;
@@ -2171,16 +2170,16 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 		//	<< "Header responder failed with status: "
 		//	<< status << ": " << reason << llendl;
 
-		// 503 (service unavailable) or 499 (timeout)
+		// 503 (service unavailable) or 499 (internal Linden-generated error)
 		// can be due to server load and can be retried
 
 		// TODO*: Add maximum retry logic, exponential backoff
 		// and (somewhat more optional than the others) retries
 		// again after some set period of time
 
-		llassert(status == 503 || status == 499);
+		llassert(status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_REQUEST_TIME_OUT || status == HTTP_INTERNAL_ERROR);
 
-		if (status == 503 || status == 499)
+		if (status == HTTP_SERVICE_UNAVAILABLE || status == HTTP_REQUEST_TIME_OUT || status == HTTP_INTERNAL_ERROR)
 		{ //retry
 			llwarns << "Timeout or service unavailable, retrying." << llendl;
 			LLMeshRepository::sHTTPRetryCount++;
@@ -2192,7 +2191,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 		}
 		else
 		{
-			llwarns << "Unhandled status." << llendl;
+			llwarns << "Unhandled status: " << status << llendl;
 		}
 	}
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index ffeea2f4df936aa827557f97016c393394a18b69..9ffc64312d176718527a5edfee59ec48f38e9e80 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -212,13 +212,13 @@ void display_stats()
 }
 
 static LLFastTimer::DeclareTimer FTM_PICK("Picking");
-static LLFastTimer::DeclareTimer FTM_RENDER("Render", true);
+static LLFastTimer::DeclareTimer FTM_RENDER("Render");
 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");
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List", true);
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete");
 static LLFastTimer::DeclareTimer FTM_RESIZE_WINDOW("Resize Window");
 static LLFastTimer::DeclareTimer FTM_HUD_UPDATE("HUD Update");
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index fc7e51d06c2bb3bf0f1b6d6264749a57a56414f9..7d7889845d419a78ade2329245c0e55413dcaf8c 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -311,47 +311,6 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void)
 	if (mReservedAttribs.empty())
 	{
 		LLShaderMgr::initAttribsAndUniforms();
-
-		mAvatarUniforms.push_back(LLStaticHashedString("matrixPalette"));
-		mAvatarUniforms.push_back(LLStaticHashedString("gWindDir"));
-		mAvatarUniforms.push_back(LLStaticHashedString("gSinWaveParams"));
-		mAvatarUniforms.push_back(LLStaticHashedString("gGravity"));
-
-		mWLUniforms.push_back(LLStaticHashedString("camPosLocal"));
-
-		mTerrainUniforms.reserve(5);
-		mTerrainUniforms.push_back(LLStaticHashedString("detail_0"));
-		mTerrainUniforms.push_back(LLStaticHashedString("detail_1"));
-		mTerrainUniforms.push_back(LLStaticHashedString("detail_2"));
-		mTerrainUniforms.push_back(LLStaticHashedString("detail_3"));
-		mTerrainUniforms.push_back(LLStaticHashedString("alpha_ramp"));
-
-		mGlowUniforms.push_back(LLStaticHashedString("glowDelta"));
-		mGlowUniforms.push_back(LLStaticHashedString("glowStrength"));
-
-		mGlowExtractUniforms.push_back(LLStaticHashedString("minLuminance"));
-		mGlowExtractUniforms.push_back(LLStaticHashedString("maxExtractAlpha"));
-		mGlowExtractUniforms.push_back(LLStaticHashedString("lumWeights"));
-		mGlowExtractUniforms.push_back(LLStaticHashedString("warmthWeights"));
-		mGlowExtractUniforms.push_back(LLStaticHashedString("warmthAmount"));
-
-		mShinyUniforms.push_back(LLStaticHashedString("origin"));
-
-		mWaterUniforms.reserve(12);
-		mWaterUniforms.push_back(LLStaticHashedString("screenTex"));
-		mWaterUniforms.push_back(LLStaticHashedString("screenDepth"));
-		mWaterUniforms.push_back(LLStaticHashedString("refTex"));
-		mWaterUniforms.push_back(LLStaticHashedString("eyeVec"));
-		mWaterUniforms.push_back(LLStaticHashedString("time"));
-		mWaterUniforms.push_back(LLStaticHashedString("d1"));
-		mWaterUniforms.push_back(LLStaticHashedString("d2"));
-		mWaterUniforms.push_back(LLStaticHashedString("lightDir"));
-		mWaterUniforms.push_back(LLStaticHashedString("specular"));
-		mWaterUniforms.push_back(LLStaticHashedString("lightExp"));
-		mWaterUniforms.push_back(LLStaticHashedString("fogCol"));
-		mWaterUniforms.push_back(LLStaticHashedString("kd"));
-		mWaterUniforms.push_back(LLStaticHashedString("refScale"));
-		mWaterUniforms.push_back(LLStaticHashedString("waterHeight"));
 	}	
 }
 	
@@ -922,7 +881,7 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment()
 		gTerrainProgram.mShaderFiles.push_back(make_pair("environment/terrainV.glsl", GL_VERTEX_SHADER_ARB));
 		gTerrainProgram.mShaderFiles.push_back(make_pair("environment/terrainF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gTerrainProgram.mShaderLevel = mVertexShaderLevel[SHADER_ENVIRONMENT];
-		success = gTerrainProgram.createShader(NULL, &mTerrainUniforms);
+		success = gTerrainProgram.createShader(NULL, NULL);
 	}
 
 	if (!success)
@@ -960,7 +919,7 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 		gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER_ARB));
 		gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER];
-		success = gWaterProgram.createShader(NULL, &mWaterUniforms);
+		success = gWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -974,7 +933,7 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 		gUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER];
 		gUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		
-		success = gUnderWaterProgram.createShader(NULL, &mWaterUniforms);
+		success = gUnderWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -992,7 +951,7 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 		gTerrainWaterProgram.mShaderFiles.push_back(make_pair("environment/terrainWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gTerrainWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_ENVIRONMENT];
 		gTerrainWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		terrainWaterSuccess = gTerrainWaterProgram.createShader(NULL, &mTerrainUniforms);
+		terrainWaterSuccess = gTerrainWaterProgram.createShader(NULL, NULL);
 	}	
 
 	/// Keep track of water shader levels
@@ -1041,7 +1000,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 		gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowV.glsl", GL_VERTEX_SHADER_ARB));
 		gGlowProgram.mShaderFiles.push_back(make_pair("effects/glowF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gGlowProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
-		success = gGlowProgram.createShader(NULL, &mGlowUniforms);
+		success = gGlowProgram.createShader(NULL, NULL);
 		if (!success)
 		{
 			LLPipeline::sRenderGlow = FALSE;
@@ -1055,7 +1014,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractV.glsl", GL_VERTEX_SHADER_ARB));
 		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gGlowExtractProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
-		success = gGlowExtractProgram.createShader(NULL, &mGlowExtractUniforms);
+		success = gGlowExtractProgram.createShader(NULL, NULL);
 		if (!success)
 		{
 			LLPipeline::sRenderGlow = FALSE;
@@ -1415,7 +1374,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		success = gDeferredWaterProgram.createShader(NULL, &mWaterUniforms);
+		success = gDeferredWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1474,7 +1433,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredAvatarShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		success = gDeferredAvatarShadowProgram.createShader(NULL, &mAvatarUniforms);
+		success = gDeferredAvatarShadowProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1495,7 +1454,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredTerrainProgram.mShaderFiles.push_back(make_pair("deferred/terrainF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredTerrainProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		success = gDeferredTerrainProgram.createShader(NULL, &mTerrainUniforms);
+		success = gDeferredTerrainProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1506,7 +1465,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredAvatarProgram.mShaderFiles.push_back(make_pair("deferred/avatarF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredAvatarProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		success = gDeferredAvatarProgram.createShader(NULL, &mAvatarUniforms);
+		success = gDeferredAvatarProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1526,7 +1485,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaNonIndexedNoColorF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredAvatarAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		success = gDeferredAvatarAlphaProgram.createShader(NULL, &mAvatarUniforms);
+		success = gDeferredAvatarAlphaProgram.createShader(NULL, NULL);
 
 		gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = true;
 		gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true;
@@ -1591,7 +1550,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredWLSkyProgram.mShaderFiles.push_back(make_pair("deferred/skyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredWLSkyProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		gDeferredWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY;
-		success = gDeferredWLSkyProgram.createShader(NULL, &mWLUniforms);
+		success = gDeferredWLSkyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1602,7 +1561,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredWLCloudProgram.mShaderFiles.push_back(make_pair("deferred/cloudsF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredWLCloudProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		gDeferredWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY;
-		success = gDeferredWLCloudProgram.createShader(NULL, &mWLUniforms);
+		success = gDeferredWLCloudProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1613,7 +1572,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredStarProgram.mShaderFiles.push_back(make_pair("deferred/starsF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredStarProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		gDeferredStarProgram.mShaderGroup = LLGLSLShader::SG_SKY;
-		success = gDeferredStarProgram.createShader(NULL, &mWLUniforms);
+		success = gDeferredStarProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1964,7 +1923,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
 		gObjectShinyNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-		success = gObjectShinyNonIndexedProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectShinyNonIndexedProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -1981,7 +1940,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, NULL);
 	}
 	
 	if (success)
@@ -1997,7 +1956,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyNonIndexedProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -2015,7 +1974,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -2094,7 +2053,6 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		success = gObjectBumpProgram.createShader(NULL, NULL);
-
 		if (success)
 		{ //lldrawpoolbump assumes "texture0" has channel 0 and "texture1" has channel 1
 			gObjectBumpProgram.bind();
@@ -2248,7 +2206,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));		
 		gObjectShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-		success = gObjectShinyProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectShinyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -2265,7 +2223,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectShinyWaterProgram.createShader(NULL, NULL);
 	}
 	
 	if (success)
@@ -2281,7 +2239,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
 		gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-		success = gObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectFullbrightShinyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -2299,7 +2257,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gObjectFullbrightShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
 		gObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
-		success = gObjectFullbrightShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+		success = gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
 	}
 
 	if (mVertexShaderLevel[SHADER_AVATAR] > 0)
@@ -2384,7 +2342,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 			gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+			success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, NULL);
 		}
 
 		if (success)
@@ -2401,7 +2359,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));
 			gSkinnedObjectShinySimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectShinySimpleProgram.createShader(NULL, &mShinyUniforms);
+			success = gSkinnedObjectShinySimpleProgram.createShader(NULL, NULL);
 		}
 
 		if (success)
@@ -2458,7 +2416,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 			gSkinnedObjectFullbrightShinyWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, &mShinyUniforms);
+			success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, NULL);
 		}
 
 		if (success)
@@ -2477,7 +2435,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
 			gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 			gSkinnedObjectShinySimpleWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
-			success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, &mShinyUniforms);
+			success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, NULL);
 		}
 	}
 
@@ -2518,7 +2476,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar()
 		gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarV.glsl", GL_VERTEX_SHADER_ARB));
 		gAvatarProgram.mShaderFiles.push_back(make_pair("avatar/avatarF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gAvatarProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR];
-		success = gAvatarProgram.createShader(NULL, &mAvatarUniforms);
+		success = gAvatarProgram.createShader(NULL, NULL);
 			
 		if (success)
 		{
@@ -2537,7 +2495,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar()
 			// Note: no cloth under water:
 			gAvatarWaterProgram.mShaderLevel = llmin(mVertexShaderLevel[SHADER_AVATAR], 1);	
 			gAvatarWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;				
-			success = gAvatarWaterProgram.createShader(NULL, &mAvatarUniforms);
+			success = gAvatarWaterProgram.createShader(NULL, NULL);
 		}
 
 		/// Keep track of avatar levels
@@ -2556,7 +2514,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar()
 		gAvatarPickProgram.mShaderFiles.push_back(make_pair("avatar/pickAvatarV.glsl", GL_VERTEX_SHADER_ARB));
 		gAvatarPickProgram.mShaderFiles.push_back(make_pair("avatar/pickAvatarF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gAvatarPickProgram.mShaderLevel = mVertexShaderLevel[SHADER_AVATAR];
-		success = gAvatarPickProgram.createShader(NULL, &mAvatarUniforms);
+		success = gAvatarPickProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -2824,7 +2782,7 @@ BOOL LLViewerShaderMgr::loadShadersWindLight()
 		gWLSkyProgram.mShaderFiles.push_back(make_pair("windlight/skyF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gWLSkyProgram.mShaderLevel = mVertexShaderLevel[SHADER_WINDLIGHT];
 		gWLSkyProgram.mShaderGroup = LLGLSLShader::SG_SKY;
-		success = gWLSkyProgram.createShader(NULL, &mWLUniforms);
+		success = gWLSkyProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
@@ -2836,7 +2794,7 @@ BOOL LLViewerShaderMgr::loadShadersWindLight()
 		gWLCloudProgram.mShaderFiles.push_back(make_pair("windlight/cloudsF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gWLCloudProgram.mShaderLevel = mVertexShaderLevel[SHADER_WINDLIGHT];
 		gWLCloudProgram.mShaderGroup = LLGLSLShader::SG_SKY;
-		success = gWLCloudProgram.createShader(NULL, &mWLUniforms);
+		success = gWLCloudProgram.createShader(NULL, NULL);
 	}
 
 	return success;
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 999baa0ad091e60cd16c5b1d755c5a72d23aff29..6cd52dc73631653fa62a63e7ce444a42cf738054 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -74,56 +74,7 @@ class LLViewerShaderMgr: public LLShaderMgr
 		SHADER_COUNT
 	};
 
-	typedef enum
-	{
-		SHINY_ORIGIN = END_RESERVED_UNIFORMS
-	} eShinyUniforms;
-
-	typedef enum
-	{
-		WATER_SCREENTEX = END_RESERVED_UNIFORMS,
-		WATER_SCREENDEPTH,
-		WATER_REFTEX,
-		WATER_EYEVEC,
-		WATER_TIME,
-		WATER_WAVE_DIR1,
-		WATER_WAVE_DIR2,
-		WATER_LIGHT_DIR,
-		WATER_SPECULAR,
-		WATER_SPECULAR_EXP,
-		WATER_FOGCOLOR,
-		WATER_FOGDENSITY,
-		WATER_REFSCALE,
-		WATER_WATERHEIGHT,
-	} eWaterUniforms;
-
-	typedef enum
-	{
-		WL_CAMPOSLOCAL = END_RESERVED_UNIFORMS,
-		WL_WATERHEIGHT
-	} eWLUniforms;
-
-	typedef enum
-	{
-		TERRAIN_DETAIL0 = END_RESERVED_UNIFORMS,
-		TERRAIN_DETAIL1,
-		TERRAIN_DETAIL2,
-		TERRAIN_DETAIL3,
-		TERRAIN_ALPHARAMP
-	} eTerrainUniforms;
-
-	typedef enum
-	{
-		GLOW_DELTA = END_RESERVED_UNIFORMS
-	} eGlowUniforms;
-
-	typedef enum
-	{
-		AVATAR_MATRIX = END_RESERVED_UNIFORMS,
-		AVATAR_WIND,
-		AVATAR_SINWAVE,
-		AVATAR_GRAVITY,
-	} eAvatarUniforms;
+	
 
 	// simple model of forward iterator
 	// http://www.sgi.com/tech/stl/ForwardIterator.html
@@ -176,25 +127,6 @@ class LLViewerShaderMgr: public LLShaderMgr
 	/* virtual */ void updateShaderUniforms(LLGLSLShader * shader);
 
 private:
-	
-	typedef std::vector< LLStaticHashedString > UniformVec;
-
-	UniformVec mShinyUniforms;
-
-	//water parameters
-	UniformVec mWaterUniforms;
-
-	UniformVec mWLUniforms;
-
-	//terrain parameters
-	UniformVec mTerrainUniforms;
-
-	//glow parameters
-	UniformVec mGlowUniforms;
-
-	UniformVec mGlowExtractUniforms;
-
-	UniformVec mAvatarUniforms;
 
 	// the list of shaders we need to propagate parameters to.
 	std::vector<LLGLSLShader *> mShaderList;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 62e93b7a53b79a50f5f398a75dd53aaff5adab16..4efd59685e9359fce36c87da64ed71bb2f160e12 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -688,6 +688,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mFullyLoaded(FALSE),
 	mPreviousFullyLoaded(FALSE),
 	mFullyLoadedInitialized(FALSE),
+	mVisualComplexity(0),
+	mVisualComplexityStale(TRUE),
 	mSupportsAlphaLayers(FALSE),
 	mLoadedCallbacksPaused(FALSE),
 	mHasPelvisOffset( FALSE ),
@@ -3434,12 +3436,23 @@ void LLVOAvatar::slamPosition()
 
 bool LLVOAvatar::isVisuallyMuted() const
 {
-	static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit");
-	static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit");
+	bool ret = false;
+
+	if (!isSelf())
+	{
+		static LLCachedControl<U32> max_attachment_bytes(gSavedSettings, "RenderAutoMuteByteLimit");
+		static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit");
+		static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderCostLimit");
 	
-	return LLMuteList::getInstance()->isMuted(getID()) ||
+		U32 max_cost = (U32) (max_render_cost*(LLVOAvatar::sLODFactor+0.5));
+
+		ret = LLMuteList::getInstance()->isMuted(getID()) ||
 			(mAttachmentGeometryBytes > max_attachment_bytes && max_attachment_bytes > 0) ||
-			(mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f);
+			(mAttachmentSurfaceArea > max_attachment_area && max_attachment_area > 0.f) ||
+			(mVisualComplexity > max_cost && max_render_cost > 0);
+	}
+
+	return ret;
 }
 
 //------------------------------------------------------------------------
@@ -4139,46 +4152,6 @@ bool LLVOAvatar::shouldAlphaMask()
 
 }
 
-U32 LLVOAvatar::renderSkinnedAttachments()
-{
-	/*U32 num_indices = 0;
-	
-	const U32 data_mask =	LLVertexBuffer::MAP_VERTEX | 
-							LLVertexBuffer::MAP_NORMAL | 
-							LLVertexBuffer::MAP_TEXCOORD0 |
-							LLVertexBuffer::MAP_COLOR |
-							LLVertexBuffer::MAP_WEIGHT4;
-
-	for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); 
-		 iter != mAttachmentPoints.end();
-		 ++iter)
-	{
-		LLViewerJointAttachment* attachment = iter->second;
-		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
-			 attachment_iter != attachment->mAttachedObjects.end();
-			 ++attachment_iter)
-		{
-			const LLViewerObject* attached_object = (*attachment_iter);
-			if (attached_object && !attached_object->isHUDAttachment())
-			{
-				const LLDrawable* drawable = attached_object->mDrawable;
-				if (drawable)
-				{
-					for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-					{
-						LLFace* face = drawable->getFace(i);
-						if (face->isState(LLFace::RIGGED))
-						{
-							
-				}
-			}
-		}
-	}
-
-	return num_indices;*/
-	return 0;
-}
-
 //-----------------------------------------------------------------------------
 // renderSkinned()
 //-----------------------------------------------------------------------------
@@ -4336,21 +4309,23 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 		BOOL first_pass = TRUE;
 		if (!LLDrawPoolAvatar::sSkipOpaque)
 		{
+			bool muted = isVisuallyMuted();
+
 			if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
 			{
-				if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
+				if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy || muted)
 				{
 					num_indices += mMeshLOD[MESH_ID_HEAD]->render(mAdjustedPixelArea, TRUE, mIsDummy);
 					first_pass = FALSE;
 				}
 			}
-			if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
+			if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy || muted)
 			{
 				num_indices += mMeshLOD[MESH_ID_UPPER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
 				first_pass = FALSE;
 			}
 			
-			if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
+			if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy || muted)
 			{
 				num_indices += mMeshLOD[MESH_ID_LOWER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
 				first_pass = FALSE;
@@ -6090,6 +6065,8 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
 		return 0;
 	}
 
+	mVisualComplexityStale = TRUE;
+
 	if (viewer_object->isSelected())
 	{
 		LLSelectMgr::getInstance()->updateSelectionCenter();
@@ -6244,6 +6221,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
 		
 		if (attachment->isObjectAttached(viewer_object))
 		{
+			mVisualComplexityStale = TRUE;
 			cleanupAttachedMesh( viewer_object );
 			attachment->removeObject(viewer_object);
 			lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl;
@@ -8456,7 +8434,7 @@ void LLVOAvatar::updateImpostors()
 
 BOOL LLVOAvatar::isImpostor() const
 {
-	return (isVisuallyMuted() || (sUseImpostors && mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE;
+	return sUseImpostors && (isVisuallyMuted() || (mUpdatePeriod >= IMPOSTOR_PERIOD)) ? TRUE : FALSE;
 }
 
 
@@ -8501,6 +8479,8 @@ void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& d
 
 void LLVOAvatar::idleUpdateRenderCost()
 {
+	static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAutoMuteRenderCostLimit");
+
 	static const U32 ARC_BODY_PART_COST = 200;
 	static const U32 ARC_LIMIT = 20000;
 
@@ -8511,123 +8491,147 @@ void LLVOAvatar::idleUpdateRenderCost()
 		setDebugText(llformat("%.1f KB, %.2f m^2", mAttachmentGeometryBytes/1024.f, mAttachmentSurfaceArea));
 	}
 
-	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
+	if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME) && max_render_cost == 0)
 	{
 		return;
 	}
 
-	U32 cost = 0;
-	LLVOVolume::texture_cost_t textures;
-
-	for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+	if (mVisualComplexityStale)
 	{
-		const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
-		ETextureIndex tex_index = baked_dict->mTextureIndex;
-		if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
+		mVisualComplexityStale = FALSE;
+		U32 cost = 0;
+		LLVOVolume::texture_cost_t textures;
+
+		for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
 		{
-			if (isTextureVisible(tex_index))
+			const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
+			ETextureIndex tex_index = baked_dict->mTextureIndex;
+			if ((tex_index != TEX_SKIRT_BAKED) || (isWearingWearableType(LLWearableType::WT_SKIRT)))
 			{
-				cost +=ARC_BODY_PART_COST;
+				if (isTextureVisible(tex_index))
+				{
+					cost +=ARC_BODY_PART_COST;
+				}
 			}
 		}
-	}
 
 
-	for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); 
-		 iter != mAttachmentPoints.end();
-		 ++iter)
-	{
-		LLViewerJointAttachment* attachment = iter->second;
-		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
-			 attachment_iter != attachment->mAttachedObjects.end();
-			 ++attachment_iter)
+		for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); 
+			 iter != mAttachmentPoints.end();
+			 ++iter)
 		{
-			const LLViewerObject* attached_object = (*attachment_iter);
-			if (attached_object && !attached_object->isHUDAttachment())
+			LLViewerJointAttachment* attachment = iter->second;
+			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+				 attachment_iter != attachment->mAttachedObjects.end();
+				 ++attachment_iter)
 			{
-				textures.clear();
-				const LLDrawable* drawable = attached_object->mDrawable;
-				if (drawable)
+				const LLViewerObject* attached_object = (*attachment_iter);
+				if (attached_object && !attached_object->isHUDAttachment())
 				{
-					const LLVOVolume* volume = drawable->getVOVolume();
-					if (volume)
+					textures.clear();
+					const LLDrawable* drawable = attached_object->mDrawable;
+					if (drawable)
 					{
-						cost += volume->getRenderCost(textures);
-
-						const_child_list_t children = volume->getChildren();
-						for (const_child_list_t::const_iterator child_iter = children.begin();
-							  child_iter != children.end();
-							  ++child_iter)
+						const LLVOVolume* volume = drawable->getVOVolume();
+						if (volume)
 						{
-							LLViewerObject* child_obj = *child_iter;
-							LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
-							if (child)
+							cost += volume->getRenderCost(textures);
+
+							const_child_list_t children = volume->getChildren();
+							for (const_child_list_t::const_iterator child_iter = children.begin();
+								  child_iter != children.end();
+								  ++child_iter)
 							{
-								cost += child->getRenderCost(textures);
+								LLViewerObject* child_obj = *child_iter;
+								LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+								if (child)
+								{
+									cost += child->getRenderCost(textures);
+								}
 							}
-						}
 
-						for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
-						{
-							// add the cost of each individual texture in the linkset
-							cost += iter->second;
+							for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
+							{
+								// add the cost of each individual texture in the linkset
+								cost += iter->second;
+							}
 						}
 					}
 				}
 			}
-		}
 
-	}
+		}
 
 
 
-	// Diagnostic output to identify all avatar-related textures.
-	// Does not affect rendering cost calculation.
-	// Could be wrapped in a debug option if output becomes problematic.
-	if (isSelf())
-	{
-		// print any attachment textures we didn't already know about.
-		for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it)
+		// Diagnostic output to identify all avatar-related textures.
+		// Does not affect rendering cost calculation.
+		// Could be wrapped in a debug option if output becomes problematic.
+		if (isSelf())
 		{
-			LLUUID image_id = it->first;
-			if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
-				continue;
-			if (all_textures.find(image_id) == all_textures.end())
+			// print any attachment textures we didn't already know about.
+			for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it)
+			{
+				LLUUID image_id = it->first;
+				if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
+					continue;
+				if (all_textures.find(image_id) == all_textures.end())
+				{
+					// attachment texture not previously seen.
+					llinfos << "attachment_texture: " << image_id.asString() << llendl;
+					all_textures.insert(image_id);
+				}
+			}
+
+			// print any avatar textures we didn't already know about
+			for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
+				 iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
+				 ++iter)
 			{
-				// attachment texture not previously seen.
-				llinfos << "attachment_texture: " << image_id.asString() << llendl;
-				all_textures.insert(image_id);
+				const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
+				// TODO: MULTI-WEARABLE: handle multiple textures for self
+				const LLViewerTexture* te_image = getImage(iter->first,0);
+				if (!te_image)
+					continue;
+				LLUUID image_id = te_image->getID();
+				if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
+					continue;
+				if (all_textures.find(image_id) == all_textures.end())
+				{
+					llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl;
+					all_textures.insert(image_id);
+				}
 			}
 		}
 
-		// print any avatar textures we didn't already know about
-		for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin();
-			 iter != LLVOAvatarDictionary::getInstance()->getTextures().end();
-			 ++iter)
-		{
-			const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second;
-			// TODO: MULTI-WEARABLE: handle multiple textures for self
-			const LLViewerTexture* te_image = getImage(iter->first,0);
-			if (!te_image)
-				continue;
-			LLUUID image_id = te_image->getID();
-			if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR)
-				continue;
-			if (all_textures.find(image_id) == all_textures.end())
+		if (isSelf() && max_render_cost > 0 && mVisualComplexity != cost)
+		{ //pop up notification that you have exceeded a render cost limit
+			if (cost > max_render_cost+max_render_cost/2)
+			{
+				LLNotificationsUtil::add("ExceededHighDetailRenderCost");
+			}
+			else if (cost > max_render_cost)
 			{
-				llinfos << "local_texture: " << texture_dict->mName << ": " << image_id << llendl;
-				all_textures.insert(image_id);
+				LLNotificationsUtil::add("ExceededMidDetailRenderCost");
+			}
+			else if (cost > max_render_cost/2)
+			{
+				LLNotificationsUtil::add("ExceededLowDetailRenderCost");
 			}
 		}
+
+		mVisualComplexity = cost;
 	}
 
 	
-	std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus());
-	setDebugText(llformat("%s %d", viz_string.c_str(), cost));
-	mVisualComplexity = cost;
-	F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);
-	F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f);
-	mText->setColor(LLColor4(red,green,0,1));
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHAME))
+	{
+		std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus());
+		setDebugText(llformat("%s %d", viz_string.c_str(), mVisualComplexity));
+		F32 green = 1.f-llclamp(((F32) mVisualComplexity-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f);
+		F32 red = llmin((F32) mVisualComplexity/(F32)ARC_LIMIT, 1.f);
+		mText->setColor(LLColor4(red,green,0,1));
+	}
 }
 
 // static
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 1adb6809625ef16385e38874a1b142d661559eab..e6569c557c10f12bc54bc20dbca173609d56e329 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -252,6 +252,7 @@ class LLVOAvatar :
 	static void		invalidateNameTags();
 	void			addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);
 	void 			idleUpdateRenderCost();
+	void			updateVisualComplexity() { mVisualComplexityStale = TRUE; }
 	void 			idleUpdateBelowWater();
 
 	//--------------------------------------------------------------------
@@ -314,6 +315,7 @@ class LLVOAvatar :
 	BOOL			mFullyLoadedInitialized;
 	S32				mFullyLoadedFrameCounter;
 	S32				mVisualComplexity;
+	BOOL			mVisualComplexityStale;
 	LLFrameTimer	mFullyLoadedTimer;
 	LLFrameTimer	mRuthTimer;
 
@@ -437,7 +439,6 @@ class LLVOAvatar :
 	U32 		renderRigid();
 	U32 		renderSkinned(EAvatarRenderPass pass);
 	F32			getLastSkinTime() { return mLastSkinTime; }
-	U32			renderSkinnedAttachments();
 	U32 		renderTransparent(BOOL first_pass);
 	void 		renderCollisionVolumes();
 	static void	deleteCachedImages(bool clearAll=true);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c0f80cf8556f1298678ffb4c6085433e85f27e17..7adf18b6d0ea037f44466ae834573cf2ce453b20 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -99,6 +99,8 @@ static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
 static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
 static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures");
 
+extern BOOL gGLDebugLoggingEnabled;
+
 // Implementation class of LLMediaDataClientObject.  See llmediadataclient.h
 class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
 {
@@ -1067,7 +1069,9 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 					break;
 				}
 				volume->genBinormals(i);
+				//gGLDebugLoggingEnabled = TRUE;
 				LLFace::cacheFaceInVRAM(face);
+				//gGLDebugLoggingEnabled = FALSE;
 			}
 		}
 		
@@ -1116,6 +1120,12 @@ void LLVOVolume::notifyMeshLoaded()
 { 
 	mSculptChanged = TRUE;
 	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
+
+	LLVOAvatar* avatar = getAvatar();
+	if (avatar)
+	{
+		avatar->updateVisualComplexity();
+	}
 }
 
 // sculpt replaces generate() for sculpted surfaces
@@ -3836,10 +3846,13 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 	}
 
 	//build matrix palette
-	LLMatrix4a mp[64];
+	static const size_t kMaxJoints = 64;
+
+	LLMatrix4a mp[kMaxJoints];
 	LLMatrix4* mat = (LLMatrix4*) mp;
 	
-	for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+	U32 maxJoints = llmin(skin->mJointNames.size(), kMaxJoints);
+	for (U32 j = 0; j < maxJoints; ++j)
 	{
 		LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
 		if (joint)
@@ -3894,8 +3907,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons
 						F32 w = wght[k];
 
 						LLMatrix4a src;
-						src.setMul(mp[idx[k]], w);
-
+						// Insure ref'd bone is in our clamped array of mats
+						llassert(idx[k] < kMaxJoints);
+						// clamp k to kMaxJoints to avoid reading garbage off stack in release
+						src.setMul(mp[idx[(k < kMaxJoints) ? k : 0]], w);
 						final_mat.add(src);
 					}
 
@@ -4644,7 +4659,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		bump_mask |= LLVertexBuffer::MAP_BINORMAL;
 		genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE);
 		genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE);
-		genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE);
+		genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, FALSE);
 		genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE);
 	}
 	else
@@ -4830,6 +4845,16 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 
 	U32 buffer_usage = group->mBufferUsage;
 	
+	static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback");
+
+	if (use_transform_feedback &&
+		gTransformPositionProgram.mProgramObject && //transform shaders are loaded
+		buffer_usage == GL_DYNAMIC_DRAW_ARB && //target buffer is in VRAM
+		!(mask & LLVertexBuffer::MAP_WEIGHT4)) //TODO: add support for weights
+	{
+		buffer_usage = GL_DYNAMIC_COPY_ARB;
+	}
+
 #if LL_DARWIN
 	// HACK from Leslie:
 	// Disable VBO usage for alpha on Mac OS X because it kills the framerate
@@ -4889,6 +4914,8 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 	//NEVER use more than 16 texture index channels (workaround for prevalent driver bug)
 	texture_index_channels = llmin(texture_index_channels, 16);
 
+	bool flexi = false;
+
 	while (face_iter != faces.end())
 	{
 		//pull off next face
@@ -4915,6 +4942,8 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 		U32 index_count = facep->getIndicesCount();
 		U32 geom_count = facep->getGeomCount();
 
+		flexi = flexi || facep->getViewerObject()->getVolume()->isUnique();
+
 		//sum up vertices needed for this render batch
 		std::vector<LLFace*>::iterator i = face_iter;
 		++i;
@@ -4983,6 +5012,9 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 						}
 
 						++i;
+
+						flexi = flexi || facep->getViewerObject()->getVolume()->isUnique();
+
 						index_count += facep->getIndicesCount();
 						geom_count += facep->getGeomCount();
 
@@ -5012,8 +5044,16 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 					++i;
 					index_count += facep->getIndicesCount();
 					geom_count += facep->getGeomCount();
+
+					flexi = flexi || facep->getViewerObject()->getVolume()->isUnique();
+				}
 				}
 			}
+
+
+		if (flexi && buffer_usage && buffer_usage != GL_STREAM_DRAW_ARB)
+		{
+			buffer_usage = GL_STREAM_DRAW_ARB;
 		}
 
 		//create vertex buffer
diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp
index 376715a2d62605e1a94baa830b0df78c47d7ecba..548890b5b5d61ee24ea05f3835be25292a7a40d1 100644
--- a/indra/newview/llwaterparammanager.cpp
+++ b/indra/newview/llwaterparammanager.cpp
@@ -57,14 +57,6 @@
 
 #include "curl/curl.h"
 
-static LLStaticHashedString sCamPosLocal("camPosLocal");
-static LLStaticHashedString sWaterFogColor("waterFogColor");
-static LLStaticHashedString sWaterFogEnd("waterFogEnd");
-static LLStaticHashedString sWaterPlane("waterPlane");
-static LLStaticHashedString sWaterFogDensity("waterFogDensity");
-static LLStaticHashedString sWaterFogKS("waterFogKS");
-static LLStaticHashedString sDistanceMultiplier("distance_multiplier");
-
 LLWaterParamManager::LLWaterParamManager() :
 	mFogColor(22.f/255.f, 43.f/255.f, 54.f/255.f, 0.0f, 0.0f, "waterFogColor", "WaterFogColor"),
 	mFogDensity(4, "waterFogDensity", 2),
@@ -196,13 +188,11 @@ void LLWaterParamManager::updateShaderUniforms(LLGLSLShader * shader)
 	if (shader->mShaderGroup == LLGLSLShader::SG_WATER)
 	{
 		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, LLWLParamManager::getInstance()->getRotatedLightDir().mV);
-		shader->uniform3fv(sCamPosLocal, 1, LLViewerCamera::getInstance()->getOrigin().mV);
-		shader->uniform4fv(sWaterFogColor, 1, LLDrawPoolWater::sWaterFogColor.mV);
-		shader->uniform1f(sWaterFogEnd, LLDrawPoolWater::sWaterFogEnd);
-		shader->uniform4fv(sWaterPlane, 1, mWaterPlane.mV);
-		shader->uniform1f(sWaterFogDensity, getFogDensity());
-		shader->uniform1f(sWaterFogKS, mWaterFogKS);
-		shader->uniform1f(sDistanceMultiplier, 0);
+		shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, LLDrawPoolWater::sWaterFogColor.mV);
+		shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, mWaterPlane.mV);
+		shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, getFogDensity());
+		shader->uniform1f(LLShaderMgr::WATER_FOGKS, mWaterFogKS);
+		shader->uniform1f(LLViewerShaderMgr::DISTANCE_MULTIPLIER, 0);
 	}
 }
 
diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp
index 65cb80c3e7df6dbc0f16848ab9c105e1ef7f37fd..04d41a25126c9f8d486016917033b46f32d00e79 100644
--- a/indra/newview/llwlparammanager.cpp
+++ b/indra/newview/llwlparammanager.cpp
@@ -61,9 +61,6 @@
 #include "curl/curl.h"
 #include "llstreamtools.h"
 
-static LLStaticHashedString sCamPosLocal("camPosLocal");
-static LLStaticHashedString sSceneLightStrength("scene_light_strength");
-
 LLWLParamManager::LLWLParamManager() :
 
 	//set the defaults for the controls
@@ -355,7 +352,7 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader)
 	if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT)
 	{
 		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, mRotatedLightDir.mV);
-		shader->uniform3fv(sCamPosLocal, 1, LLViewerCamera::getInstance()->getOrigin().mV);
+		shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
 	} 
 
 	else if (shader->mShaderGroup == LLGLSLShader::SG_SKY)
@@ -363,7 +360,7 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader)
 		shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, mClampedLightDir.mV);
 	}
 
-	shader->uniform1f(sSceneLightStrength, mSceneLightStrength);
+	shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength);
 	
 }
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 92c5ac8583ef4aa8377d5c78bb925c79beaffc56..54a62a858a987462856a084f6930fd46c6a3570a 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -253,15 +253,15 @@ LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
 static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
 static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
 
-static LLStaticHashedString sTint("tint");
-static LLStaticHashedString sAmbiance("ambiance");
-static LLStaticHashedString sAlphaScale("alpha_scale");
-static LLStaticHashedString sNormMat("norm_mat");
-static LLStaticHashedString sOffset("offset");
-static LLStaticHashedString sScreenRes("screenRes");
-static LLStaticHashedString sDelta("delta");
-static LLStaticHashedString sDistFactor("dist_factor");
-static LLStaticHashedString sKern("kern");
+static LLStaticHashedString sTint("tint");
+static LLStaticHashedString sAmbiance("ambiance");
+static LLStaticHashedString sAlphaScale("alpha_scale");
+static LLStaticHashedString sNormMat("norm_mat");
+static LLStaticHashedString sOffset("offset");
+static LLStaticHashedString sScreenRes("screenRes");
+static LLStaticHashedString sDelta("delta");
+static LLStaticHashedString sDistFactor("dist_factor");
+static LLStaticHashedString sKern("kern");
 static LLStaticHashedString sKernScale("kern_scale");
 
 //----------------------------------------
@@ -7868,13 +7868,6 @@ 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);
-	
-	static LLStaticHashedString sNormMat("norm_mat");
-	if (shader.getUniformLocation(sNormMat) >= 0)
-	{
-		glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
-		shader.uniformMatrix4fv(sNormMat, 1, FALSE, norm_mat.m);
-	}
 }
 
 static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
@@ -7984,8 +7977,7 @@ void LLPipeline::renderDeferredLighting()
 				}
 
 				gDeferredSunProgram.uniform3fv(sOffset, slice, offset);
-				gDeferredSunProgram.uniform2f(sScreenRes, mDeferredLight.getWidth(), mDeferredLight.getHeight());
-				
+								
 				{
 					LLGLDisable blend(GL_BLEND);
 					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
@@ -10258,6 +10250,13 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		avatar->mImpostor.bindTarget();
 	}
 
+	F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha;
+
+	if (muted)
+	{ //disable alpha masking for muted avatars (get whole skin silhouette)
+		LLDrawPoolAvatar::sMinimumAlpha = 0.f;
+	}
+
 	if (LLPipeline::sRenderDeferred)
 	{
 		avatar->mImpostor.clear();
@@ -10272,6 +10271,8 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		renderGeom(camera);
 	}
 	
+	LLDrawPoolAvatar::sMinimumAlpha = old_alpha;
+		
 	{ //create alpha mask based on depth buffer (grey out if muted)
 		LLFastTimer t(FTM_IMPOSTOR_BACKGROUND);
 		if (LLPipeline::sRenderDeferred)
@@ -10285,6 +10286,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		if (muted)
 		{
 			gGL.setColorMask(true, true);
+
 		}
 		else
 		{
@@ -10303,14 +10305,24 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		gGL.pushMatrix();
 		gGL.loadIdentity();
 
-		static const F32 clip_plane = 0.99999f;
+		static const F32 clip_plane = 0.999f;
 
 		if (LLGLSLShader::sNoFixedFunction)
 		{
-			gUIProgram.bind();
+			gDebugProgram.bind();
 		}
 
-		gGL.color4ub(64,64,64,255);
+
+		if (LLMuteList::getInstance()->isMuted(avatar->getID()))
+		{ //grey muted avatar
+			gGL.diffuseColor4ub(64,64,64,255);
+		}
+		else
+		{ //blue visually muted avatar
+			gGL.diffuseColor4ub(72,61,139,255);
+		}
+
+		{
 		gGL.begin(LLRender::QUADS);
 		gGL.vertex3f(-1, -1, clip_plane);
 		gGL.vertex3f(1, -1, clip_plane);
@@ -10318,10 +10330,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		gGL.vertex3f(-1, 1, clip_plane);
 		gGL.end();
 		gGL.flush();
+		}
 
 		if (LLGLSLShader::sNoFixedFunction)
 		{
-			gUIProgram.unbind();
+			gDebugProgram.unbind();
 		}
 
 		gGL.popMatrix();
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 832e05a06fa6facbd3faeb938268023825a0fa77..fb530ef22d4acf8905d489627bcc6afb5f4d780b 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -202,6 +202,45 @@ Message Template [PATH] not found.
      yestext="OK"/>
   </notification>
 
+  <notification
+   icon="notify.tga"
+   name="ExceededHighDetailRenderCost"
+   persist="false"
+   type="alertmodal">
+    Your avatar has become too complex to be rendered by even high performance computers.  Almost all Residents will see a low detail stand in instead of your actual avatar.
+    <unique/>
+    <usetemplate
+     ignoretext="Avatar exceeded high detail complexity."
+     name="okignore"
+     yestext="Close"/>
+  </notification>
+
+  <notification
+   icon="notify.tga"
+   name="ExceededMidDetailRenderCost"
+   persist="false"
+   type="alertmodal">
+    Your avatar has become too complex to be rendered by most computers.  Many Residents will see a low detail stand in instead of your actual avatar.
+  <unique/>
+  <usetemplate
+   ignoretext="Avatar exceeded mid detail complexity."
+   name="okignore"
+   yestext="Close"/>
+</notification>
+
+  <notification
+ icon="notify.tga"
+ name="ExceededLowDetailRenderCost"
+ persist="false"
+ type="alertmodal">
+    Your avatar has become too complex to be rendered by some computers.  Some Residents will see a low detail stand in instead of your actual avatar.
+  <unique/>
+  <usetemplate
+   ignoretext="Avatar exceeded low detail complexity."
+   name="okignore"
+   yestext="Close"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="WearableSave"
@@ -9935,5 +9974,5 @@ An internal error prevented us from properly updating your viewer.  The L$ balan
    <tag>fail</tag>
 Cannot create large prims that intersect other players.  Please re-try when other players have moved.
   </notification>
-
+  
 </notifications>