diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 54294890757b01ea1381c9facc35b0219cb20685..81a97c766141ea86a14599c12ceab0e369dbcaca 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -216,6 +216,11 @@ PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL;
 PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL;
 PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
 
+// GL_ARB_timer_query
+PFNGLQUERYCOUNTERPROC glQueryCounter = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = NULL;
+
 // GL_ARB_point_parameters
 PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
 PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
@@ -421,6 +426,7 @@ LLGLManager::LLGLManager() :
 	mHasFragmentShader(FALSE),
 	mNumTextureImageUnits(0),
 	mHasOcclusionQuery(FALSE),
+	mHasTimerQuery(FALSE),
 	mHasOcclusionQuery2(FALSE),
 	mHasPointParameters(FALSE),
 	mHasDrawBuffers(FALSE),
@@ -956,6 +962,7 @@ void LLGLManager::initExtensions()
 	mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts);
 	mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
 	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
+	mHasTimerQuery = ExtensionExists("GL_ARB_timer_query", gGLHExts.mSysExts);
 	mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
 	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
 	mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts);
@@ -1271,6 +1278,13 @@ void LLGLManager::initExtensions()
 		glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB");
 		glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB");
 	}
+	if (mHasTimerQuery)
+	{
+		llinfos << "initExtensions() TimerQuery-related procs..." << llendl;
+		glQueryCounter = (PFNGLQUERYCOUNTERPROC) GLH_EXT_GET_PROC_ADDRESS("glQueryCounter");
+		glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjecti64v");
+		glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectui64v");
+	}
 	if (mHasPointParameters)
 	{
 		llinfos << "initExtensions() PointParameters-related procs..." << llendl;
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 767d49cbf2c92723dc6e19b423e9f08c3064482a..60597fd090943c42d6a8eeaaf38a216eb55aac5a 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -98,6 +98,7 @@ class LLGLManager
 	BOOL mHasFragmentShader;
 	S32  mNumTextureImageUnits;
 	BOOL mHasOcclusionQuery;
+	BOOL mHasTimerQuery;
 	BOOL mHasOcclusionQuery2;
 	BOOL mHasPointParameters;
 	BOOL mHasDrawBuffers;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 509de51f4dfc4261ab7c22cf47cb817288dbd189..dace57295350d382d548ca6d50f605ff084ca259 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -116,6 +116,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
 extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
 extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
 
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
 // GL_ARB_point_parameters
 extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
 extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
@@ -378,6 +383,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
 extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
 extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
 
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
 // GL_ARB_point_parameters
 extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
 extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
@@ -619,6 +629,12 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
 extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
 extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
 
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
+
 // GL_ARB_point_parameters
 extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
 extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 39ad9b9e9b4c6808d6034a53e08f82f5e98e83fe..2c6bcdfe0047200a85e0872f6ea8edfd2b21ae39 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -53,6 +53,12 @@ GLhandleARB LLGLSLShader::sCurBoundShader = 0;
 LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
 S32 LLGLSLShader::sIndexedTextureChannels = 0;
 bool LLGLSLShader::sNoFixedFunction = false;
+bool LLGLSLShader::sProfileEnabled = false;
+std::set<LLGLSLShader*> LLGLSLShader::sInstances;
+U64 LLGLSLShader::sTotalTimeElapsed = 0;
+U32 LLGLSLShader::sTotalTrianglesDrawn = 0;
+U64 LLGLSLShader::sTotalSamplesDrawn = 0;
+U32 LLGLSLShader::sTotalDrawCalls = 0;
 
 //UI shader -- declared here so llui_libtest will link properly
 LLGLSLShader	gUIProgram;
@@ -87,19 +93,184 @@ LLShaderFeatures::LLShaderFeatures()
 //===============================
 // LLGLSL Shader implementation
 //===============================
+
+//static
+void LLGLSLShader::initProfile()
+{
+	sProfileEnabled = true;
+	sTotalTimeElapsed = 0;
+	sTotalTrianglesDrawn = 0;
+	sTotalSamplesDrawn = 0;
+	sTotalDrawCalls = 0;
+
+	for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+	{
+		(*iter)->clearStats();
+	}
+}
+
+
+//static
+void LLGLSLShader::finishProfile()
+{
+	sProfileEnabled = false;
+
+	std::vector<LLGLSLShader*> sorted;
+
+	for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+	{
+		sorted.push_back(*iter);
+	}
+
+	struct comp_func
+	{
+		bool operator()(const LLGLSLShader* const& lhs, const LLGLSLShader* const& rhs)
+		{
+			return lhs->mTimeElapsed < rhs->mTimeElapsed;
+		}
+	} func;
+
+	std::sort(sorted.begin(), sorted.end(), func);
+
+	for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
+	{
+		(*iter)->dumpStats();
+	}
+
+	llinfos << "-----------------------------------" << llendl;
+	llinfos << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed/1000000.f) << llendl;
+	llinfos << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn/1000000.f) << llendl;
+	llinfos << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn/1000000.f) << llendl;
+}
+
+void LLGLSLShader::clearStats()
+{
+	mTrianglesDrawn = 0;
+	mTimeElapsed = 0;
+	mSamplesDrawn = 0;
+	mDrawCalls = 0;
+}
+
+void LLGLSLShader::dumpStats()
+{
+	if (mDrawCalls > 0)
+	{
+		llinfos << "=============================================" << llendl;
+		llinfos << mName << llendl;
+		for (U32 i = 0; i < mShaderFiles.size(); ++i)
+		{
+			llinfos << mShaderFiles[i].first << llendl;
+		}
+		llinfos << "=============================================" << llendl;
+
+		F32 ms = mTimeElapsed/1000000.f;
+		F32 seconds = ms/1000.f;
+
+		F32 pct_tris = (F32) mTrianglesDrawn/(F32)sTotalTrianglesDrawn*100.f;
+		F32 tris_sec = (F32) (mTrianglesDrawn/1000000.0);
+		tris_sec /= seconds;
+
+		F32 pct_samples = (F32) ((F64)mSamplesDrawn/(F64)sTotalSamplesDrawn)*100.f;
+		F32 samples_sec = (F32) mSamplesDrawn/1000000000.0;
+		samples_sec /= seconds;
+
+		F32 pct_calls = (F32) mDrawCalls/(F32)sTotalDrawCalls*100.f;
+		U32 avg_batch = mTrianglesDrawn/mDrawCalls;
+
+		llinfos << "Triangles Drawn: " << mTrianglesDrawn <<  " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec ) << llendl;
+		llinfos << "Draw Calls: " << mDrawCalls << " " << llformat("(%.2f pct of total, avg %d tris/call)", pct_calls, avg_batch) << llendl;
+		llinfos << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << llendl;
+		llinfos << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32) ((F64)mTimeElapsed/(F64)sTotalTimeElapsed)*100.f, ms) << llendl;
+	}
+}
+
+//static
+void LLGLSLShader::startProfile()
+{
+	if (sProfileEnabled && sCurBoundShaderPtr)
+	{
+		sCurBoundShaderPtr->placeProfileQuery();
+	}
+
+}
+
+//static
+void LLGLSLShader::stopProfile(U32 count, U32 mode)
+{
+	if (sProfileEnabled)
+	{
+		sCurBoundShaderPtr->readProfileQuery(count, mode);
+	}
+}
+
+void LLGLSLShader::placeProfileQuery()
+{
+	if (mTimerQuery == 0)
+	{
+		glGenQueriesARB(1, &mTimerQuery);
+	}
+
+	glBeginQueryARB(GL_SAMPLES_PASSED, 1);
+	glBeginQueryARB(GL_TIME_ELAPSED, mTimerQuery);
+}
+
+void LLGLSLShader::readProfileQuery(U32 count, U32 mode)
+{
+	glEndQueryARB(GL_TIME_ELAPSED);
+	glEndQueryARB(GL_SAMPLES_PASSED);
+	
+	U64 time_elapsed = 0;
+	glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT, &time_elapsed);
+
+	U64 samples_passed = 0;
+	glGetQueryObjectui64v(1, GL_QUERY_RESULT, &samples_passed);
+
+	sTotalTimeElapsed += time_elapsed;
+	mTimeElapsed += time_elapsed;
+
+	sTotalSamplesDrawn += samples_passed;
+	mSamplesDrawn += samples_passed;
+
+	U32 tri_count = 0;
+	switch (mode)
+	{
+		case LLRender::TRIANGLES: tri_count = count/3; break;
+		case LLRender::TRIANGLE_FAN: tri_count = count-2; break;
+		case LLRender::TRIANGLE_STRIP: tri_count = count-2; break;
+		default: tri_count = count; break; //points lines etc just use primitive count
+	}
+
+	mTrianglesDrawn += tri_count;
+	sTotalTrianglesDrawn += tri_count;
+
+	sTotalDrawCalls++;
+	mDrawCalls++;
+}
+
+
+
 LLGLSLShader::LLGLSLShader()
 	: mProgramObject(0), 
 	  mAttributeMask(0),
+	  mTotalUniformSize(0),
 	  mActiveTextureChannels(0), 
 	  mShaderLevel(0), 
 	  mShaderGroup(SG_DEFAULT), 
-	  mUniformsDirty(FALSE)
+	  mUniformsDirty(FALSE),
+	  mTimerQuery(0)
 {
+	
+}
 
+LLGLSLShader::~LLGLSLShader()
+{
+	
 }
 
 void LLGLSLShader::unload()
 {
+	sInstances.erase(this);
+
 	stop_glerror();
 	mAttribute.clear();
 	mTexture.clear();
@@ -138,6 +309,8 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 								U32 varying_count,
 								const char** varyings)
 {
+	sInstances.insert(this);
+
 	//reloading, reset matrix hash values
 	for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
 	{
@@ -333,11 +506,54 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
 
 	GLenum type;
 	GLsizei length;
-	GLint size;
+	GLint size = -1;
 	char name[1024];		/* Flawfinder: ignore */
 	name[0] = 0;
 
+
 	glGetActiveUniformARB(mProgramObject, index, 1024, &length, &size, &type, (GLcharARB *)name);
+	if (size > 0)
+	{
+		switch(type)
+		{
+			case GL_FLOAT_VEC2: size *= 2; break;
+			case GL_FLOAT_VEC3: size *= 3; break;
+			case GL_FLOAT_VEC4: size *= 4; break;
+			case GL_DOUBLE: size *= 2; break;
+			case GL_DOUBLE_VEC2: size *= 2; break;
+			case GL_DOUBLE_VEC3: size *= 6; break;
+			case GL_DOUBLE_VEC4: size *= 8; break;
+			case GL_INT_VEC2: size *= 2; break;
+			case GL_INT_VEC3: size *= 3; break;
+			case GL_INT_VEC4: size *= 4; break;
+			case GL_UNSIGNED_INT_VEC2: size *= 2; break;
+			case GL_UNSIGNED_INT_VEC3: size *= 3; break;
+			case GL_UNSIGNED_INT_VEC4: size *= 4; break;
+			case GL_BOOL_VEC2: size *= 2; break;
+			case GL_BOOL_VEC3: size *= 3; break;
+			case GL_BOOL_VEC4: size *= 4; break;
+			case GL_FLOAT_MAT2: size *= 4; break;
+			case GL_FLOAT_MAT3: size *= 9; break;
+			case GL_FLOAT_MAT4: size *= 16; break;
+			case GL_FLOAT_MAT2x3: size *= 6; break;
+			case GL_FLOAT_MAT2x4: size *= 8; break;
+			case GL_FLOAT_MAT3x2: size *= 6; break;
+			case GL_FLOAT_MAT3x4: size *= 12; break;
+			case GL_FLOAT_MAT4x2: size *= 8; break;
+			case GL_FLOAT_MAT4x3: size *= 12; break;
+			case GL_DOUBLE_MAT2: size *= 8; break;
+			case GL_DOUBLE_MAT3: size *= 18; break;
+			case GL_DOUBLE_MAT4: size *= 32; break;
+			case GL_DOUBLE_MAT2x3: size *= 12; break;
+			case GL_DOUBLE_MAT2x4: size *= 16; break;
+			case GL_DOUBLE_MAT3x2: size *= 12; break;
+			case GL_DOUBLE_MAT3x4: size *= 24; break;
+			case GL_DOUBLE_MAT4x2: size *= 16; break;
+			case GL_DOUBLE_MAT4x3: size *= 24; break;
+		}
+		mTotalUniformSize += size;
+	}
+
 	S32 location = glGetUniformLocationARB(mProgramObject, name);
 	if (location != -1)
 	{
@@ -408,6 +624,7 @@ BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms)
 {
 	BOOL res = TRUE;
 	
+	mTotalUniformSize = 0;
 	mActiveTextureChannels = 0;
 	mUniform.clear();
 	mUniformMap.clear();
@@ -431,6 +648,7 @@ BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms)
 
 	unbind();
 
+	LL_DEBUGS("ShaderLoading") << "Total Uniform Size: " << mTotalUniformSize << llendl;
 	return res;
 }
 
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 725a7e2573f0425ecf4ab55d37dc61ecf4de4fa0..d67ece018f2f9b3624c373168c40133688aa3585 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -67,14 +67,29 @@ class LLGLSLShader
 		SG_WATER
 	};
 	
+	static std::set<LLGLSLShader*> sInstances;
+	static bool sProfileEnabled;
+
 	LLGLSLShader();
+	~LLGLSLShader();
 
 	static GLhandleARB sCurBoundShader;
 	static LLGLSLShader* sCurBoundShaderPtr;
 	static S32 sIndexedTextureChannels;
 	static bool sNoFixedFunction;
 
+	static void initProfile();
+	static void finishProfile();
+
+	static void startProfile();
+	static void stopProfile(U32 count, U32 mode);
+
 	void unload();
+	void clearStats();
+	void dumpStats();
+	void placeProfileQuery();
+	void readProfileQuery(U32 count, U32 mode);
+
 	BOOL createShader(std::vector<std::string> * attributes,
 						std::vector<std::string> * uniforms,
 						U32 varying_count = 0,
@@ -157,6 +172,7 @@ class LLGLSLShader
 	std::map<std::string, GLint> mUniformMap;  //lookup map of uniform name to uniform location
 	std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value
 	std::vector<GLint> mTexture;
+	S32 mTotalUniformSize;
 	S32 mActiveTextureChannels;
 	S32 mShaderLevel;
 	S32 mShaderGroup;
@@ -165,6 +181,17 @@ class LLGLSLShader
 	std::vector< std::pair< std::string, GLenum > > mShaderFiles;
 	std::string mName;
 	boost::unordered_map<std::string, std::string> mDefines;
+
+	//statistcis for profiling shader performance
+	U32 mTimerQuery;
+	U64 mTimeElapsed;
+	static U64 sTotalTimeElapsed;
+	U32 mTrianglesDrawn;
+	static U32 sTotalTrianglesDrawn;
+	U64 mSamplesDrawn;
+	static U64 sTotalSamplesDrawn;
+	U32 mDrawCalls;
+	static U32 sTotalDrawCalls;
 };
 
 //UI shader (declared here so llui_libtest will link properly)
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 29fe5400a3b4597c8617aa8cd3007c6d161f3731..6108c6f8213537f091e71f9c2b38f49f53c122dd 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -613,8 +613,9 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con
 		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
 		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
 	}
-
+	LLGLSLShader::startProfile();
 	glDrawArrays(sGLMode[mode], 0, count);
+	LLGLSLShader::stopProfile(count, mode);
 }
 
 //static
@@ -651,7 +652,9 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
 		glVertexPointer(3, GL_FLOAT, 16, pos);
 	}
 
+	LLGLSLShader::startProfile();
 	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+	LLGLSLShader::stopProfile(num_indices, mode);
 }
 
 void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
@@ -751,9 +754,14 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 	U16* idx = ((U16*) getIndicesPointer())+indices_offset;
 
 	stop_glerror();
+	LLGLSLShader::startProfile();
 	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
 		idx);
+	LLGLSLShader::stopProfile(count, mode);
 	stop_glerror();
+
+	
+
 	placeFence();
 }
 
@@ -797,8 +805,10 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 	}
 
 	stop_glerror();
+	LLGLSLShader::startProfile();
 	glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
 		((U16*) getIndicesPointer()) + indices_offset);
+	LLGLSLShader::stopProfile(count, mode);
 	stop_glerror();
 	placeFence();
 }
@@ -838,7 +848,9 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 	}
 
 	stop_glerror();
+	LLGLSLShader::startProfile();
 	glDrawArrays(sGLMode[mode], first, count);
+	LLGLSLShader::stopProfile(count, mode);
 	stop_glerror();
 	placeFence();
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
index 81961d7746053e0ebcb9570583b10b7423df5495..3f90600acefdc2d5915284c7243bee9cd8f13598 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
@@ -39,7 +39,12 @@ void main()
 	mat = modelview_matrix * mat;
 	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
 	
+
 	vec4 p = projection_matrix * vec4(pos, 1.0);
+#if !DEPTH_CLAMP
 	p.z = max(p.z, -p.w+0.01);
 	gl_Position = p;
+#else
+	gl_Position = p;
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
index 3686f2f647cedf8f932f2bdf4811a3fa4501423b..b809b73973bdf813d0401694bf350674e4074df2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
@@ -31,12 +31,16 @@ out vec4 frag_color;
 
 uniform sampler2D diffuseMap;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main() 
 {
 	frag_color = vec4(1,1,1,1);
 
+#if !DEPTH_CLAMP
 	gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0);
+#endif
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
index 23feb09d7233b8dea4a042712593574f06ff5b2e..bde1ad4e9f81cf70517257024554dd98fc0d33e9 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
@@ -31,7 +31,9 @@ ATTRIBUTE vec3 position;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main()
 {
@@ -51,9 +53,13 @@ void main()
 	norm = normalize(norm);
 	
 	pos = projection_matrix * pos;
+#if !DEPTH_CLAMP
 	post_pos = pos;
 
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 }
 
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
index 40b980bf5172c6db9d57aa9cd405431475e98629..a2c3ec3355ce16d531995a2aea881ba92c870332 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
@@ -46,7 +46,7 @@ void main()
 
 	frag_data[0] = vec4(col, 0.0);
 	frag_data[1] = vertex_color.aaaa; // spec
-	//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
+	frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
 	vec3 nvn = normalize(vary_normal);
 	frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 76d29b1df7dce0986ccdbe508f33cd13a42b1fdd..3c026796c8b3a7fdd9e8df4076dfbc3561c12218 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -47,6 +47,6 @@ void main()
 	
 	passTextureIndex();
 	vary_normal = normalize(normal_matrix * normal);
-
+	
 	vertex_color = diffuse_color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 5329ae9dd7217710b876608257960a69bbdedad6..3bd433c283700f41b4cc2dd2b5e06968c8e12d1a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -127,9 +127,9 @@ void main()
 			
 			dist_atten *= noise;
 
-			float lit = da * dist_atten;
+			float lit = pow(da, 0.7) * dist_atten;
 
-			lit = pow(lit,0.7);
+			
 						
 			vec3 col = light_col[i].rgb*lit*diff;
 			
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
index 9746218ea6cd5a541d5d6addecd84bfba58923a0..959a85330ea6a555c284f09b97cdb1f07652fe8a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
@@ -201,9 +201,7 @@ void main()
 		
 			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
 			
-			lit = da * dist_atten * noise;
-
-			lit = pow(lit, 0.7);
+			lit = pow(da, 0.7) * dist_atten * noise;
 			
 			col = lcol*lit*diff_tex;
 			amb_da += (da*0.5)*proj_ambiance;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index 27863b00952368278636cc7e0a596198e063ea58..6976fc7bd9d219bc236de8b01d8ef443dcea21cf 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -111,10 +111,8 @@ void main()
 	vec3 col = texture2DRect(diffuseRect, frag.xy).rgb;
 	float fa = falloff+1.0;
 	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
-	float lit = da * dist_atten * noise;
+	float lit = pow(da, 0.7) * dist_atten * noise;
 	
-	lit = pow(lit, 0.7);
-
 	col = color.rgb*lit*col;
 
 	vec4 spec = texture2DRect(specularRect, frag.xy);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl
index bced4a557774cc6cc9037e43ea7097f0cba3a7a1..91a96977f06c15dd306fdf64d8360b7bae9c4e70 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl
@@ -31,8 +31,12 @@ out vec4 frag_color;
 
 uniform sampler2D diffuseMap;
 
+#if !DEPTH_CLAMP
 VARYING float pos_zd2;
+#endif
+
 VARYING float pos_w;
+
 VARYING float target_pos_x;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
@@ -56,5 +60,7 @@ void main()
 
 	frag_color = vec4(1,1,1,1);
 	
+#if !DEPTH_CLAMP
 	gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0);
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl
index c1f2d90712c42b0ba81a40b23a759b0122672ccb..11411a605c69d04774360a525579aae4d5e449a6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl
@@ -31,8 +31,12 @@ ATTRIBUTE vec3 position;
 ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec2 texcoord0;
 
+#if !DEPTH_CLAMP
 VARYING float pos_zd2;
+#endif
+
 VARYING float pos_w;
+
 VARYING float target_pos_x;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
@@ -45,10 +49,16 @@ void main()
 	vec4 pre_pos = vec4(position.xyz, 1.0);
 	vec4 pos = modelview_projection_matrix * pre_pos;
 	target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x;
+
 	pos_w = pos.w;
+
+#if !DEPTH_CLAMP
 	pos_zd2 = pos.z * 0.5;
 	
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 	
 	passTextureIndex();
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
index 6195e2f1ecb30ff4d115595edae972e96f673184..ef153dfc5be3d3cb92838d8efdd1c72ea1d9ba47 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
@@ -27,7 +27,9 @@ uniform mat4 modelview_projection_matrix;
 
 ATTRIBUTE vec3 position;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 uniform vec3 box_center;
 uniform vec3 box_size;
@@ -37,8 +39,12 @@ void main()
 	//transform vertex
 	vec3 p = position*box_size+box_center;
 	vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0);
-	
+
+#if !DEPTH_CLAMP
 	post_pos = pos;
-	
+
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
index 7e55fdc12a4bf5f943c3b6c930298e3647a4ed17..3d1b1828755a2a5e54723efa9c6f32f078e415d1 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
@@ -29,11 +29,16 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main() 
 {
 	frag_color = vec4(1,1,1,1);
 	
+#if !DEPTH_CLAMP
 	gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0);
+#endif
+
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
index 8b46e81f90c03a12ed5d3b4ade3cf217c920d5db..cc77a4cea059729e64d2c67cefc9cb5032c8cb48 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
@@ -27,14 +27,20 @@ uniform mat4 modelview_projection_matrix;
 
 ATTRIBUTE vec3 position;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 pos = modelview_projection_matrix*vec4(position.xyz, 1.0);
 	
+#if !DEPTH_CLAMP
 	post_pos = pos;
-	
+
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
index d7f0ab6d8e9742a895c24339985446ff1852e262..918cdce040c6f07c9f93107485abc0d407a836d9 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -204,9 +204,7 @@ void main()
 		
 			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
 			
-			lit = da * dist_atten * noise;
-			
-			lit = pow(lit, 0.7);
+			lit = pow(da, 0.7) * dist_atten * noise;
 
 			col = lcol*lit*diff_tex;
 			amb_da += (da*0.5)*proj_ambiance;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
index b3ab8fd5109eda911c20f219051ed416554eece1..90b6856c5c89f1662a563f622b5568d5bfda2270 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -213,9 +213,7 @@ void main()
 		
 			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
 			
-			lit = da * dist_atten * noise;
-			
-			lit = pow(lit, 0.7);
+			lit = pow(da,0.7) * dist_atten * noise;
 
 			col = lcol*lit*diff_tex*shadow;
 			amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
index 43fc5dbc5ec2c58d0f7c0691961411df4f8c9911..5fd6f0afb70b3273aca7f0d047a8318451a47709 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -214,9 +214,7 @@ void main()
 		
 			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
 			
-			lit = da * dist_atten * noise;
-			
-			lit = pow(lit, 0.7);
+			lit = pow(da, 0.7) * dist_atten * noise;
 
 			col = lcol*lit*diff_tex*shadow;
 			amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index f42586c71535ad3348d8e3289634cd833eccbb5e..f6e282ad87bdcd1ae879c281f3ab681ab156bc61 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -89,7 +89,7 @@ class LLOcclusionQueryPool : public LLGLNamePool
 public:
 	LLOcclusionQueryPool()
 	{
-		mCurQuery = 1;
+		mCurQuery = 2; //1 is reserved for LLGLSLShader
 	}
 
 protected:
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index abeef7097ac57019474cc9d944df42862e0452f6..1e5c5097ea6d675fdf0e9684146e480076a122b6 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -98,6 +98,7 @@ BOOL gDepthDirty = FALSE;
 BOOL gResizeScreenTexture = FALSE;
 BOOL gWindowResized = FALSE;
 BOOL gSnapshot = FALSE;
+BOOL gShaderProfileFrame = FALSE;
 
 U32 gRecentFrameCount = 0; // number of 'recent' frames
 LLFrameTimer gRecentFPSTime;
@@ -340,6 +341,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		return;
 	}
 
+
+	if (gShaderProfileFrame)
+	{
+		LLGLSLShader::initProfile();
+	}
+
 	//LLGLState::verify(FALSE);
 
 	/////////////////////////////////////////////////
@@ -1018,6 +1025,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
 
 	gShiftFrame = false;
+
+	if (gShaderProfileFrame)
+	{
+		gShaderProfileFrame = FALSE;
+		LLGLSLShader::finishProfile();
+	}
 }
 
 void render_hud_attachments()
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 84f6248a819853c478f665ba7afe4f9c5c80cd61..2735e908cde30c5c36c49376400a6405f6899608 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -147,6 +147,8 @@ void handle_test_load_url(void*);
 //extern BOOL gDebugAvatarRotation;
 extern BOOL gDebugClicks;
 extern BOOL gDebugWindowProc;
+extern BOOL gShaderProfileFrame;
+
 //extern BOOL gDebugTextEditorTips;
 //extern BOOL gDebugSelectMgr;
 
@@ -7038,6 +7040,15 @@ class LLAdvancedClickRenderShadowOption: public view_listener_t
 	}
 };
 
+class LLAdvancedClickRenderProfile: public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		gShaderProfileFrame = TRUE;
+		return true;
+	}
+};
+
 void menu_toggle_attached_lights(void* user_data)
 {
 	LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
@@ -8473,7 +8484,7 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles");
 	view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption");
 	view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption");
-	
+	view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
 
 	#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
 	view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index ce066d85f1d62e4003bb9a2a32a3ea74cae36866..ff66828e67939bd7bc71db39aa000f2e0b1fd4cd 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -1477,6 +1477,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		success = gDeferredShadowProgram.createShader(NULL, NULL);
 	}
 
@@ -1486,6 +1487,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredShadowCubeProgram.mShaderFiles.clear();
 		gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowCubeV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShadowCubeProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredShadowCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredShadowCubeProgram.createShader(NULL, NULL);
 	}
@@ -1497,6 +1499,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredShadowAlphaMaskProgram.mShaderFiles.clear();
 		gDeferredShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredShadowAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredShadowAlphaMaskProgram.createShader(NULL, NULL);
 	}
@@ -1508,6 +1511,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarShadowProgram.mShaderFiles.clear();
 		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.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredAvatarShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredAvatarShadowProgram.createShader(NULL, &mAvatarUniforms);
 	}
@@ -1519,6 +1523,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAttachmentShadowProgram.mShaderFiles.clear();
 		gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAttachmentShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredAttachmentShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredAttachmentShadowProgram.createShader(NULL, NULL);
 	}
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 6687ce432fadaade4b53250b167e49d369312cf5..3d9c4c59b39a2c0930d54492cd39663d4d9ed80d 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -1085,132 +1085,6 @@ void LLVOTree::calcNumVerts(U32& vert_count, U32& index_count, S32 trunk_LOD, S3
 	}
 }
 
-U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha)
-{
-	U32 ret = 0;
-	//
-	//  Draws a tree by recursing, drawing branches and then a 'leaf' texture.
-	//  If stop_level = -1, simply draws the whole tree as a billboarded texture
-	//
-	
-	static F32 constant_twist;
-	static F32 width = 0;
-
-	//F32 length = ((scale == 1.f)? mTrunkLength:mBranchLength);
-	//F32 aspect = ((scale == 1.f)? mTrunkAspect:mBranchAspect);
-	F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength);
-	F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect);
-	
-	constant_twist = 360.f/branches;
-
-	if (!LLPipeline::sReflectionRender && stop_level >= 0)
-	{
-		//
-		//  Draw the tree using recursion
-		//
-		if (depth > stop_level)
-		{
-			{
-				llassert(sLODIndexCount[trunk_LOD] > 0);
-				width = scale * length * aspect;
-				LLMatrix4 scale_mat;
-				scale_mat.mMatrix[0][0] = width;
-				scale_mat.mMatrix[1][1] = width;
-				scale_mat.mMatrix[2][2] = scale*length;
-				scale_mat *= matrix;
-
-				gGL.loadMatrix((F32*) scale_mat.mMatrix);
-				gGL.syncMatrices();
- 				glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_SHORT, indicesp + sLODIndexOffset[trunk_LOD]);
-				gPipeline.addTrianglesDrawn(LEAF_INDICES);
-				stop_glerror();
-				ret += sLODIndexCount[trunk_LOD];
-			}
-			
-			// Recurse to create more branches
-			for (S32 i=0; i < (S32)branches; i++) 
-			{
-				LLMatrix4 trans_mat;
-				trans_mat.setTranslation(0,0,scale*length);
-				trans_mat *= matrix;
-
-				LLQuaternion rot = 
-					LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
-					LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
-					LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
-				
-				LLMatrix4 rot_mat(rot);
-				rot_mat *= trans_mat;
-
-				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
-			}
-			//  Recurse to continue trunk
-			if (trunk_depth)
-			{
-				LLMatrix4 trans_mat;
-				trans_mat.setTranslation(0,0,scale*length);
-				trans_mat *= matrix;
-
-				LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
-				rot_mat *= trans_mat; // rotate a bit around Z when ascending 
-				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
-			}
-		}
-		else
-		{
-			//
-			//  Draw leaves as two 90 deg crossed quads with leaf textures
-			//
-			{
-				LLMatrix4 scale_mat;
-				scale_mat.mMatrix[0][0] = 
-					scale_mat.mMatrix[1][1] =
-					scale_mat.mMatrix[2][2] = scale*mLeafScale;
-
-				scale_mat *= matrix;
-
-			
-				gGL.loadMatrix((F32*) scale_mat.mMatrix);
-				gGL.syncMatrices();
-				glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
-				gPipeline.addTrianglesDrawn(LEAF_INDICES);							
-				stop_glerror();
-				ret += LEAF_INDICES;
-			}
-		}
-	}
-	else
-	{
-		//
-		//  Draw the tree as a single billboard texture 
-		//
-
-		LLMatrix4 scale_mat;
-		scale_mat.mMatrix[0][0] = 
-			scale_mat.mMatrix[1][1] =
-			scale_mat.mMatrix[2][2] = mBillboardScale*mBillboardRatio;
-
-		scale_mat *= matrix;
-	
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.translatef(0.0, -0.5, 0.0);
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-					
-		gGL.loadMatrix((F32*) scale_mat.mMatrix);
-		gGL.syncMatrices();
-		glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
-		gPipeline.addTrianglesDrawn(LEAF_INDICES);
-		stop_glerror();
-		ret += LEAF_INDICES;
-
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.loadIdentity();
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-	}
-
-	return ret;
-}
-
 void LLVOTree::updateRadius()
 {
 	if (mDrawable.isNull())
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index 52debc85abcc6ce86317df93e3f12b8ed62d188b..2a7eb2123859a257d4914bd7b26e9fdc405b5756 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -104,10 +104,7 @@ class LLVOTree : public LLViewerObject
 								 F32 twist, 
 								 F32 droop,  
 								 F32 branches, 
-								 F32 alpha);
-
-	U32 drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha);
- 
+								 F32 alpha); 
 
 	 /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
 										  S32 face = -1,                        // which face to check, -1 = ALL_SIDES
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 89df61919eec1cd86911ec940054fe8e5c98ebce..c074a0e16ec85f84171f25d2bcbbbaa999219cb4 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -9023,6 +9023,9 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
 	LLGLEnable cull(GL_CULL_FACE);
 
+	//enable depth clamping if available
+	LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
+
 	if (use_shader)
 	{
 		gDeferredShadowCubeProgram.bind();
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 5af02a238f65632ef766773cfc1b30f76e3cba84..364c1df999e53251edc9e40980f9f3aa44b3eee8 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2359,6 +2359,12 @@
                 <menu_item_check.on_click
                  function="Advanced.ToggleFrameTest" />
             </menu_item_check>
+          <menu_item_call
+             label="Frame Profile"
+             name="Frame Profile">
+            <menu_item_call.on_click
+             function="Advanced.ClickRenderProfile" />
+          </menu_item_call>
         </menu>
       <menu
         create_jump_keys="true"