diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 607f290cee6673692801417fb889348c00798724..e56e3ef472f12e6bb93d876d4c6112bf7b040156 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1720,43 +1720,56 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 		{
 			if (sShaderLevel > 0)
 			{
-                // upload matrix palette to shader
-				LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
-				U32 count = LLSkinningUtil::getMeshJointCount(skin);
-                LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar);
+				auto rigged_matrix_data_iter = avatar->getRiggedMatrixCache().find(skin->mMeshID);
+				if (rigged_matrix_data_iter != avatar->getRiggedMatrixCache().cend())
+				{
+					LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+						rigged_matrix_data_iter->second.first,
+						FALSE,
+						(GLfloat*) rigged_matrix_data_iter->second.second.data());
 
-				stop_glerror();
+					stop_glerror();
+				}
+				else
+				{
+					// upload matrix palette to shader
+					LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT];
+					U32 count = LLSkinningUtil::getMeshJointCount(skin);
+					LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar);
 
-				F32 mp[LL_MAX_JOINTS_PER_MESH_OBJECT*12];
+					stop_glerror();
 
-				for (U32 i = 0; i < count; ++i)
-				{
-					F32* m = (F32*) mat[i].getF32ptr();
+					std::array<F32, LL_MAX_JOINTS_PER_MESH_OBJECT * 12> mp;
 
-					U32 idx = i*12;
+					for (U32 i = 0; i < count; ++i)
+					{
+						F32* m = (F32*) mat[i].getF32ptr();
 
-					mp[idx+0] = m[0];
-					mp[idx+1] = m[1];
-					mp[idx+2] = m[2];
-					mp[idx+3] = m[12];
+						U32 idx = i * 12;
 
-					mp[idx+4] = m[4];
-					mp[idx+5] = m[5];
-					mp[idx+6] = m[6];
-					mp[idx+7] = m[13];
+						mp[idx + 0] = m[0];
+						mp[idx + 1] = m[1];
+						mp[idx + 2] = m[2];
+						mp[idx + 3] = m[12];
 
-					mp[idx+8] = m[8];
-					mp[idx+9] = m[9];
-					mp[idx+10] = m[10];
-					mp[idx+11] = m[14];
-				}
+						mp[idx + 4] = m[4];
+						mp[idx + 5] = m[5];
+						mp[idx + 6] = m[6];
+						mp[idx + 7] = m[13];
 
-				LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, 
-					count,
-					FALSE,
-					(GLfloat*) mp);
+						mp[idx + 8] = m[8];
+						mp[idx + 9] = m[9];
+						mp[idx + 10] = m[10];
+						mp[idx + 11] = m[14];
+					}
+					avatar->getRiggedMatrixCache().emplace(skin->mMeshID, std::make_pair(count, mp));
+					LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
+						count,
+						FALSE,
+						(GLfloat*) mp.data());
 
-				stop_glerror();
+					stop_glerror();
+				}
 			}
 			else
 			{
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 25d966ec6f0c9c4f3394532388ca53065c275a2b..1088ee202618b021a83fddba8cde16ea8eb5a2f9 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -36,8 +36,6 @@ class LLMeshSkinInfo;
 class LLVolume;
 class LLVolumeFace;
 
-constexpr U32 JOINT_COUNT = 52;
-
 class LLDrawPoolAvatar : public LLFacePool
 {
 public:
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 0b5aa080abda1debec260d04417bdd0cbef59f60..cce918c922b4a049fb720c48369385848e6ecfa3 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -81,6 +81,7 @@
 #include "llwlparammanager.h"
 #include "llwaterparammanager.h"
 #include "llscenemonitor.h"
+#include "lldrawpoolavatar.h"
 
 #include <glm/vec3.hpp>
 #include <glm/mat4x4.hpp>
@@ -265,6 +266,14 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 {
 	LL_RECORD_BLOCK_TIME(FTM_RENDER);
 
+	for(auto avatar : LLCharacter::sInstances)
+	{
+		LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(avatar);
+		if (!avatar) continue;
+		if (avatar->isDead()) continue;
+		avatar->clearRiggedMatrixCache();
+	}
+
 	if (gWindowResized)
 	{ //skip render on frames where window has been resized
 		LL_RECORD_BLOCK_TIME(FTM_RESIZE_WINDOW);
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index a91d2a564d0b5960e1552e6ffcd955e1c0f8ee64..7fac82cfc332da3d120420ec227abc6d45ab812f 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -45,6 +45,7 @@
 #include "llviewertexlayer.h"
 #include "material_codes.h"		// LL_MCODE_END
 #include "llviewerstats.h"
+#include "llskinningutil.h"
 
 extern const LLUUID ANIM_AGENT_BODY_NOISE;
 extern const LLUUID ANIM_AGENT_BREATHE_ROT;
@@ -1037,6 +1038,20 @@ protected: // Shared with LLVOAvatarSelf
  **                                                                            **
  *******************************************************************************/
 
+public:
+	typedef std::array<F32, LL_MAX_JOINTS_PER_MESH_OBJECT * 12> rigged_matrix_array_t;
+	typedef std::map<LLUUID, std::pair<U32, rigged_matrix_array_t> > rigged_transformation_cache_t;
+	auto& getRiggedMatrixCache()
+	{
+		return mRiggedMatrixDataCache;
+	}
+	void clearRiggedMatrixCache()
+	{
+		mRiggedMatrixDataCache.clear();
+	}
+private:
+	rigged_transformation_cache_t mRiggedMatrixDataCache;
+
 }; // LLVOAvatar
 extern const F32 SELF_ADDITIONAL_PRI;
 extern const S32 MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL;