diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 3d5e2d356ea955a23dcb40a43200c3617e2bb5c1..eebdb62affff4237b50e8fb77cd4b725130d4f8f 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -330,11 +330,7 @@ void LLFace::dirtyTexture()
 				{
 					vobj->mLODChanged = TRUE;
 
-					LLVOAvatar* avatar = vobj->getAvatar();
-					if (avatar)
-					{ //avatar render cost may have changed
-						avatar->updateVisualComplexity();
-					}
+                    vobj->updateVisualComplexity();
 				}
 				gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE);
 			}
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 616db8ae2f7391c085b8d38bce3106141f9695c8..94e1390c425a2c330ccfa52c49760fd1b35ace0d 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -3627,6 +3627,22 @@ U32 LLViewerObject::getHighLODTriangleCount()
 	return 0;
 }
 
+U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const
+{
+    S32 total_tris = getTriangleCount(vcount);
+    LLViewerObject::const_child_list_t& child_list = getChildren();
+    for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
+         iter != child_list.end(); ++iter)
+    {
+        LLViewerObject* childp = *iter;
+        if (childp)
+        {
+            total_tris += childp->getTriangleCount(vcount);
+        }
+    }
+    return total_tris;
+}
+
 void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 {
 	LLVector4a center;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 345fd1fb2709d8f907ae4d92da9d278a97710231..a84b6da96c327b766c5f51b584e88415ab2b4605 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -364,6 +364,8 @@ public:
 	virtual U32 getTriangleCount(S32* vcount = NULL) const;
 	virtual U32 getHighLODTriangleCount();
 
+    U32 recursiveGetTriangleCount(S32* vcount = NULL) const;
+
 	void setObjectCost(F32 cost);
 	F32 getObjectCost();
 	
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 0fcb4ffc557f1f61743a5d4a0dc717876a78f4ab..d5301c38bad5fec2edae338018d0dbde2d8a38c8 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -620,6 +620,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	LLViewerObject(id, pcode, regionp),
 	mSpecialRenderMode(0),
 	mAttachmentSurfaceArea(0.f),
+	mAttachmentVisibleTriangleCount(0),
+	mAttachmentEstTriangleCount(0.f),
 	mReportedVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN),
 	mTurning(FALSE),
 	mLastSkeletonSerialNum( 0 ),
@@ -9167,8 +9169,13 @@ void LLVOAvatar::idleUpdateRenderComplexity()
 {
     if (isControlAvatar())
     {
-        // ARC for animated object attachments is accounted with the avatar they're attached to.
-        return;
+        LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this);
+        bool is_attachment = cav && cav->mRootVolp && cav->mRootVolp->isAttachment(); // For attached animated objects
+        if (is_attachment)
+        {
+            // ARC for animated object attachments is accounted with the avatar they're attached to.
+            return;
+        }
     }
 
     // Render Complexity
@@ -9218,10 +9225,14 @@ void LLVOAvatar::idleUpdateRenderComplexity()
 		// Visual rank
 		info_line = llformat("%d rank", mVisibilityRank);
 		// Use grey for imposters, white for normal rendering or no impostors
-		info_color.set(isImpostor() ? LLColor4::grey : LLColor4::white);
+		info_color.set(isImpostor() ? LLColor4::grey : (isControlAvatar() ? LLColor4::yellow : LLColor4::white));
 		info_style = LLFontGL::NORMAL;
 		mText->addLine(info_line, info_color, info_style);
 
+        // Triangle count
+        mText->addLine(llformat("Tris %u",mAttachmentVisibleTriangleCount), info_color, info_style);
+        mText->addLine(llformat("Est Tris %f",mAttachmentEstTriangleCount), info_color, info_style);
+
 		// Attachment Surface Area
 		static LLCachedControl<F32> max_attachment_area(gSavedSettings, "RenderAutoMuteSurfaceAreaLimit", 1000.0f);
 		info_line = llformat("%.0f m^2", mAttachmentSurfaceArea);
@@ -9263,6 +9274,133 @@ void LLVOAvatar::updateVisualComplexity()
 	mVisualComplexityStale = true;
 }
 
+// Account for the complexity of a single top-level object associated
+// with an avatar. This will be either an attached object or an animated
+// object.
+void LLVOAvatar::accountRenderComplexityForObject(
+    const LLViewerObject *attached_object,
+    const F32 max_attachment_complexity,
+    LLVOVolume::texture_cost_t& textures,
+    U32& cost,
+    hud_complexity_list_t& hud_complexity_list)
+{
+    if (attached_object && !attached_object->isHUDAttachment())
+    {
+        mAttachmentVisibleTriangleCount += attached_object->recursiveGetTriangleCount();
+        mAttachmentEstTriangleCount += attached_object->recursiveGetEstTrianglesMax();
+
+        textures.clear();
+        const LLDrawable* drawable = attached_object->mDrawable;
+        if (drawable)
+        {
+            const LLVOVolume* volume = drawable->getVOVolume();
+            if (volume)
+            {
+                F32 attachment_total_cost = 0;
+                F32 attachment_volume_cost = 0;
+                F32 attachment_texture_cost = 0;
+                F32 attachment_children_cost = 0;
+                // AXON placeholder value, will revisit in testing.
+                const F32 animated_object_attachment_surcharge = 20000;
+
+                if (attached_object->isAnimatedObject())
+                {
+                    attachment_volume_cost += animated_object_attachment_surcharge;
+                }
+                attachment_volume_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)
+                {
+                    LLViewerObject* child_obj = *child_iter;
+                    LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
+                    if (child)
+                    {
+                        attachment_children_cost += child->getRenderCost(textures);
+                    }
+                }
+
+                for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
+                     volume_texture != textures.end();
+                     ++volume_texture)
+                {
+                    // add the cost of each individual texture in the linkset
+                    attachment_texture_cost += volume_texture->second;
+                }
+                attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost;
+                LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID()
+                                       << " total: " << attachment_total_cost
+                                       << ", volume: " << attachment_volume_cost
+                                       << ", textures: " << attachment_texture_cost
+                                       << ", " << volume->numChildren()
+                                       << " children: " << attachment_children_cost
+                                       << LL_ENDL;
+                // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI
+                cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity);
+            }
+        }
+    }
+    if (isSelf()
+        && attached_object
+        && attached_object->isHUDAttachment()
+        && !attached_object->isTempAttachment()
+        && attached_object->mDrawable)
+    {
+        textures.clear();
+
+        const LLVOVolume* volume = attached_object->mDrawable->getVOVolume();
+        if (volume)
+        {
+            LLHUDComplexity hud_object_complexity;
+            hud_object_complexity.objectName = attached_object->getAttachmentItemName();
+            hud_object_complexity.objectId = attached_object->getAttachmentItemID();
+            std::string joint_name;
+            gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name);
+            hud_object_complexity.jointName = joint_name;
+            // get cost and individual textures
+            hud_object_complexity.objectsCost += volume->getRenderCost(textures);
+            hud_object_complexity.objectsCount++;
+
+            LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
+            for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+                 iter != child_list.end(); ++iter)
+            {
+                LLViewerObject* childp = *iter;
+                const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp);
+                if (chld_volume)
+                {
+                    // get cost and individual textures
+                    hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures);
+                    hud_object_complexity.objectsCount++;
+                }
+            }
+
+            hud_object_complexity.texturesCount += textures.size();
+
+            for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
+                 volume_texture != textures.end();
+                 ++volume_texture)
+            {
+                // add the cost of each individual texture (ignores duplicates)
+                hud_object_complexity.texturesCost += volume_texture->second;
+                LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first);
+                if (tex)
+                {
+                    // Note: Texture memory might be incorect since texture might be still loading.
+                    hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory();
+                    if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE)
+                    {
+                        hud_object_complexity.largeTexturesCount++;
+                    }
+                }
+            }
+            hud_complexity_list.push_back(hud_object_complexity);
+        }
+    }
+}
+
 // Calculations for mVisualComplexity value
 void LLVOAvatar::calculateUpdateRenderComplexity()
 {
@@ -9301,7 +9439,24 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
 		}
         LL_DEBUGS("ARCdetail") << "Avatar body parts complexity: " << cost << LL_ENDL;
 
+        mAttachmentVisibleTriangleCount = 0;
+        mAttachmentEstTriangleCount = 0.f;
+
+        // A standalone animated object needs to be accounted for
+        // using its associated volume. Attached animated objects
+        // will be covered by the subsequent loop over attachments.
+        LLControlAvatar *control_av = dynamic_cast<LLControlAvatar*>(this);
+        if (control_av)
+        {
+            LLVOVolume *volp = control_av->mRootVolp;
+            if (volp && !volp->isAttachment())
+            {
+                accountRenderComplexityForObject(volp, max_attachment_complexity,
+                                                 textures, cost, hud_complexity_list);
+            }
+        }
 
+        // Account for complexity of all attachments.
 		for (attachment_map_t::const_iterator attachment_point = mAttachmentPoints.begin(); 
 			 attachment_point != mAttachmentPoints.end();
 			 ++attachment_point)
@@ -9312,118 +9467,8 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
 				 ++attachment_iter)
 			{
 				const LLViewerObject* attached_object = (*attachment_iter);
-				if (attached_object && !attached_object->isHUDAttachment())
-				{
-					textures.clear();
-					const LLDrawable* drawable = attached_object->mDrawable;
-					if (drawable)
-					{
-						const LLVOVolume* volume = drawable->getVOVolume();
-						if (volume)
-						{
-                            F32 attachment_total_cost = 0;
-                            F32 attachment_volume_cost = 0;
-                            F32 attachment_texture_cost = 0;
-                            F32 attachment_children_cost = 0;
-                            // AXON placeholder value, will revisit in testing.
-                            const F32 animated_object_attachment_surcharge = 20000;
-
-                            if (attached_object->isAnimatedObject())
-                            {
-                                attachment_volume_cost += animated_object_attachment_surcharge;
-                            }
-							attachment_volume_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)
-							{
-								LLViewerObject* child_obj = *child_iter;
-								LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj );
-								if (child)
-								{
-									attachment_children_cost += child->getRenderCost(textures);
-								}
-							}
-
-							for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
-								 volume_texture != textures.end();
-								 ++volume_texture)
-							{
-								// add the cost of each individual texture in the linkset
-								attachment_texture_cost += volume_texture->second;
-							}
-                            attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost;
-                            LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID()
-                                                   << " total: " << attachment_total_cost
-                                                   << ", volume: " << attachment_volume_cost
-                                                   << ", textures: " << attachment_texture_cost
-                                                   << ", " << volume->numChildren()
-                                                   << " children: " << attachment_children_cost
-                                                   << LL_ENDL;
-                            // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI
-                            cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity);
-						}
-					}
-				}
-                if (isSelf()
-                    && attached_object
-                    && attached_object->isHUDAttachment()
-                    && !attached_object->isTempAttachment()
-                    && attached_object->mDrawable)
-                {
-                    textures.clear();
-
-                    const LLVOVolume* volume = attached_object->mDrawable->getVOVolume();
-                    if (volume)
-                    {
-                        LLHUDComplexity hud_object_complexity;
-                        hud_object_complexity.objectName = attached_object->getAttachmentItemName();
-                        hud_object_complexity.objectId = attached_object->getAttachmentItemID();
-                        std::string joint_name;
-                        gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name);
-                        hud_object_complexity.jointName = joint_name;
-                        // get cost and individual textures
-                        hud_object_complexity.objectsCost += volume->getRenderCost(textures);
-                        hud_object_complexity.objectsCount++;
-
-                        LLViewerObject::const_child_list_t& child_list = attached_object->getChildren();
-                        for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
-                            iter != child_list.end(); ++iter)
-                        {
-                            LLViewerObject* childp = *iter;
-                            const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp);
-                            if (chld_volume)
-                            {
-                                // get cost and individual textures
-                                hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures);
-                                hud_object_complexity.objectsCount++;
-                            }
-                        }
-
-                        hud_object_complexity.texturesCount += textures.size();
-
-                        for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin();
-                            volume_texture != textures.end();
-                            ++volume_texture)
-                        {
-                            // add the cost of each individual texture (ignores duplicates)
-                            hud_object_complexity.texturesCost += volume_texture->second;
-                            LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first);
-                            if (tex)
-                            {
-                                // Note: Texture memory might be incorect since texture might be still loading.
-                                hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory();
-                                if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE)
-                                {
-                                    hud_object_complexity.largeTexturesCount++;
-                                }
-                            }
-                        }
-                        hud_complexity_list.push_back(hud_object_complexity);
-                    }
-                }
+                accountRenderComplexityForObject(attached_object, max_attachment_complexity,
+                                                 textures, cost, hud_complexity_list);
 			}
 		}
 
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 5a40a45eaef6592cb8adfafa6264789d17ea062f..5f7d23050e3b56fd8f626b0c41f9c33fb0f797ae 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -50,6 +50,8 @@
 #include "llviewertexlayer.h"
 #include "material_codes.h"		// LL_MCODE_END
 #include "llviewerstats.h"
+#include "llvovolume.h"
+#include "llavatarrendernotifier.h"
 
 extern const LLUUID ANIM_AGENT_BODY_NOISE;
 extern const LLUUID ANIM_AGENT_BREATHE_ROT;
@@ -268,6 +270,11 @@ public:
 	static void		invalidateNameTags();
 	void			addNameTagLine(const std::string& line, const LLColor4& color, S32 style, const LLFontGL* font);
 	void 			idleUpdateRenderComplexity();
+    void 			accountRenderComplexityForObject(const LLViewerObject *attached_object,
+                                                     const F32 max_attachment_complexity,
+                                                     LLVOVolume::texture_cost_t& textures,
+                                                     U32& cost,
+                                                     hud_complexity_list_t& hud_complexity_list);
 	void			calculateUpdateRenderComplexity();
 	static const U32 VISUAL_COMPLEXITY_UNKNOWN;
 	void			updateVisualComplexity();
@@ -431,6 +438,8 @@ public:
         
   private:
 	F32			mAttachmentSurfaceArea; //estimated surface area of attachments
+    U32			mAttachmentVisibleTriangleCount;
+    F32			mAttachmentEstTriangleCount;
 	bool		shouldAlphaMask();
 
 	BOOL 		mNeedsSkin; // avatar has been animated and verts have not been updated
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index efddc9235e9c17bce862c6effa0c34df884459bd..7fec240d1be6ae0835622aa63e4ba9c05338d3c2 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1103,16 +1103,26 @@ void LLVOVolume::updateSculptTexture()
 	
 }
 
+void LLVOVolume::updateVisualComplexity()
+{
+    LLVOAvatar* avatar = getAvatarAncestor();
+    if (avatar)
+    {
+        avatar->updateVisualComplexity();
+    }
+    LLVOAvatar* rigged_avatar = getAvatar();
+    if(rigged_avatar && (rigged_avatar != avatar))
+    {
+        rigged_avatar->updateVisualComplexity();
+    }
+}
+
 void LLVOVolume::notifyMeshLoaded()
 { 
 	mSculptChanged = TRUE;
 	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
 
-	LLVOAvatar* avatar = getAvatar();
-	if (avatar)
-	{
-		avatar->updateVisualComplexity();
-	}
+    updateVisualComplexity();
 }
 
 // sculpt replaces generate() for sculpted surfaces
@@ -1302,18 +1312,7 @@ BOOL LLVOVolume::calcLOD()
     {
         if (isRootEdit() && getChildren().size()>0)
         {
-            S32 total_tris = getTriangleCount();
-            LLViewerObject::const_child_list_t& child_list = getChildren();
-            for (LLViewerObject::const_child_list_t::const_iterator iter = child_list.begin();
-                 iter != child_list.end(); ++iter)
-            {
-                LLViewerObject* childp = *iter;
-                LLVOVolume *child_volp = dynamic_cast<LLVOVolume*>(childp);
-                if (child_volp)
-                {
-                    total_tris += child_volp->getTriangleCount();
-                }
-            }
+            S32 total_tris = recursiveGetTriangleCount();
             setDebugText(llformat("TRIS %d TOTAL %d", getTriangleCount(), total_tris));
         }
         else
@@ -1333,7 +1332,8 @@ BOOL LLVOVolume::calcLOD()
 	{
 		mAppAngle = ll_round((F32) atan2( mDrawable->getRadius(), mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
 		mLOD = cur_detail;		
-		return TRUE;
+
+        return TRUE;
 	}
 
 	return FALSE;
@@ -1691,6 +1691,11 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled)
 
 	if ((new_lod != old_lod) || mSculptChanged)
 	{
+        if (mDrawable->isState(LLDrawable::RIGGED))
+        {
+            updateVisualComplexity();
+        }
+
 		compiled = TRUE;
 		sNumLODChanges += new_num_faces;
 
@@ -3342,7 +3347,7 @@ void LLVOVolume::setExtendedMeshFlags(U32 flags)
         parameterChanged(LLNetworkData::PARAMS_EXTENDED_MESH, true);
         if (isAttachment() && getAvatarAncestor())
         {
-            getAvatarAncestor()->updateVisualComplexity();
+            updateVisualComplexity();
             if (flags & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG)
             {
                 // Making a rigged mesh into an animated object
@@ -3392,7 +3397,7 @@ bool LLVOVolume::isAnimatedObject() const
     if (root_is_animated_flag)
     {
         bool root_can_be_animated = root_vol->canBeAnimatedObject();
-        bool this_can_be_animated = ((root_vol == this) && root_can_be_animated) || canBeAnimatedObject();
+        bool this_can_be_animated = (root_vol == this) ? root_can_be_animated : canBeAnimatedObject();
         if (this_can_be_animated && root_can_be_animated)
         {
             return true;
@@ -4923,25 +4928,29 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	group->mBuilt = 1.f;
 	
 	LLVOAvatar* pAvatarVO = NULL;
+	LLVOAvatar *attached_av = NULL;
 
 	LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
 	if (bridge)
 	{
+        LLViewerObject* vobj = bridge->mDrawable->getVObj();
 		if (bridge->mAvatar.isNull())
 		{
-			LLViewerObject* vobj = bridge->mDrawable->getVObj();
 			if (vobj)
 			{
 				bridge->mAvatar = vobj->getAvatar();
 			}
 		}
-
+        if (vobj)
+        {
+            attached_av = vobj->getAvatarAncestor();
+        }
 		pAvatarVO = bridge->mAvatar;
 	}
 
-	if (pAvatarVO)
+	if (attached_av)
 	{
-		pAvatarVO->subtractAttachmentArea( group->mSurfaceArea );
+		attached_av->subtractAttachmentArea( group->mSurfaceArea );
 	}
 
 	group->mGeometryBytes = 0;
@@ -5518,9 +5527,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	mFaceList.clear();
 
-	if (pAvatarVO)
+	if (attached_av)
 	{
-        pAvatarVO->addAttachmentArea( group->mSurfaceArea );
+        attached_av->addAttachmentArea( group->mSurfaceArea );
 	}
 }
 
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 24bcf41c74011d5cdef0524311debe76fa734e95..bc8fa9a3d34808708c8e6a923bd1d732888b4b61 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -315,7 +315,10 @@ public:
 	bool hasMedia() const;
 	
 	LLVector3 getApproximateFaceNormal(U8 face_id);
-	
+
+    // Flag any corresponding avatars as needing update.
+    void updateVisualComplexity();
+    
 	void notifyMeshLoaded();
 	
 	// Returns 'true' iff the media data for this object is in flight