diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index a7adcc672929ea1380ac80a09d2d7a5c41804eef..5dc5fdd5be2aee215fae2d1ae7cdb18411995fcd 100644
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -188,7 +188,7 @@ void TimeBlock::processTimes()
 	U64 cur_time = getCPUClockCount64();
 
 	// set up initial tree
-	for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(); 
+	for (LLInstanceTracker<TimeBlock>::instance_iter begin_it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(), it = begin_it; 
 		it != end_it; 
 		++it)
 	{
diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h
index 6cf6f4f84f73c1e1310e3027d6f2ddcaf19859ac..4419a22bbe6c7199a7c79fe92112db83e329363f 100644
--- a/indra/llcommon/lltracerecording.h
+++ b/indra/llcommon/lltracerecording.h
@@ -434,6 +434,8 @@ namespace LLTrace
 		/*virtual*/ void reset();
 		/*virtual*/ void splitTo(ExtendableRecording& other);
 		/*virtual*/ void splitFrom(ExtendableRecording& other);
+
+		const Recording& getAcceptedRecording() const {return mAcceptedRecording;}
 	private:
 		Recording mAcceptedRecording;
 		Recording mPotentialRecording;
diff --git a/indra/llmessage/lldatapacker.h b/indra/llmessage/lldatapacker.h
index b0a638c16eadd7915b643cc0068b62e5a1562c79..226752d52e2a19f6f2b7c9d601e9ef5ff538dec1 100644
--- a/indra/llmessage/lldatapacker.h
+++ b/indra/llmessage/lldatapacker.h
@@ -170,6 +170,7 @@ class LLDataPackerBinaryBuffer : public LLDataPacker
 				S32			getBufferSize() const	{ return mBufferSize; }
 				const U8*   getBuffer() const   { return mBufferp; }    
 				void		reset()				{ mCurBufferp = mBufferp; mWriteEnabled = (mCurBufferp != NULL); }
+				void        shift(S32 offset)   { reset(); mCurBufferp += offset;}
 				void		freeBuffer()		{ delete [] mBufferp; mBufferp = mCurBufferp = NULL; mBufferSize = 0; mWriteEnabled = FALSE; }
 				void		assignBuffer(U8 *bufferp, S32 size)
 				{
diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
index 050114b37e0e4b41a853d6f3b4a644cb202fe2b7..6eeb2596b2e1b99a1df7caa6ac7f0530236c8984 100644
--- a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -31,6 +31,10 @@ out vec4 frag_color;
 
 uniform sampler2D tex0;
 uniform sampler2D tex1;
+uniform sampler2D dither_tex;
+uniform float dither_scale;
+uniform float dither_scale_s;
+uniform float dither_scale_t;
 
 VARYING vec2 vary_texcoord0;
 VARYING vec2 vary_texcoord1;
@@ -38,4 +42,17 @@ VARYING vec2 vary_texcoord1;
 void main() 
 {
 	frag_color = abs(texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy));
+
+	vec2 dither_coord;
+	dither_coord[0] = vary_texcoord0[0] * dither_scale_s;
+	dither_coord[1] = vary_texcoord0[1] * dither_scale_t;
+	vec4 dither_vec = texture(dither_tex, dither_coord.xy);
+
+	for(int i = 0; i < 3; i++)
+	{
+		if(frag_color[i] < dither_vec[i] * dither_scale)
+		{
+			frag_color[i] = 0.f;
+		}
+	}
 }
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index cca94cdfd82c8801b993c98e2cdac7c8740c9003..0b0db432c894cf967edf43b1978c0c0c9e142aec 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4020,6 +4020,14 @@ void LLAppViewer::purgeCache()
 	gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), "*.*");
 }
 
+//purge cache immediately, do not wait until the next login.
+void LLAppViewer::purgeCacheImmediate()
+{
+	LL_INFOS("AppCache") << "Purging Object Cache and Texture Cache immediately..." << LL_ENDL;
+	LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
+	LLVOCache::getInstance()->removeCache(LL_PATH_CACHE, true);
+}
+
 std::string LLAppViewer::getSecondLifeTitle() const
 {
 	return LLTrans::getString("APP_NAME");
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 85a29925fb28bacdbe3d444a7f69e82410905d01..627652dc308b2ddbdd05de4224b2e7992babe1dc 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -170,6 +170,7 @@ class LLAppViewer : public LLApp
 	void addOnIdleCallback(const boost::function<void()>& cb); // add a callback to fire (once) when idle
 
 	void purgeCache(); // Clear the local cache. 
+	void purgeCacheImmediate(); //clear local cache immediately.
 	
 	// mute/unmute the system's master audio
 	virtual void setMasterSystemAudioMute(bool mute);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 28e4b3279303bb8771db59d5b66100a744e6d52b..56619563cfdb4b33d0cf87f8c11dd953f3976e67 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -2346,8 +2346,6 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist)
 			return 0.f ;
 		}
 		
-		//F32 camera_relative_speed = camera_moving_speed * (lookAt * LLViewerCamera::getInstance()->getVelocityDir()) ;
-		
 		S32 i = 0 ;
 		for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i);
 		i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ;
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 3a2171a014453e34f8c67ab605f4ab93b6b0cee9..c06d9d26897763ce98115e43199fa0e0731fff72 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -499,7 +499,7 @@ void LLSceneMonitor::fetchQueryResult()
 	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_ARB, &count);
 	
 	mDiffResult = count * 0.5f / (mDiff->getWidth() * mDiff->getHeight() * mDiffPixelRatio * mDiffPixelRatio); //0.5 -> (front face + back face)
-	
+
 	addMonitorResult();
 }
 
@@ -511,14 +511,14 @@ void LLSceneMonitor::addMonitorResult()
 		return;
 	}
 
-	mRecording->extend();
-	sample(sFramePixelDiff, mDiffResult);
+		mRecording->extend();
+		sample(sFramePixelDiff, mDiffResult);
 
 	ll_monitor_result_t result;
 	result.mTimeStamp = LLImageGL::sLastFrameTime;
 	result.mDiff = mDiffResult;
 	mMonitorResults.push_back(result);
-}
+	}
 
 //dump results to a file _scene_monitor_results.csv
 void LLSceneMonitor::dumpToFile(std::string file_name)
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index ffec284f72dd0d12f2ba8fa766cb6d8e5f1ae236..d7835d8567c9d3efa02e683ef58ee577bc6ec55d 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -100,7 +100,7 @@ class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
 	BOOL projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp = TRUE) const;
 	BOOL projectPosAgentToScreenEdge(const LLVector3 &pos_agent, LLCoordGL &out_point) const;
 
-	const LLVector3* getVelocityDir() const {return &mVelocityDir;}
+	LLVector3 getVelocityDir() const {return mVelocityDir;}
 	static LLTrace::CountStatHandle<>* getVelocityStat()		   {return &sVelocityStat; }
 	static LLTrace::CountStatHandle<>* getAngularVelocityStat()  {return &sAngularVelocityStat; }
 	F32     getCosHalfFov() {return mCosHalfCameraFOV;}
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 25907dcb523b7928df8c33140332696e6ee84b7c..eebf4f0beaedebb2264a35a45698a712aa55c6de 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -7566,6 +7566,23 @@ void handle_web_browser_test(const LLSD& param)
 	LLWeb::loadURLInternal(url);
 }
 
+bool callback_clear_cache_immediately(const LLSD& notification, const LLSD& response)
+{
+	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+	if ( option == 0 ) // YES
+	{
+		//clear cache
+		LLAppViewer::instance()->purgeCacheImmediate();
+	}
+
+	return false;
+}
+
+void handle_cache_clear_immediately()
+{
+	LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately);
+}
+
 void handle_web_content_test(const LLSD& param)
 {
 	std::string url = param.asString();
@@ -8489,6 +8506,8 @@ void initialize_menus()
 	
 	//Develop (Texture Fetch Debug Console)
 	view_listener_t::addMenu(new LLDevelopTextureFetchDebugger(), "Develop.SetTexFetchDebugger");
+	//Develop (clear cache immediately)
+	commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) );
 
 	// Admin >Object
 	view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 4b1c9c55743225db52546c83e5a07d34cfcfaa21..8dc72ba5b433b65f87574392bb89dd3088663626 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4222,6 +4222,9 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 	LLQuaternion head_rotation = gAgent.getHeadRotation();
 
 	camera_pos_agent = gAgentCamera.getCameraPositionAgent();
+	LLVector3 camera_velocity = LLViewerCamera::getInstance()->getVelocityDir() * LLViewerCamera::getInstance()->getAverageSpeed();
+	F32 time_delta = 1.0f; //predict the camera position in 1 second
+	camera_pos_agent += camera_velocity * time_delta;
 
 	render_state = gAgent.getRenderState();
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 61c5a52f983bc5acafa142d53543e83964d1c808..d5d804bc578e31c66fa945990e3c213579fee03f 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -123,6 +123,7 @@ BOOL		LLViewerObject::sUseSharedDrawables(FALSE); // TRUE
 F64			LLViewerObject::sMaxUpdateInterpolationTime = 3.0;		// For motion interpolation: after X seconds with no updates, don't predict object motion
 F64			LLViewerObject::sPhaseOutUpdateInterpolationTime = 2.0;	// For motion interpolation: after Y seconds with no updates, taper off motion prediction
 
+std::map<std::string, U32> LLViewerObject::sObjectDataMap;
 
 static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object");
 
@@ -327,22 +328,6 @@ void LLViewerObject::deleteTEImages()
 	mTEImages = NULL;
 }
 
-//if enabled, add this object to vo cache tree when removed from rendering.
-void LLViewerObject::EnableToCacheTree(bool enabled)
-{
-	if(mDrawable.notNull() && mDrawable->getEntry() && mDrawable->getEntry()->hasVOCacheEntry())
-	{
-		if(enabled)
-		{
-			((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry())->addState(LLVOCacheEntry::ADD_TO_CACHE_TREE);
-		}
-		else
-		{
-			((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry())->clearState(LLVOCacheEntry::ADD_TO_CACHE_TREE);
-		}
-	}
-}
-
 void LLViewerObject::markDead()
 {
 	if (!mDead)
@@ -501,6 +486,8 @@ void LLViewerObject::initVOClasses()
 	LLVOGrass::initClass();
 	LLVOWater::initClass();
 	LLVOVolume::initClass();
+
+	initObjectDataMap();
 }
 
 void LLViewerObject::cleanupVOClasses()
@@ -510,6 +497,118 @@ void LLViewerObject::cleanupVOClasses()
 	LLVOTree::cleanupClass();
 	LLVOAvatar::cleanupClass();
 	LLVOVolume::cleanupClass();
+
+	sObjectDataMap.clear();
+}
+
+//object data map for compressed && !OUT_TERSE_IMPROVED
+//static
+void LLViewerObject::initObjectDataMap()
+{
+	U32 count = 0;
+
+	sObjectDataMap["ID"] = count; //full id //LLUUID
+	count += sizeof(LLUUID);
+
+	sObjectDataMap["LocalID"] = count; //U32
+	count += sizeof(U32);
+
+	sObjectDataMap["PCode"] = count;   //U8
+	count += sizeof(U8);
+
+	sObjectDataMap["State"] = count;   //U8
+	count += sizeof(U8);
+
+	sObjectDataMap["CRC"] = count;     //U32
+	count += sizeof(U32);
+
+	sObjectDataMap["Material"] = count; //U8
+	count += sizeof(U8);
+
+	sObjectDataMap["ClickAction"] = count; //U8
+	count += sizeof(U8);
+
+	sObjectDataMap["Scale"] = count; //LLVector3
+	count += sizeof(LLVector3);
+
+	sObjectDataMap["Pos"] = count;   //LLVector3
+	count += sizeof(LLVector3);
+
+	sObjectDataMap["Rot"] = count;    //LLVector3
+	count += sizeof(LLVector3);
+
+	sObjectDataMap["SpecialCode"] = count; //U32
+	count += sizeof(U32);
+
+	sObjectDataMap["Owner"] = count; //LLUUID
+	count += sizeof(LLUUID);
+
+	sObjectDataMap["Omega"] = count; //LLVector3, when SpecialCode & 0x80 is set
+	count += sizeof(LLVector3);
+
+	//ParentID is after Omega if there is Omega, otherwise is after Owner
+	sObjectDataMap["ParentID"] = count;//U32, when SpecialCode & 0x20 is set
+	count += sizeof(U32);
+
+	//-------
+	//The rest items are not included here
+	//-------
+}
+
+//static 
+void LLViewerObject::unpackVector3(LLDataPackerBinaryBuffer* dp, LLVector3& value, std::string name)
+{
+	dp->shift(sObjectDataMap[name]);
+	dp->unpackVector3(value, name.c_str());
+	dp->reset();
+}
+
+//static 
+void LLViewerObject::unpackUUID(LLDataPackerBinaryBuffer* dp, LLUUID& value, std::string name)
+{
+	dp->shift(sObjectDataMap[name]);
+	dp->unpackUUID(value, name.c_str());
+	dp->reset();
+}
+	
+//static 
+void LLViewerObject::unpackU32(LLDataPackerBinaryBuffer* dp, U32& value, std::string name)
+{
+	dp->shift(sObjectDataMap[name]);
+	dp->unpackU32(value, name.c_str());
+	dp->reset();
+}
+	
+//static 
+void LLViewerObject::unpackU8(LLDataPackerBinaryBuffer* dp, U8& value, std::string name)
+{
+	dp->shift(sObjectDataMap[name]);
+	dp->unpackU8(value, name.c_str());
+	dp->reset();
+}
+
+//static 
+U32 LLViewerObject::unpackParentID(LLDataPackerBinaryBuffer* dp, U32& parent_id)
+{
+	dp->shift(sObjectDataMap["SpecialCode"]);
+	U32 value;
+	dp->unpackU32(value, "SpecialCode");
+
+	parent_id = 0;
+	if(value & 0x20)
+	{
+		S32 offset = sObjectDataMap["ParentID"];
+		if(!(value & 0x80))
+		{
+			offset -= sizeof(LLVector3);
+		}
+
+		dp->shift(offset);
+		dp->unpackU32(parent_id, "ParentID");
+	}
+	dp->reset();
+
+	return parent_id;
 }
 
 // Replaces all name value pairs with data from \n delimited list
@@ -890,6 +989,25 @@ U32 LLViewerObject::checkMediaURL(const std::string &media_url)
     return retval;
 }
 
+//extract spatial information from object update message
+//return parent_id
+//static
+U32 LLViewerObject::extractSpatialExtents(LLDataPackerBinaryBuffer *dp, LLVector3& pos, LLVector3& scale, LLQuaternion& rot)
+{
+	U32	parent_id = 0;
+	
+	LLViewerObject::unpackVector3(dp, scale, "Scale");
+	LLViewerObject::unpackVector3(dp, pos, "Pos");
+	
+	LLVector3 vec;
+	LLViewerObject::unpackVector3(dp, vec, "Rot");
+	rot.unpackFromVector3(vec);
+	
+	LLViewerObject::unpackParentID(dp, parent_id);
+	
+	return parent_id;
+}
+
 U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					 void **user_data,
 					 U32 block_num,
@@ -1718,14 +1836,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				// stores the extended permission info.
 				if(mesgsys != NULL)
 				{
-				U32 flags;
-				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
-				// keep local flags and overwrite remote-controlled flags
-				mFlags = (mFlags & FLAGS_LOCAL) | flags;
-
-					// ...new objects that should come in selected need to be added to the selected list
-				mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
-			}
+					U32 flags;
+					mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
+					loadFlags(flags);					
+				}
 			}
 			break;
 
@@ -2225,7 +2339,21 @@ BOOL LLViewerObject::isActive() const
 	return TRUE;
 }
 
+//load flags from cache or from message
+void LLViewerObject::loadFlags(U32 flags)
+{
+	if(flags == (U32)(-1))
+	{
+		return; //invalid
+	}
+
+	// keep local flags and overwrite remote-controlled flags
+	mFlags = (mFlags & FLAGS_LOCAL) | flags;
 
+	// ...new objects that should come in selected need to be added to the selected list
+	mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
+	return;
+}
 
 void LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 {
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 933b017aa624feb51ceca57ffe0e111718ed0a8c..942eb678233bc9f9323bc2b396a85242040ee274 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -70,6 +70,7 @@ class LLViewerRegion;
 class LLViewerObjectMedia;
 class LLVOInventoryListener;
 class LLVOAvatar;
+class LLDataPackerBinaryBuffer;
 
 typedef enum e_object_update_type
 {
@@ -136,8 +137,7 @@ class LLViewerObject
 	BOOL isDead() const									{return mDead;}
 	BOOL isOrphaned() const								{ return mOrphaned; }
 	BOOL isParticleSource() const;
-	void EnableToCacheTree(bool enabled);
-
+	
 	virtual LLVOAvatar* asAvatar();
 
 	static void initVOClasses();
@@ -162,6 +162,7 @@ class LLViewerObject
         INVALID_UPDATE = 0x80000000
     };
 
+	static  U32     extractSpatialExtents(LLDataPackerBinaryBuffer *dp, LLVector3& pos, LLVector3& scale, LLQuaternion& rot);
 	virtual U32		processUpdateMessage(LLMessageSystem *mesgsys,
 										void **user_data,
 										U32 block_num,
@@ -510,6 +511,7 @@ class LLViewerObject
 	virtual void	updateRegion(LLViewerRegion *regionp);
 
 	void updateFlags(BOOL physics_changed = FALSE);
+	void loadFlags(U32 flags); //load flags from cache or from message
 	BOOL setFlags(U32 flag, BOOL state);
 	BOOL setFlagsWithoutUpdate(U32 flag, BOOL state);
 	void setPhysicsShapeType(U8 type);
@@ -539,6 +541,13 @@ class LLViewerObject
 	friend class LLViewerObjectList;
 	friend class LLViewerMediaList;
 
+public:
+	static void unpackVector3(LLDataPackerBinaryBuffer* dp, LLVector3& value, std::string name);
+	static void unpackUUID(LLDataPackerBinaryBuffer* dp, LLUUID& value, std::string name);
+	static void unpackU32(LLDataPackerBinaryBuffer* dp, U32& value, std::string name);
+	static void unpackU8(LLDataPackerBinaryBuffer* dp, U8& value, std::string name);
+	static U32 unpackParentID(LLDataPackerBinaryBuffer* dp, U32& parent_id);
+
 public:
 	//counter-translation
 	void resetChildrenPosition(const LLVector3& offset, BOOL simplified = FALSE) ;
@@ -562,6 +571,8 @@ class LLViewerObject
 	// Motion prediction between updates
 	void interpolateLinearMotion(const F64 & time, const F32 & dt);
 
+	static void initObjectDataMap();
+
 public:
 	//
 	// Viewer-side only types - use the LL_PCODE_APP mask.
@@ -610,6 +621,7 @@ class LLViewerObject
 	// Grabbed from UPDATE_FLAGS
 	U32				mFlags;
 
+	static std::map<std::string, U32> sObjectDataMap;
 public:
 	// Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties
 	U8              mPhysicsShapeType;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index b26be5bc6317a8773869426576667a4f2e046809..922d3868184faac6a1865bffe821d5d9927451b9 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -262,7 +262,7 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,
 	// so that the drawable parent is set properly
 	if(msg != NULL)
 	{
-	findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort());
+		findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort());
 	}
 	else
 	{
@@ -365,7 +365,8 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*
 	}
 		
 	processUpdateCore(objectp, NULL, 0, OUT_FULL_CACHED, cached_dpp, justCreated, true);
-		
+	objectp->loadFlags(entry->getUpdateFlags()); //just in case, reload update flags from cache.
+
 	recorder.log(0.2f);
 	LLVOAvatar::cullAvatarsByPixelArea();
 
@@ -446,24 +447,37 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 		LLTimer update_timer;
 		BOOL justCreated = FALSE;
 		S32	msg_size = 0;
+		bool remove_from_cache = false; //remove from object cache if it is a full-update or terse update
 
 		if (compressed)
 		{
-			S32							uncompressed_length = 2048;
-			compressed_dp.reset();
-
+			S32	uncompressed_length = 2048;
+			compressed_dp.reset();			
+			
 			uncompressed_length = mesgsys->getSizeFast(_PREHASH_ObjectData, i, _PREHASH_Data);
 			mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i);
 			compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length);
 
 			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
 			{
-				compressed_dp.unpackUUID(fullid, "ID");
-				compressed_dp.unpackU32(local_id, "LocalID");
-				compressed_dp.unpackU8(pcode, "PCode");
+				U32 flags = 0;
+				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
+			
+				if(flags & FLAGS_TEMPORARY_ON_REZ)
+				{
+					compressed_dp.unpackUUID(fullid, "ID");
+					compressed_dp.unpackU32(local_id, "LocalID");
+					compressed_dp.unpackU8(pcode, "PCode");
+				}
+				else //send to object cache
+				{
+					regionp->cacheFullUpdate(compressed_dp, flags);
+					continue;
+				}
 			}
 			else
 			{
+				remove_from_cache = true;
 				compressed_dp.unpackU32(local_id, "LocalID");
 				getUUIDFromLocal(fullid,
 								 local_id,
@@ -493,6 +507,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 		}
 		else // OUT_FULL only?
 		{
+			remove_from_cache = true;
 			mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i);
 			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
 			msg_size += sizeof(LLUUID);
@@ -500,6 +515,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			// llinfos << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << llendl;
 		}
 		objectp = findObject(fullid);
+		
+		if(remove_from_cache)
+		{
+			objectp = regionp->forceToRemoveFromCache(local_id, objectp);
+		}
 
 		// This looks like it will break if the local_id of the object doesn't change
 		// upon boundary crossing, but we check for region id matching later...
@@ -576,11 +596,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				recorder.objectUpdateFailure(local_id, update_type, msg_size);
 				continue;
 			}
+
 			justCreated = TRUE;
 			mNumNewObjects++;
 		}
 
-
 		if (objectp->isDead())
 		{
 			llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl;
@@ -594,6 +614,8 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				objectp->mLocalID = local_id;
 			}
 			processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated);
+
+#if 0
 			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
 			{
 				U32 flags = 0;
@@ -601,11 +623,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			
 				if(!(flags & FLAGS_TEMPORARY_ON_REZ))
 				{
-				bCached = true;
-				LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+					bCached = true;
+					LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp, flags);
 					recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size);
+				}
 			}
-		}
+#endif
 		}
 		else
 		{
@@ -657,13 +680,15 @@ void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,
 		S32	msg_size = 0;
 		U32 id;
 		U32 crc;
+		U32 flags;
 		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i);
 		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i);
+		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
 		msg_size += sizeof(U32) * 2;
 		
 		// Lookup data packer and add this id to cache miss lists if necessary.
 		U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE;
-		if(!regionp->probeCache(id, crc, cache_miss_type))
+		if(!regionp->probeCache(id, crc, flags, cache_miss_type))
 		{
 			// Cache Miss.
 			recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size);
@@ -1324,7 +1349,7 @@ void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
 	}
 }
 
-BOOL LLViewerObjectList::killObject(LLViewerObject *objectp, bool cache_enabled)
+BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
 {
 	// Don't ever kill gAgentAvatarp, just force it to the agent's region
 	// unless region is NULL which is assumed to mean you are logging out.
@@ -1339,7 +1364,6 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp, bool cache_enabled)
 
 	if (objectp)
 	{
-		objectp->EnableToCacheTree(cache_enabled); //enable to add to VO cache tree if set.
 		objectp->markDead(); // does the right thing if object already dead
 		return TRUE;
 	}
@@ -2121,6 +2145,12 @@ void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port)
 		return;
 	}
 
+	//search object cache to get orphans
+	if(objectp->getRegion())
+	{
+		objectp->getRegion()->findOrphans(objectp->getLocalID());
+	}
+
 	// See if we are a parent of an orphan.
 	// Note:  This code is fairly inefficient but it should happen very rarely.
 	// It can be sped up if this is somehow a performance issue...
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index cb11ef1f5e4afb642260555a4e044b2f3d9f71a5..a7a49697682a84383f14020d92fad39d1a454ddc 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -72,7 +72,7 @@ class LLViewerObjectList
 
 	LLViewerObject *replaceObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); // TomY: hack to switch VO instances on the fly
 	
-	BOOL killObject(LLViewerObject *objectp, bool cache_enabled = false);
+	BOOL killObject(LLViewerObject *objectp);
 	void killObjects(LLViewerRegion *regionp); // Kill all objects owned by a particular region.
 	void killAllObjects();
 	void removeDrawable(LLDrawable* drawablep);
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index cfa24c32edf1c11bf3727f3343dab2be0b84e6ff..158fc4b0a936ed85b3e10852e79e94446828f73b 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -32,6 +32,7 @@
 //static variables definitions
 //-----------------------------------------------------------------------------------
 U32 LLViewerOctreeEntryData::sCurVisible = 0;
+BOOL LLViewerOctreeDebug::sInDebug = FALSE;
 
 //-----------------------------------------------------------------------------------
 //some global functions definitions
@@ -528,7 +529,7 @@ void LLviewerOctreeGroup::handleChildAddition(const OctreeNode* parent, OctreeNo
 
 	unbound();
 	
-	//((LLviewerOctreeGroup*)child->getListener(0))->unbound();
+	((LLviewerOctreeGroup*)child->getListener(0))->unbound();
 }
 	
 //virtual 
@@ -798,3 +799,46 @@ void LLViewerOctreeCull::visit(const OctreeNode* branch)
 	}
 }
 
+//--------------------------------------------------------------
+//class LLViewerOctreeDebug
+//virtual 
+void LLViewerOctreeDebug::visit(const OctreeNode* branch)
+{
+#if 0
+	llinfos << "Node: " << (U32)branch << " # Elements: " << branch->getElementCount() << " # Children: " << branch->getChildCount() << llendl;
+	for (U32 i = 0; i < branch->getChildCount(); i++)
+	{
+		llinfos << "Child " << i << " : " << (U32)branch->getChild(i) << llendl;
+	}
+#endif
+	LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) branch->getListener(0);
+	processGroup(group);	
+}
+
+//virtual 
+void LLViewerOctreeDebug::processGroup(LLviewerOctreeGroup* group)
+{
+#if 0
+	const LLVector4a* vec4 = group->getBounds();
+	LLVector3 vec[2];
+	vec[0].set(vec4[0].getF32ptr());
+	vec[1].set(vec4[1].getF32ptr());
+	llinfos << "Bounds: " << vec[0] << " : " << vec[1] << llendl;
+
+	vec4 = group->getExtents();
+	vec[0].set(vec4[0].getF32ptr());
+	vec[1].set(vec4[1].getF32ptr());
+	llinfos << "Extents: " << vec[0] << " : " << vec[1] << llendl;
+
+	vec4 = group->getObjectBounds();
+	vec[0].set(vec4[0].getF32ptr());
+	vec[1].set(vec4[1].getF32ptr());
+	llinfos << "ObjectBounds: " << vec[0] << " : " << vec[1] << llendl;
+
+	vec4 = group->getObjectExtents();
+	vec[0].set(vec4[0].getF32ptr());
+	vec[1].set(vec4[1].getF32ptr());
+	llinfos << "ObjectExtents: " << vec[0] << " : " << vec[1] << llendl;
+#endif
+}
+//--------------------------------------------------------------
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index a35c551949fdb1a5c20da703e2e12883fd15d826..21cc934d77d15ebd193c3a02680ac33f2f9f0e06 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -324,4 +324,15 @@ class LLViewerOctreeCull : public OctreeTraveler
 	S32 mRes;
 };
 
+//scan the octree, output the info of each node for debug use.
+class LLViewerOctreeDebug : public OctreeTraveler
+{
+public:
+	virtual void processGroup(LLviewerOctreeGroup* group);
+	virtual void visit(const OctreeNode* branch);
+
+public:
+	static BOOL sInDebug;
+};
+
 #endif
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 914a201ffe2a7dd6a00bb8c01e99b3b0e68c8744..bed047ff0b8c005b90b25dd541b7f9ac105c022e 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -442,6 +442,10 @@ void LLViewerRegion::loadObjectCache()
 	if(LLVOCache::hasInstance())
 	{
 		LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ;
+		if (mImpl->mCacheMap.empty())
+		{
+			mCacheDirty = TRUE;
+		}
 	}
 }
 
@@ -460,7 +464,10 @@ void LLViewerRegion::saveObjectCache()
 
 	if(LLVOCache::hasInstance())
 	{
-		LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty) ;
+		const F32 start_time_threshold = 600.0f; //seconds
+		bool removal_enabled = mRegionTimer.getElapsedTimeF32() > start_time_threshold; //allow to remove invalid objects from object cache file.
+
+		LLVOCache::getInstance()->writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty, removal_enabled) ;
 		mCacheDirty = FALSE;
 	}
 
@@ -744,11 +751,13 @@ void LLViewerRegion::dirtyHeights()
 void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry)
 {
 	U32 state = LLVOCacheEntry::INACTIVE;
+	bool in_vo_tree = false;
 
 	if(old_entry)
 	{
 		old_entry->copyTo(new_entry);
-		state = old_entry->getState();		
+		state = old_entry->getState();
+		in_vo_tree = (state == LLVOCacheEntry::INACTIVE && old_entry->getGroup() != NULL);
 		killCacheEntry(old_entry);
 	}
 
@@ -763,7 +772,7 @@ void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry
 	{
 		mImpl->mWaitingSet.insert(new_entry);
 	}
-	else if(old_entry && new_entry->getEntry())
+	else if(!old_entry || in_vo_tree)
 	{
 		addToVOCacheTree(new_entry);
 	}
@@ -895,10 +904,6 @@ void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry)
 	{
 		return;
 	}
-	if(!entry->hasState(LLVOCacheEntry::ADD_TO_CACHE_TREE))
-	{
-		return; //can not add to vo cache tree.
-	}
 
 	mImpl->mVOCachePartition->addEntry(entry->getEntry());
 }
@@ -1039,6 +1044,17 @@ F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
 			{
 				LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry();
 
+				if(vo_entry->getParentID() > 0) //is a child
+				{
+					LLVOCacheEntry* parent = getCacheEntry(vo_entry->getParentID());
+					
+					//make sure the parent is active
+					if(!parent || !parent->isState(LLVOCacheEntry::ACTIVE))
+					{
+						continue;
+					}
+				}
+
 				vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate);				
 				mImpl->mWaitingList.insert(vo_entry);
 			}
@@ -1140,7 +1156,7 @@ F32 LLViewerRegion::killInvisibleObjects(F32 max_time)
 	}
 	for(S32 i = 0; i < delete_list.size(); i++)
 	{
-		gObjectList.killObject(delete_list[i]->getVObj(), true);
+		gObjectList.killObject(delete_list[i]->getVObj());
 	}
 	delete_list.clear();
 
@@ -1194,6 +1210,28 @@ LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry)
 	return obj;
 }
 
+//remove from object cache if the object receives a full-update or terse update
+LLViewerObject* LLViewerRegion::forceToRemoveFromCache(U32 local_id, LLViewerObject* objectp)
+{
+	LLVOCacheEntry* entry = getCacheEntry(local_id);
+	if (!entry)
+	{
+		return objectp; //not in the cache, do nothing.
+	}
+	if(!objectp) //object not created
+	{
+		entry->setTouched(FALSE); //mark this entry invalid
+
+		//create a new object before delete it from cache.
+		objectp = gObjectList.processObjectUpdateFromCache(entry, this);
+	}
+
+	//remove from cache.
+	killCacheEntry(entry);
+
+	return objectp;
+}
+
 // As above, but forcibly do the update.
 void LLViewerRegion::forceUpdate()
 {
@@ -1647,14 +1685,130 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
 	mSimulatorFeatures = sim_features;
 }
 
-LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp)
+//this is called when the parent is not cacheable.
+//move all orphan children out of cache and insert to rendering octree.
+void LLViewerRegion::findOrphans(U32 parent_id)
+{
+	std::map<U32, OrphanList>::iterator iter = mOrphanMap.find(parent_id);
+	if(iter != mOrphanMap.end())
+	{
+		std::set<U32>* children = mOrphanMap[parent_id].getChildList();
+		for(std::set<U32>::iterator child_iter = children->begin(); child_iter != children->end(); ++child_iter)
+		{
+			forceToRemoveFromCache(*child_iter, NULL);
+		}
+			
+		mOrphanMap.erase(parent_id);
+	}
+}
+
+void LLViewerRegion::decodeBoundingInfo(LLVOCacheEntry* entry)
+{
+	if(entry != NULL && !entry->getEntry())
+	{
+		entry->setOctreeEntry(NULL);
+	}
+	else if(entry->getGroup() != NULL)
+	{
+		return; //already in octree, no post processing.
+	}
+
+	LLVector3 pos;
+	LLVector3 scale;
+	LLQuaternion rot;
+	U32 parent_id = LLViewerObject::extractSpatialExtents(entry->getDP(), pos, scale, rot);
+	
+	entry->setBoundingInfo(pos, scale);
+	
+	if(parent_id > 0) //has parent
+	{
+		entry->setParentID(parent_id);
+	
+		//1, find parent, update position
+		LLVOCacheEntry* parent = getCacheEntry(parent_id);
+		
+		//2, if can not, put into the orphan list.
+		if(!parent || !parent->getGroup())
+		{
+			std::map<U32, OrphanList>::iterator iter = mOrphanMap.find(parent_id);
+			if(iter != mOrphanMap.end())
+			{
+				iter->second.addChild(entry->getLocalID());
+			}
+			else 
+			{
+				//check if the parent is an uncacheable object
+				if(!parent)
+				{
+					LLUUID parent_uuid;
+					LLViewerObjectList::getUUIDFromLocal(parent_uuid,
+															parent_id,
+															getHost().getAddress(),
+															getHost().getPort());
+					LLViewerObject *parent_objp = gObjectList.findObject(parent_uuid);
+					if(parent_objp)
+					{
+						//parent is not cacheable, remove child from the cache.
+						forceToRemoveFromCache(entry->getLocalID(), NULL);
+						return;
+					}
+				}
+
+				//otherwise insert to the orphan list
+				OrphanList o_list(entry->getLocalID());
+				mOrphanMap[parent_id] = o_list;
+			}
+			
+			return;
+		}
+		else
+		{
+			//update the child position to the region space.
+			entry->updateBoundingInfo(parent);
+		}
+	}
+	
+	if(!entry->getGroup() && entry->isState(LLVOCacheEntry::INACTIVE))
+	{
+		addToVOCacheTree(entry);
+	}
+
+	if(!parent_id) //a potential parent
+	{
+		//find all children and update their bounding info
+		std::map<U32, OrphanList>::iterator iter = mOrphanMap.find(entry->getLocalID());
+		if(iter != mOrphanMap.end())
+		{
+			std::set<U32>* children = mOrphanMap[parent_id].getChildList();
+			for(std::set<U32>::iterator child_iter = children->begin(); child_iter != children->end(); ++child_iter)
+			{
+				LLVOCacheEntry* child = getCacheEntry(*child_iter);
+				if(child)
+				{
+					//update the child position to the region space.
+					child->updateBoundingInfo(entry);
+					addToVOCacheTree(child);
+				}
+			}
+			
+			mOrphanMap.erase(entry->getLocalID());
+		}
+	}
+	
+	return ;
+}
+
+LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLDataPackerBinaryBuffer &dp, U32 flags)
 {
-	U32 local_id = objectp->getLocalID();
-	U32 crc = objectp->getCRC();
 	eCacheUpdateResult result;
+	U32 crc;
+	U32 local_id;
 
-	LLVOCacheEntry* entry = getCacheEntry(local_id);
+	LLViewerObject::unpackU32(&dp, local_id, "LocalID");
+	LLViewerObject::unpackU32(&dp, crc, "CRC");
 
+	LLVOCacheEntry* entry = getCacheEntry(local_id);
+	
 	if (entry)
 	{
 		// we've seen this object before
@@ -1668,9 +1822,22 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 		{
 			// Update the cache entry
 			LLPointer<LLVOCacheEntry> new_entry = new LLVOCacheEntry(local_id, crc, dp);
-			replaceCacheEntry(entry, new_entry);
-			entry = new_entry;
-
+			
+			//if visible, update it
+			if(!entry->isState(LLVOCacheEntry::INACTIVE))
+			{
+				replaceCacheEntry(entry, new_entry);
+			}
+			else //invisible
+			{
+				//remove old entry
+				killCacheEntry(entry);
+				entry = new_entry;
+				
+				mImpl->mCacheMap[local_id] = entry;
+				decodeBoundingInfo(entry);
+			}
+			
 			result = CACHE_UPDATE_CHANGED;
 		}
 	}
@@ -1679,16 +1846,26 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 		// we haven't seen this object before
 		// Create new entry and add to map
 		result = CACHE_UPDATE_ADDED;
-		//if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
-		//{
-		//	delete mImpl->mCacheMap.begin()->second ;
-		//	mImpl->mCacheMap.erase(mImpl->mCacheMap.begin());
-		//	result = CACHE_UPDATE_REPLACED;
-		//
-		//}
 		entry = new LLVOCacheEntry(local_id, crc, dp);
-
+		
 		mImpl->mCacheMap[local_id] = entry;
+		
+		decodeBoundingInfo(entry);
+	}
+	entry->setUpdateFlags(flags);
+
+	return result;
+}
+
+LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags)
+{
+	eCacheUpdateResult result = cacheFullUpdate(dp, flags);
+
+#if 0
+	LLVOCacheEntry* entry = mImpl->mCacheMap[objectp->getLocalID()];
+	if(!entry)
+	{
+		return result;
 	}
 
 	if(objectp->mDrawable.notNull() && !entry->getEntry())
@@ -1699,6 +1876,7 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 	{
 		addActiveCacheEntry(entry);
 	}
+#endif
 
 	return result;
 }
@@ -1721,9 +1899,18 @@ LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id)
 	return NULL;
 }
 
+void LLViewerRegion::addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type)
+{
+#if 0
+	mCacheMissList.insert(CacheMissItem(id, miss_type));
+#else
+	mCacheMissList.push_back(CacheMissItem(id, miss_type));
+#endif
+}
+
 // Get data packer for this object, if we have cached data
 // AND the CRC matches. JC
-bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
+bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type)
 {
 	//llassert(mCacheLoaded);  This assert failes often, changing to early-out -- davep, 2010/10/18
 
@@ -1736,28 +1923,34 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
 		{
 			// Record a hit
 			entry->recordHit();
-		cache_miss_type = CACHE_MISS_TYPE_NONE;
+			cache_miss_type = CACHE_MISS_TYPE_NONE;
+			entry->setUpdateFlags(flags);
+			
+			if(entry->isState(LLVOCacheEntry::ACTIVE))
+			{
+				((LLDrawable*)entry->getEntry()->getDrawable())->getVObj()->loadFlags(flags);
+				return true;
+			}
 
 			if(entry->getGroup() || !entry->isState(LLVOCacheEntry::INACTIVE))
 			{
 				return true;
 			}
 
-			addVisibleCacheEntry(entry);
+			decodeBoundingInfo(entry);
 			return true;
 		}
 		else
 		{
 			// llinfos << "CRC miss for " << local_id << llendl;
-		cache_miss_type = CACHE_MISS_TYPE_CRC;
-			mCacheMissCRC.put(local_id);
+
+			addCacheMiss(local_id, CACHE_MISS_TYPE_CRC);
 		}
 	}
 	else
 	{
 		// llinfos << "Cache miss for " << local_id << llendl;
-	cache_miss_type = CACHE_MISS_TYPE_FULL;
-		mCacheMissFull.put(local_id);
+		addCacheMiss(local_id, CACHE_MISS_TYPE_FULL);
 	}
 
 	return false;
@@ -1765,49 +1958,22 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
 
 void LLViewerRegion::addCacheMissFull(const U32 local_id)
 {
-	mCacheMissFull.put(local_id);
+	addCacheMiss(local_id, CACHE_MISS_TYPE_FULL);
 }
 
 void LLViewerRegion::requestCacheMisses()
 {
-	S32 full_count = mCacheMissFull.count();
-	S32 crc_count = mCacheMissCRC.count();
-	if (full_count == 0 && crc_count == 0) return;
+	if (!mCacheMissList.size()) 
+	{
+		return;
+	}
 
 	LLMessageSystem* msg = gMessageSystem;
 	BOOL start_new_message = TRUE;
 	S32 blocks = 0;
-	S32 i;
-
-	// Send full cache miss updates.  For these, we KNOW we don't
-	// have a viewer object.
-	for (i = 0; i < full_count; i++)
-	{
-		if (start_new_message)
-		{
-			msg->newMessageFast(_PREHASH_RequestMultipleObjects);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-			start_new_message = FALSE;
-		}
-
-		msg->nextBlockFast(_PREHASH_ObjectData);
-		msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_FULL);
-		msg->addU32Fast(_PREHASH_ID, mCacheMissFull[i]);
-		blocks++;
-
-		if (blocks >= 255)
-		{
-			sendReliableMessage();
-			start_new_message = TRUE;
-			blocks = 0;
-		}
-	}
-
-	// Send CRC miss updates.  For these, we _might_ have a viewer object,
-	// but probably not.
-	for (i = 0; i < crc_count; i++)
+	
+	//send requests for all cache-missed objects
+	for (CacheMissItem::cache_miss_list_t::iterator iter = mCacheMissList.begin(); iter != mCacheMissList.end(); ++iter)
 	{
 		if (start_new_message)
 		{
@@ -1819,8 +1985,8 @@ void LLViewerRegion::requestCacheMisses()
 		}
 
 		msg->nextBlockFast(_PREHASH_ObjectData);
-		msg->addU8Fast(_PREHASH_CacheMissType, CACHE_MISS_TYPE_CRC);
-		msg->addU32Fast(_PREHASH_ID, mCacheMissCRC[i]);
+		msg->addU8Fast(_PREHASH_CacheMissType, (*iter).mType);
+		msg->addU32Fast(_PREHASH_ID, (*iter).mID);
 		blocks++;
 
 		if (blocks >= 255)
@@ -1835,14 +2001,14 @@ void LLViewerRegion::requestCacheMisses()
 	if (!start_new_message)
 	{
 		sendReliableMessage();
-	}
-	mCacheMissFull.reset();
-	mCacheMissCRC.reset();
+	}	
 
 	mCacheDirty = TRUE ;
 	// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
-	LLViewerStatsRecorder::instance().requestCacheMissesEvent(full_count + crc_count);
+	LLViewerStatsRecorder::instance().requestCacheMissesEvent(mCacheMissList.size());
 	LLViewerStatsRecorder::instance().log(0.2f);
+
+	mCacheMissList.clear();
 }
 
 void LLViewerRegion::dumpCache()
@@ -2005,8 +2171,16 @@ void LLViewerRegion::unpackRegionHandshake()
 	msg->addUUID("AgentID", gAgent.getID());
 	msg->addUUID("SessionID", gAgent.getSessionID());
 	msg->nextBlock("RegionInfo");
-	msg->addU32("Flags", 0x0 );
+
+	U32 flags = 0x00000001; //set the bit 0 to be 1 to ask sim to send all cacheable objects.
+	if(mImpl->mCacheMap.empty())
+	{
+		flags |= 0x00000002; //set the bit 1 to be 1 to tell sim the cache file is empty, no need to send cache probes.
+	}
+	msg->addU32("Flags", flags );
 	msg->sendReliable(host);
+
+	mRegionTimer.reset(); //reset region timer.
 }
 
 void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 9252923aa35d5b20ba7609dba8d488e85b1529a0..2248cf526916b459847754b55c0287a5897d3d08 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -314,11 +314,16 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	} eCacheUpdateResult;
 
 	// handle a full update message
-	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);	
+	eCacheUpdateResult cacheFullUpdate(LLDataPackerBinaryBuffer &dp, U32 flags);
+	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags);	
 	LLVOCacheEntry* getCacheEntryForOctree(U32 local_id);
-	bool probeCache(U32 local_id, U32 crc, U8 &cache_miss_type);
+	LLVOCacheEntry* getCacheEntry(U32 local_id);
+	bool probeCache(U32 local_id, U32 crc, U32 flags, U8 &cache_miss_type);
 	void requestCacheMisses();
 	void addCacheMissFull(const U32 local_id);
+	//remove from object cache if the object receives a full-update or terse update
+	LLViewerObject* forceToRemoveFromCache(U32 local_id, LLViewerObject* objectp);
+	void findOrphans(U32 parent_id);
 
 	void dumpCache();
 
@@ -346,8 +351,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 private:
 	void addToVOCacheTree(LLVOCacheEntry* entry);
 	LLViewerObject* addNewObject(LLVOCacheEntry* entry);
-	void killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list);
-	LLVOCacheEntry* getCacheEntry(U32 local_id);
+	void killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list);	
 	void removeFromVOCacheTree(LLVOCacheEntry* entry);
 	void replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry);
 	void killCacheEntry(LLVOCacheEntry* entry); //physically delete the cache entry	
@@ -356,6 +360,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	F32 createVisibleObjects(F32 max_time);
 	F32 updateVisibleEntries(F32 max_time); //update visible entries
 
+	void addCacheMiss(U32 id, LLViewerRegion::eCacheMissType miss_type);
+	void decodeBoundingInfo(LLVOCacheEntry* entry);
 public:
 	struct CompareDistance
 	{
@@ -393,6 +399,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	static BOOL sVOCacheCullingEnabled; //vo cache culling enabled or not.
 private:
 	LLViewerRegionImpl * mImpl;
+	LLFrameTimer         mRegionTimer;
 
 	F32			mWidth;			// Width of region on a side (meters)
 	U64			mHandle;
@@ -441,8 +448,44 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	BOOL    mReleaseNotesRequested;
 	BOOL    mDead;  //if true, this region is in the process of deleting.
 
-	LLDynamicArray<U32>						mCacheMissFull;
-	LLDynamicArray<U32>						mCacheMissCRC;
+	class OrphanList
+	{
+	public:
+		OrphanList(){}
+		OrphanList(U32 child_id){addChild(child_id);}
+		
+		void addChild(U32 child_id) {mChildList.insert(child_id);}
+		std::set<U32>* getChildList() {return &mChildList;}
+		
+	private:
+		std::set<U32> mChildList;
+	};
+	
+	std::map<U32, OrphanList> mOrphanMap;
+	
+	class CacheMissItem
+	{
+	public:
+		CacheMissItem(U32 id, LLViewerRegion::eCacheMissType miss_type) : mID(id), mType(miss_type){}
+
+		U32                            mID;     //local object id
+		LLViewerRegion::eCacheMissType mType;   //cache miss type
+	
+#if 0
+		struct Compare
+		{
+			bool operator()(const CacheMissItem& lhs, const CacheMissItem& rhs)
+			{
+				return lhs.mID < rhs.mID; //smaller ID first.
+			}
+		};
+
+		typedef std::set<CacheMissItem, Compare> cache_miss_list_t;
+#else
+		typedef std::list<CacheMissItem> cache_miss_list_t;
+#endif
+	};
+	CacheMissItem::cache_miss_list_t        mCacheMissList;
 	
 	caps_received_signal_t mCapabilitiesReceivedSignal;		
 	LLSD mSimulatorFeatures;
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 28bd02c606d1472705b53a0f08a9168b481c168a..78775c7205a0778946978faf24b0a75715252edb 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -2724,6 +2724,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 			gTwoTextureCompareProgram.bind();
 			gTwoTextureCompareProgram.uniform1i("tex0", 0);
 			gTwoTextureCompareProgram.uniform1i("tex1", 1);
+			gTwoTextureCompareProgram.uniform1i("dither_tex", 2);
 		}
 	}
 
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 86cfbb1d74372881da206c399bc666424bc56cc9..caa87eb1eb9a51ba5c21a833b88f054c715c38c7 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -53,13 +53,16 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &
 	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(local_id),
 	mCRC(crc),
+	mUpdateFlags(-1),
 	mHitCount(0),
 	mDupeCount(0),
 	mCRCChangeCount(0),
 	mState(INACTIVE),
 	mRepeatedVisCounter(0),
 	mVisFrameRange(64),
-	mSceneContrib(0.f)
+	mSceneContrib(0.f),
+	mTouched(TRUE),
+	mParentID(0)
 {
 	mBuffer = new U8[dp.getBufferSize()];
 	mDP.assignBuffer(mBuffer, dp.getBufferSize());
@@ -70,6 +73,7 @@ LLVOCacheEntry::LLVOCacheEntry()
 	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(0),
 	mCRC(0),
+	mUpdateFlags(-1),
 	mHitCount(0),
 	mDupeCount(0),
 	mCRCChangeCount(0),
@@ -77,7 +81,9 @@ LLVOCacheEntry::LLVOCacheEntry()
 	mState(INACTIVE),
 	mRepeatedVisCounter(0),
 	mVisFrameRange(64),
-	mSceneContrib(0.f)
+	mSceneContrib(0.f),
+	mTouched(TRUE),
+	mParentID(0)
 {
 	mDP.assignBuffer(mBuffer, 0);
 }
@@ -85,10 +91,13 @@ LLVOCacheEntry::LLVOCacheEntry()
 LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
 	mBuffer(NULL),
+	mUpdateFlags(-1),
 	mState(INACTIVE),
 	mRepeatedVisCounter(0),
 	mVisFrameRange(64),
-	mSceneContrib(0.f)
+	mSceneContrib(0.f),
+	mTouched(FALSE),
+	mParentID(0)
 {
 	S32 size = -1;
 	BOOL success;
@@ -114,36 +123,6 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32));
 	}
 	if(success)
-	{
-		success = check_read(apr_file, &mState, sizeof(U32));
-	}
-	if(success)
-	{
-		F32 ext[8];
-		success = check_read(apr_file, (void*)ext, sizeof(F32) * 8);
-
-		LLVector4a exts[2];
-		exts[0].load4a(ext);
-		exts[1].load4a(&ext[4]);
-	
-		setSpatialExtents(exts[0], exts[1]);
-	}
-	if(success)
-	{
-		LLVector4 pos;
-		success = check_read(apr_file, (void*)pos.mV, sizeof(LLVector4));
-
-		LLVector4a pos_;
-		pos_.load4a(pos.mV);
-		setPositionGroup(pos_);
-	}
-	if(success)
-	{
-		F32 rad;
-		success = check_read(apr_file, &rad, sizeof(F32));
-		setBinRadius(rad);
-	}
-	if(success)
 	{
 		success = check_read(apr_file, &size, sizeof(S32));
 
@@ -198,10 +177,8 @@ void LLVOCacheEntry::setOctreeEntry(LLViewerOctreeEntry* entry)
 	if(!entry && mDP.getBufferSize() > 0)
 	{
 		LLUUID fullid;
-		mDP.reset();
-		mDP.unpackUUID(fullid, "ID");
-		mDP.reset();
-
+		LLViewerObject::unpackUUID(&mDP, fullid, "ID");
+		
 		LLViewerObject* obj = gObjectList.findObject(fullid);
 		if(obj && obj->mDrawable)
 		{
@@ -231,9 +208,7 @@ void LLVOCacheEntry::copyTo(LLVOCacheEntry* new_entry)
 
 void LLVOCacheEntry::setState(U32 state)
 {
-	mState &= 0xffff0000; //clear the low 16 bits
-	state &= 0x0000ffff;  //clear the high 16 bits;
-	mState |= state;
+	mState = state;
 
 	if(getState() == ACTIVE)
 	{
@@ -300,6 +275,7 @@ LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP()
 
 void LLVOCacheEntry::recordHit()
 {
+	setTouched();
 	mHitCount++;
 }
 
@@ -340,33 +316,6 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32));
 	}
 	if(success)
-	{
-		U32 state = mState & 0xffff0000; //only store the high 16 bits.
-		success = check_write(apr_file, (void*)&state, sizeof(U32));
-	}
-	if(success)
-	{
-		const LLVector4a* exts = getSpatialExtents() ;
-		LLVector4 ext(exts[0][0], exts[0][1], exts[0][2], exts[0][3]);
-		success = check_write(apr_file, ext.mV, sizeof(LLVector4));		
-		if(success)
-		{
-			ext.set(exts[1][0], exts[1][1], exts[1][2], exts[1][3]);
-			success = check_write(apr_file, ext.mV, sizeof(LLVector4));		
-		}
-	}
-	if(success)
-	{
-		const LLVector4a pos_ = getPositionGroup() ;
-		LLVector4 pos(pos_[0], pos_[1], pos_[2], pos_[3]);
-		success = check_write(apr_file, pos.mV, sizeof(LLVector4));		
-	}
-	if(success)
-	{
-		F32 rad = getBinRadius();
-		success = check_write(apr_file, (void*)&rad, sizeof(F32));
-	}
-	if(success)
 	{
 		S32 size = mDP.getBufferSize();
 		success = check_write(apr_file, (void*)&size, sizeof(S32));
@@ -402,6 +351,28 @@ void LLVOCacheEntry::calcSceneContribution(const LLVector3& camera_origin, bool
 	setVisible();
 }
 
+void LLVOCacheEntry::setBoundingInfo(const LLVector3& pos, const LLVector3& scale)
+{
+	LLVector4a center, newMin, newMax;
+	center.load3(pos.mV);
+	LLVector4a size;
+	size.load3(scale.mV);
+	newMin.setSub(center, size);
+	newMax.setAdd(center, size);
+	
+	setPositionGroup(center);
+	setSpatialExtents(newMin, newMax);
+	setBinRadius(llmin(size.getLength3().getF32() * 4.f, 256.f));
+}
+
+void LLVOCacheEntry::updateBoundingInfo(LLVOCacheEntry* parent)
+{
+	//LLVector4a old_pos = getPositionGroup();
+	//parent->getPositionRegion() + (getPosition() * parent->getRotation());
+	
+	shift(parent->getPositionGroup());
+}
+
 //-------------------------------------------------------------------
 //LLVOCachePartition
 //-------------------------------------------------------------------
@@ -409,8 +380,7 @@ LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp)
 {
 	mRegionp = regionp;
 	mPartitionType = LLViewerRegion::PARTITION_VO_CACHE;
-	mVisitedTime = 0;
-
+	
 	new LLviewerOctreeGroup(mOctree);
 }
 
@@ -477,12 +447,6 @@ S32 LLVOCachePartition::cull(LLCamera &camera)
 		return 0;
 	}
 
-	if(mVisitedTime == LLViewerOctreeEntryData::getCurrentFrame())
-	{
-		return 0; //already visited.
-	}
-	mVisitedTime = LLViewerOctreeEntryData::getCurrentFrame();
-
 	((LLviewerOctreeGroup*)mOctree->getListener(0))->rebound();
 
 	//localize the camera
@@ -599,13 +563,19 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 	}	
 }
 	
-void LLVOCache::removeCache(ELLPath location) 
+void LLVOCache::removeCache(ELLPath location, bool started) 
 {
+	if(started)
+	{
+		removeCache();
+		return;
+	}
+
 	if(mReadOnly)
 	{
 		llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl;
 		return ;
-	}
+	}	
 
 	llinfos << "about to remove the object cache due to settings." << llendl ;
 
@@ -628,10 +598,8 @@ void LLVOCache::removeCache()
 		return ;
 	}
 
-	llinfos << "about to remove the object cache due to some error." << llendl ;
-
 	std::string mask = "*";
-	llinfos << "Removing cache at " << mObjectCacheDirName << llendl;
+	llinfos << "Removing object cache at " << mObjectCacheDirName << llendl;
 	gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); 
 
 	clearCacheInMemory() ;
@@ -938,7 +906,7 @@ void LLVOCache::purgeEntries(U32 size)
 	mNumEntries = mHandleEntryMap.size() ;
 }
 
-void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) 
+void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled) 
 {
 	if(!mEnabled)
 	{
@@ -1011,7 +979,10 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 	
 			for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter)
 			{
-				success = iter->second->writeToFile(&apr_file) ;
+				if(!removal_enabled || iter->second->isTouched())
+				{
+					success = iter->second->writeToFile(&apr_file) ;
+				}
 			}
 		}
 	}
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index c631e127390d532a1734fa5f0191b2d0374554f9..5f2dd630514073d5a5d3df504b8c0f6cda48786d 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -41,7 +41,7 @@ class LLCamera;
 class LLVOCacheEntry : public LLViewerOctreeEntryData
 {
 public:
-	enum
+	enum //low 16-bit state
 	{
 		INACTIVE = 0x00000000,     //not visible
 		IN_QUEUE = 0x00000001,     //in visible queue, object to be created
@@ -49,11 +49,6 @@ class LLVOCacheEntry : public LLViewerOctreeEntryData
 		ACTIVE   = 0x00000004      //object created, and in rendering pipeline.
 	};
 
-	enum
-	{
-		ADD_TO_CACHE_TREE = 0x00010000, //has parent
-	};
-
 	struct CompareVOCacheEntry
 	{
 		bool operator()(const LLVOCacheEntry* const& lhs, const LLVOCacheEntry* const& rhs)
@@ -84,12 +79,10 @@ class LLVOCacheEntry : public LLViewerOctreeEntryData
 	LLVOCacheEntry();	
 
 	void setState(U32 state);
-	void clearState(U32 state) {mState &= ~state;}
-	void addState(U32 state)   {mState |= state;}
-	bool isState(U32 state)    {return (mState & 0xffff) == state;}
+	//void clearState(U32 state) {mState &= ~state;}
+	bool isState(U32 state)    {return mState == state;}
 	bool hasState(U32 state)   {return mState & state;}
-	U32  getState() const      {return (mState & 0xffff);}
-	U32  getFullState() const  {return mState;}
+	U32  getState() const      {return mState;}
 	
 	U32 getLocalID() const			{ return mLocalID; }
 	U32 getCRC() const				{ return mCRC; }
@@ -111,11 +104,24 @@ class LLVOCacheEntry : public LLViewerOctreeEntryData
 	void copyTo(LLVOCacheEntry* new_entry); //copy variables 
 	/*virtual*/ void setOctreeEntry(LLViewerOctreeEntry* entry);
 
+	void setParentID(U32 id) {mParentID = id;}
+	U32  getParentID() const {return mParentID;}
+
 	void addChild(LLVOCacheEntry* entry);
 	LLVOCacheEntry* getChild(S32 i) {return mChildrenList[i];}
 	S32  getNumOfChildren()         {return mChildrenList.size();}
 	void clearChildrenList()        {mChildrenList.clear();}
 
+	//called from processing object update message
+	void setBoundingInfo(const LLVector3& pos, const LLVector3& scale);
+	void updateBoundingInfo(LLVOCacheEntry* parent);
+
+	void setTouched(BOOL touched = TRUE) {mTouched = touched;}
+	BOOL isTouched() const {return mTouched;}
+	
+	void setUpdateFlags(U32 flags) {mUpdateFlags = flags;}
+	U32  getUpdateFlags() const    {return mUpdateFlags;}
+
 public:
 	typedef std::map<U32, LLPointer<LLVOCacheEntry> >	   vocache_entry_map_t;
 	typedef std::set<LLVOCacheEntry*>                      vocache_entry_set_t;
@@ -123,7 +129,9 @@ class LLVOCacheEntry : public LLViewerOctreeEntryData
 
 protected:
 	U32							mLocalID;
+	U32                         mParentID;
 	U32							mCRC;
+	U32                         mUpdateFlags; //receive from sim
 	S32							mHitCount;
 	S32							mDupeCount;
 	S32							mCRCChangeCount;
@@ -135,6 +143,8 @@ class LLVOCacheEntry : public LLViewerOctreeEntryData
 	S32                         mRepeatedVisCounter; //number of repeatedly visible within a short time.
 	U32                         mState; //high 16 bits reserved for special use.
 	std::vector<LLVOCacheEntry*> mChildrenList; //children entries in a linked set.
+
+	BOOL                        mTouched; //if set, this entry is valid, otherwise it is invalid.
 };
 
 class LLVOCachePartition : public LLViewerOctreePartition
@@ -145,9 +155,6 @@ class LLVOCachePartition : public LLViewerOctreePartition
 	void addEntry(LLViewerOctreeEntry* entry);
 	void removeEntry(LLViewerOctreeEntry* entry);
 	/*virtual*/ S32 cull(LLCamera &camera);
-
-private:
-	U32 mVisitedTime;
 };
 
 //
@@ -192,10 +199,10 @@ class LLVOCache
 	~LLVOCache() ;
 
 	void initCache(ELLPath location, U32 size, U32 cache_version) ;
-	void removeCache(ELLPath location) ;
+	void removeCache(ELLPath location, bool started = false) ;
 
 	void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ;
-	void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) ;
+	void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled);
 	void removeEntry(U64 handle) ;
 
 	void setReadOnly(BOOL read_only) {mReadOnly = read_only;} 
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 2f0acba23e290ddec6f82923aec5c6c4d80a8c18..a52c2b3192fb38bee58c9ca1f31ef7bb07d8f0a6 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2750,6 +2750,16 @@
                  function="ToggleControl"
                  parameter="RenderHoverGlowEnable" />
             </menu_item_check>
+          <menu_item_separator />
+          
+          <menu_item_call
+            enabled="true"
+            label="Clear Cache Immediately"
+            name="Cache Clear">
+            <menu_item_call.on_click
+             function="Develop.ClearCache" />
+          </menu_item_call>
+          
         </menu>
 
         <menu
diff --git a/indra/newview/tests/llviewerassetstats_test.cpp b/indra/newview/tests/llviewerassetstats_test.cpp
index 41d141255bd13745b7a7c487710b99ac4538de50..ae93778534c772cf5cfbafe1c738a6bce2c1d52e 100644
--- a/indra/newview/tests/llviewerassetstats_test.cpp
+++ b/indra/newview/tests/llviewerassetstats_test.cpp
@@ -39,7 +39,7 @@
 
 namespace LLStatViewer
 {
-	LLTrace::<>		FPS_SAMPLE("fpssample");
+	LLTrace::MeasurementStatHandle<>		FPS_SAMPLE("fpssample");
 }
 
 void LLVOAvatar::getNearbyRezzedStats(std::vector<S32>& counts)