diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 35620bb6568963985a8546aad582b9af2a1bfe92..1c50a51d024e56290ca42afda685f5b90848d3cd 100755
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -717,7 +717,14 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms)
 
 BOOL LLGLSLShader::link(BOOL suppress_errors)
 {
-	return LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
+	BOOL success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors);
+
+	if (!suppress_errors)
+	{
+        LLShaderMgr::instance()->dumpObjectLog(mProgramObject, !success, mName);
+	}
+
+	return success;
 }
 
 void LLGLSLShader::bind()
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index d230574752d9aed6ef373aabb5c1b2f908772799..6e04fc82dfd1f396db0c59b44ee51a0d93df853e 100755
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -505,9 +505,25 @@ static std::string get_object_log(GLhandleARB ret)
 	return res;
 }
 
-void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) 
+void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string& filename) 
 {
 	std::string log = get_object_log(ret);
+
+	if (log.length() > 0 || warns)
+	{
+		if (!filename.empty())
+		{
+			if (warns)
+			{
+				LL_WARNS("ShaderLoading") << "From " << filename << ":" << LL_ENDL;
+			}
+			else
+			{
+				LL_INFOS("ShaderLoading") << "From " << filename << ":" << LL_ENDL;
+			}
+		}
+	}
+
 	if ( log.length() > 0 )
 	{
 		if (warns)
@@ -558,7 +574,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 		file = LLFile::fopen(fname.str(), "r");		/* Flawfinder: ignore */
 		if (file)
 		{
-			LL_INFOS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL;
+			LL_DEBUGS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL;
 			break; // done
 		}
 	}
@@ -812,8 +828,8 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 			if (error != GL_NO_ERROR || success == GL_FALSE) 
 			{
 				//an error occured, print log
-				LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
-				dumpObjectLog(ret);
+				LL_WARNS("ShaderLoading") << "GLSL Compilation Error:" << LL_ENDL;
+				dumpObjectLog(ret, TRUE, filename);
 #if LL_WINDOWS
 				std::stringstream ostr;
 				//dump shader source for debugging
@@ -938,11 +954,6 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors)
 		suppress_errors = FALSE;
 	}
 #endif
-	if (!suppress_errors)
-	{
-        dumpObjectLog(obj, !success);
-	}
-
 	return success;
 }
 
@@ -1146,6 +1157,7 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("env_intensity");
 
 	mReservedUniforms.push_back("matrixPalette");
+	mReservedUniforms.push_back("translationPalette");
 	
 	mReservedUniforms.push_back("screenTex");
 	mReservedUniforms.push_back("screenDepth");
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 51c27fc8b66f7a5a4141a25c2a89e10f2f80d01e..394b38f832329964798deee031671f4b6d715fa2 100755
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -176,6 +176,7 @@ class LLShaderMgr
 		ENVIRONMENT_INTENSITY,
 		
 		AVATAR_MATRIX,
+		AVATAR_TRANSLATION,
 
 		WATER_SCREENTEX,
 		WATER_SCREENDEPTH,
@@ -224,7 +225,7 @@ DISPLAY_GAMMA,
 	virtual void initAttribsAndUniforms(void);
 
 	BOOL attachShaderFeatures(LLGLSLShader * shader);
-	void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
+	void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE, const std::string& filename = "");
 	BOOL	linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
 	BOOL	validateProgramObject(GLhandleARB obj);
 	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1);
diff --git a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
index efd0d03965725dcdd8b3fcb42efc68c0c9718690..3bbcf3248289f6a031a9f7bec485055b07d64ac8 100755
--- a/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
+++ b/indra/newview/app_settings/shaders/class1/avatar/objectSkinV.glsl
@@ -26,7 +26,9 @@
 
 ATTRIBUTE vec4 weight4;  
 
-uniform mat4 matrixPalette[32];
+uniform mat3 matrixPalette[64];
+uniform vec3 translationPalette[64];
+
 
 mat4 getObjectSkinnedTransform()
 {
@@ -34,15 +36,35 @@ mat4 getObjectSkinnedTransform()
 	
 	vec4 w = fract(weight4);
 	vec4 index = floor(weight4);
-	
+
+		 index = min(index, vec4(63.0));
+		 index = max(index, vec4( 0.0));
+
 	float scale = 1.0/(w.x+w.y+w.z+w.w);
 	w *= scale;
-	
-	mat4 mat = matrixPalette[int(index.x)]*w.x;
-	mat += matrixPalette[int(index.y)]*w.y;
-	mat += matrixPalette[int(index.z)]*w.z;
-	mat += matrixPalette[int(index.w)]*w.w;
+
+	int i1 = int(index.x);
+	int i2 = int(index.y);
+	int i3 = int(index.z);
+	int i4 = int(index.w);
 		
-	return mat;
+	mat3 mat  = matrixPalette[i1]*w.x;
+		 mat += matrixPalette[i2]*w.y;
+		 mat += matrixPalette[i3]*w.z;
+		 mat += matrixPalette[i4]*w.w;
+
+	vec3 trans = translationPalette[i1]*w.x;
+	trans += translationPalette[i2]*w.y;
+	trans += translationPalette[i3]*w.z;
+	trans += translationPalette[i4]*w.w;
+
+	mat4 ret;
+
+	ret[0] = vec4(mat[0], 0);
+	ret[1] = vec4(mat[1], 0);
+	ret[2] = vec4(mat[2], 0);
+	ret[3] = vec4(trans, 1.0);
+				
+	return ret;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index e5f7366b707264dc9d7feebc657458c7d9a504f4..2b5f0018736626911660254fc1cc6f17ea70aade 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -534,6 +534,7 @@ void main()
 #ifdef FOR_IMPOSTOR
 	vec4 color;
 	color.rgb = diff.rgb;
+	color.a = 1.0;
 
 #ifdef USE_VERTEX_COLOR
 	float final_alpha = diff.a * vertex_color.a;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index f622d5a63ac820ba26c91027815b308f2e65768e..e77ed27fa2b5d7e2f771c3fb48105c7bfa6dd3cf 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1708,9 +1708,9 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 		{
 			if (sShaderLevel > 0)
 			{ //upload matrix palette to shader
-				LLMatrix4 mat[32];
+				LLMatrix4 mat[64];
 
-				U32 count = llmin((U32) skin->mJointNames.size(), (U32) 32);
+				U32 count = llmin((U32) skin->mJointNames.size(), (U32) 64);
 
 				for (U32 i = 0; i < count; ++i)
 				{
@@ -1724,10 +1724,42 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 				
 				stop_glerror();
 
-				LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv(LLViewerShaderMgr::AVATAR_MATRIX, 
+				F32 mp[64*9];
+
+				F32 transp[64*3];
+
+				for (U32 i = 0; i < count; ++i)
+				{
+					F32* m = (F32*) mat[i].mMatrix;
+
+					U32 idx = i*9;
+
+					mp[idx+0] = m[0];
+					mp[idx+1] = m[1];
+					mp[idx+2] = m[2];
+
+					mp[idx+3] = m[4];
+					mp[idx+4] = m[5];
+					mp[idx+5] = m[6];
+
+					mp[idx+6] = m[8];
+					mp[idx+7] = m[9];
+					mp[idx+8] = m[10];
+
+					idx = i*3;
+
+					transp[idx+0] = m[12];
+					transp[idx+1] = m[13];
+					transp[idx+2] = m[14];
+				}
+
+				LLDrawPoolAvatar::sVertexProgram->uniformMatrix3fv(LLViewerShaderMgr::AVATAR_MATRIX, 
 					count,
 					FALSE,
-					(GLfloat*) mat[0].mMatrix);
+					(GLfloat*) mp);
+
+				LLDrawPoolAvatar::sVertexProgram->uniform3fv(LLShaderMgr::AVATAR_TRANSLATION, count, transp);
+
 				
 				stop_glerror();
 			}
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index ac2940fcfccf6652f21f620ec7cda53563118182..fb07ab8fbec00aaa143f534109ab3b41c2b8f518 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1025,6 +1025,10 @@ U32 info_display_from_string(std::string info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME;
 	}
+	else if ("joints" == info_display)
+	{
+		return LLPipeline::RENDER_DEBUG_AVATAR_JOINTS;
+	}
 	else if ("raycast" == info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_RAYCAST;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index fe035a0a7f9374644164491d180e624d4546230b..bd33ddf1a5f010f74643ef65e78fbf5a288af758 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -1392,9 +1392,11 @@ void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 //-----------------------------------------------------------------------------
 void LLVOAvatar::renderCollisionVolumes()
 {
+	std::ostringstream ostr;
 	for (S32 i = 0; i < mNumCollisionVolumes; i++)
 	{
 		mCollisionVolumes[i].renderCollision();
+		ostr << mCollisionVolumes[i].getName() << ", ";
 	}
 
 	if (mNameText.notNull())
@@ -1403,6 +1405,96 @@ void LLVOAvatar::renderCollisionVolumes()
 	
 		mNameText->lineSegmentIntersect(unused, unused, unused, TRUE);
 	}
+
+	mDebugText.clear();
+	addDebugText(ostr.str());
+}
+
+void LLVOAvatar::renderJoints()
+{
+	std::ostringstream ostr;
+	std::ostringstream nullstr;
+
+	for (joint_map_t::iterator iter = mJointMap.begin(); iter != mJointMap.end(); ++iter)
+	{
+		LLJoint* jointp = iter->second;
+		if (!jointp)
+		{
+			nullstr << iter->first << " is NULL" << std::endl;
+			continue;
+		}
+
+		ostr << jointp->getName() << ", ";
+
+		jointp->updateWorldMatrix();
+	
+		gGL.pushMatrix();
+		gGL.multMatrix( &jointp->getXform()->getWorldMatrix().mMatrix[0][0] );
+
+		gGL.diffuseColor3f( 1.f, 0.f, 1.f );
+	
+		gGL.begin(LLRender::LINES);
+	
+		LLVector3 v[] = 
+		{
+			LLVector3(1,0,0),
+			LLVector3(-1,0,0),
+			LLVector3(0,1,0),
+			LLVector3(0,-1,0),
+
+			LLVector3(0,0,-1),
+			LLVector3(0,0,1),
+		};
+
+		//sides
+		gGL.vertex3fv(v[0].mV); 
+		gGL.vertex3fv(v[2].mV);
+
+		gGL.vertex3fv(v[0].mV); 
+		gGL.vertex3fv(v[3].mV);
+
+		gGL.vertex3fv(v[1].mV); 
+		gGL.vertex3fv(v[2].mV);
+
+		gGL.vertex3fv(v[1].mV); 
+		gGL.vertex3fv(v[3].mV);
+
+
+		//top
+		gGL.vertex3fv(v[0].mV); 
+		gGL.vertex3fv(v[4].mV);
+
+		gGL.vertex3fv(v[1].mV); 
+		gGL.vertex3fv(v[4].mV);
+
+		gGL.vertex3fv(v[2].mV); 
+		gGL.vertex3fv(v[4].mV);
+
+		gGL.vertex3fv(v[3].mV); 
+		gGL.vertex3fv(v[4].mV);
+
+
+		//bottom
+		gGL.vertex3fv(v[0].mV); 
+		gGL.vertex3fv(v[5].mV);
+
+		gGL.vertex3fv(v[1].mV); 
+		gGL.vertex3fv(v[5].mV);
+
+		gGL.vertex3fv(v[2].mV); 
+		gGL.vertex3fv(v[5].mV);
+
+		gGL.vertex3fv(v[3].mV); 
+		gGL.vertex3fv(v[5].mV);
+
+		gGL.end();
+
+		gGL.popMatrix();
+	}
+
+	mDebugText.clear();
+	addDebugText(ostr.str());
+	addDebugText(nullstr.str());
 }
 
 BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
@@ -3077,9 +3169,6 @@ void	LLVOAvatar::forceUpdateVisualMuteSettings()
 //------------------------------------------------------------------------
 BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 {
-	// clear debug text
-	mDebugText.clear();
-
 	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
 	{
 		S32 central_bake_version = -1;
@@ -3588,6 +3677,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 	{
 		setDebugText(mDebugText);
 	}
+	mDebugText.clear();
 
 	//mesh vertices need to be reskinned
 	mNeedsSkin = TRUE;
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 931e65b3ea1ca37e66c374ec655b322715dfcf9b..5d897ee44ee9905be4294dcc3843d566f8aa20db 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -406,6 +406,7 @@ class LLVOAvatar :
 	F32			getLastSkinTime() { return mLastSkinTime; }
 	U32 		renderTransparent(BOOL first_pass);
 	void 		renderCollisionVolumes();
+	void		renderJoints();
 	static void	deleteCachedImages(bool clearAll=true);
 	static void	destroyGL();
 	static void	restoreGL();
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 9aeb2d4978cdc3afa9a6a3a7afd3f109c78152fc..1c7154d413ba069549b37f6b9649c940f1064cd4 100755
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -535,15 +535,16 @@ class LLPipeline
 		RENDER_DEBUG_SHADOW_FRUSTA		= 0x00040000,
 		RENDER_DEBUG_SCULPTED           = 0x00080000,
 		RENDER_DEBUG_AVATAR_VOLUME      = 0x00100000,
-		RENDER_DEBUG_BUILD_QUEUE		= 0x00200000,
-		RENDER_DEBUG_AGENT_TARGET       = 0x00400000,
-		RENDER_DEBUG_UPDATE_TYPE		= 0x00800000,
-		RENDER_DEBUG_PHYSICS_SHAPES     = 0x01000000,
-		RENDER_DEBUG_NORMALS	        = 0x02000000,
-		RENDER_DEBUG_LOD_INFO	        = 0x04000000,
-		RENDER_DEBUG_RENDER_COMPLEXITY  = 0x08000000,
-		RENDER_DEBUG_ATTACHMENT_BYTES	= 0x10000000,
-		RENDER_DEBUG_TEXEL_DENSITY		= 0x20000000
+		RENDER_DEBUG_AVATAR_JOINTS      = 0x00200000,
+		RENDER_DEBUG_BUILD_QUEUE		= 0x00400000,
+		RENDER_DEBUG_AGENT_TARGET       = 0x00800000,
+		RENDER_DEBUG_UPDATE_TYPE		= 0x01000000,
+		RENDER_DEBUG_PHYSICS_SHAPES     = 0x02000000,
+		RENDER_DEBUG_NORMALS	        = 0x04000000,
+		RENDER_DEBUG_LOD_INFO	        = 0x08000000,
+		RENDER_DEBUG_RENDER_COMPLEXITY  = 0x10000000,
+		RENDER_DEBUG_ATTACHMENT_BYTES	= 0x20000000,
+		RENDER_DEBUG_TEXEL_DENSITY		= 0x40000000
 	};
 
 public:
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index d635b8ee93e3c39c02e9e5440ff3f61493d6c939..7d28d87f637d3dd0bd4ea0286be6c88a0403abf9 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2571,6 +2571,16 @@
            function="Advanced.ToggleInfoDisplay"
            parameter="collision skeleton" />
         </menu_item_check>
+        <menu_item_check
+         label="Joints"
+         name="Joints">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="joints" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="joints" />
+        </menu_item_check>
         <menu_item_check
          label="Raycast"
          name="Raycast">