diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index c3a54002c2fbe7a89bc8d1d3a7f738acd0ef92f3..c0be54a1051b3d4f2ff5176727a6ffe57edf0887 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -574,14 +574,14 @@
       <key>Value</key>
       <integer>2</integer>
     </map>
-    <key>AvatarUseBakedTextureTimeout</key>
+    <key>AvatarBakedTextureTimeout</key>
     <map>
       <key>Comment</key>
-      <string>Specifes whether to send your baked textures for avatar appearance even before textures are fully ressed in case of timeout</string>
+      <string>Specifes the maximum time in seconds to wait before sending your baked textures for avatar appearance.  Set to 0 to disable and wait until all baked textures are at highest resolution.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
-      <string>Boolean</string>
+      <string>U32</string>
       <key>Value</key>
       <integer>0</integer>
     </map>
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 3f3aefa4b513e1811cfb691800f8d34a6de0e385..7a3aeae3cca711059ca1aac40f2240410dbb5862 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -138,21 +138,22 @@ void LLTexLayerSetBuffer::requestUpdate()
 
 void LLTexLayerSetBuffer::requestUpload()
 {
-	// New upload request
-	if (!mNeedsUpload)
+	// 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 && mNeedsLowResUpload)
 	{
-		mNeedsUploadTimer.start();
+		mNeedsUploadTimer.reset();
 	}
-
 	mNeedsUpload = TRUE;
 	mNeedsLowResUpload = TRUE;
 	mUploadPending = TRUE;
+	mNeedsUploadTimer.unpause();
 }
 
 void LLTexLayerSetBuffer::cancelUpload()
 {
 	mNeedsUpload = FALSE;
-	mNeedsLowResUpload = FALSE;
 	mUploadPending = FALSE;
 	mNeedsUploadTimer.pause();
 }
@@ -254,7 +255,6 @@ BOOL LLTexLayerSetBuffer::render()
 			{
 				mUploadPending = FALSE;
 				mNeedsUpload = FALSE;
-				mNeedsLowResUpload = FALSE;
 				mNeedsUploadTimer.pause();
 				mTexLayerSet->getAvatar()->setNewBakedTexture(mTexLayerSet->getBakedTexIndex(),IMG_INVISIBLE);
 			}
@@ -286,12 +286,13 @@ BOOL LLTexLayerSetBuffer::isReadyToUpload() const
 	const BOOL can_highest_lod = mTexLayerSet->isLocalTextureDataFinal();
 	if (can_highest_lod) return TRUE;
 
-	if (gSavedSettings.getBOOL("AvatarUseBakedTextureTimeout"))
+	const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureTimeout");
+	if (texture_timeout)
 	{
 		// If we hit our timeout and have textures available at even lower resolution, then upload.
-		const BOOL is_upload_textures_timeout = isUploadTimeout();
-		const BOOL can_lower_lod = mTexLayerSet->isLocalTextureDataAvailable();
-		if (can_lower_lod && is_upload_textures_timeout && mNeedsLowResUpload) return TRUE; 
+		const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout;
+		const BOOL has_lower_lod = mTexLayerSet->isLocalTextureDataAvailable();
+		if (has_lower_lod && is_upload_textures_timeout && mNeedsLowResUpload) return TRUE; 
 	}
 	return FALSE;
 }
@@ -437,7 +438,9 @@ void LLTexLayerSetBuffer::readBackAndUpload()
 					mNeedsUploadTimer.pause();
 				}
 				else
+				{
 					mNeedsLowResUpload = FALSE;
+				}
 			}
 			else
 			{
@@ -2227,14 +2230,6 @@ BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLIma
 	return success;
 }
 
-BOOL LLTexLayerSetBuffer::isUploadTimeout() const
-{
-	//const F32 BAKED_TEXTURES_TIMEOUT_THRESHOLD__SECONDS = 20.f;
-	const F32 UPLOAD_TEXTURES_TIMEOUT_THRESHOLD__SECONDS = 5.f; // SERAPH Reduced timeout for testing.
-
-	return (mNeedsUploadTimer.getElapsedTimeF32() >= UPLOAD_TEXTURES_TIMEOUT_THRESHOLD__SECONDS);
-}
-
 const std::string LLTexLayerSetBuffer::dumpTextureInfo() const
 {
 	if (!isAgentAvatarValid()) return "";
diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h
index f2d86032fb74edb3fc3f29b394a391b101e5a27f..8f386b5a19164a92bbcec7313037062584a7ce9b 100644
--- a/indra/newview/lltexlayer.h
+++ b/indra/newview/lltexlayer.h
@@ -366,10 +366,6 @@ class LLTexLayerSetBuffer : public LLViewerDynamicTexture
 
 	static S32				sGLByteCount;
 	
-	// Low res upload methods
-protected:
-	BOOL					isUploadTimeout() const;
-private:
 	LLFrameTimer    		mNeedsUploadTimer; // Tracks time since upload was requested
 
 };
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index e04568d4ed35a49e7e3fd2c44e953b1c97c587d0..7a8b6557bb52636464c1ed202c2d238b85b5c832 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -418,7 +418,7 @@ void LLAvatarTexBar::draw()
 	const S32 v_offset = (S32)((texture_bar_height + 2.5f) * mTextureView->mNumTextureBars + 2.5f);
 	//----------------------------------------------------------------------------
 	LLGLSUIDefault gls_ui;
-	LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
+	LLColor4 text_color(1.f, 1.f, 1.f, 1.f);
 	LLColor4 color;
 	
 	U32 line_num = 6;
@@ -433,15 +433,17 @@ void LLAvatarTexBar::draw()
 		if (!layerset_buffer) continue;
 		std::string text = layerset_buffer->dumpTextureInfo();
 		LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*line_num,
-												 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+												 text_color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
 		line_num++;
 	}
-	/*
-	std::string text = "Baked Textures:";
-	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*line_num,
-											 text_color, LLFontGL::LEFT, LLFontGL::TOP);
-	*/
-
+	const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureTimeout");
+	const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+	
+	const std::string texture_timeout_str = texture_timeout ? llformat("%d",texture_timeout) : "Disabled";
+	const std::string override_tex_discard_level_str = override_tex_discard_level ? llformat("%d",override_tex_discard_level) : "Disabled";
+	std::string header_text = llformat("[ Timeout('AvatarBakedTextureTimeout'):%s ] [ LOD_Override('TextureDiscardLevel'):%s ]", texture_timeout_str.c_str(), override_tex_discard_level_str.c_str());
+	LLFontGL::getFontMonospace()->renderUTF8(header_text, 0, 0, v_offset + line_height*line_num,
+											 text_color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT);
 }
 
 BOOL LLAvatarTexBar::handleMouseDown(S32 x, S32 y, MASK mask)
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 9df5abd38c15d0bb8dcf831dc22409aee9971647..ce8f64404e494792a6710e2be91022ef826a7726 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1302,6 +1302,32 @@ BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLTexLayerSet* layerset) cons
 	return FALSE;
 }
 
+BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const
+{
+	const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+
+	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+	{
+		const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i);
+		for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
+			 local_tex_iter != baked_dict->mLocalTextures.end();
+			 ++local_tex_iter)
+		{
+			const ETextureIndex tex_index = *local_tex_iter;
+			const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
+			const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
+			for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
+			{
+				if (getLocalDiscardLevel(*local_tex_iter, wearable_index) > (S32)(override_tex_discard_level))
+				{
+					return FALSE;
+				}
+			}
+		}
+	}
+	return TRUE;
+}
+
 BOOL LLVOAvatarSelf::isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index) const
 {
 	LLUUID id;
@@ -1831,7 +1857,7 @@ void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, BOOL fini
 	mDebugBakedTextureTimes[index][done] = mDebugSelfLoadTimer.getElapsedTimeF32();
 }
 
-std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLTexLayerSet* layerset) const
+const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLTexLayerSet* layerset) const
 {
 	std::string text="";
 
@@ -1847,7 +1873,7 @@ std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLTexLayerSet* l
 		if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet)
 		{
 			const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second;
-			text += llformat("[%d] '%s' ",baked_index, baked_dict->mName.c_str());
+			text += llformat("[%d] '%s' ( ",baked_index, baked_dict->mName.c_str());
 			for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
 				 local_tex_iter != baked_dict->mLocalTextures.end();
 				 ++local_tex_iter)
@@ -1866,12 +1892,39 @@ std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLTexLayerSet* l
 					}
 				}
 			}
+			text += ")";
 			break;
 		}
 	}
 	return text;
 }
 
+const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const
+{
+	std::string text;
+	const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
+
+	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+	{
+		const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i);
+		BOOL is_texture_final = TRUE;
+		for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
+			 local_tex_iter != baked_dict->mLocalTextures.end();
+			 ++local_tex_iter)
+		{
+			const ETextureIndex tex_index = *local_tex_iter;
+			const LLWearableType::EType wearable_type = LLVOAvatarDictionary::getTEWearableType(tex_index);
+			const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
+			for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
+			{
+				is_texture_final &= (getLocalDiscardLevel(*local_tex_iter, wearable_index) <= (S32)(override_tex_discard_level));
+			}
+		}
+		text += llformat("%s:%d ",baked_dict->mName.c_str(),is_texture_final);
+	}
+	return text;
+}
+
 const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const
 {
 	if (canGrabBakedTexture(baked_index))
@@ -2053,7 +2106,15 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )
 			LLSD args;
 			args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32());
 			args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32());
-			LLNotificationsUtil::add("AvatarRezSelfNotification",args);
+			if (isAllLocalTextureDataFinal())
+			{
+				LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args);
+			}
+			else
+			{
+				args["STATUS"] = debugDumpAllLocalTextureDataInfo();
+				LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args);
+			}
 		}
 
 		outputRezDiagnostics();
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index ad92807a72816439093ebe8f84b368a11c10daad..e461dc07da80f22cdab83ab974f390e3c6052f62 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -349,21 +349,24 @@ class LLVOAvatarSelf :
 		LLUUID			mAvatarID;
 		LLVOAvatarDefines::ETextureIndex	mIndex;
 	};
-	void debugWearablesLoaded() { mDebugTimeWearablesLoaded = mDebugSelfLoadTimer.getElapsedTimeF32(); }
-	void debugAvatarVisible() { mDebugTimeAvatarVisible = mDebugSelfLoadTimer.getElapsedTimeF32(); }
-	void outputRezDiagnostics() const;
-	void debugBakedTextureUpload(LLVOAvatarDefines::EBakedTextureIndex index, BOOL finished);
-	static void		debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
-
-	const LLTexLayerSet*  debugGetLayerSet(LLVOAvatarDefines::EBakedTextureIndex index) const { return mBakedTextureDatas[index].mTexLayerSet; }
-	std::string		debugDumpLocalTextureDataInfo(const LLTexLayerSet* layerset) const;
+	void 					debugWearablesLoaded() { mDebugTimeWearablesLoaded = mDebugSelfLoadTimer.getElapsedTimeF32(); }
+	void 					debugAvatarVisible() { mDebugTimeAvatarVisible = mDebugSelfLoadTimer.getElapsedTimeF32(); }
+	void 					outputRezDiagnostics() const;
+	void 					debugBakedTextureUpload(LLVOAvatarDefines::EBakedTextureIndex index, BOOL finished);
+	static void				debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+
+	BOOL					isAllLocalTextureDataFinal() const;
+
+	const LLTexLayerSet*  	debugGetLayerSet(LLVOAvatarDefines::EBakedTextureIndex index) const { return mBakedTextureDatas[index].mTexLayerSet; }
+	const std::string		debugDumpLocalTextureDataInfo(const LLTexLayerSet* 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
 private:
-	LLFrameTimer    mDebugSelfLoadTimer;
-	F32				mDebugTimeWearablesLoaded;
-	F32 			mDebugTimeAvatarVisible;
-	F32 			mDebugTextureLoadTimes[LLVOAvatarDefines::TEX_NUM_INDICES][MAX_DISCARD_LEVEL+1]; // load time for each texture at each discard level
-	F32 			mDebugBakedTextureTimes[LLVOAvatarDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture
-	void			debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
+	LLFrameTimer    		mDebugSelfLoadTimer;
+	F32						mDebugTimeWearablesLoaded;
+	F32 					mDebugTimeAvatarVisible;
+	F32 					mDebugTextureLoadTimes[LLVOAvatarDefines::TEX_NUM_INDICES][MAX_DISCARD_LEVEL+1]; // load time for each texture at each discard level
+	F32 					mDebugBakedTextureTimes[LLVOAvatarDefines::BAKED_NUM_INDICES][2]; // time to start upload and finish upload of each baked texture
+	void					debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata);
 
 /**                    Diagnostics
  **                                                                            **
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 404b87ec1c99cb275276f2419b4dc7a289f5c8a8..d87f115385176d8f324a04425f11d9722e41e336 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6130,15 +6130,24 @@ Deed to group failed.
    name="AvatarRezNotification"
    type="notifytip">
 ( [EXISTENCE] seconds alive )
-Avatar '[NAME]' declouded in [TIME] seconds.
+Avatar '[NAME]' declouded after [TIME] seconds.
   </notification>
 
   <notification
    icon="notifytip.tga"
-   name="AvatarRezSelfNotification"
+   name="AvatarRezSelfBakedDoneNotification"
    type="notifytip">
 ( [EXISTENCE] seconds alive )
-You finished baking your outfit in [TIME] seconds.
+You finished baking your outfit after [TIME] seconds.
+  </notification>
+
+  <notification
+   icon="notifytip.tga"
+   name="AvatarRezSelfBakedUpdateNotification"
+   type="notifytip">
+( [EXISTENCE] seconds alive )
+You sent out an update of your appearance after [TIME] seconds.
+[STATUS]
   </notification>