diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 86301b7601e6e25d12d208264cc8116a4583c4ef..84c30506fda9afd8afa4ec2f96862ba4f02797e9 100755
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -491,6 +491,7 @@ void LLAvatarAppearance::computeBodySize()
 	if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])
 	{
 		mBodySize = new_body_size;
+		bodySizeChanged();
 	}
 }
 
@@ -1394,14 +1395,14 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )
 	return TRUE;
 }
 
-void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color)
+void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake )
 {
 	U32 param_name[3];
 	if( teToColorParams( te, param_name ) )
 	{
-		setVisualParamWeight( param_name[0], new_color.mV[VX]);
-		setVisualParamWeight( param_name[1], new_color.mV[VY]);
-		setVisualParamWeight( param_name[2], new_color.mV[VZ]);
+		setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake );
+		setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake );
+		setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake );
 	}
 }
 
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index 9c827f85ef98605148ea54e66346d259733117f1..7926648f0ea4ff21be7b47132321b99fd21a02c7 100755
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -109,6 +109,7 @@ public:
 public:
 	virtual bool 	isSelf() const { return false; } // True if this avatar is for this viewer's agent
 	virtual BOOL	isValid() const;
+	virtual BOOL	isUsingServerBakes() const = 0;
 	virtual BOOL	isUsingLocalAppearance() const = 0;
 	virtual BOOL	isEditingAppearance() const = 0;
 
@@ -145,6 +146,7 @@ protected:
 	static BOOL			parseSkeletonFile(const std::string& filename);
 	virtual void		buildCharacter();
 	virtual BOOL		loadAvatar();
+	virtual void		bodySizeChanged() = 0;
 
 	BOOL				setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
 	BOOL				allocateCharacterJoints(U32 num);
@@ -231,7 +233,7 @@ public:
 	// Composites
 	//--------------------------------------------------------------------
 public:
-	virtual void	invalidateComposite(LLTexLayerSet* layerset) = 0;
+	virtual void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0;
 
 /********************************************************************************
  **                                                                            **
@@ -262,7 +264,7 @@ protected:
 	// Clothing colors (convenience functions to access visual parameters)
 	//--------------------------------------------------------------------
 public:
-	void			setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);
+	void			setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake);
 	LLColor4		getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);
 	static BOOL		teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name);
 
@@ -271,7 +273,7 @@ public:
 	//--------------------------------------------------------------------
 public:
 	LLColor4		getGlobalColor(const std::string& color_name ) const;
-	virtual void	onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;
+	virtual void	onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0;
 protected:
 	LLTexGlobalColor* mTexSkinColor;
 	LLTexGlobalColor* mTexHairColor;
diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp
index e630c1118bc859c71c8c0911e3ceb6ec0d0a144b..bdabd0716a6e73fbf3f573103a8ce0a4ec7e82dd 100755
--- a/indra/llappearance/lldriverparam.cpp
+++ b/indra/llappearance/lldriverparam.cpp
@@ -190,7 +190,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
 	mID = info->mID;
 	info->mDriverParam = this;
 
-	setWeight(getDefaultWeight());
+	setWeight(getDefaultWeight(), FALSE );
 
 	return TRUE;
 }
@@ -201,7 +201,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)
 	return new LLDriverParam(*this);
 }
 
-void LLDriverParam::setWeight(F32 weight)
+void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)
 {
 	F32 min_weight = getMinWeight();
 	F32 max_weight = getMaxWeight();
@@ -260,7 +260,7 @@ void LLDriverParam::setWeight(F32 weight)
 					driven_weight = driven_min;
 				}
 				
-				setDrivenWeight(driven,driven_weight);
+				setDrivenWeight(driven,driven_weight,upload_bake);
 				continue;
 			}
 			else 
@@ -284,13 +284,13 @@ void LLDriverParam::setWeight(F32 weight)
 					driven_weight = driven_min;
 				}
 
-				setDrivenWeight(driven,driven_weight);
+				setDrivenWeight(driven,driven_weight,upload_bake);
 				continue;
 			}
 		}
 
 		driven_weight = getDrivenWeight(driven, mCurWeight);
-		setDrivenWeight(driven,driven_weight);
+		setDrivenWeight(driven,driven_weight, upload_bake);
 	}
 }
 
@@ -436,9 +436,9 @@ const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const
 //-----------------------------------------------------------------------------
 // setAnimationTarget()
 //-----------------------------------------------------------------------------
-void LLDriverParam::setAnimationTarget( F32 target_value)
+void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )
 {
-	LLVisualParam::setAnimationTarget(target_value);
+	LLVisualParam::setAnimationTarget(target_value, upload_bake);
 
 	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
 	{
@@ -447,16 +447,16 @@ void LLDriverParam::setAnimationTarget( F32 target_value)
 
 		// this isn't normally necessary, as driver params handle interpolation of their driven params
 		// but texture params need to know to assume their final value at beginning of interpolation
-		driven->mParam->setAnimationTarget(driven_weight);
+		driven->mParam->setAnimationTarget(driven_weight, upload_bake);
 	}
 }
 
 //-----------------------------------------------------------------------------
 // stopAnimating()
 //-----------------------------------------------------------------------------
-void LLDriverParam::stopAnimating()
+void LLDriverParam::stopAnimating(BOOL upload_bake)
 {
-	LLVisualParam::stopAnimating();
+	LLVisualParam::stopAnimating(upload_bake);
 
 	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
 	{
@@ -536,7 +536,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)
 		LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);
 		if (wearable)
 		{
-			wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));
+			wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false);
 		}
 	}
 }
@@ -599,7 +599,7 @@ F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight
 	return driven_weight;
 }
 
-void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
+void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake)
 {
 	bool use_self = false;
 	if(mWearablep &&
@@ -616,10 +616,10 @@ void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)
 	if (use_self)
 	{
 		// call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values
-		mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);
+		mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake);
 	}
 	else
 	{
-		driven->mParam->setWeight( driven_weight);
+		driven->mParam->setWeight( driven_weight, upload_bake);
 	}
 }
diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h
index f71c930e5e3716fbf67683690f9f372fd5f02142..ab28f41590d8334d5c0884ec7d87af439405a846 100755
--- a/indra/llappearance/lldriverparam.h
+++ b/indra/llappearance/lldriverparam.h
@@ -111,9 +111,9 @@ public:
 
 	// LLVisualParam Virtual functions
 	/*virtual*/ void				apply( ESex sex ) {} // apply is called separately for each driven param.
-	/*virtual*/ void				setWeight(F32 weight);
-	/*virtual*/ void				setAnimationTarget( F32 target_value);
-	/*virtual*/ void				stopAnimating();
+	/*virtual*/ void				setWeight(F32 weight, BOOL upload_bake) override;
+	/*virtual*/ void				setAnimationTarget( F32 target_value, BOOL upload_bake) override;
+	/*virtual*/ void				stopAnimating(BOOL upload_bake) override;
 	/*virtual*/ BOOL				linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
 	/*virtual*/ void				resetDrivenParams();
 	
@@ -131,7 +131,7 @@ public:
 protected:
 	LLDriverParam(const LLDriverParam& pOther);
 	F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
-	void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight);
+	void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake);
 
 
 	LL_ALIGN_16(LLVector4a	mDefaultVec); // temp holder
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index 907f8823c0aa02b23f42c6de49c9d22f9bd72807..bbd2ea69c544379ec7046d88f38a7c306902970c 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -358,7 +358,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
 		return FALSE;
 	mInfo = info;
 	mID = info->mID;
-	setWeight(getDefaultWeight());
+	setWeight(getDefaultWeight(), FALSE);
 
 	LLAvatarAppearance* avatarp = mMesh->getAvatar();
 	LLPolyMorphTargetInfo::volume_info_list_t::iterator iter;
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
index 3dd83f675cd9ea55080fb0c5a12b1b268f6f550f..bb0f526cd874395e638319459c56d3fbe7fe81aa 100644
--- a/indra/llappearance/llpolyskeletaldistortion.cpp
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -139,7 +139,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
                 return FALSE;
         mInfo = info;
         mID = info->mID;
-        setWeight(getDefaultWeight());
+        setWeight(getDefaultWeight(), FALSE);
 
         LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
         for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp
index 3df2254b1423ec8477b270050b38dfe320b6e12a..a8283ea2e632dfe8e95e39a7166c58388008b563 100755
--- a/indra/llappearance/lltexglobalcolor.cpp
+++ b/indra/llappearance/lltexglobalcolor.cpp
@@ -117,9 +117,9 @@ LLTexParamGlobalColor::~LLTexParamGlobalColor()
 	return new LLTexParamGlobalColor(*this);
 }
 
-void LLTexParamGlobalColor::onGlobalColorChanged()
+void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake)
 {
-	mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);
+	mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake);
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h
index 3b426053dee2556bb06ef9ee24ba85624b9349fe..5e312bf3d7f7032a4fffff9ab21902bbaa5e5c55 100755
--- a/indra/llappearance/lltexglobalcolor.h
+++ b/indra/llappearance/lltexglobalcolor.h
@@ -77,7 +77,7 @@ public:
 	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
 protected:
 	LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther);
-	/*virtual*/ void onGlobalColorChanged();
+	/*virtual*/  void onGlobalColorChanged(bool upload_bake) override;
 private:
 	LLTexGlobalColor*		mTexGlobalColor;
 };
diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp
index ff682d69069ad15696e65852734dd488e227c39c..b556f66a43b969bc7a1a95c1017bc5464f87da8e 100755
--- a/indra/llappearance/lltexlayerparams.cpp
+++ b/indra/llappearance/lltexlayerparams.cpp
@@ -183,7 +183,7 @@ BOOL LLTexLayerParamAlpha::getMultiplyBlend() const
 	return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend; 	
 }
 
-void LLTexLayerParamAlpha::setWeight(F32 weight)
+void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)
 {
 	if (mIsAnimating || mTexLayer == NULL)
 	{
@@ -201,35 +201,36 @@ void LLTexLayerParamAlpha::setWeight(F32 weight)
 		if ((mAvatarAppearance->getSex() & getSex()) &&
 			(mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
 		{
-			mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
+			mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
 			mTexLayer->invalidateMorphMasks();
 		}
 	}
 }
 
-void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)
+void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake)
 { 
 	// do not animate dummy parameters
 	if (mIsDummy)
 	{
-		setWeight(target_value);
+		setWeight(target_value, upload_bake);
 		return;
 	}
 
 	mTargetWeight = target_value; 
-	setWeight(target_value); 
+	setWeight(target_value, upload_bake); 
 	mIsAnimating = TRUE;
 	if (mNext)
 	{
-		mNext->setAnimationTarget(target_value);
+		mNext->setAnimationTarget(target_value, upload_bake);
 	}
 }
 
-void LLTexLayerParamAlpha::animate(F32 delta)
+void LLTexLayerParamAlpha::animate(F32 delta, BOOL upload_bake)
 {
 	if (mNext)
 	{
-		mNext->animate(delta);
+		mNext->animate(delta, upload_bake);
+
 	}
 }
 
@@ -477,7 +478,7 @@ LLColor4 LLTexLayerParamColor::getNetColor() const
 }
 
 
-void LLTexLayerParamColor::setWeight(F32 weight)
+void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)
 {
 	if (mIsAnimating)
 	{
@@ -503,10 +504,10 @@ void LLTexLayerParamColor::setWeight(F32 weight)
 
 		if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.
 		{
-			onGlobalColorChanged();
+			onGlobalColorChanged(upload_bake);
 			if (mTexLayer)
 			{
-				mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());
+				mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake);
 			}
 		}
 
@@ -514,23 +515,23 @@ void LLTexLayerParamColor::setWeight(F32 weight)
 	}
 }
 
-void LLTexLayerParamColor::setAnimationTarget(F32 target_value)
+void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake)
 { 
 	// set value first then set interpolating flag to ignore further updates
 	mTargetWeight = target_value; 
-	setWeight(target_value);
+	setWeight(target_value, upload_bake);
 	mIsAnimating = TRUE;
 	if (mNext)
 	{
-		mNext->setAnimationTarget(target_value);
+		mNext->setAnimationTarget(target_value, upload_bake);
 	}
 }
 
-void LLTexLayerParamColor::animate(F32 delta)
+void LLTexLayerParamColor::animate(F32 delta, BOOL upload_bake)
 {
 	if (mNext)
 	{
-		mNext->animate(delta);
+		mNext->animate(delta, upload_bake);
 	}
 }
 
diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h
index 0cb2dedbff869d21e70f45f16ecf166c173a799a..900dd5c205c32da507c87fb64fbef597d7a527a2 100755
--- a/indra/llappearance/lltexlayerparams.h
+++ b/indra/llappearance/lltexlayerparams.h
@@ -85,10 +85,9 @@ public:
 	// LLVisualParam Virtual functions
 	///*virtual*/ BOOL		parseData(LLXmlTreeNode* node);
 	/*virtual*/ void		apply( ESex avatar_sex ) {}
-	/*virtual*/ void		setWeight(F32 weight);
-	/*virtual*/ void		setAnimationTarget(F32 target_value); 
-	/*virtual*/ void		animate(F32 delta);
-
+	/*virtual*/ void		setWeight(F32 weight, BOOL upload_bake) override;
+	/*virtual*/ void		setAnimationTarget(F32 target_value, BOOL upload_bake) override;
+	/*virtual*/ void		animate(F32 delta, BOOL upload_bake) override;
 	// LLViewerVisualParam Virtual functions
 	/*virtual*/ F32					getTotalDistortion()									{ return 1.f; }
 	/*virtual*/ const LLVector4a&	getAvgDistortion()										{ return mAvgDistortionVec; }
@@ -178,9 +177,9 @@ public:
 	// LLVisualParam Virtual functions
 	///*virtual*/ BOOL			parseData(LLXmlTreeNode* node);
 	/*virtual*/ void			apply( ESex avatar_sex ) {}
-	/*virtual*/ void			setWeight(F32 weight);
-	/*virtual*/ void			setAnimationTarget(F32 target_value);
-	/*virtual*/ void			animate(F32 delta);
+	/*virtual*/ void			setWeight(F32 weight, BOOL upload_bake) override;
+	/*virtual*/ void			setAnimationTarget(F32 target_value, BOOL upload_bake) override;
+	/*virtual*/ void			animate(F32 delta, BOOL upload_bake) override;
 
 
 	// LLViewerVisualParam Virtual functions
@@ -196,7 +195,7 @@ public:
 protected:
 	LLTexLayerParamColor(const LLTexLayerParamColor& pOther);
 
-	virtual void onGlobalColorChanged() {}
+	virtual void onGlobalColorChanged(bool upload_bake) {}
 private:
 	LL_ALIGN_16(LLVector4a				mAvgDistortionVec);
 } LL_ALIGN_POSTFIX(16);
diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp
index af8394b60ce9209fe92bde53ec38a2e55c18fbe7..52e204205d254f64ec9e335bf15d4e9c760a20f0 100644
--- a/indra/llappearance/llviewervisualparam.cpp
+++ b/indra/llappearance/llviewervisualparam.cpp
@@ -153,7 +153,7 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
 		return FALSE;
 	mInfo = info;
 	mID = info->mID;
-	setWeight(getDefaultWeight());
+	setWeight(getDefaultWeight(), FALSE);
 	return TRUE;
 }
 
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp
index dd94afeb9ee32174f6df3d4fe146d5f769b7b322..6a94f7015b1e13f06f05bc5ee80a7b3b16ea555c 100755
--- a/indra/llappearance/llwearable.cpp
+++ b/indra/llappearance/llwearable.cpp
@@ -549,7 +549,7 @@ void LLWearable::revertValues()
 		LLVisualParam *param = getVisualParam(id);
 		if(param &&  !dynamic_cast<LLDriverParam*>(param) )
 		{
-			setVisualParamWeight(id, value);
+			setVisualParamWeight(id, value, TRUE);
 		}
 	}
 
@@ -561,7 +561,7 @@ void LLWearable::revertValues()
 		LLVisualParam *param = getVisualParam(id);
 		if(param &&  dynamic_cast<LLDriverParam*>(param) )
 		{
-			setVisualParamWeight(id, value);
+			setVisualParamWeight(id, value, TRUE);
 		}
 	}
 
@@ -664,12 +664,12 @@ void LLWearable::addVisualParam(LLVisualParam *param)
 }
 
 
-void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
+void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake)
 {
 	if( is_in_map(mVisualParamIndexMap, param_index ) )
 	{
 		LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
-		wearable_param->setWeight(value);
+		wearable_param->setWeight(value, upload_bake);
 	}
 	else
 	{
@@ -713,14 +713,14 @@ void LLWearable::getVisualParams(visual_param_vec_t &list)
 	}
 }
 
-void LLWearable::animateParams(F32 delta)
+void LLWearable::animateParams(F32 delta, BOOL upload_bake)
 {
 	for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin();
 		 iter != mVisualParamIndexMap.end();
 		 ++iter)
 	{
 		LLVisualParam *param = (LLVisualParam*) iter->second;
-		param->animate(delta);
+		param->animate(delta, upload_bake);
 	}
 }
 
@@ -738,14 +738,14 @@ LLColor4 LLWearable::getClothesColor(S32 te) const
 	return color;
 }
 
-void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)
+void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake)
 {
 	U32 param_name[3];
 	if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )
 	{
 		for( U8 index = 0; index < 3; index++ )
 		{
-			setVisualParamWeight(param_name[index], new_color.mV[index]);
+			setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake);
 		}
 	}
 }
@@ -764,7 +764,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
 			S32 param_id = param->getID();
 			F32 weight = getVisualParamWeight(param_id);
 
-			avatarp->setVisualParamWeight( param_id, weight);
+			avatarp->setVisualParamWeight( param_id, weight, FALSE);
 		}
 	}
 #else
@@ -772,7 +772,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
 	{
 		LLVisualParam* param = it->second;
 		if(!((LLViewerVisualParam*)param)->getCrossWearable())
-			avatarp->setVisualParamWeight( param->getID(), param->getWeight() );
+			avatarp->setVisualParamWeight( param->getID(), param->getWeight(), FALSE );
 	}
 #endif
 }
diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h
index f50119418f554188950e3e165b190e848659de2d..eb668ac07d7b85af32878d2d1565468e8c87eb18 100755
--- a/indra/llappearance/llwearable.h
+++ b/indra/llappearance/llwearable.h
@@ -96,14 +96,13 @@ public:
 
 	void				setLocalTextureObject(S32 index, LLLocalTextureObject &lto);
 	void				addVisualParam(LLVisualParam *param);
-	void 				setVisualParamWeight(S32 index, F32 value);
+	void 				setVisualParamWeight(S32 index, F32 value, BOOL upload_bake);
 	F32					getVisualParamWeight(S32 index) const;
 	LLVisualParam*		getVisualParam(S32 index) const;
 	void				getVisualParams(visual_param_vec_t &list);
-	void				animateParams(F32 delta);
-
+	void				animateParams(F32 delta, BOOL upload_bake);
 	LLColor4			getClothesColor(S32 te) const;
-	void 				setClothesColor( S32 te, const LLColor4& new_color);
+	void 				setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake);
 
 	virtual void		revertValues();
 	virtual void		saveValues();
diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index 5416304c93d52ab53ba50398928e8e1f4af0cb73..b6e3fb26a3f14935fe4b9e85ede5d830c4411650 100755
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -287,13 +287,13 @@ void LLCharacter::removeAnimationData(std::string name)
 //-----------------------------------------------------------------------------
 // setVisualParamWeight()
 //-----------------------------------------------------------------------------
-BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight)
+BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, BOOL upload_bake)
 {
 	S32 index = which_param->getID();
 	visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
 	if (index_iter != mVisualParamIndexMap.end())
 	{
-		index_iter->second->setWeight(weight);
+		index_iter->second->setWeight(weight, upload_bake);
 		return TRUE;
 	}
 	return FALSE;
@@ -302,7 +302,7 @@ BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 wei
 //-----------------------------------------------------------------------------
 // setVisualParamWeight()
 //-----------------------------------------------------------------------------
-BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)
+BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake)
 {
 	std::string tname(param_name);
 	LLStringUtil::toLower(tname);
@@ -310,7 +310,7 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)
 	visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr);
 	if (name_iter != mVisualParamNameMap.end())
 	{
-		name_iter->second->setWeight(weight);
+		name_iter->second->setWeight(weight, upload_bake);
 		return TRUE;
 	}
 	LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL;
@@ -320,12 +320,12 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)
 //-----------------------------------------------------------------------------
 // setVisualParamWeight()
 //-----------------------------------------------------------------------------
-BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight)
+BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake)
 {
 	visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);
 	if (index_iter != mVisualParamIndexMap.end())
 	{
-		index_iter->second->setWeight(weight);
+		index_iter->second->setWeight(weight, upload_bake);
 		return TRUE;
 	}
 	LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL;
@@ -395,7 +395,7 @@ void LLCharacter::clearVisualParamWeights()
 	{
 		if (param->isTweakable())
 		{
-			param->setWeight( param->getDefaultWeight());
+			param->setWeight( param->getDefaultWeight(), FALSE);
 		}
 	}
 }
diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h
index 174899d7b5845eec1354cd600c107184f0fd2bcb..4840b44dc41ac55b17076e24670fe4a0542eb15c 100755
--- a/indra/llcharacter/llcharacter.h
+++ b/indra/llcharacter/llcharacter.h
@@ -194,9 +194,10 @@ public:
 	void addVisualParam(LLVisualParam *param);
 	void addSharedVisualParam(LLVisualParam *param);
 
-	virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight);
-	virtual BOOL setVisualParamWeight(const char* param_name, F32 weight);
-	virtual BOOL setVisualParamWeight(S32 index, F32 weight);
+	virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE );
+	virtual BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE );
+	virtual BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE );
+
 
 	// get visual param weight by param or name
 	F32 getVisualParamWeight(LLVisualParam *distortion);
diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp
index 2235496ac5f411882df6cf387887ea9755447eb2..aae176b4e82cc8a8556857564f75aa92cd5c74c6 100755
--- a/indra/llcharacter/llvisualparam.cpp
+++ b/indra/llcharacter/llvisualparam.cpp
@@ -236,7 +236,7 @@ BOOL LLVisualParam::parseData(LLXmlTreeNode *node)
 //-----------------------------------------------------------------------------
 // setWeight()
 //-----------------------------------------------------------------------------
-void LLVisualParam::setWeight(F32 weight)
+void LLVisualParam::setWeight(F32 weight, BOOL upload_bake)
 {
 	if (mIsAnimating)
 	{
@@ -254,19 +254,19 @@ void LLVisualParam::setWeight(F32 weight)
 	
 	if (mNext)
 	{
-		mNext->setWeight(weight);
+		mNext->setWeight(weight, upload_bake);
 	}
 }
 
 //-----------------------------------------------------------------------------
 // setAnimationTarget()
 //-----------------------------------------------------------------------------
-void LLVisualParam::setAnimationTarget(F32 target_value)
+void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake)
 {
 	// don't animate dummy parameters
 	if (mIsDummy)
 	{
-		setWeight(target_value);
+		setWeight(target_value, upload_bake);
 		mTargetWeight = mCurWeight;
 		return;
 	}
@@ -286,7 +286,7 @@ void LLVisualParam::setAnimationTarget(F32 target_value)
 
 	if (mNext)
 	{
-		mNext->setAnimationTarget(target_value);
+		mNext->setAnimationTarget(target_value, upload_bake);
 	}
 }
 
@@ -311,24 +311,24 @@ void LLVisualParam::clearNextParam()
 //-----------------------------------------------------------------------------
 // animate()
 //-----------------------------------------------------------------------------
-void LLVisualParam::animate( F32 delta)
+void LLVisualParam::animate( F32 delta, BOOL upload_bake)
 {
 	if (mIsAnimating)
 	{
 		F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight;
-		setWeight(new_weight);
+		setWeight(new_weight, upload_bake);
 	}
 }
 
 //-----------------------------------------------------------------------------
 // stopAnimating()
 //-----------------------------------------------------------------------------
-void LLVisualParam::stopAnimating()
+void LLVisualParam::stopAnimating(BOOL upload_bake)
 { 
 	if (mIsAnimating && isTweakable())
 	{
 		mIsAnimating = FALSE; 
-		setWeight(mTargetWeight);
+		setWeight(mTargetWeight, upload_bake);
 	}
 }
 
diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h
index b1269a20736190f66e188a2dd3b17868f9ee9083..6592f4ece436235bc8f52aca5ea7a4b7ff7a4bf2 100755
--- a/indra/llcharacter/llvisualparam.h
+++ b/indra/llcharacter/llvisualparam.h
@@ -132,10 +132,10 @@ public:
 	//virtual BOOL			parseData( LLXmlTreeNode *node ) = 0;
 	virtual void			apply( ESex avatar_sex ) = 0;
 	//  Default functions
-	virtual void			setWeight(F32 weight);
-	virtual void			setAnimationTarget( F32 target_value);
-	virtual void			animate(F32 delta);
-	virtual void			stopAnimating();
+	virtual void			setWeight(F32 weight, BOOL upload_bake);
+	virtual void			setAnimationTarget( F32 target_value, BOOL upload_bake);
+	virtual void			animate(F32 delta, BOOL upload_bake);
+	virtual void			stopAnimating(BOOL upload_bake);
 
 	virtual BOOL			linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
 	virtual void			resetDrivenParams();
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index ded47875ad62de2c81e7cd4bf18fa53a7282fc71..290b30f4dd3f04dbd278aede7502a4a02e76cc03 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -133,6 +133,7 @@ set(viewer_SOURCE_FILES
     llagentpilot.cpp
     llagentui.cpp
     llagentwearables.cpp
+    llagentwearablesfetch.cpp
     llaisapi.cpp
     llanimstatelabels.cpp
     llappcorehttp.cpp
@@ -772,6 +773,7 @@ set(viewer_HEADER_FILES
     llagentpilot.h
     llagentui.h
     llagentwearables.h
+    llagentwearablesfetch.h
     llaisapi.h
     llanimstatelabels.h
     llappcorehttp.h
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index c343a30144eecaea08f4696e20ae4daee050bc61..67c0fc8a6b0965a1296b93984982c2101a44b96f 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -429,6 +429,7 @@ LLAgent::LLAgent() :
 
 	mVoiceConnected(false),
 
+	mAppearanceSerialNum(0),
 	mMouselookModeInSignal(NULL),
 	mMouselookModeOutSignal(NULL)
 {
@@ -834,6 +835,29 @@ void LLAgent::standUp()
 	setControlFlags(AGENT_CONTROL_STAND_UP);
 }
 
+void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id)
+{
+	LL_INFOS() << "called" << LL_ENDL;
+
+
+	// Old-style appearance entering a server-bake region.
+	if (isAgentAvatarValid() &&
+		!gAgentAvatarp->isUsingServerBakes() &&
+		(mRegionp->getCentralBakeVersion()>0))
+	{
+		LL_INFOS() << "update requested due to region transition" << LL_ENDL;
+		LLAppearanceMgr::instance().requestServerAppearanceUpdate();
+	}
+	// new-style appearance entering a non-bake region,
+	// need to check for existence of the baking service.
+	else if (isAgentAvatarValid() &&
+			 gAgentAvatarp->isUsingServerBakes() &&
+			 mRegionp->getCentralBakeVersion()==0)
+	{
+		gAgentAvatarp->checkForUnsupportedServerBakeAppearance();
+	}
+}
+
 void LLAgent::changeParcels()
 {
 	LL_DEBUGS("AgentLocation") << "Calling ParcelChanged callbacks" << LL_ENDL;
@@ -929,6 +953,19 @@ void LLAgent::setRegion(LLViewerRegion *regionp)
 
 	LLFloaterMove::sUpdateFlyingStatus();
 
+	// If the newly entered region is using server bakes, and our
+	// current appearance is non-baked, request appearance update from
+	// server.
+	if (mRegionp->capabilitiesReceived())
+	{
+		handleServerBakeRegionTransition(mRegionp->getRegionID());
+	}
+	else
+	{
+		// Need to handle via callback after caps arrive.
+		mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition,this,_1));
+	}
+
 	LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL;
 	mRegionChangedSignal();
 }
@@ -3707,6 +3744,82 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **)
 }
 */
 
+//static
+void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data)
+{
+	gAgentQueryManager.mNumPendingQueries--;
+	if (gAgentQueryManager.mNumPendingQueries == 0)
+	{
+		selfStopPhase("fetch_texture_cache_entries");
+	}
+
+	if (!isAgentAvatarValid() || gAgentAvatarp->isDead())
+	{
+		LL_WARNS() << "No avatar for user in cached texture update!" << LL_ENDL;
+		return;
+	}
+
+	if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance())
+	{
+		// ignore baked textures when in customize mode
+		return;
+	}
+
+	S32 query_id;
+	mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id);
+
+	S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData);
+
+
+	S32 num_results = 0;
+	for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++)
+	{
+		LLUUID texture_id;
+		U8 texture_index;
+
+		mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block);
+		mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block);
+
+
+		if ((S32)texture_index < TEX_NUM_INDICES )
+		{
+			const LLAvatarAppearanceDictionary::TextureEntry *texture_entry = LLAvatarAppearanceDictionary::instance().getTexture((ETextureIndex)texture_index);
+			if (texture_entry)
+			{
+				EBakedTextureIndex baked_index = texture_entry->mBakedTextureIndex;
+
+				if (gAgentQueryManager.mActiveCacheQueries[baked_index] == query_id)
+				{
+					if (texture_id.notNull())
+					{
+						//LL_INFOS() << "Received cached texture " << (U32)texture_index << ": " << texture_id << LL_ENDL;
+						gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id);
+						//gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
+						gAgentQueryManager.mActiveCacheQueries[baked_index] = 0;
+						num_results++;
+					}
+					else
+					{
+						// no cache of this bake. request upload.
+						gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE);
+					}
+				}
+			}
+		}
+	}
+	LL_INFOS() << "Received cached texture response for " << num_results << " textures." << LL_ENDL;
+	gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them");
+
+	gAgentAvatarp->updateMeshTextures();
+
+	if (gAgentQueryManager.mNumPendingQueries == 0)
+	{
+		// RN: not sure why composites are disabled at this point
+		gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
+		gAgent.sendAgentSetAppearance();
+	}
+}
+
 BOOL LLAgent::anyControlGrabbed() const
 {
 	for (U32 i = 0; i < TOTAL_CONTROLS; i++)
@@ -4326,6 +4439,193 @@ void LLAgent::requestLeaveGodMode()
 	sendReliableMessage();
 }
 
+// For debugging, trace agent state at times appearance message are sent out.
+void LLAgent::dumpSentAppearance(const std::string& dump_prefix)
+{
+	std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");
+
+	LLAPRFile outfile;
+	std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename);
+	outfile.open(fullpath, LL_APR_WB );
+	apr_file_t* file = outfile.getFileHandle();
+	if (!file)
+	{
+		return;
+	}
+	else
+	{
+		LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << LL_ENDL;
+	}
+
+	LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000);
+	if (appearance_version_param)
+	{
+		F32 value = appearance_version_param->getWeight();
+		dump_visual_param(file, appearance_version_param, value);
+	}
+	for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
+		 iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
+		 ++iter)
+	{
+		const ETextureIndex index = iter->first;
+		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
+		if (texture_dict->mIsBakedTexture)
+		{
+			LLTextureEntry* entry = gAgentAvatarp->getTE((U8) index);
+			const LLUUID& uuid = entry->getID();
+			apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", index, uuid.asString().c_str());
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// sendAgentSetAppearance()
+//-----------------------------------------------------------------------------
+void LLAgent::sendAgentSetAppearance()
+{
+	if (gAgentQueryManager.mNumPendingQueries > 0) 
+	{
+		return;
+	}
+
+	if (!isAgentAvatarValid() || gAgentAvatarp->isEditingAppearance() || (getRegion() && getRegion()->getCentralBakeVersion())) return;
+
+	// At this point we have a complete appearance to send and are in a non-baking region.
+	// DRANO FIXME
+	//gAgentAvatarp->setIsUsingServerBakes(FALSE);
+	S32 sb_count, host_count, both_count, neither_count;
+	gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count);
+	if (both_count != 0 || neither_count != 0)
+	{
+		LL_WARNS() << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << LL_ENDL;
+	}
+	if (sb_count != 0 && host_count == 0)
+	{
+		gAgentAvatarp->setIsUsingServerBakes(true);
+	}
+	else if (sb_count == 0 && host_count != 0)
+	{
+		gAgentAvatarp->setIsUsingServerBakes(false);
+	}
+	else if (sb_count + host_count > 0)
+	{
+		LL_WARNS() << "unclear baked texture state, not sending appearance" << LL_ENDL;
+		return;
+	}
+	
+
+	LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL;
+	//dumpAvatarTEs( "sendAgentSetAppearance()" );
+
+	LLMessageSystem* msg = gMessageSystem;
+	msg->newMessageFast(_PREHASH_AgentSetAppearance);
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, getID());
+	msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+
+	// correct for the collision tolerance (to make it look like the 
+	// agent is actually walking on the ground/object)
+	// NOTE -- when we start correcting all of the other Havok geometry 
+	// to compensate for the COLLISION_TOLERANCE ugliness we will have 
+	// to tweak this number again
+	const LLVector3 body_size = gAgentAvatarp->mBodySize + gAgentAvatarp->mAvatarOffset;
+	msg->addVector3Fast(_PREHASH_Size, body_size);	
+
+	// To guard against out of order packets
+	// Note: always start by sending 1.  This resets the server's count. 0 on the server means "uninitialized"
+	mAppearanceSerialNum++;
+	msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum );
+
+	// is texture data current relative to wearables?
+	// KLW - TAT this will probably need to check the local queue.
+	BOOL textures_current = gAgentAvatarp->areTexturesCurrent();
+
+	for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ )
+	{
+		const ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index);
+
+		// if we're not wearing a skirt, we don't need the texture to be baked
+		if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))
+		{
+			continue;
+		}
+
+		// IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures
+		if (!gAgentAvatarp->isTextureDefined(texture_index, 0))
+		{
+			LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << LL_ENDL;
+			textures_current = FALSE;
+			break;
+		}
+	}
+
+	// only update cache entries if we have all our baked textures
+
+	// FIXME DRANO need additional check for not in appearance editing
+	// mode, if still using local composites need to set using local
+	// composites to false, and update mesh textures.
+	if (textures_current)
+	{
+		bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage");
+		std::string dump_prefix = gAgentAvatarp->getFullname() + "_sent_appearance";
+		if (enable_verbose_dumps)
+		{
+			dumpSentAppearance(dump_prefix);
+		}
+		LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL;
+		for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+		{
+			BOOL generate_valid_hash = TRUE;
+			if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLAvatarAppearanceDefines::EBakedTextureIndex)baked_index))
+			{
+				generate_valid_hash = FALSE;
+				LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL;
+			}
+
+			const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash);
+			if (hash.notNull())
+			{
+				ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index);
+				msg->nextBlockFast(_PREHASH_WearableData);
+				msg->addUUIDFast(_PREHASH_CacheID, hash);
+				msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index);
+			}
+		}
+		msg->nextBlockFast(_PREHASH_ObjectData);
+		gAgentAvatarp->sendAppearanceMessage( gMessageSystem );
+	}
+	else
+	{
+		// If the textures aren't baked, send NULL for texture IDs
+		// This means the baked texture IDs on the server will be untouched.
+		// Once all textures are baked, another AvatarAppearance message will be sent to update the TEs
+		msg->nextBlockFast(_PREHASH_ObjectData);
+		gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0);
+	}
+
+
+	S32 transmitted_params = 0;
+	for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam();
+		 param;
+		 param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam())
+	{
+		if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ||
+				param->getGroup() == VISUAL_PARAM_GROUP_TRANSMIT_NOT_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
+		{
+			msg->nextBlockFast(_PREHASH_VisualParam );
+
+			// We don't send the param ids.  Instead, we assume that the receiver has the same params in the same sequence.
+			const F32 param_value = param->getWeight();
+			const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight());
+			msg->addU8Fast(_PREHASH_ParamValue, new_weight );
+			transmitted_params++;
+		}
+	}
+
+	LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL;
+	sendReliableMessage();
+}
+
 void LLAgent::sendAgentDataUpdateRequest()
 {
 	gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest);
@@ -4468,6 +4768,23 @@ void LLAgent::renderAutoPilotTarget()
 
 /********************************************************************************/
 
+LLAgentQueryManager gAgentQueryManager;
+
+LLAgentQueryManager::LLAgentQueryManager() :
+	mWearablesCacheQueryID(0),
+	mNumPendingQueries(0),
+	mUpdateSerialNum(0)
+{
+	for (U32 i = 0; i < BAKED_NUM_INDICES; i++)
+	{
+		mActiveCacheQueries[i] = 0;
+	}
+}
+
+LLAgentQueryManager::~LLAgentQueryManager()
+{
+}
+
 //-----------------------------------------------------------------------------
 // LLTeleportRequest
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h
index 3a8920fa7e2021439f1425f344aab79ac9bbeb83..c27ed8ea5d6a412e546ca9b37d5360afd4a45cb5 100755
--- a/indra/newview/llagent.h
+++ b/indra/newview/llagent.h
@@ -672,6 +672,7 @@ private:
 
 	void            handleTeleportFinished();
 	void            handleTeleportFailed();
+	void			handleServerBakeRegionTransition(const LLUUID& region_id);
 
 	//--------------------------------------------------------------------
 	// Teleport State
@@ -806,6 +807,7 @@ public:
 	
 private:
 	BOOL			mShowAvatar; 		// Should we render the avatar?
+	U32				mAppearanceSerialNum;
 
 	//--------------------------------------------------------------------
 	// Rendering state bitmap helpers
@@ -906,6 +908,8 @@ private:
 public:
 	void			sendMessage(); // Send message to this agent's region
 	void			sendReliableMessage();
+	void 			dumpSentAppearance(const std::string& dump_prefix);
+	void			sendAgentSetAppearance();
 	void 			sendAgentDataUpdateRequest();
 	void 			sendAgentUserInfoRequest();
 	// IM to Email and Online visibility
@@ -919,6 +923,7 @@ public:
 	static void		processAgentGroupDataUpdate(LLMessageSystem *msg, void **);
 	static void		processAgentDropGroup(LLMessageSystem *msg, void **);
 	static void		processScriptControlChange(LLMessageSystem *msg, void **);
+	static void		processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data);
 	
 /**                    Messaging
  **                                                                            **
@@ -947,4 +952,24 @@ inline bool operator==(const LLGroupData &a, const LLGroupData &b)
 	return (a.mID == b.mID);
 }
 
+class LLAgentQueryManager
+{
+	friend class LLAgent;
+	friend class LLAgentWearables;
+	
+public:
+	LLAgentQueryManager();
+	virtual ~LLAgentQueryManager();
+	
+	BOOL 			hasNoPendingQueries() const 	{ return getNumPendingQueries() == 0; }
+	S32 			getNumPendingQueries() const 	{ return mNumPendingQueries; }
+private:
+	S32				mNumPendingQueries;
+	S32				mWearablesCacheQueryID;
+	U32				mUpdateSerialNum;
+	S32		    	mActiveCacheQueries[LLAvatarAppearanceDefines::BAKED_NUM_INDICES];
+};
+
+extern LLAgentQueryManager gAgentQueryManager;
+
 #endif
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 06b86e311a0233a2ad976bac1545930a335e1cdd..9470207342b3341c0fdfe7e12231035967894d01 100755
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -54,6 +54,8 @@
 
 #include <boost/scoped_ptr.hpp>
 
+#include "llagentwearablesfetch.h"
+#include "llviewernetwork.h"
 LLAgentWearables gAgentWearables;
 
 BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;
@@ -210,6 +212,11 @@ void LLAgentWearables::initClass()
 void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
 {
 	llassert(avatar);
+	if (!LLGridManager::getInstance()->isInSecondlife())
+	{
+		avatar->outputRezTiming("Sending wearables request");
+		sendAgentWearablesRequest();
+	}
 	setAvatarAppearance(avatar);
 }
 
@@ -242,9 +249,24 @@ void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& i
 
 	gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable);
 
+	if (mTodo & CALL_UPDATE)
+	{
+		gAgentWearables.sendAgentWearablesUpdate();
+	}
+	if (mTodo & CALL_RECOVERDONE)
+	{
+		LLAppearanceMgr::instance().addCOFItemLink(inv_item);
+		gAgentWearables.recoverMissingWearableDone();
+	}
+
 	/*
 	 * Do this for every one in the loop
 	 */
+	if (mTodo & CALL_CREATESTANDARDDONE)
+	{
+		LLAppearanceMgr::instance().addCOFItemLink(inv_item);
+		gAgentWearables.createStandardWearablesDone(mType, mIndex);
+	}
 	if (mTodo & CALL_MAKENEWOUTFITDONE)
 	{
 		gAgentWearables.makeNewOutfitDone(mType, mIndex);
@@ -299,7 +321,81 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy
 	gInventory.notifyObservers();
 }
 
-void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index,
+void LLAgentWearables::sendAgentWearablesUpdate()
+{
+	// First make sure that we have inventory items for each wearable
+	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
+	{
+		for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index)
+		{
+			LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type,index);
+			if (wearable)
+			{
+				if (wearable->getItemID().isNull())
+				{
+					LLPointer<LLInventoryCallback> cb =
+						new AddWearableToAgentInventoryCallback(
+							LLPointer<LLRefCount>(NULL),
+							(LLWearableType::EType)type,
+							index,
+							wearable,
+							AddWearableToAgentInventoryCallback::CALL_NONE);
+					addWearableToAgentInventory(cb, wearable);
+				}
+				else
+				{
+					gInventory.addChangedMask(LLInventoryObserver::LABEL,
+											  wearable->getItemID());
+				}
+			}
+		}
+	}
+
+	// Then make sure the inventory is in sync with the avatar.
+	gInventory.notifyObservers();
+
+	// Send the AgentIsNowWearing 
+	gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
+
+	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+	LL_DEBUGS() << "sendAgentWearablesUpdate()" << LL_ENDL;
+	// MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables.
+	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
+	{
+		gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+
+		U8 type_u8 = (U8)type;
+		gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8);
+
+		LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type, 0);
+		if (wearable)
+		{
+			//LL_INFOS() << "Sending wearable " << wearable->getName() << LL_ENDL;
+			LLUUID item_id = wearable->getItemID();
+			const LLViewerInventoryItem *item = gInventory.getItem(item_id);
+			if (item && item->getIsLinkType())
+			{
+				// Get the itemID that this item points to.  i.e. make sure
+				// we are storing baseitems, not their links, in the database.
+				item_id = item->getLinkedUUID();
+			}
+			gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);			
+		}
+		else
+		{
+			//LL_INFOS() << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << LL_ENDL;
+			gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
+		}
+
+		LL_DEBUGS() << "       " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL;
+	}
+	gAgent.sendReliableMessage();
+}
+
+void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update,
 									const std::string new_name)
 {
 	LLViewerWearable* old_wearable = getViewerWearable(type, index);
@@ -346,6 +442,10 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32
 		{
 			// Add a new inventory item (shouldn't ever happen here)
 			U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE;
+			if (send_update)
+			{
+				todo |= AddWearableToAgentInventoryCallback::CALL_UPDATE;
+			}
 			LLPointer<LLInventoryCallback> cb =
 				new AddWearableToAgentInventoryCallback(
 					LLPointer<LLRefCount>(NULL),
@@ -357,7 +457,12 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32
 			return;
 		}
 
-		gAgentAvatarp->wearableUpdated(type);
+		gAgentAvatarp->wearableUpdated(type, TRUE);
+
+		if (send_update)
+		{
+			sendAgentWearablesUpdate();
+		}
 	}
 }
 
@@ -434,6 +539,8 @@ void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U3
 	{
 		wearable->revertValues();
 	}
+
+	gAgent.sendAgentSetAppearance();
 }
 
 void LLAgentWearables::saveAllWearables()
@@ -446,8 +553,10 @@ void LLAgentWearables::saveAllWearables()
 	for (S32 i=0; i < LLWearableType::WT_COUNT; i++)
 	{
 		for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++)
-			saveWearable((LLWearableType::EType)i, j);
+			saveWearable((LLWearableType::EType)i, j, FALSE);
 	}
+	//sendAgentWearablesUpdate();
+	gAgent.sendAgentSetAppearance();
 }
 
 // Called when the user changes the name of a wearable inventory item that is currently being worn.
@@ -476,6 +585,7 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&
 				old_wearable->setName(old_name);
 
 				setWearable((LLWearableType::EType)i,j,new_wearable);
+				sendAgentWearablesUpdate();
 				break;
 			}
 		}
@@ -596,6 +706,15 @@ LLViewerWearable*	LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i
 	return NULL;
 }
 
+void LLAgentWearables::sendAgentWearablesRequest()
+{
+	gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
+	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	gAgent.sendReliableMessage();
+}
+
 LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/)
 {
 	return dynamic_cast<LLViewerWearable*> (getWearable(type, index));
@@ -617,7 +736,8 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
 {
 	if (isAgentAvatarValid())
 	{
-		gAgentAvatarp->wearableUpdated(wearable->getType());
+		const BOOL upload_result = removed;
+		gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result);
 	}
 
 	LLWearableData::wearableUpdated(wearable, removed);
@@ -639,7 +759,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
 			{
 				LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL;
 				wearable->setDefinitionVersion(22);
-				saveWearable(wearable->getType(),index);
+				saveWearable(wearable->getType(),index, TRUE);
 			}
 		}
 
@@ -647,6 +767,18 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
 	}
 }
 
+
+
+BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const
+{
+	return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end();
+}
+
+U32 LLAgentWearables::itemUpdatePendingCount() const
+{
+	return mItemsAwaitingWearableUpdate.size();
+}
+
 const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const
 {
 	const LLViewerWearable *wearable = getViewerWearable(type,index);
@@ -670,6 +802,157 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const
 	return getWearableFromItemID(item_id) != NULL;
 }
 
+// MULTI-WEARABLE: DEPRECATED (see backwards compatibility)
+// static
+// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume
+// that viewers have a Current Outfit Folder and won't need this message, and thus
+// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted
+void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data)
+{
+	// We should only receive this message a single time.  Ignore subsequent AgentWearablesUpdates
+	// that may result from AgentWearablesRequest having been sent more than once.
+	if (mInitialWearablesUpdateReceived)
+		return;
+
+	if (isAgentAvatarValid())
+	{
+		gAgentAvatarp->startPhase("process_initial_wearables_update");
+		gAgentAvatarp->outputRezTiming("Received initial wearables update");
+	}
+
+	// notify subscribers that wearables started loading. See EXT-7777
+	// *TODO: find more proper place to not be called from deprecated method.
+	// Seems such place is found: LLInitialWearablesFetch::processContents()
+	gAgentWearables.notifyLoadingStarted();
+
+	mInitialWearablesUpdateReceived = true;
+
+	LLUUID agent_id;
+	gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+
+	if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID()))
+	{
+		gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum);
+
+		const S32 NUM_BODY_PARTS = 4;
+		S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
+		if (num_wearables < NUM_BODY_PARTS)
+		{
+			// Transitional state.  Avatars should always have at least their body parts (hair, eyes, shape and skin).
+			// The fact that they don't have any here (only a dummy is sent) implies that either:
+			// 1. This account existed before we had wearables
+			// 2. The database has gotten messed up
+			// 3. This is the account's first login (i.e. the wearables haven't been generated yet).
+			return;
+		}
+
+		// Get the UUID of the current outfit folder (will be created if it doesn't exist)
+		const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+		LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id);
+
+		//LL_DEBUGS() << "processAgentInitialWearablesUpdate()" << LL_ENDL;
+		// Add wearables
+		// MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future.
+		gAgentWearables.mItemsAwaitingWearableUpdate.clear();
+		for (S32 i = 0; i < num_wearables; i++)
+		{
+			// Parse initial wearables data from message system
+			U8 type_u8 = 0;
+			gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);
+			if (type_u8 >= LLWearableType::WT_COUNT)
+			{
+				continue;
+			}
+			const LLWearableType::EType type = (LLWearableType::EType) type_u8;
+
+			LLUUID item_id;
+			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i);
+
+			LLUUID asset_id;
+			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i);
+			if (asset_id.isNull())
+			{
+				LLViewerWearable::removeFromAvatar(type, FALSE);
+			}
+			else
+			{
+				LLAssetType::EType asset_type = LLWearableType::getAssetType(type);
+				if (asset_type == LLAssetType::AT_NONE)
+				{
+					continue;
+				}
+
+				// MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions
+
+				// Store initial wearables data until we know whether we have the current outfit folder or need to use the data.
+				LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id);
+				outfit->add(wearable_data);
+			}
+
+			LL_DEBUGS() << "       " << LLWearableType::getTypeLabel(type) << LL_ENDL;
+		}
+
+		// Get the complete information on the items in the inventory and set up an observer
+		// that will trigger when the complete information is fetched.
+		outfit->startFetch();
+		if (outfit->isFinished())
+		{
+			// everything is already here - call done.
+			outfit->done();
+		}
+		else
+		{
+			// it's all on it's way - add an observer, and the inventory
+			// will call done for us when everything is here.
+			gInventory.addObserver(outfit);
+		}
+
+	}
+}
+
+// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
+// database.  If for some reason, we can't load one of those assets, we can try to reconstruct it so that
+// the user isn't left without a shape, for example.  (We can do that only after the inventory has loaded.)
+void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index)
+{
+	// Try to recover by replacing missing wearable with a new one.
+	LLNotificationsUtil::add("ReplacedMissingWearable");
+	LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL;
+	LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);
+
+	setWearable(type,index,new_wearable);
+	//new_wearable->writeToAvatar(TRUE);
+
+	// Add a new one in the lost and found folder.
+	// (We used to overwrite the "not found" one, but that could potentially
+	// destory content.) JC
+	const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
+	LLPointer<LLInventoryCallback> cb =
+		new AddWearableToAgentInventoryCallback(
+			LLPointer<LLRefCount>(NULL),
+			type,
+			index,
+			new_wearable,
+			AddWearableToAgentInventoryCallback::CALL_RECOVERDONE);
+	addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE);
+}
+
+void LLAgentWearables::recoverMissingWearableDone()
+{
+	// Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
+	updateWearablesLoaded();
+	if (areWearablesLoaded())
+	{
+		// Make sure that the server's idea of the avatar's wearables actually match the wearables.
+		gAgent.sendAgentSetAppearance();
+	}
+	else
+	{
+		gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null);
+		gInventory.notifyObservers();
+	}
+}
+
 void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index)
 {
 	LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index);
@@ -837,6 +1120,29 @@ void LLAgentWearables::sendDummyAgentWearablesUpdate()
 
 	gAgent.sendReliableMessage();
 }
+void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index)
+{
+	LL_INFOS() << "type " << type << " index " << index << LL_ENDL;
+
+	if (!isAgentAvatarValid()) return;
+	gAgentAvatarp->updateVisualParams();
+}
+
+void LLAgentWearables::createStandardWearablesAllDone()
+{
+	// ... because sendAgentWearablesUpdate will notify inventory
+	// observers.
+	LL_INFOS() << "all done?" << LL_ENDL;
+
+	mWearablesLoaded = TRUE; 
+	checkWearablesLoaded();
+	notifyLoadingFinished();
+	
+	updateServer();
+
+	// Treat this as the first texture entry message, if none received yet
+	gAgentAvatarp->onFirstTEMessageReceived();
+}
 
 void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)
 {
@@ -954,7 +1260,7 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
 			if (old_wearable)
 			{
 				eraseWearable(old_wearable);
-				old_wearable->removeFromAvatar();
+				old_wearable->removeFromAvatar(TRUE);
 			}
 		}
 		clearWearableType(type);
@@ -966,10 +1272,13 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo
 		if (old_wearable)
 		{
 			eraseWearable(old_wearable);
-			old_wearable->removeFromAvatar();
+			old_wearable->removeFromAvatar(TRUE);
 		}
 	}
 
+	queryWearableCache();
+	updateServer();
+
 	gInventory.notifyObservers();
 }
 
@@ -1107,6 +1416,7 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
 	// Start rendering & update the server
 	mWearablesLoaded = TRUE; 
 
+	checkWearablesLoaded();
 	notifyLoadingFinished();
 
 	// Copy wearable params to avatar.
@@ -1115,6 +1425,9 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it
 	// Then update the avatar based on the copied params.
 	gAgentAvatarp->updateVisualParams();
 
+	queryWearableCache();
+	updateServer();
+
 	gAgentAvatarp->dumpAvatarTEs("setWearableOutfit");
 
 	LL_DEBUGS("Avatar") << "setWearableOutfit() end" << LL_ENDL;
@@ -1241,6 +1554,72 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWeara
 				<< " size is now " << getWearableCount(type) << LL_ENDL;
 	}
 }
+void LLAgentWearables::queryWearableCache()
+{
+	if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion()))
+	{
+		return;
+	}
+
+	// Look up affected baked textures.
+	// If they exist:
+	//		disallow updates for affected layersets (until dataserver responds with cache request.)
+	//		If cache miss, turn updates back on and invalidate composite.
+	//		If cache hit, modify baked texture entries.
+	//
+	// Cache requests contain list of hashes for each baked texture entry.
+	// Response is list of valid baked texture assets. (same message)
+
+	gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
+	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID);
+
+	S32 num_queries = 0;
+	for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+	{
+		LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index);
+		if (hash_id.notNull())
+		{
+			num_queries++;
+			// *NOTE: make sure at least one request gets packed
+
+			ETextureIndex te_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index);
+
+			//LL_INFOS() << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << LL_ENDL;
+			gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+			gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id);
+			gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index);
+		}
+
+		gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID;
+	}
+	//VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout
+	if(gAgent.getRegion())
+	{
+		if (isAgentAvatarValid())
+		{
+			selfStartPhase("fetch_texture_cache_entries");
+			gAgentAvatarp->outputRezTiming("Fetching textures from cache");
+		}
+
+		LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL;
+		gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
+		gAgentQueryManager.mNumPendingQueries++;
+		gAgentQueryManager.mWearablesCacheQueryID++;
+	}
+}
+
+// virtual
+void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const
+{
+	// Add some garbage into the hash so that it becomes invalid.
+	if (isAgentAvatarValid())
+	{
+		hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES);
+	}
+}
 
 // User has picked "remove from avatar" from a menu.
 // static
@@ -1263,6 +1642,8 @@ void LLAgentWearables::userRemoveWearablesOfType(const LLWearableType::EType &ty
 	}
 }
 
+
+
 // Given a desired set of attachments, find what objects need to be
 // removed, and what additional inventory items need to be added.
 void LLAgentWearables::findAttachmentsAddRemoveInfo(LLInventoryModel::item_array_t& obj_item_array,
@@ -1394,6 +1775,17 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
     }
 }
 
+void LLAgentWearables::checkWearablesLoaded() const
+{
+#ifdef SHOW_ASSERT
+	U32 item_pend_count = itemUpdatePendingCount();
+	if (mWearablesLoaded)
+	{
+		llassert(item_pend_count==0);
+	}
+#endif
+}
+
 // Returns false if the given wearable is already topmost/bottommost
 // (depending on closer_to_body parameter).
 bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const
@@ -1410,9 +1802,20 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod
 
 BOOL LLAgentWearables::areWearablesLoaded() const
 {
+	checkWearablesLoaded();
 	return mWearablesLoaded;
 }
 
+// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate
+void LLAgentWearables::updateWearablesLoaded()
+{
+	mWearablesLoaded = (itemUpdatePendingCount()==0);
+	if (mWearablesLoaded)
+	{
+		notifyLoadingFinished();
+	}
+}
+
 bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const
 {
 	if (!wearable) return false;
@@ -1422,7 +1825,7 @@ bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) co
 	return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES))
 			 && (getWearableCount(type) <= 1) );		  
 }
-void LLAgentWearables::animateAllWearableParams(F32 delta)
+void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)
 {
 	for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type )
 	{
@@ -1432,7 +1835,7 @@ void LLAgentWearables::animateAllWearableParams(F32 delta)
 			llassert(wearable);
 			if (wearable)
 			{
-				wearable->animateParams(delta);
+				wearable->animateParams(delta, upload_bake);
 			}
 		}
 	}
@@ -1569,6 +1972,12 @@ void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id)
 	}
 }
 
+void LLAgentWearables::updateServer()
+{
+	sendAgentWearablesUpdate();
+	gAgent.sendAgentSetAppearance();
+}
+
 boost::signals2::connection LLAgentWearables::addLoadingStartedCallback(loading_started_callback_t cb)
 {
 	return mLoadingStartedSignal.connect(cb);
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 100448202080c8a2f6ecdfae5dd086e01dc4a5b5..566478c8eeae3c4f1c7ab7bb13fa0dabc7ba73c8 100755
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -42,6 +42,7 @@
 class LLInventoryItem;
 class LLVOAvatarSelf;
 class LLViewerWearable;
+class LLInitialWearablesFetch;
 class LLViewerObject;
 
 class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearableData
@@ -50,6 +51,7 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable
 	// Constructors / destructors / Initializers
 	//--------------------------------------------------------------------
 public:
+	friend class LLInitialWearablesFetch;
 
 	LLAgentWearables();
 	virtual ~LLAgentWearables();
@@ -60,6 +62,9 @@ public:
 
 	// LLInitClass interface
 	static void initClass();
+protected:
+	void			createStandardWearablesDone(S32 type, U32 index/* = 0*/);
+	void			createStandardWearablesAllDone();
 	
 	//--------------------------------------------------------------------
 	// Queries
@@ -80,7 +85,7 @@ public:
 	// Note: False for shape, skin, eyes, and hair, unless you have MORE than 1.
 	bool			canWearableBeRemoved(const LLViewerWearable* wearable) const;
 
-	void			animateAllWearableParams(F32 delta);
+	void			animateAllWearableParams(F32 delta, BOOL upload_bake);
 
 	//--------------------------------------------------------------------
 	// Accessors
@@ -147,10 +152,28 @@ private:
 	void			removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);
 protected:
 	static bool		onRemoveWearableDialog(const LLSD& notification, const LLSD& response);
+	
+	//--------------------------------------------------------------------
+	// Server Communication
+	//--------------------------------------------------------------------
+public:
+	// Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant)
+	static void		processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data);
+
+protected:
+
+	/*virtual*/ void	invalidateBakedTextureHash(LLMD5& hash) const;
+	void			sendAgentWearablesUpdate();
+	void			sendAgentWearablesRequest();
+	void			queryWearableCache();
+	void 			updateServer();
+	static void		onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata);
 
 	//--------------------------------------------------------------------
 	// Outfits
 	//--------------------------------------------------------------------
+
+
 private:
 	void			makeNewOutfitDone(S32 type, U32 index); 
 
@@ -159,7 +182,7 @@ private:
 	//--------------------------------------------------------------------
 public:	
 	void			saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found);
-	void			saveWearable(const LLWearableType::EType type, const U32 index,
+	void			saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE,
 								 const std::string new_name = "");
 	void			saveAllWearables();
 	void			revertWearable(const LLWearableType::EType type, const U32 index);
@@ -185,6 +208,9 @@ public:
 	static void		userRemoveMultipleAttachments(llvo_vec_t& llvo_array);
 	static void		userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array);
 
+	BOOL			itemUpdatePending(const LLUUID& item_id) const;
+	U32				itemUpdatePendingCount() const;
+
 	//--------------------------------------------------------------------
 	// Signals
 	//--------------------------------------------------------------------
@@ -211,6 +237,7 @@ private:
 private:
 	static BOOL		mInitialWearablesUpdateReceived;
 	BOOL			mWearablesLoaded;
+	std::set<LLUUID>	mItemsAwaitingWearableUpdate;
 
 	/**
 	 * True if agent's outfit is being changed now.
@@ -222,6 +249,18 @@ private:
 	// Support classes
 	//--------------------------------------------------------------------------------
 private:
+
+	class createStandardWearablesAllDoneCallback : public LLRefCount
+	{
+	protected:
+		~createStandardWearablesAllDoneCallback();
+	};
+	class sendAgentWearablesUpdateCallback : public LLRefCount
+	{
+	protected:
+		~sendAgentWearablesUpdateCallback();
+	};
+
 	class AddWearableToAgentInventoryCallback : public LLInventoryCallback
 	{
 	public:
diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c56ac6d82291a07f9fe14f49ee82c8bb7b80211a
--- /dev/null
+++ b/indra/newview/llagentwearablesfetch.cpp
@@ -0,0 +1,202 @@
+/** 
+ * @file llagentwearablesfetch.cpp
+ * @brief LLAgentWearblesFetch class implementation
+ *
+ * $LicenseInfo:firstyear=2001&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 "llagentwearablesfetch.h"
+
+#include "llagent.h"
+#include "llagentwearables.h"
+#include "llappearancemgr.h"
+#include "llinventoryfunctions.h"
+#include "llstartup.h"
+#include "llvoavatarself.h"
+
+
+LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) :
+	LLInventoryFetchDescendentsObserver(cof_id)
+{
+	if (isAgentAvatarValid())
+	{
+		gAgentAvatarp->startPhase("initial_wearables_fetch");
+		gAgentAvatarp->outputRezTiming("Initial wearables fetch started");
+	}
+}
+
+LLInitialWearablesFetch::~LLInitialWearablesFetch()
+{
+}
+
+// virtual
+void LLInitialWearablesFetch::done()
+{
+	// Delay processing the actual results of this so it's not handled within
+	// gInventory.notifyObservers.  The results will be handled in the next
+	// idle tick instead.
+	gInventory.removeObserver(this);
+	doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this));
+	if (isAgentAvatarValid())
+	{
+		gAgentAvatarp->stopPhase("initial_wearables_fetch");
+		gAgentAvatarp->outputRezTiming("Initial wearables fetch done");
+	}
+}
+
+void LLInitialWearablesFetch::add(InitialWearableData &data)
+
+{
+	mAgentInitialWearables.push_back(data);
+}
+
+void LLInitialWearablesFetch::processContents()
+{
+	if(!gAgentAvatarp) //no need to process wearables if the agent avatar is deleted.
+	{
+		delete this;
+		return ;
+	}
+
+	// Fetch the wearable items from the Current Outfit Folder
+	LLInventoryModel::cat_array_t cat_array;
+	LLInventoryModel::item_array_t wearable_array;
+	LLFindWearables is_wearable;
+	llassert_always(mComplete.size() != 0);
+	gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array, 
+									LLInventoryModel::EXCLUDE_TRASH, is_wearable);
+
+	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
+	if (!wearable_array.empty())
+	{
+		gAgentWearables.notifyLoadingStarted();
+		LLAppearanceMgr::instance().updateAppearanceFromCOF();
+	}
+	else
+	{
+		// if we're constructing the COF from the wearables message, we don't have a proper outfit link
+		LLAppearanceMgr::instance().setOutfitDirty(true);
+		processWearablesMessage();
+	}
+	delete this;
+}
+
+class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver
+{
+public:
+	LLFetchAndLinkObserver(uuid_vec_t& ids):
+		LLInventoryFetchItemsObserver(ids)
+	{
+	}
+	~LLFetchAndLinkObserver()
+	{
+	}
+	virtual void done()
+	{
+		gInventory.removeObserver(this);
+
+		// Link to all fetched items in COF.
+		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
+		LLInventoryObject::const_object_list_t item_array;
+		for (uuid_vec_t::iterator it = mIDs.begin();
+			 it != mIDs.end();
+			 ++it)
+		{
+			LLUUID id = *it;
+			LLConstPointer<LLInventoryObject> item = gInventory.getItem(*it);
+			if (!item)
+			{
+				LL_WARNS() << "fetch failed for item " << (*it) << "!" << LL_ENDL;
+				continue;
+			}
+
+			item_array.push_back(item);
+		}
+		link_inventory_array(LLAppearanceMgr::instance().getCOF(), item_array, link_waiter);
+	}
+};
+
+void LLInitialWearablesFetch::processWearablesMessage()
+{
+	if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead.
+	{
+		const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF();
+		uuid_vec_t ids;
+		for (U8 i = 0; i < mAgentInitialWearables.size(); ++i)
+		{
+			// Populate the current outfit folder with links to the wearables passed in the message
+			InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback.
+			
+			if (wearable_data->mAssetID.notNull())
+			{
+				ids.push_back(wearable_data->mItemID);
+			}
+			else
+			{
+				LL_INFOS() << "Invalid wearable, type " << wearable_data->mType << " itemID "
+				<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << LL_ENDL;
+				delete wearable_data;
+			}
+		}
+
+		// Add all current attachments to the requested items as well.
+		if (isAgentAvatarValid())
+		{
+			for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); 
+				 iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter)
+			{
+				LLViewerJointAttachment* attachment = iter->second;
+				if (!attachment) continue;
+				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+					 attachment_iter != attachment->mAttachedObjects.end();
+					 ++attachment_iter)
+				{
+					LLViewerObject* attached_object = (*attachment_iter);
+					if (!attached_object) continue;
+					const LLUUID& item_id = attached_object->getAttachmentItemID();
+					if (item_id.isNull()) continue;
+					ids.push_back(item_id);
+				}
+			}
+		}
+
+		// Need to fetch the inventory items for ids, then create links to them after they arrive.
+		LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids);
+		fetcher->startFetch();
+		// If no items to be fetched, done will never be triggered.
+		// TODO: Change LLInventoryFetchItemsObserver::fetchItems to trigger done() on this condition.
+		if (fetcher->isFinished())
+		{
+			fetcher->done();
+		}
+		else
+		{
+			gInventory.addObserver(fetcher);
+		}
+	}
+	else
+	{
+		LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL;
+	}
+}
+
diff --git a/indra/newview/llagentwearablesfetch.h b/indra/newview/llagentwearablesfetch.h
new file mode 100644
index 0000000000000000000000000000000000000000..81b03110ae34ec487c321300a94a95021f2b2ca8
--- /dev/null
+++ b/indra/newview/llagentwearablesfetch.h
@@ -0,0 +1,73 @@
+/** 
+ * @file llagentwearablesinitialfetch.h
+ * @brief LLAgentWearablesInitialFetch class header file
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#ifndef LL_LLAGENTWEARABLESINITIALFETCH_H
+#define LL_LLAGENTWEARABLESINITIALFETCH_H
+
+#include "llinventoryobserver.h"
+#include "llwearabletype.h"
+#include "lluuid.h"
+
+//--------------------------------------------------------------------
+// InitialWearablesFetch
+// 
+// This grabs contents from the COF and processes them.
+// The processing is handled in idle(), i.e. outside of done(),
+// to avoid gInventory.notifyObservers recursion.
+//--------------------------------------------------------------------
+class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver
+{
+	LOG_CLASS(LLInitialWearablesFetch);
+
+public:
+	LLInitialWearablesFetch(const LLUUID& cof_id);
+	~LLInitialWearablesFetch();
+	virtual void done();
+
+	struct InitialWearableData
+	{
+		LLWearableType::EType mType;
+		LLUUID mItemID;
+		LLUUID mAssetID;
+		InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) :
+			mType(type),
+			mItemID(itemID),
+			mAssetID(assetID)
+		{}
+	};
+
+	void add(InitialWearableData &data);
+
+protected:
+	void processWearablesMessage();
+	void processContents();
+
+private:
+	typedef std::vector<InitialWearableData> initial_wearable_data_vec_t;
+	initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg
+};
+
+#endif // LL_AGENTWEARABLESINITIALFETCH_H
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 10a6630917bfe910177fb933e7c2586c94d731a7..24a4f6cdcec12555a4b7db5359be0878348f02ed 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -3900,7 +3900,7 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b
 	bool result = false;
 	if ((result = gAgentWearables.moveWearable(item, closer_to_body)))
 	{
-		gAgentAvatarp->wearableUpdated(item->getWearableType());
+		gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE);
 	}
 
 	setOutfitDirty(true);
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index d2b1dcbf359d3365263d8720934067be261d95c4..0f9d357f8eebdbdccb97183946585dea1da4c60c 100755
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -474,6 +474,57 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);
 }
 
+LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data,
+												 const LLUUID& vfile_id,
+												 LLAssetType::EType asset_type,
+												 LLBakedUploadData * baked_upload_data) : 
+	LLAssetUploadResponder(post_data, vfile_id, asset_type),
+	mBakedUploadData(baked_upload_data)
+{
+}
+
+LLSendTexLayerResponder::~LLSendTexLayerResponder()
+{
+	// mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below
+	if (mBakedUploadData)
+	{	// ...but delete it in the case where uploadComplete() is never called
+		delete mBakedUploadData;
+		mBakedUploadData = NULL;
+	}
+}
+
+
+// Baked texture upload completed
+void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
+{
+	LLUUID item_id = mPostData["item_id"];
+
+	std::string result = content["state"];
+	LLUUID new_id = content["new_asset"];
+
+	llinfos << "result: " << result << " new_id: " << new_id << llendl;
+	if (result == "complete"
+		&& mBakedUploadData != NULL)
+	{	// Invoke 
+		LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE);
+		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
+	}
+	else
+	{	// Invoke the original callback with an error result
+		LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
+		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
+	}
+}
+
+void LLSendTexLayerResponder::httpFailure()
+{
+	llwarns << dumpResponse() << llendl;
+	
+	// Invoke the original callback with an error result
+	LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
+	mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
+}
+
 LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
 	const LLSD& post_data,
 	const LLUUID& vfile_id,
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index 7fbebc7481c1f585dacf23f1c13be02276da9aee..abfdc4ca7712e84a2555d48dd78032d7f3a9aab3 100755
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -116,6 +116,27 @@ private:
 	Impl* mImpl;
 };
 
+struct LLBakedUploadData;
+class LLSendTexLayerResponder : public LLAssetUploadResponder
+{
+	LOG_CLASS(LLSendTexLayerResponder);
+public:
+	LLSendTexLayerResponder(const LLSD& post_data,
+							const LLUUID& vfile_id,
+							LLAssetType::EType asset_type,
+							LLBakedUploadData * baked_upload_data);
+
+	~LLSendTexLayerResponder();
+
+	virtual void uploadComplete(const LLSD& content);
+
+protected:
+	virtual void httpFailure();
+
+private:
+	LLBakedUploadData * mBakedUploadData;
+};
+
 class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder
 {
 public:
diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp
index 3a88bab3b3621ac8b9ad9f90b26c8fe2a4ceb30a..d8d3ec1fab6edc29053ec74ce630eaebc35e2e02 100755
--- a/indra/newview/llbreastmotion.cpp
+++ b/indra/newview/llbreastmotion.cpp
@@ -340,7 +340,7 @@ BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask)
 		if (mBreastParamsDriven[i])
 		{
 			mCharacter->setVisualParamWeight(mBreastParamsDriven[i],
-											 new_local_pt[i]);
+											 new_local_pt[i], FALSE);
 		}
 	}
 
diff --git a/indra/newview/llemote.cpp b/indra/newview/llemote.cpp
index 5c3bee24f8fc81fd0804f94042fc27c779a7de95..9033144a614a1e88166196b0e03b6c3db078dfd0 100755
--- a/indra/newview/llemote.cpp
+++ b/indra/newview/llemote.cpp
@@ -80,13 +80,13 @@ BOOL LLEmote::onActivate()
 	LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );
 	if( default_param )
 	{
-		default_param->setWeight( default_param->getMaxWeight());
+		default_param->setWeight( default_param->getMaxWeight(), FALSE);
 	}
 
 	mParam = mCharacter->getVisualParam(mName.c_str());
 	if (mParam)
 	{
-		mParam->setWeight(0.f);
+		mParam->setWeight(0.f, FALSE);
 		mCharacter->updateVisualParams();
 	}
 	
@@ -102,7 +102,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)
 	if( mParam )
 	{
 		F32 weight = mParam->getMinWeight() + mPose.getWeight() * (mParam->getMaxWeight() - mParam->getMinWeight());
-		mParam->setWeight(weight);
+		mParam->setWeight(weight, FALSE);
 
 		// Cross fade against the default parameter
 		LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );
@@ -111,7 +111,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)
 			F32 default_param_weight = default_param->getMinWeight() + 
 				(1.f - mPose.getWeight()) * ( default_param->getMaxWeight() - default_param->getMinWeight() );
 			
-			default_param->setWeight( default_param_weight);
+			default_param->setWeight( default_param_weight, FALSE);
 		}
 
 		mCharacter->updateVisualParams();
@@ -128,13 +128,13 @@ void LLEmote::onDeactivate()
 {
 	if( mParam )
 	{
-		mParam->setWeight( mParam->getDefaultWeight());
+		mParam->setWeight( mParam->getDefaultWeight(), FALSE);
 	}
 
 	LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );
 	if( default_param )
 	{
-		default_param->setWeight( default_param->getMaxWeight());
+		default_param->setWeight( default_param->getMaxWeight(), FALSE);
 	}
 
 	mCharacter->updateVisualParams();
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index c6dedda38c229d1cc6b0f1d2b39f253244acb3bd..0086e5c8a2777a3cb9462b6bac4fe193e06fc47d 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -554,7 +554,7 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp
 						if (gAgentWearables.getWearableIndex(wearable,index))
 						{
 							gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index);
-							gAgentAvatarp->wearableUpdated(type);
+							gAgentAvatarp->wearableUpdated(type, FALSE);
 							/* telling the manager to rebake once update cycle is fully done */
 							LLLocalBitmapMgr::setNeedsRebake();
 						}
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 95e11472c2b2e38a89c7e673e3752b21f98d5011..e8299beceafc85268128c4079995bfa69498c23a 100755
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -946,11 +946,11 @@ void LLPanelEditWearable::onCommitSexChange()
         LLViewerWearable*     wearable = gAgentWearables.getViewerWearable(type, index);
         if (wearable)
         {
-                wearable->setVisualParamWeight(param->getID(), is_new_sex_male);
+                wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE);
         }
-        param->setWeight( is_new_sex_male);
+        param->setWeight( is_new_sex_male, FALSE);
 
-        gAgentAvatarp->updateSexDependentLayerSets();
+        gAgentAvatarp->updateSexDependentLayerSets(FALSE);
 
         gAgentAvatarp->updateVisualParams();
         showWearable(mWearablePtr, TRUE, TRUE);
@@ -987,7 +987,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)
 							{
 								gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);
 								LLVisualParamHint::requestHintUpdates();
-								gAgentAvatarp->wearableUpdated(type);
+								gAgentAvatarp->wearableUpdated(type, FALSE);
 							}
 							else
 							{
@@ -1016,9 +1016,9 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl)
                         const LLColor4& new_color = LLColor4(ctrl->getValue());
                         if( old_color != new_color )
                         {
-                                getWearable()->setClothesColor(entry->mTextureIndex, new_color);
+                                getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE);
                                 LLVisualParamHint::requestHintUpdates();
-                                gAgentAvatarp->wearableUpdated(getWearable()->getType());
+                                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
                         }
                 }
                 else
@@ -1119,7 +1119,7 @@ void LLPanelEditWearable::saveChanges(bool force_save_as)
 				// Remove old link
 				remove_inventory_item(link_item->getUUID(), gAgentAvatarp->mEndCustomizeCallback);
 			}
-			gAgentWearables.saveWearable(mWearablePtr->getType(), index, new_name);
+			gAgentWearables.saveWearable(mWearablePtr->getType(), index, TRUE, new_name);
         }
 
 	
@@ -1137,7 +1137,7 @@ void LLPanelEditWearable::revertChanges()
         mNameEditor->setText(mWearableItem->getName());
         updatePanelPickerControls(mWearablePtr->getType());
         updateTypeSpecificControls(mWearablePtr->getType());
-        gAgentAvatarp->wearableUpdated(mWearablePtr->getType());
+        gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE);
 }
 
 void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BOOL disable_camera_switch)
@@ -1604,7 +1604,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
                 
                 LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );
 				gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
-				gAgentAvatarp->wearableUpdated(getWearable()->getType());
+				gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
         }
         else
         {
@@ -1620,7 +1620,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL
                 if (!image) return;
 
                 gAgentAvatarp->setLocalTexture(te, image, FALSE, index);
-                gAgentAvatarp->wearableUpdated(getWearable()->getType());
+                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE);
         }
 
         updatePanelPickerControls(getWearable()->getType());
@@ -1708,7 +1708,7 @@ void LLPanelEditWearable::onClickedImportBtn()
 			{
 				LLVisualParam* visual_param = getWearable()->getVisualParam(id);
 				if (visual_param)
-					visual_param->setWeight(value);
+					visual_param->setWeight(value, FALSE);
 			}
 			else
 			{
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index 5ea2267f3f18cc80fc7ced963bb6a87c084d17e9..873b85ae2232033be647f55582671aac2131a00a 100755
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -669,7 +669,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)
 			if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&
 			    (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))
 			{
-				mCharacter->setVisualParamWeight(driver_param, 0);
+				mCharacter->setVisualParamWeight(driver_param, 0, FALSE);
 			}
 			S32 num_driven = driver_param->getDrivenParamsCount();
 			for (S32 i = 0; i < num_driven; ++i)
@@ -769,5 +769,5 @@ void LLPhysicsMotion::setParamValue(const LLViewerVisualParam *param,
 	// Scale from [0,1] to [value_min_local,value_max_local]
         const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled;
 
-        mCharacter->setVisualParamWeight(param, new_value_local);
+        mCharacter->setVisualParamWeight(param, new_value_local, FALSE);
 }
diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp
index bfa453a0ae1862f72286ef4be3453f13e7e2a734..797ed261de30e2cff2d4df5889b1ac8ca4ad3eb5 100755
--- a/indra/newview/llscrollingpanelparam.cpp
+++ b/indra/newview/llscrollingpanelparam.cpp
@@ -266,8 +266,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint )
 			if (slider->getMinValue() < new_percent
 				&& new_percent < slider->getMaxValue())
 			{
-				mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight);
-				mWearable->writeToAvatar(gAgentAvatarp);
+				mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE);				mWearable->writeToAvatar(gAgentAvatarp);
 				gAgentAvatarp->updateVisualParams();
 
 				slider->setValue( weightToPercent( new_weight ) );
@@ -299,7 +298,7 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata )
 			if (slider->getMinValue() < new_percent
 				&& new_percent < slider->getMaxValue())
 			{
-				self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);
+				self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE);
 				self->mWearable->writeToAvatar(gAgentAvatarp);
 				slider->setValue( self->weightToPercent( new_weight ) );
 			}
@@ -333,7 +332,7 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata )
 				if (slider->getMinValue() < new_percent
 					&& new_percent < slider->getMaxValue())
 				{
-					self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);
+					self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE);
 					self->mWearable->writeToAvatar(gAgentAvatarp);
 					slider->setValue( self->weightToPercent( new_weight ) );
 				}
diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp
index fe7a3627235560c7cd38b126d7417477c928aece..b1ac39bfff7707a892e42702ae7e26634f14b31b 100755
--- a/indra/newview/llscrollingpanelparambase.cpp
+++ b/indra/newview/llscrollingpanelparambase.cpp
@@ -93,7 +93,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata)
 	F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );
 	if (current_weight != new_weight )
 	{
-		self->mWearable->setVisualParamWeight( param->getID(), new_weight);
+		self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE);
 		self->mWearable->writeToAvatar(gAgentAvatarp);
 		gAgentAvatarp->updateVisualParams();
 	}
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 95500d72fff263c4cb694c7a015b5f8031cb2c2b..45d7d40d1bab6b109a74de821a7f853fae193fab 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2078,7 +2078,8 @@ bool idle_startup()
 		{
 			gAgentWearables.notifyLoadingStarted();
 			gAgent.setOutfitChosen(TRUE);
-			gAgentWearables.sendDummyAgentWearablesUpdate();
+			if (LLGridManager::getInstance()->isInSecondlife())
+				gAgentWearables.sendDummyAgentWearablesUpdate();
 			callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance);
 		}
 
@@ -2137,7 +2138,8 @@ bool idle_startup()
 		
 		display_startup();
 
-		if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time))
+		if ((LLGridManager::getInstance()->isInSecondlife() && gAgent.isOutfitChosen() && (wearables_time > max_wearables_time)) ||
+			(!LLGridManager::getInstance()->isInSecondlife() && (wearables_time > max_wearables_time)))
 		{
 			LLNotificationsUtil::add("ClothingLoading");
 			record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time);
@@ -2413,6 +2415,8 @@ void register_viewer_callbacks(LLMessageSystem* msg)
 	msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair,	process_remove_name_value);
 	msg->setHandlerFuncFast(_PREHASH_AvatarAnimation,		process_avatar_animation);
 	msg->setHandlerFuncFast(_PREHASH_AvatarAppearance,		process_avatar_appearance);
+	msg->setHandlerFunc("AgentCachedTextureResponse",	LLAgent::processAgentCachedTextureResponse);
+	msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);
 	msg->setHandlerFuncFast(_PREHASH_CameraConstraint,		process_camera_constraint);
 	msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse,		process_avatar_sit_response);
 	msg->setHandlerFunc("SetFollowCamProperties",			process_set_follow_cam_properties);
@@ -2486,6 +2490,8 @@ void register_viewer_callbacks(LLMessageSystem* msg)
 	// msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply,
 	//					LLFloaterRate::processReputationIndividualReply);
 
+	msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, LLAgentWearables::processAgentInitialWearablesUpdate );
+
 	msg->setHandlerFunc("ScriptControlChange",
 						LLAgent::processScriptControlChange );
 
@@ -2650,7 +2656,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
 	}
 
 	gAgent.setOutfitChosen(TRUE);
-	gAgentWearables.sendDummyAgentWearablesUpdate();
+	if (LLGridManager::getInstance()->isInSecondlife())
+		gAgentWearables.sendDummyAgentWearablesUpdate();
 }
 
 //static
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index edc0271451e6d5b02f505d992e428990e904427f..bd456413ae0eccf951aa68609ad39f41842a1744 100755
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -435,6 +435,15 @@ void LLAvatarTexBar::draw()
 
 		LLColor4 text_color = LLColor4::white;
 
+		if (layerset_buffer->uploadNeeded())
+		{
+			text_color = LLColor4::red;
+		}
+ 		if (layerset_buffer->uploadInProgress())
+		{
+			text_color = LLColor4::magenta;
+		}
+
 		std::string text = layerset_buffer->dumpTextureInfo();
 		LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num,
 												 text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 2d458db36bb782d86be08b836c4e65380c2b6a1d..71e0509d03795d01b77d781e1a243399e8bfbbb7 100755
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -154,8 +154,8 @@ void LLVisualParamHint::preRender(BOOL clear_depth)
 		wearable->setVolatile(TRUE);
 	}
 	mLastParamWeight = mVisualParam->getWeight();
-	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight);
-	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight);
+	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);
+	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE);
 	gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f);
 	gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f);
 	gAgentAvatarp->updateComposites();
@@ -246,7 +246,7 @@ BOOL LLVisualParamHint::render()
 		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	}
 	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
-	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
+	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE);
 	LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr;
 	if (wearable)
 	{
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 2387b4b53f2b99101e8373f7b82587bfd9e09231..531d0b55800224c1bb9ccfbfe3890e3c269f2f7b 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4325,6 +4325,10 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)
 
 		gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL );
 
+		// set the appearance on teleport since the new sim does not
+		// know what you look like.
+		gAgent.sendAgentSetAppearance();
+
 		if (isAgentAvatarValid())
 		{
 			// Set the new position
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index e13633def49f537190edde7fe7a1704b8dd830c5..9c54272bd952be30d587a2781bd5a92cb68382f8 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -102,6 +102,7 @@
 #include "llmediaentry.h"
 #include "llfloaterperms.h"
 #include "llvocache.h"
+#include "llviewernetwork.h"
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -154,7 +155,11 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco
 			{
 				gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp);
 				gAgentAvatarp->initInstance();
-				gAgentWearables.setAvatarObject(gAgentAvatarp);
+				if (LLGridManager::getInstance()->isInSecondlife())
+				{
+					gAgentWearables.setAvatarObject(gAgentAvatarp);
+
+				}
 			}
 			else 
 			{
@@ -5631,7 +5636,7 @@ BOOL LLViewerObject::permOwnerModify() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLGridManager::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInSLMain()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 	{
 			return TRUE;
@@ -5655,7 +5660,7 @@ BOOL LLViewerObject::permModify() const
 		return TRUE;
 #else
 # ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-		if (!LLGridManager::getInstance()->isInProductionGrid()
+		if (!LLGridManager::getInstance()->isInSLMain()
             && (gAgent.getGodLevel() >= GOD_MAINTENANCE))
 	{
 			return TRUE;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 8e5600006bb4ab415405e4704877e7858e8b3799..f74958b4f03c94c4d9dfad5461524dbf0db7f454 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -416,7 +416,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mSimAccess( SIM_ACCESS_MIN ),
 	mBillableFactor(1.0),
 	mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT),
-	mCentralBakeVersion(1),
+	mCentralBakeVersion(0),
 	mClassID(0),
 	mCPURatio(0),
 	mColoName("unknown"),
diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp
index 66e5742911e85d03128fa23328f2b638d5dc94c0..cadb8d2aa433cc6dff5e831865531bd07ac2489e 100755
--- a/indra/newview/llviewertexlayer.cpp
+++ b/indra/newview/llviewertexlayer.cpp
@@ -37,11 +37,32 @@
 #include "llglslshader.h"
 #include "llvoavatarself.h"
 #include "pipeline.h"
+#include "llassetuploadresponders.h"
 #include "llviewercontrol.h"
+#include "llviewerstats.h"
+
+static const S32 BAKE_UPLOAD_ATTEMPTS = 7;
+static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power of 2 each attempt
 
 // runway consolidate
 extern std::string self_av_string();
 
+
+//-----------------------------------------------------------------------------
+// LLBakedUploadData()
+//-----------------------------------------------------------------------------
+LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar,
+									 LLViewerTexLayerSet* layerset,
+									 const LLUUID& id,
+									 bool highest_res) :
+	mAvatar(avatar),
+	mTexLayerSet(layerset),
+	mID(id),
+	mStartTime(LLFrameTimer::getTotalTime()),		// Record starting time
+	mIsHighestRes(highest_res)
+{ 
+}
+
 //-----------------------------------------------------------------------------
 // LLViewerTexLayerSetBuffer
 // The composite image that a LLViewerTexLayerSet writes to.  Each LLViewerTexLayerSet has one.
@@ -55,10 +76,15 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner,
 	// ORDER_LAST => must render these after the hints are created.
 	LLTexLayerSetBuffer(owner),
 	LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ), 
+	mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates
+	mNeedsUpload(FALSE),
+	mNumLowresUploads(0),
+	mUploadFailCount(0),
 	mNeedsUpdate(TRUE),
 	mNumLowresUpdates(0)
 {
 	LLViewerTexLayerSetBuffer::sGLByteCount += getSize();
+	mNeedsUploadTimer.start();
 	mNeedsUpdateTimer.start();
 }
 
@@ -101,6 +127,33 @@ void LLViewerTexLayerSetBuffer::requestUpdate()
 	restartUpdateTimer();
 	mNeedsUpdate = TRUE;
 	mNumLowresUpdates = 0;
+	// If we're in the middle of uploading a baked texture, we don't care about it any more.
+	// When it's downloaded, ignore it.
+	mUploadID.setNull();
+}
+
+void LLViewerTexLayerSetBuffer::requestUpload()
+{
+	conditionalRestartUploadTimer();
+	mNeedsUpload = TRUE;
+	mNumLowresUploads = 0;
+	mUploadPending = TRUE;
+}
+
+void LLViewerTexLayerSetBuffer::conditionalRestartUploadTimer()
+{
+	// If we requested a new upload but haven't even uploaded
+	// a low res version of our last upload request, then
+	// keep the timer ticking instead of resetting it.
+	if (mNeedsUpload && (mNumLowresUploads == 0))
+	{
+		mNeedsUploadTimer.unpause();
+	}
+	else
+	{
+		mNeedsUploadTimer.reset();
+		mNeedsUploadTimer.start();
+	}
 }
 
 void LLViewerTexLayerSetBuffer::restartUpdateTimer()
@@ -109,16 +162,25 @@ void LLViewerTexLayerSetBuffer::restartUpdateTimer()
 	mNeedsUpdateTimer.start();
 }
 
+void LLViewerTexLayerSetBuffer::cancelUpload()
+{
+	mNeedsUpload = FALSE;
+	mUploadPending = FALSE;
+	mNeedsUploadTimer.pause();
+	mUploadRetryTimer.reset();
+}
+
 // virtual
 BOOL LLViewerTexLayerSetBuffer::needsRender()
 {
 	llassert(mTexLayerSet->getAvatarAppearance() == gAgentAvatarp);
 	if (!isAgentAvatarValid()) return FALSE;
 
+	const BOOL upload_now = mNeedsUpload && isReadyToUpload();
 	const BOOL update_now = mNeedsUpdate && isReadyToUpdate();
 
 	// Don't render if we don't want to (or aren't ready to) update.
-	if (!update_now)
+	if (!(update_now || upload_now))
 	{
 		return FALSE;
 	}
@@ -133,6 +195,7 @@ BOOL LLViewerTexLayerSetBuffer::needsRender()
 	if (gAgentAvatarp->getBakedTE(getViewerTexLayerSet()) == LLAvatarAppearanceDefines::TEX_SKIRT_BAKED && 
 		!gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))
 	{
+		cancelUpload();
 		return FALSE;
 	}
 
@@ -160,7 +223,36 @@ void LLViewerTexLayerSetBuffer::postRenderTexLayerSet(BOOL success)
 // virtual
 void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success)
 {
+	// do we need to upload, and do we have sufficient data to create an uploadable composite?
+	// TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero?
+	const BOOL upload_now = mNeedsUpload && isReadyToUpload();
 	const BOOL update_now = mNeedsUpdate && isReadyToUpdate();
+
+	if(upload_now)
+	{
+		if (!success)
+		{
+			LL_INFOS() << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << LL_ENDL;
+			mUploadPending = FALSE;
+		}
+		else
+		{
+			LLViewerTexLayerSet* layer_set = getViewerTexLayerSet();
+			if (layer_set->isVisible())
+			{
+				layer_set->getAvatar()->debugBakedTextureUpload(layer_set->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish.
+				doUpload();
+			}
+			else
+			{
+				mUploadPending = FALSE;
+				mNeedsUpload = FALSE;
+				mNeedsUploadTimer.pause();
+				layer_set->getAvatar()->setNewBakedTexture(layer_set->getBakedTexIndex(),IMG_INVISIBLE);
+			}
+		}
+	}
+
 	if (update_now)
 	{
 		doUpdate();
@@ -176,6 +268,60 @@ BOOL LLViewerTexLayerSetBuffer::isInitialized(void) const
 	return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated();
 }
 
+BOOL LLViewerTexLayerSetBuffer::uploadPending() const
+{
+	return mUploadPending;
+}
+
+BOOL LLViewerTexLayerSetBuffer::uploadNeeded() const
+{
+	return mNeedsUpload;
+}
+
+BOOL LLViewerTexLayerSetBuffer::uploadInProgress() const
+{
+	return !mUploadID.isNull();
+}
+
+BOOL LLViewerTexLayerSetBuffer::isReadyToUpload() const
+{
+	if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries.
+	if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) return FALSE; // Don't upload if avatar is being edited.
+
+	BOOL ready = FALSE;
+	if (getViewerTexLayerSet()->isLocalTextureDataFinal())
+	{
+		// If we requested an upload and have the final LOD ready, upload (or wait a while if this is a retry)
+		if (mUploadFailCount == 0)
+		{
+			ready = TRUE;
+		}
+		else
+		{
+			ready = mUploadRetryTimer.getElapsedTimeF32() >= BAKE_UPLOAD_RETRY_DELAY * (1 << (mUploadFailCount - 1));
+		}
+	}
+	else
+	{
+		// Upload if we've hit a timeout.  Upload is a pretty expensive process so we need to make sure
+		// we aren't doing uploads too frequently.
+		const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout");
+		if (texture_timeout != 0)
+		{
+			// The timeout period increases exponentially between every lowres upload in order to prevent
+			// spamming the server with frequent uploads.
+			const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads);
+
+			// If we hit our timeout and have textures available at even lower resolution, then upload.
+			const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold;
+			const BOOL has_lower_lod = getViewerTexLayerSet()->isLocalTextureDataAvailable();
+			ready = has_lower_lod && is_upload_textures_timeout;
+		}
+	}
+
+	return ready;
+}
+
 BOOL LLViewerTexLayerSetBuffer::isReadyToUpdate() const
 {
 	// If we requested an update and have the final LOD ready, then update.
@@ -212,6 +358,158 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate()
 
 	return result;
 }
+// Create the baked texture, send it out to the server, then wait for it to come
+// back so we can switch to using it.
+void LLViewerTexLayerSetBuffer::doUpload()
+{
+	LLViewerTexLayerSet* layer_set = getViewerTexLayerSet();
+	LL_INFOS() << "Uploading baked " << layer_set->getBodyRegionName() << LL_ENDL;
+	add(LLStatViewer::TEX_BAKES, 1);
+
+	// Don't need caches since we're baked now.  (note: we won't *really* be baked 
+	// until this image is sent to the server and the Avatar Appearance message is received.)
+	layer_set->deleteCaches();
+
+	// Get the COLOR information from our texture
+	U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ];
+	glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data );
+	stop_glerror();
+
+	// Get the MASK information from our texture
+	LLGLSUIDefault gls_ui;
+	LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 );
+	U8* baked_mask_data = baked_mask_image->getData(); 
+	layer_set->gatherMorphMaskAlpha(baked_mask_data,
+									mOrigin.mX, mOrigin.mY,
+									mFullWidth, mFullHeight);
+
+
+	// Create the baked image from our color and mask information
+	const S32 baked_image_components = 5; // red green blue [bump] clothing
+	LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components );
+	U8* baked_image_data = baked_image->getData();
+	S32 i = 0;
+	for (S32 u=0; u < mFullWidth; u++)
+	{
+		for (S32 v=0; v < mFullHeight; v++)
+		{
+			baked_image_data[5*i + 0] = baked_color_data[4*i + 0];
+			baked_image_data[5*i + 1] = baked_color_data[4*i + 1];
+			baked_image_data[5*i + 2] = baked_color_data[4*i + 2];
+			baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes.
+			baked_image_data[5*i + 4] = baked_mask_data[i];
+			i++;
+		}
+	}
+	
+	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C;
+	const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask)
+	if (compressedImage->encode(baked_image, comment_text))
+	{
+		LLTransactionID tid;
+		tid.generate();
+		const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
+		if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(),
+							   gVFS, asset_id, LLAssetType::AT_TEXTURE))
+		{
+			// Read back the file and validate.
+			BOOL valid = FALSE;
+			LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C;
+			S32 file_size = 0;
+			LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE);
+			file_size = file.getSize();
+			U8* data = integrity_test->allocateData(file_size);
+			file.read(data, file_size);
+			if (data)
+			{
+				valid = integrity_test->validate(data, file_size); // integrity_test will delete 'data'
+			}
+			else
+			{
+				integrity_test->setLastError("Unable to read entire file");
+			}
+			
+			if (valid)
+			{
+				const bool highest_lod = layer_set->isLocalTextureDataFinal();
+				// Baked_upload_data is owned by the responder and deleted after the request completes.
+				LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp, 
+																			 layer_set, 
+																			 asset_id,
+																			 highest_lod);
+				// upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit.
+				mUploadID = asset_id;
+
+				// Upload the image
+				const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture");
+				if(!url.empty()
+					&& !LLPipeline::sForceOldBakedUpload // toggle debug setting UploadBakedTexOld to change between the new caps method and old method
+					&& (mUploadFailCount < (BAKE_UPLOAD_ATTEMPTS - 1))) // Try last ditch attempt via asset store if cap upload is failing.
+				{
+					LLSD body = LLSD::emptyMap();
+					// The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete()
+					LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data));
+					LL_INFOS() << "Baked texture upload via capability of " << mUploadID << " to " << url << LL_ENDL;
+				} 
+				else
+				{
+					gAssetStorage->storeAssetData(tid,
+												  LLAssetType::AT_TEXTURE,
+												  LLViewerTexLayerSetBuffer::onTextureUploadComplete,
+												  baked_upload_data,
+												  TRUE,		// temp_file
+												  TRUE,		// is_priority
+												  TRUE);	// store_local
+					LL_INFOS() << "Baked texture upload via Asset Store." <<  LL_ENDL;
+				}
+
+				if (highest_lod)
+				{
+					// Sending the final LOD for the baked texture.  All done, pause 
+					// the upload timer so we know how long it took.
+					mNeedsUpload = FALSE;
+					mNeedsUploadTimer.pause();
+				}
+				else
+				{
+					// Sending a lower level LOD for the baked texture.  Restart the upload timer.
+					mNumLowresUploads++;
+					mNeedsUploadTimer.unpause();
+					mNeedsUploadTimer.reset();
+				}
+
+				// Print out notification that we uploaded this texture.
+				if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+				{
+					const std::string lod_str = highest_lod ? "HighRes" : "LowRes";
+					LLSD args;
+					args["EXISTENCE"] = llformat("%d",(U32)layer_set->getAvatar()->debugGetExistenceTimeElapsedF32());
+					args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32());
+					args["BODYREGION"] = layer_set->getBodyRegionName();
+					args["RESOLUTION"] = lod_str;
+					LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args);
+					LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << layer_set->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL;
+				}
+			}
+			else
+			{
+				// The read back and validate operation failed.  Remove the uploaded file.
+				mUploadPending = FALSE;
+				LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE);
+				file.remove();
+				LL_INFOS() << "Unable to create baked upload file (reason: corrupted)." << LL_ENDL;
+			}
+		}
+	}
+	else
+	{
+		// The VFS write file operation failed.
+		mUploadPending = FALSE;
+		LL_INFOS() << "Unable to create baked upload file (reason: failed to write file)" << LL_ENDL;
+	}
+
+	delete [] baked_color_data;
+}
 
 // Mostly bookkeeping; don't need to actually "do" anything since
 // render() will actually do the update.
@@ -249,6 +547,82 @@ void LLViewerTexLayerSetBuffer::doUpdate()
 	}
 }
 
+// static
+void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid,
+												  void* userdata,
+												  S32 result,
+												  LLExtStat ext_status) // StoreAssetData callback (not fixed)
+{
+	LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata;
+
+	if (isAgentAvatarValid() &&
+		!gAgentAvatarp->isDead() &&
+		(baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures.
+		(baked_upload_data->mTexLayerSet->hasComposite()))
+	{
+		LLViewerTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getViewerComposite();
+		S32 failures = layerset_buffer->mUploadFailCount;
+		layerset_buffer->mUploadFailCount = 0;
+
+		if (layerset_buffer->mUploadID.isNull())
+		{
+			// The upload got canceled, we should be in the
+			// process of baking a new texture so request an
+			// upload with the new data
+
+			// BAP: does this really belong in this callback, as
+			// opposed to where the cancellation takes place?
+			// suspect this does nothing.
+			layerset_buffer->requestUpload();
+		}
+		else if (baked_upload_data->mID == layerset_buffer->mUploadID)
+		{
+			// This is the upload we're currently waiting for.
+			layerset_buffer->mUploadID.setNull();
+			const std::string name(baked_upload_data->mTexLayerSet->getBodyRegionName());
+			const std::string resolution = baked_upload_data->mIsHighestRes ? " full res " : " low res ";
+			if (result >= 0)
+			{
+				layerset_buffer->mUploadPending = FALSE; // Allows sending of AgentSetAppearance later
+				LLAvatarAppearanceDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->getViewerTexLayerSet());
+				// Update baked texture info with the new UUID
+				U64 now = LLFrameTimer::getTotalTime();		// Record starting time
+				LL_INFOS() << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << LL_ENDL;
+				gAgentAvatarp->setNewBakedTexture(baked_te, uuid);
+			}
+			else
+			{	
+				++failures;
+				S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes
+				LL_WARNS() << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << LL_ENDL;
+				if (failures < max_attempts)
+				{
+					layerset_buffer->mUploadFailCount = failures;
+					layerset_buffer->mUploadRetryTimer.start();
+					layerset_buffer->requestUpload();
+				}
+			}
+		}
+		else
+		{
+			LL_INFOS() << "Received baked texture out of date, ignored." << LL_ENDL;
+		}
+
+		gAgentAvatarp->dirtyMesh();
+	}
+	else
+	{
+		// Baked texture failed to upload (in which case since we
+		// didn't set the new baked texture, it means that they'll try
+		// and rebake it at some point in the future (after login?)),
+		// or this response to upload is out of date, in which case a
+		// current response should be on the way or already processed.
+		LL_WARNS() << "Baked upload failed" << LL_ENDL;
+	}
+
+	delete baked_upload_data;
+}
+
 //-----------------------------------------------------------------------------
 // LLViewerTexLayerSet
 // An ordered set of texture layers that get composited into a single texture.
@@ -290,6 +664,20 @@ void LLViewerTexLayerSet::requestUpdate()
 	}
 }
 
+void LLViewerTexLayerSet::requestUpload()
+{
+	createComposite();
+	getViewerComposite()->requestUpload();
+}
+
+void LLViewerTexLayerSet::cancelUpload()
+{
+	if(mComposite)
+	{
+		getViewerComposite()->cancelUpload();
+	}
+}
+
 void LLViewerTexLayerSet::updateComposite()
 {
 	createComposite();
@@ -342,12 +730,19 @@ const std::string LLViewerTexLayerSetBuffer::dumpTextureInfo() const
 {
 	if (!isAgentAvatarValid()) return "";
 
-	const BOOL is_high_res = TRUE; 
-	const U32 num_low_res = 0;
+	const BOOL is_high_res = !mNeedsUpload;
+	const U32 num_low_res = mNumLowresUploads;
+	const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32();
 	const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(getViewerTexLayerSet());
 
-	std::string text = llformat("[HiRes:%d LoRes:%d] %s",
+	std::string status 				= "CREATING ";
+	if (!uploadNeeded()) status 	= "DONE     ";
+	if (uploadInProgress()) status 	= "UPLOADING";
+
+	std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s",
+								status.c_str(),
 								is_high_res, num_low_res,
+								upload_time, 
 								local_texture_info.c_str());
 	return text;
 }
diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h
index 027ae255ec3b53fef615dd18eec97b96ee6613d0..0de6bbe389ef769acf2ed308f4bfc9d3e42b2ae6 100755
--- a/indra/newview/llviewertexlayer.h
+++ b/indra/newview/llviewertexlayer.h
@@ -47,6 +47,8 @@ public:
 	virtual ~LLViewerTexLayerSet();
 
 	/*virtual*/void				requestUpdate();
+	void						requestUpload();
+	void						cancelUpload();
 	BOOL						isLocalTextureDataAvailable() const;
 	BOOL						isLocalTextureDataFinal() const;
 	void						updateComposite();
@@ -112,7 +114,33 @@ protected:
 	virtual void			preRender(BOOL clear_depth) { preRenderTexLayerSet(); }
 	virtual void			postRender(BOOL success) { postRenderTexLayerSet(success); }
 	virtual BOOL			render() { return renderTexLayerSet(); }
-	
+
+
+	//--------------------------------------------------------------------
+	// Uploads
+	//--------------------------------------------------------------------
+public:
+	void					requestUpload();
+	void					cancelUpload();
+	BOOL					uploadNeeded() const; 			// We need to upload a new texture
+	BOOL					uploadInProgress() const; 		// We have started uploading a new texture and are awaiting the result
+	BOOL					uploadPending() const; 			// We are expecting a new texture to be uploaded at some point
+	static void				onTextureUploadComplete(const LLUUID& uuid,
+													void* userdata,
+													S32 result, LLExtStat ext_status);
+protected:
+	BOOL					isReadyToUpload() const;
+	void					doUpload(); 					// Does a read back and upload.
+	void					conditionalRestartUploadTimer();
+private:
+	BOOL					mNeedsUpload; 					// Whether we need to send our baked textures to the server
+	U32						mNumLowresUploads; 				// Number of times we've sent a lowres version of our baked textures to the server
+	BOOL					mUploadPending; 				// Whether we have received back the new baked textures
+	LLUUID					mUploadID; 						// The current upload process (null if none).
+	LLFrameTimer    		mNeedsUploadTimer; 				// Tracks time since upload was requested and performed.
+	S32						mUploadFailCount;				// Number of consecutive upload failures
+	LLFrameTimer    		mUploadRetryTimer; 				// Tracks time since last upload failure.
+
 	//--------------------------------------------------------------------
 	// Updates
 	//--------------------------------------------------------------------
@@ -129,5 +157,24 @@ private:
 	LLFrameTimer    		mNeedsUpdateTimer; 				// Tracks time since update was requested and performed.
 };
 
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLBakedUploadData
+//
+// Used by LLTexLayerSetBuffer for a callback.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+struct LLBakedUploadData
+{
+	LLBakedUploadData(const LLVOAvatarSelf* avatar,
+					  LLViewerTexLayerSet* layerset, 
+					  const LLUUID& id,
+					  bool highest_res);
+	~LLBakedUploadData() {}
+	const LLUUID				mID;
+	const LLVOAvatarSelf*		mAvatar; // note: backlink only; don't LLPointer 
+	LLViewerTexLayerSet*		mTexLayerSet;
+   	const U64					mStartTime;	// for measuring baked texture upload time
+   	const bool					mIsHighestRes; // whether this is a "final" bake, or intermediate low res
+};
 #endif  // LL_VIEWER_TEXLAYER_H
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 411c46e32daf40c72f496ca9ab16bb47ba28d7b7..6e2681e63bc5fde87c338ff61953af0f9dcae9de 100755
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1018,7 +1018,8 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type,
 	mFTType = f_type;
 	if (mFTType == FTT_HOST_BAKE)
 	{
-		LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL;
+		//LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL;
+		mCanUseHTTP = false;
 	}
 	generateGLTexture();
 }
diff --git a/indra/newview/llviewerwearable.cpp b/indra/newview/llviewerwearable.cpp
index 47d0592ae6aa9a9b0bd4196dd1677ed76f40410b..a2565c7fe8d1f1182d7fd13b0e06e28ce56c8857 100755
--- a/indra/newview/llviewerwearable.cpp
+++ b/indra/newview/llviewerwearable.cpp
@@ -268,7 +268,7 @@ void LLViewerWearable::setParamsToDefaults()
 	{
 		if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) )
 		{
-			setVisualParamWeight(param->getID(),param->getDefaultWeight());
+			setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE);
 		}
 	}
 }
@@ -353,14 +353,14 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)
 	ESex new_sex = avatarp->getSex();
 	if( old_sex != new_sex )
 	{
-		viewer_avatar->updateSexDependentLayerSets();
+		viewer_avatar->updateSexDependentLayerSets(FALSE);
 	}	
 }
 
 
 // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values.
 // static 
-void LLViewerWearable::removeFromAvatar( LLWearableType::EType type)
+void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake)
 {
 	if (!isAgentAvatarValid()) return;
 
@@ -379,7 +379,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type)
 		if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) )
 		{
 			S32 param_id = param->getID();
-			gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight());
+			gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake);
 		}
 	}
 
@@ -389,7 +389,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type)
 	}
 
 	gAgentAvatarp->updateVisualParams();
-	gAgentAvatarp->wearableUpdated(type);
+	gAgentAvatarp->wearableUpdated(type, FALSE);
 }
 
 // Does not copy mAssetID.
@@ -499,6 +499,12 @@ void LLViewerWearable::refreshName()
 	}
 }
 
+void LLViewerWearable::addToBakedTextureHash(LLMD5& hash) const
+{
+	LLUUID asset_id = getAssetID();
+	hash.update((const unsigned char*)asset_id.mData, UUID_BYTES);
+}
+
 struct LLWearableSaveData
 {
 	LLWearableType::EType mType;
diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h
index 62cd5e21add899551997d32ba06a1b773e315f4a..869aec3c95761d1f8ff4b54b3d84e81c52a777fd 100755
--- a/indra/newview/llviewerwearable.h
+++ b/indra/newview/llviewerwearable.h
@@ -62,8 +62,8 @@ public:
 	BOOL				isOldVersion() const;
 
 	/*virtual*/ void	writeToAvatar(LLAvatarAppearance *avatarp);
-	void				removeFromAvatar()	{ LLViewerWearable::removeFromAvatar( mType); }
-	static void			removeFromAvatar( LLWearableType::EType type); 
+	void				removeFromAvatar( BOOL upload_bake )	{ LLViewerWearable::removeFromAvatar( mType, upload_bake ); }
+	static void			removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ); 
 
 	/*virtual*/ EImportResult	importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
 	
@@ -91,7 +91,7 @@ public:
 	// the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem,
 	// not the wearable asset itself.
 	void				refreshName();
-	/*virtual*/void		addToBakedTextureHash(LLMD5& hash) const {}
+	/*virtual*/void		addToBakedTextureHash(LLMD5& hash) const;
 
 protected:
 	LLAssetID			mAssetID;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7f427a2136feba551fe891144a6c4ab4e01a235c..14b1801eab4b13c5a66b2b92b09206bd4d75a8b6 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -725,6 +725,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mLastRezzedStatus(-1),
 	mIsEditingAppearance(FALSE),
 	mUseLocalAppearance(FALSE),
+	mUseServerBakes(FALSE),
 	mLastUpdateRequestCOFVersion(-1),
 	mLastUpdateReceivedCOFVersion(-1),
 	mCachedMuteListUpdateTime(0),
@@ -1102,7 +1103,7 @@ void LLVOAvatar::restoreGL()
 	gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);
 	for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++)
 	{
-		gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i));
+		gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i), FALSE);
 	}
 	gAgentAvatarp->updateMeshTextures();
 }
@@ -2091,14 +2092,20 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU
 	{
 		const std::string url = getImageURL(te,uuid);
 
-		if (url.empty())
+		if (!url.empty())
 		{
-			LL_WARNS() << "unable to determine URL for te " << te << " uuid " << uuid << LL_ENDL;
-			return NULL;
+			LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL;
+			result = LLViewerTextureManager::getFetchedTextureFromUrl(
+				url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
 		}
-		LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL;
-		result = LLViewerTextureManager::getFetchedTextureFromUrl(
-			url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
+		else
+		{
+			LL_DEBUGS("Avatar") << avString() << "get old-bake image from host " << uuid << LL_ENDL;
+			LLHost host = getObjectHost();
+			result = LLViewerTextureManager::getFetchedTexture(
+				uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
+		}
+
 		if (result->isMissingAsset())
 		{
 			result->setIsMissingAsset(false);
@@ -2332,8 +2339,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 				
 				if ( mLipSyncActive )
 				{
-					if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight());
-					if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight());
+					if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE);
+					if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE);
 					
 					mLipSyncActive = false;
 					LLCharacter::updateVisualParams();
@@ -2539,10 +2546,14 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()
 			{
 				if (param->isTweakable())
 				{
-					param->stopAnimating();
+					param->stopAnimating(FALSE);
 				}
 			}
 			updateVisualParams();
+			if (isSelf())
+			{
+				gAgent.sendAgentSetAppearance();
+			}
 		}
 		else
 		{
@@ -2558,7 +2569,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()
 				{
 					if (param->isTweakable())
 					{
-						param->animate(morph_amt);
+						param->animate(morph_amt, FALSE);
 					}
 				}
 			}
@@ -2611,7 +2622,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
 			F32 ooh_weight = mOohMorph->getMinWeight()
 				+ ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight());
 
-			mOohMorph->setWeight( ooh_weight);
+			mOohMorph->setWeight( ooh_weight, FALSE);
 		}
 
 		if( mAahMorph )
@@ -2619,7 +2630,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)
 			F32 aah_weight = mAahMorph->getMinWeight()
 				+ aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight());
 
-			mAahMorph->setWeight( aah_weight);
+			mAahMorph->setWeight( aah_weight, FALSE);
 		}
 
 		mLipSyncActive = true;
@@ -3363,7 +3374,7 @@ void LLVOAvatar::updateDebugText()
 										  isSelf() ? (all_local_downloaded ? "L" : "l") : "-",
 										  all_baked_downloaded ? "B" : "b",
 										  mUseLocalAppearance, mIsEditingAppearance,
-										  1, central_bake_version);
+										  mUseServerBakes, central_bake_version);
 		std::string origin_string = bakedTextureOriginInfo();
 		debug_line += " [" + origin_string + "]";
 		S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion();
@@ -4510,6 +4521,34 @@ bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const
 	return allTexturesCompletelyDownloaded(baked_ids);
 }
 
+void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has origin URL.
+										  S32 &host_count, // host-based bake, has host.
+										  S32 &both_count, // error - both host and URL set.
+										  S32 &neither_count) // error - neither set.
+{
+	sb_count = host_count = both_count = neither_count = 0;
+	
+	std::set<LLUUID> baked_ids;
+	collectBakedTextureUUIDs(baked_ids);
+	for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it)
+	{
+		LLViewerFetchedTexture *imagep = gTextureList.findImage(*it);
+		bool has_url = false, has_host = false;
+		if (!imagep->getUrl().empty())
+		{
+			has_url = true;
+		}
+		if (imagep->getTargetHost().isOk())
+		{
+			has_host = true;
+		}
+		if (has_url && !has_host) sb_count++;
+		else if (has_host && !has_url) host_count++;
+		else if (has_host && has_url) both_count++;
+		else if (!has_host && !has_url) neither_count++;
+	}
+}
+
 std::string LLVOAvatar::bakedTextureOriginInfo()
 {
 	std::string result;
@@ -4750,6 +4789,19 @@ void LLVOAvatar::updateTextures()
 		{
 			const S32 boost_level = getAvatarBakedBoostLevel();
 			imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE);
+			// Spam if this is a baked texture, not set to default image, without valid host info
+			if (isIndexBakedTexture((ETextureIndex)texture_index)
+				&& imagep->getID() != IMG_DEFAULT_AVATAR
+				&& imagep->getID() != IMG_INVISIBLE
+				&& !isUsingServerBakes() 
+				&& !imagep->getTargetHost().isOk())
+			{
+				LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture "
+										 << imagep->getID() << " for avatar "
+										 << (isSelf() ? "<myself>" : getID().asString()) 
+										 << " on host " << getRegion()->getHost() << LL_ENDL;
+			}
+
 			addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );			
 		}
 	}
@@ -4881,19 +4933,22 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid)
 {
 	llassert(isIndexBakedTexture(ETextureIndex(te)));
 	std::string url = "";
-	const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL();
-	if (appearance_service_url.empty())
+	if (isUsingServerBakes())
 	{
-		// Probably a server-side issue if we get here:
-		LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL;
-		return url;
-	}
+		const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL();
+		if (appearance_service_url.empty())
+		{
+			// Probably a server-side issue if we get here:
+			LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL;
+			return url;
+		}
 	
-	const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te);
-	if (texture_entry != NULL)
-	{
-		url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString();
-		//LL_INFOS() << "baked texture url: " << url << LL_ENDL;
+		const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te);
+		if (texture_entry != NULL)
+		{
+			url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString();
+			//LL_INFOS() << "baked texture url: " << url << LL_ENDL;
+		}
 	}
 	return url;
 }
@@ -5851,11 +5906,11 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
 //-----------------------------------------------------------------------------
 // updateSexDependentLayerSets()
 //-----------------------------------------------------------------------------
-void LLVOAvatar::updateSexDependentLayerSets()
+void LLVOAvatar::updateSexDependentLayerSets(BOOL upload_bake)
 {
-	invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet);
-	invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet);
-	invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);
+	invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake);
+	invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake);
+	invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake);
 }
 
 //-----------------------------------------------------------------------------
@@ -6443,8 +6498,7 @@ LLViewerObject *	LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons
 }
 
 // virtual
-void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset)
-{
+void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result){
 }
 
 void LLVOAvatar::invalidateAll()
@@ -6452,19 +6506,18 @@ void LLVOAvatar::invalidateAll()
 }
 
 // virtual
-void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
+void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake)
 {
 	if (global_color == mTexSkinColor)
 	{
-		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet);
-		invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet);
-		invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);
+		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake);
+		invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake);
+		invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake);	
 	}
 	else if (global_color == mTexHairColor)
 	{
-		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet);
-		invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet);
-		
+		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake);
+		invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake);		
 		// ! BACKWARDS COMPATIBILITY !
 		// Fix for dealing with avatars from viewers that don't bake hair.
 		if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex))
@@ -6485,8 +6538,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)
 	else if (global_color == mTexEyeColor)
 	{
 		// LL_INFOS() << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << LL_ENDL; 
-		invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet);
-	}
+		invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, upload_bake);	}
 	updateMeshTextures();
 }
 
@@ -6681,7 +6733,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
 	}
 	record["grid_x"] = LLSD::Integer(grid_x);
 	record["grid_y"] = LLSD::Integer(grid_y);
-	record["is_using_server_bakes"] = true;
+	record["is_using_server_bakes"] = ((bool) isUsingServerBakes());
 	record["is_self"] = isSelf();
 		
 	if (isAgentAvatarValid())
@@ -7538,13 +7590,13 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32
 	{
 		appearance_version = contents.mParamAppearanceVersion;
 	}
-	else if (contents.mAppearanceVersion > 0)
+	if (contents.mAppearanceVersion >= 0)
 	{
 		appearance_version = contents.mAppearanceVersion;
 	}
-	else // still not set, go with 1.
+	if (appearance_version < 0) // still not set, go with 0.
 	{
-		appearance_version = 1;
+		appearance_version = 0;
 	}
 	LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion
 						<< " param: " << contents.mParamAppearanceVersion
@@ -7599,6 +7651,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 		LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version
 				<< " last_update_request_cof_version " << last_update_request_cof_version
 				<<  " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL;
+		if (getRegion() && (getRegion()->getCentralBakeVersion()==0))
+		{
+			LL_WARNS() << avString() << "Received AvatarAppearance message for self in non-server-bake region" << LL_ENDL;
+		}
+		if( mFirstTEMessageReceived && (appearance_version == 0))
+		{
+			return;
+		}
 	}
 	else
 	{
@@ -7607,6 +7667,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 
 	// Check for stale update.
 	if (isSelf()
+		&& (appearance_version>0)
 		&& (this_update_cof_version < last_update_request_cof_version))
 	{
 		LL_WARNS() << "Stale appearance update, wanted version " << last_update_request_cof_version
@@ -7633,13 +7694,17 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 	}
 
 	// No backsies zone - if we get here, the message should be valid and usable, will be processed.
+	setIsUsingServerBakes(appearance_version > 0);
 
+	if (appearance_version > 0)
+	{
 	// Note:
 	// RequestAgentUpdateAppearanceResponder::onRequestRequested()
 	// assumes that cof version is only updated with server-bake
 	// appearance messages.
 	mLastUpdateReceivedCOFVersion = this_update_cof_version;
 		
+	}
 	applyParsedTEMessage(contents.mTEContents);
 
 	// prevent the overwriting of valid baked textures with invalid baked textures
@@ -7649,13 +7714,13 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 			&& mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT
 			&& baked_index != BAKED_SKIRT)
 		{
-			LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL;
+			LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL;
 			setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, 
 				LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureID, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
 		}
 		else
 		{
-			LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using texture id "
+			LL_DEBUGS("Avatar") << avString() << "sb " << (S32) isUsingServerBakes() << " baked_index " << (S32) baked_index << " using texture id "
 								<< getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << LL_ENDL;
 		}
 	}
@@ -7698,12 +7763,12 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 				if(is_first_appearance_message)
 				{
 					//LL_DEBUGS("Avatar") << "param slam " << i << " " << newWeight << LL_ENDL;
-					param->setWeight(newWeight);
+					param->setWeight(newWeight, FALSE);
 				}
 				else
 				{
 					interp_params = TRUE;
-					param->setAnimationTarget(newWeight);
+					param->setAnimationTarget(newWeight, FALSE);
 				}
 			}
 		}
@@ -7726,7 +7791,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 			ESex new_sex = getSex();
 			if( old_sex != new_sex )
 			{
-				updateSexDependentLayerSets();
+				updateSexDependentLayerSets(FALSE);
 			}	
 		}
 
@@ -8294,6 +8359,39 @@ void LLVOAvatar::startAppearanceAnimation()
 	}
 }
 
+// virtual
+void LLVOAvatar::bodySizeChanged()
+{
+	if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())
+	{	// notify simulator of change in size
+		// but not if we are in the middle of updating appearance
+		gAgent.sendAgentSetAppearance();
+	}
+}
+
+BOOL LLVOAvatar::isUsingServerBakes() const
+{
+	// Sanity check - visual param for appearance version should match mUseServerBakes
+	LLVisualParam* appearance_version_param = getVisualParam(11000);
+	llassert(appearance_version_param);
+	F32 wt = appearance_version_param->getWeight();
+	F32 expect_wt = mUseServerBakes ? 1.0 : 0.0;
+	if (!is_approx_equal(wt, expect_wt))
+	{
+		LL_WARNS() << "wt " << wt << " differs from expected " << expect_wt << LL_ENDL;
+	}
+
+	return mUseServerBakes;
+}
+
+void LLVOAvatar::setIsUsingServerBakes(BOOL newval)
+{
+	mUseServerBakes = newval;
+	LLVisualParam* appearance_version_param = getVisualParam(11000);
+	llassert(appearance_version_param);
+	appearance_version_param->setWeight(newval ? 1.0 : 0.0, false);
+}
+
 // virtual
 void LLVOAvatar::removeMissingBakedTextures()
 {
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index b3bd471960cf901574bd2d145e7d014217ad6ce6..53746b450d97890e6ec0d30a8e2affdaa6e5e36e 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -442,7 +442,7 @@ public:
 	// Global colors
 	//--------------------------------------------------------------------
 public:
-	/*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color);
+	/*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) override;
 
 	//--------------------------------------------------------------------
 	// Visibility
@@ -602,7 +602,7 @@ protected:
 	// Composites
 	//--------------------------------------------------------------------
 public:
-	virtual void	invalidateComposite(LLTexLayerSet* layerset);
+	virtual void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result);
 	virtual void	invalidateAll();
 	virtual void	setCompositeUpdatesEnabled(bool b) {}
 	virtual void 	setCompositeUpdatesEnabled(U32 index, bool b) {}
@@ -639,7 +639,7 @@ private:
 public:
 	void			debugColorizeSubMeshes(U32 i, const LLColor4& color);
 	virtual void 	updateMeshTextures();
-	void 			updateSexDependentLayerSets();
+	void 			updateSexDependentLayerSets(BOOL upload_bake);
 	virtual void	dirtyMesh(); // Dirty the avatar mesh
 	void 			updateMeshData();
 protected:
@@ -671,8 +671,9 @@ public:
 	void 			parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& msg);
 	void 			processAvatarAppearance(LLMessageSystem* mesgsys);
 	void 			hideSkirt();
-	void			startAppearanceAnimation();
-	
+	void			startAppearanceAnimation();	
+	/*virtual*/ void bodySizeChanged();
+
 	//--------------------------------------------------------------------
 	// Appearance morphing
 	//--------------------------------------------------------------------
@@ -684,6 +685,9 @@ public:
 	// editing or when waiting for a subsequent server rebake.
 	/*virtual*/ BOOL	isUsingLocalAppearance() const { return mUseLocalAppearance; }
 
+	BOOL				isUsingServerBakes() const;
+	void 				setIsUsingServerBakes(BOOL newval);
+
 	// True if we are currently in appearance editing mode. Often but
 	// not always the same as isUsingLocalAppearance().
 	/*virtual*/ BOOL	isEditingAppearance() const { return mIsEditingAppearance; }
@@ -696,6 +700,7 @@ private:
 	F32				mLastAppearanceBlendTime;
 	BOOL			mIsEditingAppearance; // flag for if we're actively in appearance editing mode
 	BOOL			mUseLocalAppearance; // flag for if we're using a local composite
+	BOOL			mUseServerBakes; // flag for if baked textures should be fetched from baking service (false if they're temporary uploads)
 
 	//--------------------------------------------------------------------
 	// Visibility
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index dd8838ad4c96be9c1e0eefce98db2c3e6d7f2638..9f3bd97d987b44d8e65d8f5fbf713f710c1b799c 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -59,6 +59,7 @@
 #include "llsdutil.h"
 #include "llstartup.h"
 #include "llsdserialize.h"
+#include "llviewernetwork.h"
 
 LLPointer<LLVOAvatarSelf> gAgentAvatarp = NULL;
 
@@ -170,6 +171,10 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
 	// first time through.
 	mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f))
 {
+	if (!LLGridManager::getInstance()->isInSecondlife())
+	{
+		gAgentWearables.setAvatarObject(this);
+	}
 	mMotionController.mIsSelf = TRUE;
 
 	LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL;
@@ -195,6 +200,16 @@ bool update_avatar_rez_metrics()
 	return false;
 }
 
+bool check_for_unsupported_baked_appearance()
+{
+	if (!isAgentAvatarValid())
+		return true;
+
+	gAgentAvatarp->checkForUnsupportedServerBakeAppearance();
+	return false;
+
+}
+
 void LLVOAvatarSelf::initInstance()
 {
 	BOOL status = TRUE;
@@ -233,14 +248,16 @@ void LLVOAvatarSelf::initInstance()
 
 	//doPeriodically(output_self_av_texture_diagnostics, 30.0);
 	doPeriodically(update_avatar_rez_metrics, 5.0);
+	doPeriodically(check_for_unsupported_baked_appearance, 120.0);
 	doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0);
 }
 
 void LLVOAvatarSelf::setHoverIfRegionEnabled()
 {
-	if (getRegion() && getRegion()->simulatorFeaturesReceived())
+	LLViewerRegion* region = getRegion();
+	if (region && region->simulatorFeaturesReceived())
 	{
-		if (getRegion()->avatarHoverHeightEnabled())
+		if (region->avatarHoverHeightEnabled())
 		{
 			F32 hover_z = gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ");
 			setHoverOffset(LLVector3(0.0, 0.0, llclamp(hover_z,MIN_HOVER_Z,MAX_HOVER_Z)));
@@ -255,9 +272,9 @@ void LLVOAvatarSelf::setHoverIfRegionEnabled()
 	else
 	{
 		LL_INFOS("Avatar") << avString() << " region or simulator features not known, no change on hover" << LL_ENDL;
-		if (getRegion())
+		if (region)
 		{
-			getRegion()->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived,this,_1));
+			region->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived, this, _1));
 		}
 
 	}
@@ -707,35 +724,35 @@ LLJoint *LLVOAvatarSelf::getJoint(const std::string &name)
 	//return LLVOAvatar::getJoint(name);
 }
 // virtual
-BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight)
+BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake)
 {
 	if (!which_param)
 	{
 		return FALSE;
 	}
 	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID());
-	return setParamWeight(param,weight);
+	return setParamWeight(param,weight,upload_bake);
 }
 
 // virtual
-BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight)
+BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake)
 {
 	if (!param_name)
 	{
 		return FALSE;
 	}
 	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name);
-	return setParamWeight(param,weight);
+	return setParamWeight(param,weight,upload_bake);
 }
 
 // virtual
-BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight)
+BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake)
 {
 	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index);
-	return setParamWeight(param,weight);
+	return setParamWeight(param,weight,upload_bake);
 }
 
-BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight)
+BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake)
 {
 	if (!param)
 	{
@@ -751,12 +768,12 @@ BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight
 			LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count);
 			if (wearable)
 			{
-				wearable->setVisualParamWeight(param->getID(), weight);
+				wearable->setVisualParamWeight(param->getID(), weight, upload_bake);
 			}
 		}
 	}
 
-	return LLCharacter::setVisualParamWeight(param,weight);
+	return LLCharacter::setVisualParamWeight(param,weight,upload_bake);
 }
 
 /*virtual*/ 
@@ -782,7 +799,7 @@ void LLVOAvatarSelf::writeWearablesToAvatar()
 void LLVOAvatarSelf::idleUpdateAppearanceAnimation()
 {
 	// Animate all top-level wearable visual parameters
-	gAgentWearables.animateAllWearableParams(calcMorphAmount());
+	gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE);
 
 	// Apply wearable visual params to avatar
 	writeWearablesToAvatar();
@@ -876,9 +893,13 @@ void LLVOAvatarSelf::removeMissingBakedTextures()
 		{
 			LLViewerTexLayerSet *layerset = getTexLayerSet(i);
 			layerset->setUpdatesEnabled(TRUE);
-			invalidateComposite(layerset);
+			invalidateComposite(layerset, FALSE);
 		}
 		updateMeshTextures();
+		if (getRegion() && !getRegion()->getCentralBakeVersion())
+		{
+			requestLayerSetUploads();
+		}
 	}
 }
 
@@ -1155,7 +1176,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
 // forces an update to any baked textures relevant to type.
 // will force an upload of the resulting bake if the second parameter is TRUE
 //-----------------------------------------------------------------------------
-void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type)
+void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type, BOOL upload_result)
 {
 	for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin();
 		 baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end();
@@ -1177,13 +1198,20 @@ void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type)
 					if (layerset)
 					{
 						layerset->setUpdatesEnabled(true);
-						invalidateComposite(layerset);
+						invalidateComposite(layerset, upload_result);
 					}
 					break;
 				}
 			}
 		}
 	}
+
+	// Physics type has no associated baked textures, but change of params needs to be sent to
+	// other avatars.
+	if (type == LLWearableType::WT_PHYSICS)
+	{
+		gAgent.sendAgentSetAppearance();
+	}
 }
 
 //-----------------------------------------------------------------------------
@@ -1565,6 +1593,15 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const
 	return TRUE;
 }
 
+BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const
+{
+	const LLViewerTexLayerSet *layerset = getLayerSet(index);
+	if (!layerset) return FALSE;
+	const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite();
+	if (!layerset_buffer) return FALSE;
+	return !layerset_buffer->uploadNeeded();
+}
+
 BOOL LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const
 {
 	LLUUID id;
@@ -1630,12 +1667,48 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t
 	}
 }
 
+//-----------------------------------------------------------------------------
+// requestLayerSetUploads()
+//-----------------------------------------------------------------------------
+void LLVOAvatarSelf::requestLayerSetUploads()
+{
+	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+	{
+		requestLayerSetUpload((EBakedTextureIndex)i);
+	}
+}
+
+void LLVOAvatarSelf::requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i)
+{
+	ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex;
+	const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index));
+	LLViewerTexLayerSet *layerset = getLayerSet(i);
+	if (!layer_baked && layerset)
+	{
+		layerset->requestUpload();
+	}
+}
+
 bool LLVOAvatarSelf::areTexturesCurrent() const
 {
-	return gAgentWearables.areWearablesLoaded();
+	return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded();
 }
 
-void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset)
+// virtual
+bool LLVOAvatarSelf::hasPendingBakedUploads() const
+{
+	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+	{
+		LLViewerTexLayerSet* layerset = getTexLayerSet(i);
+		if (layerset && layerset->getViewerComposite() && layerset->getViewerComposite()->uploadPending())
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result)
 {
 	LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset);
 	if( !layer_set || !layer_set->getUpdatesEnabled() )
@@ -1646,6 +1719,16 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset)
 
 	layer_set->requestUpdate();
 	layer_set->invalidateMorphMasks();
+
+	if( upload_result  && (getRegion() && !getRegion()->getCentralBakeVersion()))
+	{
+		llassert(isSelf());
+
+		ETextureIndex baked_te = getBakedTE( layer_set );
+		setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) );
+		layer_set->requestUpload();
+		updateMeshTextures();
+	}
 }
 
 void LLVOAvatarSelf::invalidateAll()
@@ -1653,7 +1736,7 @@ void LLVOAvatarSelf::invalidateAll()
 	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
 	{
 		LLViewerTexLayerSet *layerset = getTexLayerSet(i);
-		invalidateComposite(layerset);
+		invalidateComposite(layerset, TRUE);
 	}
 	//mDebugSelfLoadTimer.reset();
 }
@@ -2428,6 +2511,59 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
 	}
 }
 
+class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder
+{
+public:
+	CheckAgentAppearanceServiceResponder() {}
+	
+	virtual ~CheckAgentAppearanceServiceResponder()	{}
+
+	/* virtual */ void httpSuccess()
+	{
+		LL_DEBUGS("Avatar") << "OK" << LL_ENDL;
+	}
+
+	// Error
+	/*virtual*/ void httpFailure()
+	{
+		if (isAgentAvatarValid())
+		{
+			LL_DEBUGS("Avatar") << "failed, will rebake "
+					<< dumpResponse() << LL_ENDL;
+			forceAppearanceUpdate();
+		}
+	}	
+
+	static void forceAppearanceUpdate()
+	{
+		// Trying to rebake immediately after crossing region boundary
+		// seems to be failure prone; adding a delay factor. Yes, this
+		// fix is ad-hoc and not guaranteed to work in all cases.
+		doAfterInterval(boost::bind(&LLVOAvatarSelf::forceBakeAllTextures,
+									gAgentAvatarp.get(), true), 5.0);
+	}
+};
+
+void LLVOAvatarSelf::checkForUnsupportedServerBakeAppearance()
+{
+	// Need to check only if we have a server baked appearance and are
+	// in a non-baking region.
+	if (!gAgentAvatarp->isUsingServerBakes())
+		return;
+	if (!gAgent.getRegion() || gAgent.getRegion()->getCentralBakeVersion()!=0)
+		return;
+
+	// if baked image service is unknown, need to refresh.
+	if (LLAppearanceMgr::instance().getAppearanceServiceURL().empty())
+	{
+		CheckAgentAppearanceServiceResponder::forceAppearanceUpdate();
+	}
+	// query baked image service to check status.
+	std::string image_url = gAgentAvatarp->getImageURL(TEX_HEAD_BAKED,
+													   getTE(TEX_HEAD_BAKED)->getID());
+	LLHTTPClient::head(image_url, new CheckAgentAppearanceServiceResponder);
+}
+
 const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const
 {
 	if (canGrabBakedTexture(baked_index))
@@ -2584,6 +2720,81 @@ ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset )
 	return TEX_HEAD_BAKED;
 }
 
+
+void LLVOAvatarSelf::setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid)
+{
+	ETextureIndex index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(i);
+	setNewBakedTexture(index, uuid);
+}
+
+
+//-----------------------------------------------------------------------------
+// setNewBakedTexture()
+// A new baked texture has been successfully uploaded and we can start using it now.
+//-----------------------------------------------------------------------------
+void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )
+{
+	// Baked textures live on other sims.
+	LLHost target_host = getObjectHost();	
+	setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, FTT_HOST_BAKE, target_host ) );
+	updateMeshTextures();
+	dirtyMesh();
+
+	LLVOAvatar::cullAvatarsByPixelArea();
+
+	/* switch(te)
+		case TEX_HEAD_BAKED:
+			LL_INFOS() << "New baked texture: HEAD" << LL_ENDL; */
+	const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(te);
+	if (texture_dict->mIsBakedTexture)
+	{
+		debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish.
+		LL_INFOS() << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <<LL_ENDL;
+	}
+	else
+	{
+		LL_WARNS() << "New baked texture: unknown te " << te << LL_ENDL;
+	}
+	
+	//	dumpAvatarTEs( "setNewBakedTexture() send" );
+	// RN: throttle uploads
+	if (!hasPendingBakedUploads())
+	{
+		gAgent.sendAgentSetAppearance();
+
+		if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
+		{
+			LLSD args;
+			args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
+			args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32());
+			if (isAllLocalTextureDataFinal())
+			{
+				LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args);
+				LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32()
+						<< "sec ]"
+						<< avString() 
+						<< "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32()
+						<< " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32()
+						<< " Notification " << "AvatarRezSelfBakedDoneNotification"
+						<< LL_ENDL;
+			}
+			else
+			{
+				args["STATUS"] = debugDumpAllLocalTextureDataInfo();
+				LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args);
+				LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32()
+						<< "sec ]"
+						<< avString() 
+						<< "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32()
+						<< " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32()
+						<< " Notification " << "AvatarRezSelfBakedUpdateNotification"
+						<< LL_ENDL;
+			}
+		}
+
+		outputRezDiagnostics();
+	}
+}
 // FIXME: This is not called consistently. Something may be broken.
 void LLVOAvatarSelf::outputRezDiagnostics() const
 {
@@ -2658,8 +2869,88 @@ void LLVOAvatarSelf::reportAvatarRezTime() const
 {
 	// TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow.
 }
+//-----------------------------------------------------------------------------
+// setCachedBakedTexture()
+// A baked texture id was received from a cache query, make it active
+//-----------------------------------------------------------------------------
+void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid )
+{
+	setTETexture( te, uuid );
+
+	/* switch(te)
+		case TEX_HEAD_BAKED:
+			if( mHeadLayerSet )
+				mHeadLayerSet->cancelUpload(); */
+	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+	{
+		LLViewerTexLayerSet *layerset = getTexLayerSet(i);
+		if ( mBakedTextureDatas[i].mTextureIndex == te && layerset)
+		{
+			if (mInitialBakeIDs[i] != LLUUID::null)
+			{
+				if (mInitialBakeIDs[i] == uuid)
+				{
+					LL_INFOS() << "baked texture correctly loaded at login! " << i << LL_ENDL;
+				}
+				else
+				{
+					LL_WARNS() << "baked texture does not match id loaded at login!" << i << LL_ENDL;
+				}
+				mInitialBakeIDs[i] = LLUUID::null;
+			}
+			layerset->cancelUpload();
+		}
+	}
+}
+
+// static
+void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**)
+{
+	LLUUID texture_id;
+	msg->getUUID("TextureData", "TextureID", texture_id);
+	if (!isAgentAvatarValid()) return;
+
+	// If this is a texture corresponding to one of our baked entries, 
+	// just rebake that layer set.
+	BOOL found = FALSE;
+
+	/* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] =
+			TEX_HEAD_BAKED,
+			TEX_UPPER_BAKED, */
+	for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin();
+		 iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end();
+		 ++iter)
+	{
+		const ETextureIndex index = iter->first;
+		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
+		if (texture_dict->mIsBakedTexture)
+		{
+			if (texture_id == gAgentAvatarp->getTEImage(index)->getID())
+			{
+				LLViewerTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index);
+				if (layer_set)
+				{
+					LL_INFOS() << "TAT: rebake - matched entry " << (S32)index << LL_ENDL;
+					gAgentAvatarp->invalidateComposite(layer_set, TRUE);
+					found = TRUE;
+					add(LLStatViewer::TEX_REBAKES, 1);
+				}
+			}
+		}
+	}
+
+	// If texture not found, rebake all entries.
+	if (!found)
+	{
+		gAgentAvatarp->forceBakeAllTextures();
+	}
+	else
+	{
+		// Not sure if this is necessary, but forceBakeAllTextures() does it.
+		gAgentAvatarp->updateMeshTextures();
+	}
+}
 
-// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures()
 void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)
 {
 	LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL;
@@ -2673,9 +2964,10 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)
 			if (slam_for_debug)
 			{
 				layer_set->setUpdatesEnabled(TRUE);
+				layer_set->cancelUpload();
 			}
 
-			invalidateComposite(layer_set);
+			invalidateComposite(layer_set, TRUE);
 			add(LLStatViewer::TEX_REBAKES, 1);
 		}
 		else
@@ -2775,6 +3067,12 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)
 	if (isAgentAvatarValid())
 	{
 		gAgentAvatarp->mIsEditingAppearance = false;
+		if (gAgentAvatarp->getRegion() && !gAgentAvatarp->getRegion()->getCentralBakeVersion())
+		{
+			// FIXME DRANO - move to sendAgentSetAppearance, make conditional on upload complete.
+			gAgentAvatarp->mUseLocalAppearance = false;
+		}
+
 		gAgentAvatarp->invalidateAll();
 
 		if (gAgentCamera.cameraCustomizeAvatar() && !disable_camera_switch)
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index a64fc42132bcba65f8235bdf2d957791289b3f5c..e53f85fdfe61f067e0db4f1f05e1364d6075c26e 100755
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -90,16 +90,16 @@ public:
 	/*virtual*/ void 		requestStopMotion(LLMotion* motion);
 	/*virtual*/ LLJoint*	getJoint(const std::string &name);
 	
-	/*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight);
-	/*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight);
-	/*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight);
+	/*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE) override;
+	/*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE) override;
+	/*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE) override;
 	/*virtual*/ void updateVisualParams();
 	void writeWearablesToAvatar();
 	/*virtual*/ void idleUpdateAppearanceAnimation();
 
 private:
 	// helper function. Passed in param is assumed to be in avatar's parameter list.
-	BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight);
+	BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE);
 
 
 
@@ -184,10 +184,12 @@ public:
 	// Loading status
 	//--------------------------------------------------------------------
 public:
+	/*virtual*/ bool	hasPendingBakedUploads() const;
 	S32					getLocalDiscardLevel(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;
 	bool				areTexturesCurrent() const;
 	BOOL				isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const;
 	BOOL				isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const;
+	BOOL				isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const;
 	// If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index
 	/*virtual*/ BOOL    isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;
 	/*virtual*/ BOOL	isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const;
@@ -224,6 +226,12 @@ public:
 	LLAvatarAppearanceDefines::ETextureIndex getBakedTE(const LLViewerTexLayerSet* layerset ) const;
 	// SUNSHINE CLEANUP - dead? or update to just call request appearance update?
 	void				forceBakeAllTextures(bool slam_for_debug = false);
+
+	void				setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid);
+	void				setNewBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid);
+	void				setCachedBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid);
+	static void			processRebakeAvatarTextures(LLMessageSystem* msg, void**);
+
 protected:
 	/*virtual*/ void	removeMissingBakedTextures();
 
@@ -231,6 +239,8 @@ protected:
 	// Layers
 	//--------------------------------------------------------------------
 public:
+	void 				requestLayerSetUploads();
+	void				requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i);
 	void				requestLayerSetUpdate(LLAvatarAppearanceDefines::ETextureIndex i);
 	LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;
 	LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const;
@@ -240,7 +250,7 @@ public:
 	// Composites
 	//--------------------------------------------------------------------
 public:
-	/* virtual */ void	invalidateComposite(LLTexLayerSet* layerset);
+	/* virtual */ void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result);
 	/* virtual */ void	invalidateAll();
 	/* virtual */ void	setCompositeUpdatesEnabled(bool b); // only works for self
 	/* virtual */ void  setCompositeUpdatesEnabled(U32 index, bool b);
@@ -282,7 +292,7 @@ protected:
  **/
 
 public:
-	void				wearableUpdated(LLWearableType::EType type);
+	void				wearableUpdated(LLWearableType::EType type, BOOL upload_result);
 protected:
 	U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const;
 
@@ -386,6 +396,7 @@ public:
 	const std::string		debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer
 	const std::string		debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD
 	void					sendViewerAppearanceChangeMetrics(); // send data associated with completing a change.
+	void 					checkForUnsupportedServerBakeAppearance();
 private:
 	LLFrameTimer    		mDebugSelfLoadTimer;
 	F32						mDebugTimeWearablesLoaded;