From c0ba626c8009b22310b3923e8170e5db2a021253 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Mon, 15 Oct 2012 21:34:29 -0600
Subject: For SH-3333: Design and implement a new object cache system on viewer
 side

---
 indra/newview/CMakeLists.txt            |   2 +
 indra/newview/app_settings/settings.xml |  11 +
 indra/newview/llappviewer.cpp           |   2 +-
 indra/newview/lldrawable.cpp            | 349 +++++++-------
 indra/newview/lldrawable.h              |  62 +--
 indra/newview/llspatialpartition.cpp    | 787 +++++++++++---------------------
 indra/newview/llspatialpartition.h      | 128 +++---
 indra/newview/lltextureview.cpp         |   9 +-
 indra/newview/llviewermessage.cpp       |  25 +-
 indra/newview/llviewerobject.cpp        | 105 +++--
 indra/newview/llviewerobjectlist.cpp    | 145 +++++-
 indra/newview/llviewerobjectlist.h      |   6 +-
 indra/newview/llvieweroctree.cpp        | 704 ++++++++++++++++++++++++++++
 indra/newview/llvieweroctree.h          | 274 +++++++++++
 indra/newview/llviewerpartsim.cpp       |   4 +-
 indra/newview/llviewerregion.cpp        | 478 +++++++++++++++++--
 indra/newview/llviewerregion.h          |  38 +-
 indra/newview/llviewerstatsrecorder.cpp |   2 +-
 indra/newview/llvoavatarself.cpp        |   6 +-
 indra/newview/llvocache.cpp             |  78 +++-
 indra/newview/llvocache.h               |  36 +-
 indra/newview/llvograss.cpp             |  14 +-
 indra/newview/llvopartgroup.cpp         |  20 +-
 indra/newview/llvosurfacepatch.cpp      |   4 +-
 indra/newview/llvotree.cpp              |   4 +-
 indra/newview/llvovolume.cpp            |  44 +-
 indra/newview/llvowater.cpp             |   6 +-
 indra/newview/llworld.cpp               |  20 +-
 indra/newview/llworld.h                 |   3 +-
 indra/newview/pipeline.cpp              |  50 +-
 30 files changed, 2429 insertions(+), 987 deletions(-)
 create mode 100644 indra/newview/llvieweroctree.cpp
 create mode 100644 indra/newview/llvieweroctree.h

(limited to 'indra')

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 04ea646100..c81ade6937 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -583,6 +583,7 @@ set(viewer_SOURCE_FILES
     llviewernetwork.cpp
     llviewerobject.cpp
     llviewerobjectlist.cpp
+	llvieweroctree.cpp
     llviewerparcelmedia.cpp
     llviewerparcelmediaautoplay.cpp
     llviewerparcelmgr.cpp
@@ -1148,6 +1149,7 @@ set(viewer_HEADER_FILES
     llviewernetwork.h
     llviewerobject.h
     llviewerobjectlist.h
+	llvieweroctree.h
     llviewerparcelmedia.h
     llviewerparcelmediaautoplay.h
     llviewerparcelmgr.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7497a273ea..13c95c2381 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6400,6 +6400,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>ObjectCacheViewCullingEnabled</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable the object cache view culling. Needs to restart viewer.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>OpenDebugStatAdvanced</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index a43776912c..bffa1708ec 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3685,7 +3685,7 @@ U32 LLAppViewer::getObjectCacheVersion()
 {
 	// Viewer object cache version, change if object update
 	// format changes. JC
-	const U32 INDRA_OBJECT_CACHE_VERSION = 14;
+	const U32 INDRA_OBJECT_CACHE_VERSION = 15;
 
 	return INDRA_OBJECT_CACHE_VERSION;
 }
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 46ec1abec1..e29551e83c 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -49,6 +49,7 @@
 #include "llspatialpartition.h"
 #include "llviewerobjectlist.h"
 #include "llviewerwindow.h"
+#include "llvocache.h"
 
 const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f;
 const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f;
@@ -75,7 +76,6 @@ extern bool gShiftFrame;
 //
 
 // static
-U32 LLDrawable::sCurVisible = 0;
 U32 LLDrawable::sNumZombieDrawables = 0;
 F32 LLDrawable::sCurPixelAngle = 0;
 LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList;
@@ -85,33 +85,59 @@ LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList;
 // static
 void LLDrawable::incrementVisible() 
 {
-	sCurVisible++;
+	LLViewerOctreeEntryData::incrementVisible();
 	sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView();
 }
 
-void LLDrawable::init()
+LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry)
+	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE),
+	  mVObjp(vobj)
+{
+	init(new_entry); 
+}
+
+void LLDrawable::init(bool new_entry)
 {
 	// mXform
 	mParent = NULL;
 	mRenderType = 0;
 	mCurrentScale = LLVector3(1,1,1);
-	mDistanceWRTCamera = 0.0f;
-	mPositionGroup.clear();
-	mExtents[0].clear();
-	mExtents[1].clear();
-
+	mDistanceWRTCamera = 0.0f;	
 	mState     = 0;
-	mVObjp   = NULL;
-	// mFaces
-	mSpatialGroupp = NULL;
-	mVisible = sCurVisible - 2;//invisible for the current frame and the last frame.
-	mRadius = 0.f;
 	
-	mGeneration = -1;
-	mBinRadius = 1.f;
-	mBinIndex = -1;
-
+	// mFaces	
+	mRadius = 0.f;	
+	mGeneration = -1;	
 	mSpatialBridge = NULL;
+
+	LLViewerOctreeEntry* entry = NULL;
+	LLVOCacheEntry* vo_entry = NULL;
+	if(!new_entry && mVObjp && getRegion() != NULL)
+	{
+		vo_entry = getRegion()->getCacheEntryForOctree(mVObjp->getLocalID());
+		if(vo_entry)
+		{
+			entry = vo_entry->getEntry();			
+		}
+	}
+	setOctreeEntry(entry);
+	if(vo_entry)
+	{
+		if(!entry)
+		{
+			vo_entry->setOctreeEntry(mEntry);
+		}
+		else if(vo_entry->getNumOfChildren() > 0)
+		{
+			getRegion()->addVisibleCacheEntry(vo_entry); //to load all children.
+		}
+
+		getRegion()->addActiveCacheEntry(vo_entry);		
+	}
+
+	llassert(!vo_entry || vo_entry->getEntry() == mEntry);
+
+	initVisible(sCurVisible - 2);//invisible for the current frame and the last frame.
 }
 
 // static
@@ -155,6 +181,7 @@ void LLDrawable::markDead()
 		llwarns << "Warning!  Marking dead multiple times!" << llendl;
 		return;
 	}
+	setState(DEAD);
 
 	if (mSpatialBridge)
 	{
@@ -164,8 +191,7 @@ void LLDrawable::markDead()
 
 	sNumZombieDrawables++;
 
-	// We're dead.  Free up all of our references to other objects
-	setState(DEAD);
+	// We're dead.  Free up all of our references to other objects	
 	cleanupReferences();
 //	sDeadList.put(this);
 }
@@ -219,6 +245,8 @@ void LLDrawable::cleanupReferences()
 	
 	gPipeline.unlinkDrawable(this);
 	
+	removeFromOctree();
+
 	{
 		LLFastTimer t(FTM_DEREF_DRAWABLE);
 		// Cleanup references to other objects
@@ -227,6 +255,21 @@ void LLDrawable::cleanupReferences()
 	}
 }
 
+void LLDrawable::removeFromOctree()
+{
+	if(!mEntry)
+	{
+		return;
+	}
+
+	mEntry->removeData(this);
+	if(mEntry->hasVOCacheEntry())
+	{
+		getRegion()->removeActiveCacheEntry((LLVOCacheEntry*)mEntry->getVOCacheEntry(), this);
+	}
+	mEntry = NULL;
+}
+
 void LLDrawable::cleanupDeadDrawables()
 {
 	/*
@@ -715,7 +758,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 		LLVOVolume* volume = getVOVolume();
 		if (volume)
 		{
-			if (getSpatialGroup())
+			if (getGroup())
 			{
 				pos.set(getPositionGroup().getF32ptr());
 			}
@@ -833,9 +876,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector)
 			}
 		}
 		
-		mExtents[0].add(shift_vector);
-		mExtents[1].add(shift_vector);
-		mPositionGroup.add(shift_vector);
+		shift(shift_vector);
 	}
 	else if (mSpatialBridge)
 	{
@@ -843,9 +884,7 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector)
 	}
 	else if (isAvatar())
 	{
-		mExtents[0].add(shift_vector);
-		mExtents[1].add(shift_vector);
-		mPositionGroup.add(shift_vector);
+		shift(shift_vector);
 	}
 	
 	mVObjp->onShift(shift_vector);
@@ -857,40 +896,24 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
 	return mXform.getPositionW();
 }
 
-const LLVector4a* LLDrawable::getSpatialExtents() const
-{
-	return mExtents;
-}
-
-void LLDrawable::setSpatialExtents(const LLVector3& min, const LLVector3& max)
-{ 
-	mExtents[0].load3(min.mV); 
-	mExtents[1].load3(max.mV);
-}
-
-void LLDrawable::setSpatialExtents(const LLVector4a& min, const LLVector4a& max)
-{ 
-	mExtents[0] = min; 
-	mExtents[1] = max;
-}
-
-void LLDrawable::setPositionGroup(const LLVector4a& pos)
-{
-	mPositionGroup = pos;
-}
-
 void LLDrawable::updateSpatialExtents()
 {
 	if (mVObjp)
 	{
-		mVObjp->updateSpatialExtents(mExtents[0], mExtents[1]);
+		const LLVector4a* exts = getSpatialExtents();
+		LLVector4a extents[2];
+		extents[0] = exts[0];
+		extents[1] = exts[1];
+
+		mVObjp->updateSpatialExtents(extents[0], extents[1]);
+		setSpatialExtents(extents[0], extents[1]);
 	}
 	
 	updateBinRadius();
 	
 	if (mSpatialBridge.notNull())
 	{
-		mPositionGroup.splat(0.f);
+		getGroupPosition().splat(0.f);
 	}
 }
 
@@ -899,11 +922,11 @@ void LLDrawable::updateBinRadius()
 {
 	if (mVObjp.notNull())
 	{
-		mBinRadius = llmin(mVObjp->getBinRadius(), 256.f);
+		setBinRadius(llmin(mVObjp->getBinRadius(), 256.f));
 	}
 	else
 	{
-		mBinRadius = llmin(getRadius()*4.f, 256.f);
+		setBinRadius(llmin(getRadius()*4.f, 256.f));
 	}
 }
 
@@ -937,20 +960,48 @@ void LLDrawable::updateUVMinMax()
 {
 }
 
-LLSpatialGroup* LLDrawable::getSpatialGroup() const
-{ 
-	llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1);
-	return mSpatialGroupp; 
+//virtual
+bool LLDrawable::isVisible() const
+{
+	if (LLViewerOctreeEntryData::isVisible())
+	{
+		return true;
+	}
+	
+	{
+		LLviewerOctreeGroup* group = mEntry->getGroup();
+		if (group && group->isVisible())
+		{
+			LLViewerOctreeEntryData::setVisible();
+			return true;
+		}
+	}
+
+	return false;
 }
 
-void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
+//virtual
+bool LLDrawable::isRecentlyVisible() const
 {
-/*if (mSpatialGroupp && (groupp != mSpatialGroupp))
+	//currently visible or visible in the previous frame.
+	bool vis = LLViewerOctreeEntryData::isRecentlyVisible();
+
+	if(!vis)
 	{
-		mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY);
-	}*/
+		LLviewerOctreeGroup* group = getGroup();
+		if (group && group->isRecentlyVisible())
+		{
+			LLViewerOctreeEntryData::setVisible();
+			vis = TRUE ;
+		}
+	}
+
+	return vis ;
+}
 
-	if (mSpatialGroupp != groupp && getVOVolume())
+void LLDrawable::setGroup(LLviewerOctreeGroup *groupp)
+{
+	if (getGroup() != groupp && getVOVolume())
 	{ //NULL out vertex buffer references for volumes on spatial group change to maintain
 		//requirement that every face vertex buffer is either NULL or points to a vertex buffer
 		//contained by its drawable's spatial group
@@ -964,9 +1015,7 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
 		}
 	}
 
-	mSpatialGroupp = groupp;
-
-	llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1);
+	LLViewerOctreeEntryData::setGroup(groupp);
 }
 
 LLSpatialPartition* LLDrawable::getSpatialPartition()
@@ -985,11 +1034,11 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
 		{
 			if (mVObjp->isHUDAttachment())
 			{
-				setSpatialBridge(new LLHUDBridge(this));
+				setSpatialBridge(new LLHUDBridge(this, getRegion()));
 			}
 			else
 			{
-				setSpatialBridge(new LLVolumeBridge(this));
+				setSpatialBridge(new LLVolumeBridge(this, getRegion()));
 			}
 		}
 		return mSpatialBridge->asPartition();
@@ -1008,89 +1057,26 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
 	return retval;
 }
 
-const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one.
-//static 
-S32 LLDrawable::getMinVisFrameRange()
+//virtual
+S32 LLDrawable::getMinVisFrameRange() const
 {
-	return MIN_VIS_FRAME_RANGE ;
-}
-
-BOOL LLDrawable::isRecentlyVisible() const
-{
-	//currently visible or visible in the previous frame.
-	BOOL vis = isVisible() || (sCurVisible - mVisible < MIN_VIS_FRAME_RANGE)  ;
-
-	if(!vis)
-	{
-		LLSpatialGroup* group = getSpatialGroup();
-		if (group && group->isRecentlyVisible())
-		{
-			mVisible = sCurVisible;
-			vis = TRUE ;
-		}
-	}
-
-	return vis ;
-}
-
-BOOL LLDrawable::isVisible() const
-{
-	if (mVisible == sCurVisible)
-	{
-		return TRUE;
-	}
-	
-#if 0
-	//disabling this code fixes DEV-20105.  Leaving in place in case some other bug pops up as a a result.
-	//should be safe to just always ask the spatial group for visibility.
-	if (isActive())
-	{
-		if (isRoot())
-		{
-			LLSpatialGroup* group = mSpatialBridge.notNull() ? mSpatialBridge->getSpatialGroup() :
-									getSpatialGroup();
-			if (group && group->isVisible())
-			{
-				mVisible = sCurVisible;
-				return TRUE;
-			}
-		}
-		else
-		{
-			if (getParent()->isVisible())
-			{
-				mVisible = sCurVisible;
-				return TRUE;
-			}
-		}
-	}
-	else
-#endif
-	{
-		LLSpatialGroup* group = getSpatialGroup();
-		if (group && group->isVisible())
-		{
-			mVisible = sCurVisible;
-			return TRUE;
-		}
-	}
+	const S32 MIN_VIS_FRAME_RANGE = 2 ; //two frames:the current one and the last one.
 
-	return FALSE;
+	return MIN_VIS_FRAME_RANGE ;
 }
 
 //=======================================
 // Spatial Partition Bridging Drawable
 //=======================================
 
-LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask)
-: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB)
+LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask, LLViewerRegion* regionp) : 
+	LLDrawable(root->getVObj(), true),
+	LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB, regionp)
 {
 	mBridge = this;
 	mDrawable = root;
 	root->setSpatialBridge(this);
 	
-	mBinIndex = -1;
-
 	mRenderType = mDrawable->mRenderType;
 	mDrawableType = mDrawable->mRenderType;
 	
@@ -1111,10 +1097,13 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat
 
 LLSpatialBridge::~LLSpatialBridge()
 {	
-	LLSpatialGroup* group = getSpatialGroup();
-	if (group)
+	if(mEntry)
 	{
-		group->mSpatialPartition->remove(this, group);
+		LLSpatialGroup* group = getSpatialGroup();
+		if (group)
+		{
+			group->mSpatialPartition->remove(this, group);
+		}
 	}
 
 	//delete octree here so listeners will still be able to access bridge specific state
@@ -1136,8 +1125,9 @@ void LLSpatialBridge::updateSpatialExtents()
 		root->rebound();
 	}
 	
+	const LLVector4a* root_bounds = root->getBounds();
 	LLVector4a offset;
-	LLVector4a size = root->mBounds[1];
+	LLVector4a size = root_bounds[1];
 		
 	//VECTORIZE THIS
 	LLMatrix4a mat;
@@ -1149,7 +1139,7 @@ void LLSpatialBridge::updateSpatialExtents()
 	LLVector4a center;
 	mat.affineTransform(t, center);
 	
-	mat.rotate(root->mBounds[0], offset);
+	mat.rotate(root_bounds[0], offset);
 	center.add(offset);
 	
 	LLVector4a v[4];
@@ -1171,12 +1161,9 @@ void LLSpatialBridge::updateSpatialExtents()
 	scale.mul(size);
 	mat.rotate(scale, v[3]);
 
-	
-	LLVector4a& newMin = mExtents[0];
-	LLVector4a& newMax = mExtents[1];
-	
-	newMin = newMax = center;
-	
+	LLVector4a newMin;
+	LLVector4a newMax;	
+	newMin = newMax = center;	
 	for (U32 i = 0; i < 4; i++)
 	{
 		LLVector4a delta;
@@ -1189,19 +1176,21 @@ void LLSpatialBridge::updateSpatialExtents()
 		newMin.setMin(newMin, min);
 		newMax.setMax(newMax, max);
 	}
-	
+	setSpatialExtents(newMin, newMax);
+
 	LLVector4a diagonal;
 	diagonal.setSub(newMax, newMin);
 	mRadius = diagonal.getLength3().getF32() * 0.5f;
 	
-	mPositionGroup.setAdd(newMin,newMax);
-	mPositionGroup.mul(0.5f);
+	LLVector4a& pos = getGroupPosition();
+	pos.setAdd(newMin,newMax);
+	pos.mul(0.5f);
 	updateBinRadius();
 }
 
 void LLSpatialBridge::updateBinRadius()
 {
-	mBinRadius = llmin( mOctree->getSize()[0]*0.5f, 256.f);
+	setBinRadius(llmin( mOctree->getSize()[0]*0.5f, 256.f));
 }
 
 LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
@@ -1236,7 +1225,7 @@ LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
 
 void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select)
 {
-	mVisible = sCurVisible;
+	LLViewerOctreeEntryData::setVisible();
 	
 #if 0 && !LL_RELEASE_FOR_DOWNLOAD
 	//crazy paranoid rules checking
@@ -1271,21 +1260,21 @@ void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results,
 #endif
 }
 
-class LLOctreeMarkNotCulled: public LLOctreeTraveler<LLDrawable>
+class LLOctreeMarkNotCulled: public OctreeTraveler
 {
 public:
 	LLCamera* mCamera;
 	
 	LLOctreeMarkNotCulled(LLCamera* camera_in) : mCamera(camera_in) { }
 	
-	virtual void traverse(const LLOctreeNode<LLDrawable>* node)
+	virtual void traverse(const OctreeNode* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 		group->setVisible();
-		LLOctreeTraveler<LLDrawable>::traverse(node);
+		OctreeTraveler::traverse(node);
 	}
 	
-	void visit(const LLOctreeNode<LLDrawable>* branch)
+	void visit(const OctreeNode* branch)
 	{
 		gPipeline.markNotCulled((LLSpatialGroup*) branch->getListener(0), *mCamera);
 	}
@@ -1329,7 +1318,7 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 			}
 
 			if (!group ||
-				LLDrawable::getCurrentFrame() - av->mVisible > 1 ||
+				LLDrawable::getCurrentFrame() - av->getVisible() > 1 ||
 				impostor ||
 				!loaded)
 			{
@@ -1343,16 +1332,17 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 	group->rebound();
 	
 	LLVector4a center;
-	center.setAdd(mExtents[0], mExtents[1]);
+	const LLVector4a* exts = getSpatialExtents();
+	center.setAdd(exts[0], exts[1]);
 	center.mul(0.5f);
 	LLVector4a size;
-	size.setSub(mExtents[1], mExtents[0]);
+	size.setSub(exts[1], exts[0]);
 	size.mul(0.5f);
 
 	if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
 		LLPipeline::sImpostorRender ||
 		(camera_in.AABBInFrustumNoFarClip(center, size) && 
-		AABBSphereIntersect(mExtents[0], mExtents[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))
+		AABBSphereIntersect(exts[0], exts[1], camera_in.getOrigin(), camera_in.mFrustumCornerDist)))
 	{
 		if (!LLPipeline::sImpostorRender &&
 			!LLPipeline::sShadowRender && 
@@ -1467,22 +1457,28 @@ BOOL LLSpatialBridge::updateMove()
 
 void LLSpatialBridge::shiftPos(const LLVector4a& vec)
 {
-	mExtents[0].add(vec);
-	mExtents[1].add(vec);
-	mPositionGroup.add(vec);
+	LLDrawable::shift(vec);
 }
 
 void LLSpatialBridge::cleanupReferences()
 {	
+	LLPointer<LLVOCacheEntry> dummy_entry;
+	if (mDrawable && mDrawable->isDead() && mDrawable->getEntry()->hasVOCacheEntry())
+	{
+		//create a dummy entry to insert the entire LLSpatialBridge to the vo_cache partition so it can be reloaded.
+
+		dummy_entry = new LLVOCacheEntry();
+		dummy_entry->setOctreeEntry(mEntry);
+		dummy_entry->addChild((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry());
+		llassert(!mDrawable->getParent());
+		
+		mDrawable->mParent = this;
+	}
+
 	LLDrawable::cleanupReferences();
 	if (mDrawable)
 	{
-		LLSpatialGroup* group = mDrawable->getSpatialGroup();
-		if (group)
-		{
-			group->mOctreeNode->remove(mDrawable);
-			mDrawable->setSpatialGroup(NULL);
-		}
+		mDrawable->setGroup(NULL);
 		
 		if (mDrawable->getVObj())
 		{
@@ -1494,12 +1490,7 @@ void LLSpatialBridge::cleanupReferences()
 				LLDrawable* drawable = child->mDrawable;					
 				if (drawable)
 				{
-					LLSpatialGroup* group = drawable->getSpatialGroup();
-					if (group)
-					{
-						group->mOctreeNode->remove(drawable);
-						drawable->setSpatialGroup(NULL);
-					}
+					drawable->setGroup(NULL);				
 				}
 			}
 		}
@@ -1571,8 +1562,8 @@ void LLDrawable::updateFaceSize(S32 idx)
 	}
 }
 
-LLBridgePartition::LLBridgePartition()
-: LLSpatialPartition(0, FALSE, 0) 
+LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp)
+: LLSpatialPartition(0, FALSE, 0, regionp) 
 { 
 	mDrawableType = LLPipeline::RENDER_TYPE_AVATAR; 
 	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
@@ -1580,8 +1571,8 @@ LLBridgePartition::LLBridgePartition()
 	mSlopRatio = 0.25f;
 }
 
-LLHUDBridge::LLHUDBridge(LLDrawable* drawablep)
-: LLVolumeBridge(drawablep)
+LLHUDBridge::LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp)
+: LLVolumeBridge(drawablep, regionp)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_HUD;
 	mPartitionType = LLViewerRegion::PARTITION_HUD;
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 4608d16fec..8e193a02bd 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -42,6 +42,7 @@
 #include "llviewerobject.h"
 #include "llrect.h"
 #include "llappviewer.h" // for gFrameTimeSeconds
+#include "llvieweroctree.h"
 
 class LLCamera;
 class LLDrawPool;
@@ -59,10 +60,10 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;
 
 // All data for new renderer goes into this class.
 LL_ALIGN_PREFIX(16)
-class LLDrawable : public LLRefCount
+class LLDrawable : public LLViewerOctreeEntryData
 {
 public:
-	LLDrawable(const LLDrawable& rhs)
+	LLDrawable(const LLDrawable& rhs) : LLViewerOctreeEntryData(rhs)
 	{
 		*this = rhs;
 	}
@@ -85,19 +86,17 @@ public:
 		ll_aligned_free_16(ptr);
 	}
 
-	LLDrawable()				{ init(); }
+	LLDrawable(LLViewerObject *vobj, bool new_entry = false);
 	
 	void markDead();			// Mark this drawable as dead
 	BOOL isDead() const			{ return isState(DEAD); }
 	BOOL isNew() const			{ return !isState(BUILT); }
 
 	BOOL isLight() const;
-
-	BOOL isVisible() const;	
-	BOOL isRecentlyVisible() const;	
+	
 	virtual void setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results = NULL, BOOL for_select = FALSE);
 
-
+	LLSpatialGroup* getSpatialGroup()const          {return (LLSpatialGroup*)getGroup();}
 	LLViewerRegion* getRegion()               const { return mVObjp->getRegion(); }
 	const LLTextureEntry* getTextureEntry(U8 which) const { return mVObjp->getTE(which); }
 	LLPointer<LLViewerObject>& getVObj()							  { return mVObjp; }
@@ -110,17 +109,13 @@ public:
 	const LLVector3&	  getPosition() const			{ return mXform.getPosition(); }
 	const LLVector3&      getWorldPosition() const		{ return mXform.getPositionW(); }
 	const LLVector3		  getPositionAgent() const;
-	const LLVector4a&	  getPositionGroup() const		{ return mPositionGroup; }
 	const LLVector3&	  getScale() const				{ return mCurrentScale; }
 	void				  setScale(const LLVector3& scale) { mCurrentScale = scale; }
 	const LLQuaternion&   getWorldRotation() const		{ return mXform.getWorldRotation(); }
 	const LLQuaternion&   getRotation() const			{ return mXform.getRotation(); }
 	F32			          getIntensity() const			{ return llmin(mXform.getScale().mV[0], 4.f); }
 	S32					  getLOD() const				{ return mVObjp ? mVObjp->getLOD() : 1; }
-	F32					  getBinRadius() const			{ return mBinRadius; }
-	S32					  getBinIndex() const			{ return mBinIndex; }
-	void				  setBinIndex(S32 index) const	{ mBinIndex = index; }
-
+	
 	void  getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); }
 	LLXformMatrix*		getXform() { return &mXform; }
 
@@ -150,7 +145,7 @@ public:
 	void                setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep);
 	void				mergeFaces(LLDrawable* src);
 
-	void init();
+	void init(bool new_entry);
 	void destroy();
 
 	void update();
@@ -181,8 +176,12 @@ public:
 	BOOL getLit() const							{ return isState(UNLIT) ? FALSE : TRUE; }
 	void setLit(BOOL lit)						{ lit ? clearState(UNLIT) : setState(UNLIT); }
 
+	bool isVisible() const;
+	bool isRecentlyVisible() const;
+
 	virtual void cleanupReferences();
 
+	void setGroup(LLviewerOctreeGroup* group);
 	void setRadius(const F32 radius);
 	F32 getRadius() const						{ return mRadius; }
 	F32 getVisibilityRadius() const;
@@ -192,11 +191,6 @@ public:
 	const LLVector3& getBounds(LLVector3& min, LLVector3& max) const;
 	virtual void updateSpatialExtents();
 	virtual void updateBinRadius();
-	const LLVector4a* getSpatialExtents() const;
-	void setSpatialExtents(const LLVector3& min, const LLVector3& max);
-	void setSpatialExtents(const LLVector4a& min, const LLVector4a& max);
-
-	void setPositionGroup(const LLVector4a& pos);
 	
 	void setRenderType(S32 type) 				{ mRenderType = type; }
 	BOOL isRenderType(S32 type) 				{ return mRenderType == type; }
@@ -205,10 +199,14 @@ public:
 	// Debugging methods
 	S32 findReferences(LLDrawable *drawablep); // Not const because of @#$! iterators...
 
-	void setSpatialGroup(LLSpatialGroup *groupp);
-	LLSpatialGroup *getSpatialGroup() const;
 	LLSpatialPartition* getSpatialPartition();
 	
+	virtual S32 getMinVisFrameRange()const;
+	void removeFromOctree();
+
+	void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; }
+	LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; }
+
 	// Statics
 	static void incrementVisible();
 	static void cleanupDeadDrawables();
@@ -292,10 +290,6 @@ public:
 		ANIMATED_CHILD  = 0x20000000,
 		ACTIVE_CHILD	= 0x40000000,
 	} EDrawableFlags;
-
-private: //aligned members
-	LL_ALIGN_16(LLVector4a		mExtents[2]);
-	LL_ALIGN_16(LLVector4a		mPositionGroup);
 	
 public:
 	LLXformMatrix       mXform;
@@ -303,35 +297,23 @@ public:
 	// vis data
 	LLPointer<LLDrawable> mParent;
 
-	F32				mDistanceWRTCamera;
-
-	static S32 getCurrentFrame() { return sCurVisible; }
-	static S32 getMinVisFrameRange();
-
-	void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; }
-	LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; }
+	F32				mDistanceWRTCamera;	
 	
 	static F32 sCurPixelAngle; //current pixels per radian
 
 private:
 	typedef std::vector<LLFace*> face_list_t;
 	
-	U32				mState;
+	U32             mState;
 	S32				mRenderType;
 	LLPointer<LLViewerObject> mVObjp;
 	face_list_t     mFaces;
-	LLSpatialGroup* mSpatialGroupp;
 	LLPointer<LLDrawable> mSpatialBridge;
-	
-	mutable U32		mVisible;
+		
 	F32				mRadius;
-	F32				mBinRadius;
-	mutable S32		mBinIndex;
 	S32				mGeneration;
 	
-	LLVector3		mCurrentScale;
-	
-	static U32 sCurVisible; // Counter for what value of mVisible means currently visible
+	LLVector3		mCurrentScale;	
 
 	static U32 sNumZombieDrawables;
 	static LLDynamicArrayPtr<LLPointer<LLDrawable> > sDeadList;
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 5083478392..debb790c58 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -138,94 +138,6 @@ void sg_assert(BOOL expr)
 #endif
 }
 
-S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
-{
-	return AABBSphereIntersectR2(min, max, origin, rad*rad);
-}
-
-S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r)
-{
-	F32 d = 0.f;
-	F32 t;
-	
-	if ((min-origin).magVecSquared() < r &&
-		(max-origin).magVecSquared() < r)
-	{
-		return 2;
-	}
-
-	for (U32 i = 0; i < 3; i++)
-	{
-		if (origin.mV[i] < min.mV[i])
-		{
-			t = min.mV[i] - origin.mV[i];
-			d += t*t;
-		}
-		else if (origin.mV[i] > max.mV[i])
-		{
-			t = origin.mV[i] - max.mV[i];
-			d += t*t;
-		}
-
-		if (d > r)
-		{
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-
-S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
-{
-	return AABBSphereIntersectR2(min, max, origin, rad*rad);
-}
-
-S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
-{
-	F32 d = 0.f;
-	F32 t;
-	
-	LLVector4a origina;
-	origina.load3(origin.mV);
-
-	LLVector4a v;
-	v.setSub(min, origina);
-	
-	if (v.dot3(v) < r)
-	{
-		v.setSub(max, origina);
-		if (v.dot3(v) < r)
-		{
-			return 2;
-		}
-	}
-
-
-	for (U32 i = 0; i < 3; i++)
-	{
-		if (origin.mV[i] < min[i])
-		{
-			t = min[i] - origin.mV[i];
-			d += t*t;
-		}
-		else if (origin.mV[i] > max[i])
-		{
-			t = origin.mV[i] - max[i];
-			d += t*t;
-		}
-
-		if (d > r)
-		{
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-
 typedef enum
 {
 	b000 = 0x00,
@@ -352,13 +264,17 @@ LLSpatialGroup::~LLSpatialGroup()
 	{
 		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
 	}*/
+	if(isVisible())
+	{
+		mSpatialPartition->mRegionp->clearVisibleGroup(this);
+	}
 
 	if (gDebugGL)
 	{
 		gPipeline.checkReferences(this);
 	}
 
-	if (isState(DEAD))
+	if (hasState(DEAD))
 	{
 		sZombieGroups--;
 	}
@@ -514,7 +430,8 @@ BOOL LLSpatialGroup::isHUDGroup()
 
 BOOL LLSpatialGroup::isRecentlyVisible() const
 {
-	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ;
+	const S32 MIN_VIS_FRAME_RANGE = 2;
+	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < MIN_VIS_FRAME_RANGE ;
 }
 
 BOOL LLSpatialGroup::isVisible() const
@@ -619,7 +536,7 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 	OctreeNode* parent = mOctreeNode->getOctParent();
 	
 	if (mOctreeNode->isInside(drawablep->getPositionGroup()) && 
-		(mOctreeNode->contains(drawablep) ||
+		(mOctreeNode->contains(drawablep->getEntry()) ||
 		 (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
 				parent && parent->getElementCount() >= gOctreeMaxCapacity)))
 	{
@@ -633,15 +550,14 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 }
 
 
-BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_octree)
+BOOL LLSpatialGroup::addObject(LLDrawable *drawablep)
 {
-	if (!from_octree)
+	if(!drawablep)
 	{
-		mOctreeNode->insert(drawablep);
+		return FALSE;
 	}
-	else
 	{
-		drawablep->setSpatialGroup(this);
+		drawablep->setGroup(this);
 		setState(OBJECT_DIRTY | GEOM_DIRTY);
 		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
 		gPipeline.markRebuild(this, TRUE);
@@ -664,7 +580,7 @@ void LLSpatialGroup::rebuildGeom()
 	{
 		mSpatialPartition->rebuildGeom(this);
 
-		if (isState(LLSpatialGroup::MESH_DIRTY))
+		if (hasState(LLSpatialGroup::MESH_DIRTY))
 		{
 			gPipeline.markMeshDirty(this);
 		}
@@ -686,7 +602,7 @@ static LLFastTimer::DeclareTimer FTM_GET_GEOMETRY("Get Geometry");
 
 void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 {
-	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY))
+	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
 		return;
 	}
@@ -751,103 +667,6 @@ void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
 
 }
 
-BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
-{	
-	const OctreeNode* node = mOctreeNode;
-
-	if (node->isEmpty())
-	{	//don't do anything if there are no objects
-		if (empty && mOctreeNode->getParent())
-		{	//only root is allowed to be empty
-			OCT_ERRS << "Empty leaf found in octree." << llendl;
-		}
-		return FALSE;
-	}
-
-	LLVector4a& newMin = mObjectExtents[0];
-	LLVector4a& newMax = mObjectExtents[1];
-	
-	if (isState(OBJECT_DIRTY))
-	{ //calculate new bounding box
-		clearState(OBJECT_DIRTY);
-
-		//initialize bounding box to first element
-		OctreeNode::const_element_iter i = node->getDataBegin();
-		LLDrawable* drawablep = *i;
-		const LLVector4a* minMax = drawablep->getSpatialExtents();
-
-		newMin = minMax[0];
-		newMax = minMax[1];
-
-		for (++i; i != node->getDataEnd(); ++i)
-		{
-			drawablep = *i;
-			minMax = drawablep->getSpatialExtents();
-			
-			update_min_max(newMin, newMax, minMax[0]);
-			update_min_max(newMin, newMax, minMax[1]);
-
-			//bin up the object
-			/*for (U32 i = 0; i < 3; i++)
-			{
-				if (minMax[0].mV[i] < newMin.mV[i])
-				{
-					newMin.mV[i] = minMax[0].mV[i];
-				}
-				if (minMax[1].mV[i] > newMax.mV[i])
-				{
-					newMax.mV[i] = minMax[1].mV[i];
-				}
-			}*/
-		}
-		
-		mObjectBounds[0].setAdd(newMin, newMax);
-		mObjectBounds[0].mul(0.5f);
-		mObjectBounds[1].setSub(newMax, newMin);
-		mObjectBounds[1].mul(0.5f);
-	}
-	
-	if (empty)
-	{
-		minOut = newMin;
-		maxOut = newMax;
-	}
-	else
-	{
-		minOut.setMin(minOut, newMin);
-		maxOut.setMax(maxOut, newMax);
-	}
-		
-	return TRUE;
-}
-
-void LLSpatialGroup::unbound()
-{
-	if (isState(DIRTY))
-	{
-		return;
-	}
-
-	setState(DIRTY);
-	
-	//all the parent nodes need to rebound this child
-	if (mOctreeNode)
-	{
-		OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent();
-		while (parent != NULL)
-		{
-			LLSpatialGroup* group = (LLSpatialGroup*) parent->getListener(0);
-			if (group->isState(DIRTY))
-			{
-				return;
-			}
-			
-			group->setState(DIRTY);
-			parent = (OctreeNode*) parent->getParent();
-		}
-	}
-}
-
 LLSpatialGroup* LLSpatialGroup::getParent()
 {
 	if (isDead())
@@ -871,17 +690,19 @@ LLSpatialGroup* LLSpatialGroup::getParent()
 
 BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 {
+	if(!drawablep)
+	{
+		return FALSE;
+	}
+
 	unbound();
 	if (mOctreeNode && !from_octree)
 	{
-		if (!mOctreeNode->remove(drawablep))
-		{
-			OCT_ERRS << "Could not remove drawable from spatial group" << llendl;
-		}
+		drawablep->setGroup(NULL);
 	}
 	else
 	{
-		drawablep->setSpatialGroup(NULL);
+		drawablep->setGroup(NULL);
 		setState(GEOM_DIRTY);
 		gPipeline.markRebuild(this, TRUE);
 
@@ -928,12 +749,12 @@ void LLSpatialGroup::shift(const LLVector4a &offset)
 	}
 }
 
-class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
+class LLSpatialSetState : public OctreeTraveler
 {
 public:
 	U32 mState;
 	LLSpatialSetState(U32 state) : mState(state) { }
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	
+	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setState(mState); }	
 };
 
 class LLSpatialSetStateDiff : public LLSpatialSetState
@@ -941,24 +762,17 @@ class LLSpatialSetStateDiff : public LLSpatialSetState
 public:
 	LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { }
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	virtual void traverse(const OctreeNode* n)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 		
-		if (!group->isState(mState))
+		if (!group->hasState(mState))
 		{
-			LLSpatialGroup::OctreeTraveler::traverse(n);
+			OctreeTraveler::traverse(n);
 		}
 	}
 };
 
-void LLSpatialGroup::setState(U32 state) 
-{ 
-	mState |= state; 
-	
-	llassert(state <= LLSpatialGroup::STATE_MASK);
-}	
-
 void LLSpatialGroup::setState(U32 state, S32 mode) 
 {
 	llassert(state <= LLSpatialGroup::STATE_MASK);
@@ -982,12 +796,12 @@ void LLSpatialGroup::setState(U32 state, S32 mode)
 	}
 }
 
-class LLSpatialClearState : public LLSpatialGroup::OctreeTraveler
+class LLSpatialClearState : public OctreeTraveler
 {
 public:
 	U32 mState;
 	LLSpatialClearState(U32 state) : mState(state) { }
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
+	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearState(mState); }
 };
 
 class LLSpatialClearStateDiff : public LLSpatialClearState
@@ -995,24 +809,17 @@ class LLSpatialClearStateDiff : public LLSpatialClearState
 public:
 	LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { }
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	virtual void traverse(const OctreeNode* n)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 		
-		if (group->isState(mState))
+		if (group->hasState(mState))
 		{
-			LLSpatialGroup::OctreeTraveler::traverse(n);
+			OctreeTraveler::traverse(n);
 		}
 	}
 };
 
-void LLSpatialGroup::clearState(U32 state)
-{
-	llassert(state <= LLSpatialGroup::STATE_MASK);
-
-	mState &= ~state; 
-}
-
 void LLSpatialGroup::clearState(U32 state, S32 mode)
 {
 	llassert(state <= LLSpatialGroup::STATE_MASK);
@@ -1036,22 +843,15 @@ void LLSpatialGroup::clearState(U32 state, S32 mode)
 	}
 }
 
-BOOL LLSpatialGroup::isState(U32 state) const
-{ 
-	llassert(state <= LLSpatialGroup::STATE_MASK);
-
-	return mState & state ? TRUE : FALSE; 
-}
-
 //=====================================
 //		Occlusion State Set/Clear
 //=====================================
-class LLSpatialSetOcclusionState : public LLSpatialGroup::OctreeTraveler
+class LLSpatialSetOcclusionState : public OctreeTraveler
 {
 public:
 	U32 mState;
 	LLSpatialSetOcclusionState(U32 state) : mState(state) { }
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }	
+	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->setOcclusionState(mState); }	
 };
 
 class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
@@ -1059,13 +859,13 @@ class LLSpatialSetOcclusionStateDiff : public LLSpatialSetOcclusionState
 public:
 	LLSpatialSetOcclusionStateDiff(U32 state) : LLSpatialSetOcclusionState(state) { }
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	virtual void traverse(const OctreeNode* n)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 		
 		if (!group->isOcclusionState(mState))
 		{
-			LLSpatialGroup::OctreeTraveler::traverse(n);
+			OctreeTraveler::traverse(n);
 		}
 	}
 };
@@ -1110,13 +910,13 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
 	}
 }
 
-class LLSpatialClearOcclusionState : public LLSpatialGroup::OctreeTraveler
+class LLSpatialClearOcclusionState : public OctreeTraveler
 {
 public:
 	U32 mState;
 	
 	LLSpatialClearOcclusionState(U32 state) : mState(state) { }
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
+	virtual void visit(const OctreeNode* branch) { ((LLSpatialGroup*) branch->getListener(0))->clearOcclusionState(mState); }
 };
 
 class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
@@ -1124,13 +924,13 @@ class LLSpatialClearOcclusionStateDiff : public LLSpatialClearOcclusionState
 public:
 	LLSpatialClearOcclusionStateDiff(U32 state) : LLSpatialClearOcclusionState(state) { }
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	virtual void traverse(const OctreeNode* n)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 		
 		if (group->isOcclusionState(mState))
 		{
-			LLSpatialGroup::OctreeTraveler::traverse(n);
+			OctreeTraveler::traverse(n);
 		}
 	}
 };
@@ -1166,13 +966,11 @@ void LLSpatialGroup::clearOcclusionState(U32 state, S32 mode)
 //		Octree Listener Implementation
 //======================================
 
-LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
+LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLviewerOctreeGroup(node),
 	mObjectBoxSize(1.f),
-	mState(0),
 	mGeometryBytes(0),
 	mSurfaceArea(0.f),
 	mBuilt(0.f),
-	mOctreeNode(node),
 	mSpatialPartition(part),
 	mVertexBuffer(NULL), 
 	mBufferUsage(part->mBufferUsage),
@@ -1191,17 +989,11 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 
 	mViewAngle.splat(0.f);
 	mLastUpdateViewAngle.splat(-1.f);
-	mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = 
-		mObjectExtents[0] = mObjectExtents[1] = mViewAngle;
-
+	
 	sg_assert(mOctreeNode->getListenerCount() == 0);
-	mOctreeNode->addListener(this);
 	setState(SG_INITIAL_STATE_MASK);
 	gPipeline.markRebuild(this, TRUE);
 
-	mBounds[0] = node->getCenter();
-	mBounds[1] = node->getSize();
-
 	part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
 	mLODHash = part->mLODSeed;
 
@@ -1235,7 +1027,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 	}
 
 #if !LL_RELEASE_FOR_DOWNLOAD
-	if (isState(LLSpatialGroup::OBJECT_DIRTY))
+	if (hasState(LLSpatialGroup::OBJECT_DIRTY))
 	{
 		llerrs << "Spatial group dirty on distance update." << llendl;
 	}
@@ -1266,7 +1058,7 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 		dist = eye.getLength3().getF32();
 		eye.normalize3fast();
 
-		if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
+		if (!group->hasState(LLSpatialGroup::ALPHA_DIRTY))
 		{
 			if (!group->mSpatialPartition->isBridge())
 			{
@@ -1343,7 +1135,7 @@ BOOL LLSpatialGroup::needsUpdate()
 
 BOOL LLSpatialGroup::changeLOD()
 {
-	if (isState(ALPHA_DIRTY | OBJECT_DIRTY))
+	if (hasState(ALPHA_DIRTY | OBJECT_DIRTY))
 	{ ///a rebuild is going to happen, update distance and LoD
 		return TRUE;
 	}
@@ -1371,29 +1163,51 @@ BOOL LLSpatialGroup::changeLOD()
 	return FALSE;
 }
 
-void LLSpatialGroup::handleInsertion(const TreeNode* node, LLDrawable* drawablep)
+void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry)
 {
-	addObject(drawablep, FALSE, TRUE);
+	if(mSpatialPartition->isVOCachePartition())
+	{
+		LLviewerOctreeGroup::handleInsertion(node, entry);
+		return;
+	}
+		
+	addObject((LLDrawable*)entry->getDrawable());
 	unbound();
 	setState(OBJECT_DIRTY);
 }
 
-void LLSpatialGroup::handleRemoval(const TreeNode* node, LLDrawable* drawable)
+void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry)
 {
-	removeObject(drawable, TRUE);
-	setState(OBJECT_DIRTY);
+	if(!mSpatialPartition->isVOCachePartition())
+	{
+		removeObject((LLDrawable*)entry->getDrawable(), TRUE);
+	}
+	LLviewerOctreeGroup::handleRemoval(node, entry);
 }
 
 void LLSpatialGroup::handleDestruction(const TreeNode* node)
 {
 	setState(DEAD);
-	
+
+	if(mSpatialPartition->isVOCachePartition())
+	{
+		LLviewerOctreeGroup::handleDestruction(node);
+		return;
+	}
+
 	for (element_iter i = getDataBegin(); i != getDataEnd(); ++i)
 	{
-		LLDrawable* drawable = *i;
-		if (drawable->getSpatialGroup() == this)
+		LLViewerOctreeEntry* entry = *i;
+		if (entry->getGroup() == this)
 		{
-			drawable->setSpatialGroup(NULL);
+			if(entry->hasDrawable())
+			{
+				((LLDrawable*)entry->getDrawable())->setGroup(NULL);
+			}
+			else
+			{
+				llerrs << "No Drawable found in the entry." << llendl;
+			}
 		}
 	}
 	
@@ -1415,16 +1229,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 	mOctreeNode = NULL;
 }
 
-void LLSpatialGroup::handleStateChange(const TreeNode* node)
-{
-	//drop bounding box upon state change
-	if (mOctreeNode != node)
-	{
-		mOctreeNode = (OctreeNode*) node;
-	}
-	unbound();
-}
-
 void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) 
 {
 	if (child->getListenerCount() == 0)
@@ -1441,11 +1245,6 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
 	assert_states_valid(this);
 }
 
-void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
-{
-	unbound();
-}
-
 void LLSpatialGroup::destroyGL(bool keep_occlusion) 
 {
 	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
@@ -1476,7 +1275,11 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)
 
 	for (LLSpatialGroup::element_iter i = getDataBegin(); i != getDataEnd(); ++i)
 	{
-		LLDrawable* drawable = *i;
+		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+		if(!drawable)
+		{
+			continue;
+		}
 		for (S32 j = 0; j < drawable->getNumFaces(); j++)
 		{
 			LLFace* facep = drawable->getFace(j);
@@ -1488,69 +1291,6 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)
 	}
 }
 
-BOOL LLSpatialGroup::rebound()
-{
-	if (!isState(DIRTY))
-	{	//return TRUE if we're not empty
-		return TRUE;
-	}
-	
-	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
-		group->rebound();
-		
-		//copy single child's bounding box
-		mBounds[0] = group->mBounds[0];
-		mBounds[1] = group->mBounds[1];
-		mExtents[0] = group->mExtents[0];
-		mExtents[1] = group->mExtents[1];
-		
-		group->setState(SKIP_FRUSTUM_CHECK);
-	}
-	else if (mOctreeNode->isLeaf())
-	{ //copy object bounding box if this is a leaf
-		boundObjects(TRUE, mExtents[0], mExtents[1]);
-		mBounds[0] = mObjectBounds[0];
-		mBounds[1] = mObjectBounds[1];
-	}
-	else
-	{
-		LLVector4a& newMin = mExtents[0];
-		LLVector4a& newMax = mExtents[1];
-		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
-		group->clearState(SKIP_FRUSTUM_CHECK);
-		group->rebound();
-		//initialize to first child
-		newMin = group->mExtents[0];
-		newMax = group->mExtents[1];
-
-		//first, rebound children
-		for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
-		{
-			group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
-			group->clearState(SKIP_FRUSTUM_CHECK);
-			group->rebound();
-			const LLVector4a& max = group->mExtents[1];
-			const LLVector4a& min = group->mExtents[0];
-
-			newMax.setMax(newMax, max);
-			newMin.setMin(newMin, min);
-		}
-
-		boundObjects(FALSE, newMin, newMax);
-		
-		mBounds[0].setAdd(newMin, newMax);
-		mBounds[0].mul(0.5f);
-		mBounds[1].setSub(newMax, newMin);
-		mBounds[1].mul(0.5f);
-	}
-	
-	clearState(DIRTY);
-
-	return TRUE;
-}
-
 static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");
 static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait");
 
@@ -1769,8 +1509,8 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 
 //==============================================
 
-LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
-: mRenderByGroup(render_by_group), mBridge(NULL)
+LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage, LLViewerRegion* regionp)
+: mRenderByGroup(render_by_group), mBridge(NULL), mRegionp(regionp)
 {
 	mOcclusionEnabled = TRUE;
 	mDrawableType = 0;
@@ -1782,13 +1522,13 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32
 	mDepthMask = FALSE;
 	mSlopRatio = 0.25f;
 	mInfiniteFarClip = FALSE;
+	mVisitedTime = 0;
 
 	LLVector4a center, size;
 	center.splat(0.f);
 	size.splat(1.f);
 
-	mOctree = new LLSpatialGroup::OctreeRoot(center,size,
-											NULL);
+	mOctree = new OctreeRoot(center,size, NULL);
 	new LLSpatialGroup(mOctree, this);
 }
 
@@ -1799,6 +1539,10 @@ LLSpatialPartition::~LLSpatialPartition()
 	mOctree = NULL;
 }
 
+BOOL LLSpatialPartition::isVOCachePartition() const
+{
+	return mPartitionType == LLViewerRegion::PARTITION_VO_CACHE;
+}
 
 LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 {
@@ -1806,12 +1550,16 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 
 	//keep drawable from being garbage collected
 	LLPointer<LLDrawable> ptr = drawablep;
-		
-	assert_octree_valid(mOctree);
-	mOctree->insert(drawablep);
-	assert_octree_valid(mOctree);
+			
+	if(!drawablep->getGroup())
+	{
+		assert_octree_valid(mOctree);
+		mOctree->insert(drawablep->getEntry());
+		assert_octree_valid(mOctree);
+	}	
 	
 	LLSpatialGroup* group = drawablep->getSpatialGroup();
+	llassert(group != NULL);
 
 	if (group && was_visible && group->isOcclusionState(LLSpatialGroup::QUERY_PENDING))
 	{
@@ -1829,7 +1577,7 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 	}
 	else
 	{
-		drawablep->setSpatialGroup(NULL);
+		drawablep->setGroup(NULL);
 	}
 
 	assert_octree_valid(mOctree);
@@ -1881,13 +1629,13 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL
 	put(drawablep, was_visible);
 }
 
-class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
+class LLSpatialShift : public OctreeTraveler
 {
 public:
 	const LLVector4a& mOffset;
 
 	LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
+	virtual void visit(const OctreeNode* branch) 
 	{ 
 		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); 
 	}
@@ -1899,17 +1647,17 @@ void LLSpatialPartition::shift(const LLVector4a &offset)
 	shifter.traverse(mOctree);
 }
 
-class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
+class LLOctreeCull : public LLViewerOctreeCull
 {
 public:
-	LLOctreeCull(LLCamera* camera)
-		: mCamera(camera), mRes(0) { }
+	LLOctreeCull(LLCamera* camera) : LLViewerOctreeCull(camera) {}
 
-	virtual bool earlyFail(LLSpatialGroup* group)
+	virtual bool earlyFail(LLviewerOctreeGroup* base_group)
 	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
 		group->checkOcclusion();
 
-		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
+		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
 		  	LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
@@ -1919,79 +1667,30 @@ public:
 		
 		return false;
 	}
-	
-	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
-	{
-		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
-
-		if (earlyFail(group))
-		{
-			return;
-		}
 		
-		if (mRes == 2 || 
-			(mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)))
-		{	//fully in, just add everything
-			LLSpatialGroup::OctreeTraveler::traverse(n);
-		}
-		else
-		{
-			mRes = frustumCheck(group);
-				
-			if (mRes)
-			{ //at least partially in, run on down
-				LLSpatialGroup::OctreeTraveler::traverse(n);
-			}
-
-			mRes = 0;
-		}
-	}
-	
-	virtual S32 frustumCheck(const LLSpatialGroup* group)
+	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)
 	{
-		S32 res = mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+		S32 res = AABBInFrustumNoFarClipGroupBounds(group);
 		if (res != 0)
 		{
-			res = llmin(res, AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
+			res = llmin(res, AABBSphereIntersectGroupExtents(group));
 		}
 		return res;
 	}
 
-	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)
 	{
-		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
 		if (res != 0)
 		{
-			res = llmin(res, AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist));
+			res = llmin(res, AABBSphereIntersectObjectExtents(group));
 		}
 		return res;
 	}
 
-	virtual bool checkObjects(const LLSpatialGroup::OctreeNode* branch, const LLSpatialGroup* group)
-	{
-		if (branch->getElementCount() == 0) //no elements
-		{
-			return false;
-		}
-		else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box
-		{
-			return true;
-		}
-		else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum
-		{
-			return false;
-		}
-		
-		return true;
-	}
-
-	virtual void preprocess(LLSpatialGroup* group)
-	{
-		
-	}
-	
-	virtual void processGroup(LLSpatialGroup* group)
+	virtual void processGroup(LLviewerOctreeGroup* base_group)
 	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
 		if (group->needsUpdate() ||
 			group->mVisible[LLViewerCamera::sCurCameraID] < LLDrawable::getCurrentFrame() - 1)
 		{
@@ -1999,21 +1698,6 @@ public:
 		}
 		gPipeline.markNotCulled(group, *mCamera);
 	}
-	
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
-	{	
-		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
-
-		preprocess(group);
-		
-		if (checkObjects(branch, group))
-		{
-			processGroup(group);
-		}
-	}
-
-	LLCamera *mCamera;
-	S32 mRes;
 };
 
 class LLOctreeCullNoFarClip : public LLOctreeCull
@@ -2022,14 +1706,14 @@ public:
 	LLOctreeCullNoFarClip(LLCamera* camera) 
 		: LLOctreeCull(camera) { }
 
-	virtual S32 frustumCheck(const LLSpatialGroup* group)
+	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)
 	{
-		return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+		return AABBInFrustumNoFarClipGroupBounds(group);
 	}
 
-	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)
 	{
-		S32 res = mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
 		return res;
 	}
 };
@@ -2040,14 +1724,14 @@ public:
 	LLOctreeCullShadow(LLCamera* camera)
 		: LLOctreeCull(camera) { }
 
-	virtual S32 frustumCheck(const LLSpatialGroup* group)
+	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)
 	{
-		return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+		return AABBInFrustumGroupBounds(group);
 	}
 
-	virtual S32 frustumCheckObjects(const LLSpatialGroup* group)
+	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)
 	{
-		return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+		return AABBInFrustumObjectBounds(group);
 	}
 };
 
@@ -2057,9 +1741,11 @@ public:
 	LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
 		: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
 
-	virtual bool earlyFail(LLSpatialGroup* group)
+	virtual bool earlyFail(LLviewerOctreeGroup* base_group)
 	{
-		if (group->mOctreeNode->getParent() &&	//never occlusion cull the root node
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+
+		if (group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
 			LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 			group->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{
@@ -2069,7 +1755,7 @@ public:
 		return false;
 	}
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	virtual void traverse(const OctreeNode* n)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 
@@ -2078,10 +1764,10 @@ public:
 			return;
 		}
 		
-		if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
+		if ((mRes && group->hasState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
 			mRes == 2)
 		{	//don't need to do frustum check
-			LLSpatialGroup::OctreeTraveler::traverse(n);
+			OctreeTraveler::traverse(n);
 		}
 		else
 		{  
@@ -2089,31 +1775,35 @@ public:
 				
 			if (mRes)
 			{ //at least partially in, run on down
-				LLSpatialGroup::OctreeTraveler::traverse(n);
+				OctreeTraveler::traverse(n);
 			}
 
 			mRes = 0;
 		}
 	}
 
-	virtual void processGroup(LLSpatialGroup* group)
+	virtual void processGroup(LLviewerOctreeGroup* base_group)
 	{
-		llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->isEmpty())
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+		
+		llassert(!group->hasState(LLSpatialGroup::DIRTY) && !group->isEmpty())
 		
 		if (mRes < 2)
 		{
-			if (mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]) > 0)
+			if (AABBInFrustumObjectBounds(group) > 0)
 			{
 				mEmpty = FALSE;
-				update_min_max(mMin, mMax, group->mObjectExtents[0]);
-				update_min_max(mMin, mMax, group->mObjectExtents[1]);
+				const LLVector4a* exts = group->getObjectExtents();
+				update_min_max(mMin, mMax, exts[0]);
+				update_min_max(mMin, mMax, exts[1]);
 			}
 		}
 		else
 		{
 			mEmpty = FALSE;
-			update_min_max(mMin, mMax, group->mExtents[0]);
-			update_min_max(mMin, mMax, group->mExtents[1]);
+			const LLVector4a* exts = group->getExtents();
+			update_min_max(mMin, mMax, exts[0]);
+			update_min_max(mMin, mMax, exts[1]);
 		}
 	}
 
@@ -2128,10 +1818,12 @@ public:
 	LLOctreeCullDetectVisible(LLCamera* camera)
 		: LLOctreeCullShadow(camera), mResult(FALSE) { }
 
-	virtual bool earlyFail(LLSpatialGroup* group)
+	virtual bool earlyFail(LLviewerOctreeGroup* base_group)
 	{
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+
 		if (mResult || //already found a node, don't check any more
-			(group->mOctreeNode->getParent() &&	//never occlusion cull the root node
+			(group->getOctreeNode()->getParent() &&	//never occlusion cull the root node
 			 LLPipeline::sUseOcclusion &&			//ignore occlusion if disabled
 			 group->isOcclusionState(LLSpatialGroup::OCCLUDED)))
 		{
@@ -2141,9 +1833,9 @@ public:
 		return false;
 	}
 
-	virtual void processGroup(LLSpatialGroup* group)
+	virtual void processGroup(LLviewerOctreeGroup* base_group)
 	{
-		if (group->isVisible())
+		if (base_group->isVisible())
 		{
 			mResult = TRUE;
 		}
@@ -2158,17 +1850,21 @@ public:
 	LLOctreeSelect(LLCamera* camera, std::vector<LLDrawable*>* results)
 		: LLOctreeCull(camera), mResults(results) { }
 
-	virtual bool earlyFail(LLSpatialGroup* group) { return false; }
-	virtual void preprocess(LLSpatialGroup* group) { }
+	virtual bool earlyFail(LLviewerOctreeGroup* group) { return false; }
+	virtual void preprocess(LLviewerOctreeGroup* group) { }
 
-	virtual void processGroup(LLSpatialGroup* group)
+	virtual void processGroup(LLviewerOctreeGroup* base_group)
 	{
-		LLSpatialGroup::OctreeNode* branch = group->mOctreeNode;
+		LLSpatialGroup* group = (LLSpatialGroup*)base_group;
+		OctreeNode* branch = group->getOctreeNode();
 
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
-			LLDrawable* drawable = *i;
-			
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+			{
+				continue;
+			}
 			if (!drawable->isDead())
 			{
 				if (drawable->isSpatialBridge())
@@ -2281,17 +1977,21 @@ void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
 	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
 }
 
-class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
+class LLOctreeDirty : public OctreeTraveler
 {
 public:
-	virtual void visit(const LLOctreeNode<LLDrawable>* state)
+	virtual void visit(const OctreeNode* state)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
 		group->destroyGL();
 
 		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 		{
-			LLDrawable* drawable = *i;
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+			{
+				continue;
+			}
 			if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup)
 			{
 				gPipeline.markRebuild(drawable, LLDrawable::REBUILD_ALL, TRUE);
@@ -2350,6 +2050,13 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
+	bool is_vo_cache_part = (mPartitionType == LLViewerRegion::PARTITION_VO_CACHE);
+	
+	if(is_vo_cache_part && mVisitedTime == LLViewerOctreeEntryData::getCurrentFrame())
+	{
+		return 0; //no need to visit more than once per frame
+	}		
+
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
@@ -2364,18 +2071,18 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 #endif
 
 	
-	if (for_select)
+	if (for_select && !is_vo_cache_part)
 	{
 		LLOctreeSelect selecter(&camera, results);
 		selecter.traverse(mOctree);
 	}
-	else if (LLPipeline::sShadowRender)
+	else if (LLPipeline::sShadowRender && !is_vo_cache_part)
 	{
 		LLFastTimer ftm(FTM_FRUSTUM_CULL);
 		LLOctreeCullShadow culler(&camera);
 		culler.traverse(mOctree);
 	}
-	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+	else if ((mInfiniteFarClip || !LLPipeline::sUseFarClip) && !is_vo_cache_part)
 	{
 		LLFastTimer ftm(FTM_FRUSTUM_CULL);		
 		LLOctreeCullNoFarClip culler(&camera);
@@ -2383,6 +2090,11 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	}
 	else
 	{
+		if(is_vo_cache_part)
+		{
+			mVisitedTime = LLViewerOctreeEntryData::getCurrentFrame();
+		}
+
 		LLFastTimer ftm(FTM_FRUSTUM_CULL);		
 		LLOctreeCull culler(&camera);
 		culler.traverse(mOctree);
@@ -2402,9 +2114,10 @@ BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
 	LLVector4a fudge;
 	fudge.splat(vel);
 
-	const LLVector4a& c = group->mBounds[0];
+	const LLVector4a* bounds = group->getBounds();
+	const LLVector4a& c = bounds[0];
 	LLVector4a r;
-	r.setAdd(group->mBounds[1], fudge);
+	r.setAdd(bounds[1], fudge);
 
 	/*if (r.magVecSquared() > 1024.0*1024.0)
 	{
@@ -2529,7 +2242,8 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask)
 	}
 	else
 	{
-		drawBox(group->mBounds[0], group->mBounds[1]);
+		const LLVector4a* bounds = group->getBounds();
+		drawBox(bounds[0], bounds[1]);
 	}
 }
 
@@ -2593,13 +2307,19 @@ void renderOctree(LLSpatialGroup* group)
 			gGL.diffuseColor4f(1,0,0,group->mBuilt);
 			gGL.flush();
 			glLineWidth(5.f);
-			drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
+
+			const LLVector4a* bounds = group->getObjectBounds();
+			drawBoxOutline(bounds[0], bounds[1]);
 			gGL.flush();
 			glLineWidth(1.f);
 			gGL.flush();
 			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 			{
-				LLDrawable* drawable = *i;
+				LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+				if(!drawable)
+				{
+					continue;
+				}
 				if (!group->mSpatialPartition->isBridge())
 				{
 					gGL.pushMatrix();
@@ -2657,9 +2377,10 @@ void renderOctree(LLSpatialGroup* group)
 	gGL.diffuseColor4fv(col.mV);
 	LLVector4a fudge;
 	fudge.splat(0.001f);
-	LLVector4a size = group->mObjectBounds[1];
-	size.mul(1.01f);
-	size.add(fudge);
+
+	//LLVector4a size = group->mObjectBounds[1];
+	//size.mul(1.01f);
+	//size.add(fudge);
 
 	//{
 	//	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
@@ -2675,7 +2396,9 @@ void renderOctree(LLSpatialGroup* group)
 		//drawBoxOutline(group->mObjectBounds[0], group->mObjectBounds[1]);
 
 		gGL.diffuseColor4f(0,1,1,1);
-		drawBoxOutline(group->mBounds[0],group->mBounds[1]);
+
+		const LLVector4a* bounds = group->getBounds();
+		drawBoxOutline(bounds[0], bounds[1]);
 		
 		//draw bounding box for draw info
 		/*if (group->mSpatialPartition->mRenderByGroup)
@@ -3442,9 +3165,13 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 
 void renderPhysicsShapes(LLSpatialGroup* group)
 {
-	for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+	for (OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
-		LLDrawable* drawable = *i;
+		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+		if(!drawable)
+		{
+			continue;
+		}
 		LLVOVolume* volume = drawable->getVOVolume();
 		if (volume && !volume->isAttachment() && volume->getPhysicsShapeType() != LLViewerObject::PHYSICS_SHAPE_NONE )
 		{
@@ -4001,17 +3728,18 @@ void renderAgentTarget(LLVOAvatar* avatar)
 	}
 }
 
-class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
+class LLOctreeRenderNonOccluded : public OctreeTraveler
 {
 public:
 	LLCamera* mCamera;
 	LLOctreeRenderNonOccluded(LLCamera* camera): mCamera(camera) {}
 	
-	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	virtual void traverse(const OctreeNode* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 		
-		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+		const LLVector4a* bounds = group->getBounds();
+		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))
 		{
 			node->accept(this);
 			stop_glerror();
@@ -4051,17 +3779,17 @@ public:
 		}
 	}
 
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+	virtual void visit(const OctreeNode* branch)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
-
-		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
+		const LLVector4a* bounds = group->getBounds();
+		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))
 		{
 			return;
 		}
 
-		LLVector4a nodeCenter = group->mBounds[0];
-		LLVector4a octCenter = group->mOctreeNode->getCenter();
+		LLVector4a nodeCenter = bounds[0];
+		LLVector4a octCenter = group->getOctreeNode()->getCenter();
 
 		group->rebuildGeom();
 		group->rebuildMesh();
@@ -4071,15 +3799,20 @@ public:
 			if (!group->isEmpty())
 			{
 				gGL.diffuseColor3f(0,0,1);
-				drawBoxOutline(group->mObjectBounds[0],
-								group->mObjectBounds[1]);
+
+				const LLVector4a* obj_bounds = group->getObjectBounds();
+				drawBoxOutline(obj_bounds[0], obj_bounds[1]);
 			}
 		}
 
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
-			LLDrawable* drawable = *i;
-					
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+			{
+				continue;
+			}
+
 			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
 			{
 				renderBoundingBox(drawable);			
@@ -4201,17 +3934,18 @@ public:
 };
 
 
-class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
+class LLOctreeRenderPhysicsShapes : public OctreeTraveler
 {
 public:
 	LLCamera* mCamera;
 	LLOctreeRenderPhysicsShapes(LLCamera* camera): mCamera(camera) {}
 	
-	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	virtual void traverse(const OctreeNode* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 		
-		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+		const LLVector4a* bounds = group->getBounds();
+		if (!mCamera || mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1]))
 		{
 			node->accept(this);
 			stop_glerror();
@@ -4229,23 +3963,24 @@ public:
 		}
 	}
 
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+	virtual void visit(const OctreeNode* branch)
 	{
 		
 	}
 };
 
-class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
+class LLOctreePushBBoxVerts : public OctreeTraveler
 {
 public:
 	LLCamera* mCamera;
 	LLOctreePushBBoxVerts(LLCamera* camera): mCamera(camera) {}
 	
-	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	virtual void traverse(const OctreeNode* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 		
-		if (!mCamera || mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+		const LLVector4a* bounds = group->getBounds();
+		if (!mCamera || mCamera->AABBInFrustum(bounds[0], bounds[1]))
 		{
 			node->accept(this);
 
@@ -4256,19 +3991,23 @@ public:
 		}
 	}
 
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch)
+	virtual void visit(const OctreeNode* branch)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) branch->getListener(0);
 
-		if (group->isState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1])))
+		const LLVector4a* bounds = group->getBounds();
+		if (group->hasState(LLSpatialGroup::GEOM_DIRTY) || (mCamera && !mCamera->AABBInFrustumNoFarClip(bounds[0], bounds[1])))
 		{
 			return;
 		}
 
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
-			LLDrawable* drawable = *i;
-						
+			LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+			if(!drawable)
+			{
+				continue;
+			}
 			renderBoundingBox(drawable, FALSE);			
 		}
 	}
@@ -4280,7 +4019,7 @@ void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
 	pusher.traverse(mOctree);
 }
 
-class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
+class LLOctreeStateCheck : public OctreeTraveler
 {
 public:
 	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
@@ -4293,7 +4032,7 @@ public:
 		}
 	}
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	virtual void traverse(const OctreeNode* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 		
@@ -4320,7 +4059,7 @@ public:
 	}
 	
 
-	virtual void visit(const LLOctreeNode<LLDrawable>* state)
+	virtual void visit(const OctreeNode* state)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
 
@@ -4332,7 +4071,7 @@ public:
 			}
 		}
 
-		if (group->isState(LLSpatialGroup::DIRTY))
+		if (group->hasState(LLSpatialGroup::DIRTY))
 		{
 			assert_parent_state(group, LLSpatialGroup::DIRTY);
 		}
@@ -4343,7 +4082,7 @@ public:
 		LLSpatialGroup* parent = group->getParent();
 		while (parent)
 		{
-			if (!parent->isState(state))
+			if (!parent->hasState(state))
 			{
 				llerrs << "Spatial group failed parent state check." << llendl;
 			}
@@ -4458,7 +4197,7 @@ BOOL LLSpatialPartition::isVisible(const LLVector3& v)
 	return TRUE;
 }
 
-class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
+class LLOctreeIntersect : public OctreeTraveler
 {
 public:
 	LLVector3 mStart;
@@ -4485,21 +4224,21 @@ public:
 	{
 	}
 	
-	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
+	virtual void visit(const OctreeNode* branch) 
 	{	
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
+		for (OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
 			check(*i);
 		}
 	}
 
-	virtual LLDrawable* check(const LLSpatialGroup::OctreeNode* node)
+	virtual LLDrawable* check(const OctreeNode* node)
 	{
 		node->accept(this);
 	
 		for (U32 i = 0; i < node->getChildCount(); i++)
 		{
-			const LLSpatialGroup::OctreeNode* child = node->getChild(i);
+			const OctreeNode* child = node->getChild(i);
 			LLVector3 res;
 
 			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
@@ -4507,8 +4246,9 @@ public:
 			LLVector4a size;
 			LLVector4a center;
 			
-			size = group->mBounds[1];
-			center = group->mBounds[0];
+			const LLVector4a* bounds = group->getBounds();
+			size = bounds[1];
+			center = bounds[0];
 			
 			LLVector3 local_start = mStart;
 			LLVector3 local_end   = mEnd;
@@ -4535,8 +4275,9 @@ public:
 		return mHit;
 	}
 
-	virtual bool check(LLDrawable* drawable)
+	virtual bool check(LLViewerOctreeEntry* entry)
 	{	
+		LLDrawable* drawable = (LLDrawable*)entry->getDrawable();
 		LLVector3 local_start = mStart;
 		LLVector3 local_end = mEnd;
 
@@ -4922,5 +4663,21 @@ void LLCullResult::assertDrawMapsEmpty()
 	}
 }
 
+LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp) : LLSpatialPartition(0, FALSE, 0, regionp)
+{
+	mPartitionType = LLViewerRegion::PARTITION_VO_CACHE;
+}
+
+void LLVOCachePartition::addEntry(LLViewerOctreeEntry* entry)
+{
+	llassert(entry->hasVOCacheEntry());
 
+	mOctree->insert(entry);
+}
+	
+void LLVOCachePartition::removeEntry(LLViewerOctreeEntry* entry)
+{
+	entry->getVOCacheEntry()->setGroup(NULL);
 
+	llassert(!entry->getGroup());
+}
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index f050df2b39..dd189d751d 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -50,12 +50,8 @@ class LLSpatialBridge;
 class LLSpatialGroup;
 class LLTextureAtlas;
 class LLTextureAtlasSlot;
+class LLViewerRegion;
 
-S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad);
-S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared);
-
-S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
-S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);
 void pushVerts(LLFace* face, U32 mask);
 
 // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
@@ -192,13 +188,13 @@ public:
 };
 
 LL_ALIGN_PREFIX(16)
-class LLSpatialGroup : public LLOctreeListener<LLDrawable>
+class LLSpatialGroup : public LLviewerOctreeGroup
 {
 	friend class LLSpatialPartition;
 	friend class LLOctreeStateCheck;
 public:
 
-	LLSpatialGroup(const LLSpatialGroup& rhs)
+	LLSpatialGroup(const LLSpatialGroup& rhs) : LLviewerOctreeGroup(rhs)
 	{
 		*this = rhs;
 	}
@@ -231,14 +227,8 @@ public:
 	typedef std::map<LLFace*, buffer_list_t> buffer_texture_map_t;
 	typedef std::map<U32, buffer_texture_map_t> buffer_map_t;
 
-	typedef LLOctreeListener<LLDrawable>	BaseType;
-	typedef LLOctreeListener<LLDrawable>	OctreeListener;
-	typedef LLTreeNode<LLDrawable>			TreeNode;
-	typedef LLOctreeNode<LLDrawable>		OctreeNode;
-	typedef LLOctreeRoot<LLDrawable>		OctreeRoot;
-	typedef LLOctreeTraveler<LLDrawable>	OctreeTraveler;
-	typedef LLOctreeNode<LLDrawable>::element_iter element_iter;
-	typedef LLOctreeNode<LLDrawable>::element_list element_list;
+	typedef LLOctreeNode<LLViewerOctreeEntry>::element_iter element_iter;
+	typedef LLOctreeNode<LLViewerOctreeEntry>::element_list element_list;
 
 	struct CompareDistanceGreater
 	{
@@ -275,18 +265,15 @@ public:
 
 	typedef enum
 	{
-		DEAD					= 0x00000001,
-		DIRTY					= 0x00000002,
-		OBJECT_DIRTY			= 0x00000004,
-		GEOM_DIRTY				= 0x00000008,
-		ALPHA_DIRTY				= 0x00000010,
-		SKIP_FRUSTUM_CHECK		= 0x00000020,
-		IN_IMAGE_QUEUE			= 0x00000040,
-		IMAGE_DIRTY				= 0x00000080,
-		MESH_DIRTY				= 0x00000100,
-		NEW_DRAWINFO			= 0x00000200,
-		IN_BUILD_Q1				= 0x00000400,
-		IN_BUILD_Q2				= 0x00000800,
+		DEAD					= LLviewerOctreeGroup::INVALID_STATE,
+		GEOM_DIRTY				= (DEAD << 1),
+		ALPHA_DIRTY				= (GEOM_DIRTY << 1),
+		IN_IMAGE_QUEUE			= (ALPHA_DIRTY << 1),
+		IMAGE_DIRTY				= (IN_IMAGE_QUEUE << 1),
+		MESH_DIRTY				= (IMAGE_DIRTY << 1),
+		NEW_DRAWINFO			= (MESH_DIRTY << 1),
+		IN_BUILD_Q1				= (NEW_DRAWINFO << 1),
+		IN_BUILD_Q2				= (IN_BUILD_Q1 << 1),
 		STATE_MASK				= 0x0000FFFF,
 	} eSpatialState;
 
@@ -301,12 +288,8 @@ public:
 	LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part);
 
 	BOOL isHUDGroup() ;
-	BOOL isDead()							{ return isState(DEAD); }
-	BOOL isState(U32 state) const;	
+	BOOL isDead()							{ return hasState(DEAD); }
 	BOOL isOcclusionState(U32 state) const	{ return mOcclusionState[LLViewerCamera::sCurCameraID] & state ? TRUE : FALSE; }
-	U32 getState()							{ return mState; }
-	void setState(U32 state);	
-	void clearState(U32 state);	
 	
 	void clearDrawMap();
 	void validate();
@@ -315,23 +298,20 @@ public:
 	
 	void setState(U32 state, S32 mode);
 	void clearState(U32 state, S32 mode);
+	void clearState(U32 state)     {mState &= ~state;}	
 
 	void setOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
 	void clearOcclusionState(U32 state, S32 mode = STATE_MODE_SINGLE);
 
 	LLSpatialGroup* getParent();
-
 	
-	BOOL addObject(LLDrawable *drawablep, BOOL add_all = FALSE, BOOL from_octree = FALSE);
+	BOOL addObject(LLDrawable *drawablep);
 	BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE);
 	BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group
 	BOOL isVisible() const;
 	BOOL isRecentlyVisible() const;
 	void setVisible();
 	void shift(const LLVector4a &offset);
-	BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax);
-	void unbound();
-	BOOL rebound();
 	void checkOcclusion(); //read back last occlusion query (if any)
 	void doOcclusion(LLCamera* camera); //issue occlusion query
 	void destroyGL(bool keep_occlusion = false);
@@ -343,6 +323,7 @@ public:
 	void rebuildGeom();
 	void rebuildMesh();
 
+	void setState(U32 state)       {mState |= state;}
 	void dirtyGeom() { setState(GEOM_DIRTY); }
 	void dirtyMesh() { setState(MESH_DIRTY); }
 
@@ -356,13 +337,11 @@ public:
 	void drawObjectBox(LLColor4 col);
 
 	 //LISTENER FUNCTIONS
-	virtual void handleInsertion(const TreeNode* node, LLDrawable* face);
-	virtual void handleRemoval(const TreeNode* node, LLDrawable* face);
+	virtual void handleInsertion(const TreeNode* node, LLViewerOctreeEntry* face);
+	virtual void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* face);
 	virtual void handleDestruction(const TreeNode* node);
-	virtual void handleStateChange(const TreeNode* node);
 	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
-	virtual void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child);
-
+	
 //-------------------
 //for atlas use
 //-------------------
@@ -384,21 +363,6 @@ public:
 
 public:
 
-	typedef enum
-	{
-		BOUNDS = 0,
-		EXTENTS = 2,
-		OBJECT_BOUNDS = 4,
-		OBJECT_EXTENTS = 6,
-		VIEW_ANGLE = 8,
-		LAST_VIEW_ANGLE = 9,
-		V4_COUNT = 10
-	} eV4Index;
-
-	LL_ALIGN_16(LLVector4a mBounds[2]); // bounding box (center, size) of this node and all its children (tight fit to objects)
-	LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
-	LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node
-	LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node
 	LL_ALIGN_16(LLVector4a mViewAngle);
 	LL_ALIGN_16(LLVector4a mLastUpdateViewAngle);
 
@@ -419,7 +383,6 @@ private:
 protected:
 	virtual ~LLSpatialGroup();
 
-	U32 mState;
 	U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS];
 	U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS];
 
@@ -434,7 +397,6 @@ public:
 	F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node
 
 	F32 mBuilt;
-	OctreeNode* mOctreeNode;
 	LLSpatialPartition* mSpatialPartition;
 	
 	LLPointer<LLVertexBuffer> mVertexBuffer;
@@ -469,7 +431,7 @@ public:
 class LLSpatialPartition: public LLGeometryManager
 {
 public:
-	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage);
+	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage, LLViewerRegion* regionp);
 	virtual ~LLSpatialPartition();
 
 	LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE);
@@ -511,9 +473,10 @@ public:
 	void resetVertexBuffers();
 	BOOL isOcclusionEnabled();
 	BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax);
+	BOOL isVOCachePartition() const;
 
 public:
-	LLSpatialGroup::OctreeNode* mOctree;
+	OctreeNode*      mOctree;
 	LLSpatialBridge* mBridge; // NULL for non-LLSpatialBridge instances, otherwise, mBridge == this
 							// use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe
 							// to call asBridge() from the destructor
@@ -528,6 +491,8 @@ public:
 	BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering
 	U32 mDrawableType;
 	U32 mPartitionType;
+	U32 mVisitedTime;
+	LLViewerRegion* mRegionp; // the region this partition belongs to.
 };
 
 // class for creating bridges between spatial partitions
@@ -539,7 +504,7 @@ protected:
 public:
 	typedef std::vector<LLPointer<LLSpatialBridge> > bridge_vector_t;
 	
-	LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask);
+	LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask, LLViewerRegion* regionp);
 	
 	void destroyTree();
 
@@ -562,7 +527,7 @@ public:
 
 };
 
-class LLCullResult 
+class LLCullResult
 {
 public:
 	LLCullResult();
@@ -661,7 +626,7 @@ private:
 class LLWaterPartition : public LLSpatialPartition
 {
 public:
-	LLWaterPartition();
+	LLWaterPartition(LLViewerRegion* regionp);
 	virtual void getGeometry(LLSpatialGroup* group) {  }
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { }
 };
@@ -670,14 +635,27 @@ public:
 class LLVoidWaterPartition : public LLWaterPartition
 {
 public:
-	LLVoidWaterPartition();
+	LLVoidWaterPartition(LLViewerRegion* regionp);
+};
+
+//spatial partition for hole and edge water (implemented in LLVOWater.cpp)
+class LLVOCachePartition : public LLSpatialPartition
+{
+public:
+	LLVOCachePartition(LLViewerRegion* regionp);
+
+	void addEntry(LLViewerOctreeEntry* entry);
+	void removeEntry(LLViewerOctreeEntry* entry);
+
+	virtual void getGeometry(LLSpatialGroup* group) {  }
+	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { }
 };
 
 //spatial partition for terrain (impelmented in LLVOSurfacePatch.cpp)
 class LLTerrainPartition : public LLSpatialPartition
 {
 public:
-	LLTerrainPartition();
+	LLTerrainPartition(LLViewerRegion* regionp);
 	virtual void getGeometry(LLSpatialGroup* group);
 	virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage);
 };
@@ -686,7 +664,7 @@ public:
 class LLTreePartition : public LLSpatialPartition
 {
 public:
-	LLTreePartition();
+	LLTreePartition(LLViewerRegion* regionp);
 	virtual void getGeometry(LLSpatialGroup* group) { }
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { }
 
@@ -696,7 +674,7 @@ public:
 class LLParticlePartition : public LLSpatialPartition
 {
 public:
-	LLParticlePartition();
+	LLParticlePartition(LLViewerRegion* regionp);
 	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count);
@@ -708,14 +686,14 @@ protected:
 class LLHUDParticlePartition : public LLParticlePartition
 {
 public:
-	LLHUDParticlePartition();
+	LLHUDParticlePartition(LLViewerRegion* regionp);
 };
 
 //spatial partition for grass (implemented in LLVOGrass.cpp)
 class LLGrassPartition : public LLSpatialPartition
 {
 public:
-	LLGrassPartition();
+	LLGrassPartition(LLViewerRegion* regionp);
 	virtual void getGeometry(LLSpatialGroup* group);
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count);
 protected:
@@ -745,7 +723,7 @@ class LLVolumeGeometryManager: public LLGeometryManager
 class LLVolumePartition : public LLSpatialPartition, public LLVolumeGeometryManager
 {
 public:
-	LLVolumePartition();
+	LLVolumePartition(LLViewerRegion* regionp);
 	virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); }
 	virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); }
 	virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); }
@@ -756,7 +734,7 @@ public:
 class LLVolumeBridge : public LLSpatialBridge, public LLVolumeGeometryManager
 {
 public:
-	LLVolumeBridge(LLDrawable* drawable);
+	LLVolumeBridge(LLDrawable* drawable, LLViewerRegion* regionp);
 	virtual void rebuildGeom(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildGeom(group); }
 	virtual void getGeometry(LLSpatialGroup* group) { LLVolumeGeometryManager::getGeometry(group); }
 	virtual void rebuildMesh(LLSpatialGroup* group) { LLVolumeGeometryManager::rebuildMesh(group); }
@@ -766,7 +744,7 @@ public:
 class LLHUDBridge : public LLVolumeBridge
 {
 public:
-	LLHUDBridge(LLDrawable* drawablep);
+	LLHUDBridge(LLDrawable* drawablep, LLViewerRegion* regionp);
 	virtual void shiftPos(const LLVector4a& vec);
 	virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);
 };
@@ -775,7 +753,7 @@ public:
 class LLBridgePartition : public LLSpatialPartition
 {
 public:
-	LLBridgePartition();
+	LLBridgePartition(LLViewerRegion* regionp);
 	virtual void getGeometry(LLSpatialGroup* group) { }
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) {  }
 };
@@ -783,7 +761,7 @@ public:
 class LLHUDPartition : public LLBridgePartition
 {
 public:
-	LLHUDPartition();
+	LLHUDPartition(LLViewerRegion* regionp);
 	virtual void shift(const LLVector4a &offset);
 };
 
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index c60b4155a0..a5ccf97d1e 100755
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -49,6 +49,8 @@
 #include "llviewertexturelist.h"
 #include "llvovolume.h"
 #include "llviewerstats.h"
+#include "llworld.h"
+#include "llviewerobjectlist.h"
 
 // For avatar texture view
 #include "llvoavatarself.h"
@@ -515,6 +517,9 @@ void LLGLTexMemBar::draw()
 	F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024);
 	F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024);
 	U32 total_http_requests = LLAppViewer::getTextureFetch()->getCurlRequest().getTotalIssuedRequests() ;
+	U32 total_active_cached_objects = LLWorld::getInstance()->getNumOfActiveCachedObjects();
+	U32 total_objects = gObjectList.getNumObjects();
+
 	//----------------------------------------------------------------------------
 	LLGLSUIDefault gls_ui;
 	LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
@@ -536,8 +541,8 @@ void LLGLTexMemBar::draw()
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*4,
 											 text_color, LLFontGL::LEFT, LLFontGL::TOP);
 
-	text = llformat("Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d",
-					total_texture_downloaded, total_object_downloaded, total_http_requests);
+	text = llformat("Net Tot Tex: %.1f MB Tot Obj: %.1f MB #Objs/#cached: %d/%d Tot Htp: %d",
+					total_texture_downloaded, total_object_downloaded, total_objects, total_active_cached_objects, total_http_requests);
 	//, cache_entries, cache_max_entries
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3,
 											 text_color, LLFontGL::LEFT, LLFontGL::TOP);
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ec7d91ec4f..67d400af2d 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4490,12 +4490,22 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 
 	LLUUID		id;
 	U32			local_id;
-	S32			i;
+	S32			i = 0;
 	S32			num_objects;
 
 	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
 
-	for (i = 0; i < num_objects; i++)
+	mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
+	LLViewerRegion* regionp = NULL;
+	bool remove_from_cache = !local_id; //if the first local id is 0, physically remove all objects from VO cache.
+	if(remove_from_cache)
+	{
+		i++;
+
+		LLHost host(gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort());
+		regionp = LLWorld::getInstance()->getRegion(host);
+	}
+	for (; i < num_objects; i++)
 	{
 		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
 
@@ -4530,10 +4540,15 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 				// Do the kill
 				gObjectList.killObject(objectp);
 			}
-			else
+			//else
+			//{
+			//	LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL;
+			//	gObjectList.mNumUnknownKills++;
+			//}
+
+			if(remove_from_cache)
 			{
-				LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL;
-				gObjectList.mNumUnknownKills++;
+				regionp->killCacheEntry(local_id);
 			}
 		}
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index aba1d131e1..dbccb2a4d9 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -100,6 +100,7 @@
 #include "lltrans.h"
 #include "llsdutil.h"
 #include "llmediaentry.h"
+#include "llvocache.h"
 
 //#define DEBUG_UPDATE_TYPE
 
@@ -344,7 +345,7 @@ void LLViewerObject::markDead()
 			childp = mChildList.back();
 			if (childp->getPCode() != LL_PCODE_LEGACY_AVATAR)
 			{
-				//llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl;
+				//llinfos << "Marking child " << childp->getLocalID() << " as dead." << llendl;				
 				childp->setParent(NULL); // LLViewerObject::markDead 1
 				childp->markDead();
 			}
@@ -885,10 +886,11 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 	}
 
 	// Coordinates of objects on simulators are region-local.
-	U64 region_handle;
-	mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
+	U64 region_handle = 0;	
 	
+	if(mesgsys != NULL)
 	{
+		mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);
 		LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle);
 		if(regionp != mRegionp && regionp && mRegionp)//region cross
 		{
@@ -914,11 +916,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 		return retval;
 	}
 
-	U16 time_dilation16;
-	mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16);
-	F32 time_dilation = ((F32) time_dilation16) / 65535.f;
-	mTimeDilation = time_dilation;
-	mRegionp->setTimeDilation(time_dilation);
+	if(mesgsys != NULL)
+	{
+		U16 time_dilation16;
+		mesgsys->getU16Fast(_PREHASH_RegionData, _PREHASH_TimeDilation, time_dilation16);
+		F32 time_dilation = ((F32) time_dilation16) / 65535.f;
+		mTimeDilation = time_dilation;
+		mRegionp->setTimeDilation(time_dilation);
+	}
 
 	// this will be used to determine if we've really changed position
 	// Use getPosition, not getPositionRegion, since this is what we're comparing directly against.
@@ -1692,13 +1697,16 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				// Preload these five flags for every object.
 				// Finer shades require the object to be selected, and the selection manager
 				// stores the extended permission info.
-				U32 flags;
-				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, block_num);
-				// keep local flags and overwrite remote-controlled flags
-				mFlags = (mFlags & FLAGS_LOCAL) | flags;
+				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);
+					mCreateSelected = ((flags & FLAGS_CREATE_SELECTED) != 0);
+				}
 			}
 			break;
 
@@ -1726,10 +1734,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 			{
 				// No parent now, new parent in message -> attach to that parent if possible
 				LLUUID parent_uuid;
-				LLViewerObjectList::getUUIDFromLocal(parent_uuid,
+
+				if(mesgsys != NULL)
+				{
+					LLViewerObjectList::getUUIDFromLocal(parent_uuid,
 														parent_id,
 														mesgsys->getSenderIP(),
 														mesgsys->getSenderPort());
+				}
+				else
+				{
+					LLViewerObjectList::getUUIDFromLocal(parent_uuid,
+														parent_id,
+														mRegionp->getHost().getAddress(),
+														mRegionp->getHost().getPort());
+				}
 
 				LLViewerObject *sent_parentp = gObjectList.findObject(parent_uuid);
 
@@ -1805,9 +1824,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 					//
 					
 					//parent_id
-					U32 ip = mesgsys->getSenderIP();
-					U32 port = mesgsys->getSenderPort();
+					U32 ip, port; 
 					
+					if(mesgsys != NULL)
+					{
+						ip = mesgsys->getSenderIP();
+						port = mesgsys->getSenderPort();
+					}
+					else
+					{
+						ip = mRegionp->getHost().getAddress();
+						port = mRegionp->getHost().getPort();
+					}
 					gObjectList.orphanize(this, parent_id, ip, port);
 
 					// Hide particles, icon and HUD
@@ -1845,10 +1873,21 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				else
 				{
 					LLUUID parent_uuid;
-					LLViewerObjectList::getUUIDFromLocal(parent_uuid,
+
+					if(mesgsys != NULL)
+					{
+						LLViewerObjectList::getUUIDFromLocal(parent_uuid,
 														parent_id,
 														gMessageSystem->getSenderIP(),
 														gMessageSystem->getSenderPort());
+					}
+					else
+					{
+						LLViewerObjectList::getUUIDFromLocal(parent_uuid,
+														parent_id,
+														mRegionp->getHost().getAddress(),
+														mRegionp->getHost().getPort());
+					}
 					sent_parentp = gObjectList.findObject(parent_uuid);
 					
 					if (isAvatar())
@@ -1869,8 +1908,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 						//
 						// Switching parents, but we don't know the new parent.
 						//
-						U32 ip = mesgsys->getSenderIP();
-						U32 port = mesgsys->getSenderPort();
+						U32 ip, port; 
+					
+						if(mesgsys != NULL)
+						{
+							ip = mesgsys->getSenderIP();
+							port = mesgsys->getSenderPort();
+						}
+						else
+						{
+							ip = mRegionp->getHost().getAddress();
+							port = mRegionp->getHost().getPort();
+						}
 
 						// We're an orphan, flag things appropriately.
 						gObjectList.orphanize(this, parent_id, ip, port);
@@ -1954,7 +2003,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 
 	new_rot.normQuat();
 
-	if (sPingInterpolate)
+	if (sPingInterpolate && mesgsys != NULL)
 	{ 
 		LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender());
 		if (cdp)
@@ -1977,16 +2026,18 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 
 	// If we're going to skip this message, why are we 
 	// doing all the parenting, etc above?
-	U32 packet_id = mesgsys->getCurrentRecvPacketID(); 
-	if (packet_id < mLatestRecvPacketID && 
-		mLatestRecvPacketID - packet_id < 65536)
+	if(mesgsys != NULL)
 	{
-		//skip application of this message, it's old
-		return retval;
+		U32 packet_id = mesgsys->getCurrentRecvPacketID(); 
+		if (packet_id < mLatestRecvPacketID && 
+			mLatestRecvPacketID - packet_id < 65536)
+		{
+			//skip application of this message, it's old
+			return retval;
+		}
+		mLatestRecvPacketID = packet_id;
 	}
 
-	mLatestRecvPacketID = packet_id;
-
 	// Set the change flags for scale
 	if (new_scale != getScale())
 	{
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 88bb087742..a1db1f7237 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -76,6 +76,7 @@
 #include "object_flags.h"
 
 #include "llappviewer.h"
+#include "llvocache.h"
 
 extern F32 gMinObjectDistance;
 extern BOOL gAnimateTextures;
@@ -228,9 +229,15 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,
 										   U32 i, 
 										   const EObjectUpdateType update_type, 
 										   LLDataPacker* dpp, 
-										   BOOL just_created)
+										   bool just_created,
+										   bool from_cache)
 {
-	LLMessageSystem* msg = gMessageSystem;
+	LLMessageSystem* msg = NULL;
+	
+	if(!from_cache)
+	{
+		msg = gMessageSystem;
+	}
 
 	// ignore returned flags
 	objectp->processUpdateMessage(msg, user_data, i, update_type, dpp);
@@ -254,7 +261,18 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,
 	// RN: this must be called after we have a drawable 
 	// (from gPipeline.addObject)
 	// so that the drawable parent is set properly
-	findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort());
+	if(msg != NULL)
+	{
+		findOrphans(objectp, msg->getSenderIP(), msg->getSenderPort());
+	}
+	else
+	{
+		LLViewerRegion* regionp = objectp->getRegion();
+		if(regionp != NULL)
+		{
+			findOrphans(objectp, regionp->getHost().getAddress(), regionp->getHost().getPort());
+		}
+	}
 	
 	// If we're just wandering around, don't create new objects selected.
 	if (just_created 
@@ -277,6 +295,82 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp,
 
 static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects");
 
+LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp)
+{
+	LLDataPacker *cached_dpp = entry->getDP();
+
+	if (!cached_dpp)
+	{
+		return NULL; //nothing cached.
+	}
+	
+	LLViewerObject *objectp;
+	U32			    local_id;
+	LLPCode		    pcode = 0;
+	LLUUID		    fullid;
+	LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance();
+
+	// Cache Hit.
+	cached_dpp->reset();
+	cached_dpp->unpackUUID(fullid, "ID");
+	cached_dpp->unpackU32(local_id, "LocalID");
+	cached_dpp->unpackU8(pcode, "PCode");
+
+	objectp = findObject(fullid);
+
+	if (objectp)
+	{
+		if(!objectp->isDead() && (objectp->mLocalID != entry->getLocalID() ||
+			objectp->getRegion() != regionp))
+		{
+			removeFromLocalIDTable(objectp);
+			setUUIDAndLocal(fullid, entry->getLocalID(),
+							regionp->getHost().getAddress(),
+							regionp->getHost().getPort());
+				
+			if (objectp->mLocalID != entry->getLocalID())
+			{	// Update local ID in object with the one sent from the region
+				objectp->mLocalID = entry->getLocalID();
+			}
+			
+			if (objectp->getRegion() != regionp)
+			{	// Object changed region, so update it
+				objectp->updateRegion(regionp); // for LLVOAvatar
+			}
+		}
+
+		//return TRUE; //already loaded.
+	}
+
+	bool justCreated = false;
+	if (!objectp)
+	{
+		objectp = createObjectFromCache(pcode, regionp, fullid, entry->getLocalID());
+		
+		if (!objectp)
+		{
+			llinfos << "createObject failure for object: " << fullid << llendl;
+			recorder.objectUpdateFailure(entry->getLocalID(), OUT_FULL_CACHED, 0);
+			return NULL;
+		}
+		justCreated = true;
+		mNumNewObjects++;
+		sCacheHitRate.addValue(100.f);
+	}
+
+	if (objectp->isDead())
+	{
+		llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl;
+	}
+		
+	processUpdateCore(objectp, NULL, 0, OUT_FULL_CACHED, cached_dpp, justCreated, true);
+		
+	recorder.log(0.2f);
+	LLVOAvatar::cullAvatarsByPixelArea();
+
+	return objectp;
+}
+
 void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 											 void **user_data,
 											 const EObjectUpdateType update_type,
@@ -382,14 +476,8 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 		}
 		else if (compressed)
 		{
-			S32							uncompressed_length = 2048;
-			compressed_dp.reset();
-
-			U32 flags = 0;
-			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
-			{
-				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
-			}
+			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);
@@ -540,9 +628,15 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated);
 			if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only?
 			{
-				bCached = true;
-				LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
-				recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size);
+				U32 flags = 0;
+				mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_UpdateFlags, flags, i);
+			
+				if(!(flags & FLAGS_TEMPORARY_ON_REZ))
+				{
+					bCached = true;
+					LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp);
+					recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size);
+				}
 			}
 		}
 		else if (cached) // Cache hit only?
@@ -1887,7 +1981,30 @@ LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLVi
 	return objectp;
 }
 
+LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id)
+{
+	llassert_always(uuid.notNull());
 
+	LLViewerObject *objectp = LLViewerObject::createObject(uuid, pcode, regionp);
+	if (!objectp)
+	{
+// 		llwarns << "Couldn't create object of type " << LLPrimitive::pCodeToString(pcode) << " id:" << fullid << llendl;
+		return NULL;
+	}
+
+	objectp->mLocalID = local_id;
+	mUUIDObjectMap[uuid] = objectp;
+	setUUIDAndLocal(uuid,
+					local_id,
+					regionp->getHost().getAddress(),
+					regionp->getHost().getPort());
+	mObjects.push_back(objectp);
+	
+	updateActive(objectp);
+
+	return objectp;
+}
+ 
 LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp,
 												 const LLUUID &uuid, const U32 local_id, const LLHost &sender)
 {
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 9936432a71..1476f44215 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -40,6 +40,7 @@
 class LLCamera;
 class LLNetMap;
 class LLDebugBeacon;
+class LLVOCacheEntry;
 
 const U32 CLOSE_BIN_SIZE = 10;
 const U32 NUM_BINS = 128;
@@ -65,6 +66,7 @@ public:
 	
 	inline LLViewerObject *findObject(const LLUUID &id);
 	LLViewerObject *createObjectViewer(const LLPCode pcode, LLViewerRegion *regionp); // Create a viewer-side object
+	LLViewerObject *createObjectFromCache(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id);
 	LLViewerObject *createObject(const LLPCode pcode, LLViewerRegion *regionp,
 								 const LLUUID &uuid, const U32 local_id, const LLHost &sender);
 
@@ -78,7 +80,9 @@ public:
 	void cleanDeadObjects(const BOOL use_timer = TRUE);	// Clean up the dead object list.
 
 	// Simulator and viewer side object updates...
-	void processUpdateCore(LLViewerObject* objectp, void** data, U32 block, const EObjectUpdateType update_type, LLDataPacker* dpp, BOOL justCreated);
+	void processUpdateCore(LLViewerObject* objectp, void** data, U32 block, const EObjectUpdateType update_type, 
+		                   LLDataPacker* dpp, bool justCreated, bool from_cache = false);
+	LLViewerObject* processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp);
 	void processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type, bool cached=false, bool compressed=false);
 	void processCompressedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type);
 	void processCachedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type);
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
new file mode 100644
index 0000000000..05f977036c
--- /dev/null
+++ b/indra/newview/llvieweroctree.cpp
@@ -0,0 +1,704 @@
+/** 
+ * @file llvieweroctree.cpp
+ * @brief LLViewerOctreeGroup class implementation and supporting functions
+ *
+ * $LicenseInfo:firstyear=2003&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 "llvieweroctree.h"
+
+//-----------------------------------------------------------------------------------
+//static variables definitions
+//-----------------------------------------------------------------------------------
+U32 LLViewerOctreeEntryData::sCurVisible = 0;
+
+//-----------------------------------------------------------------------------------
+//some global functions definitions
+//-----------------------------------------------------------------------------------
+S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
+{
+	return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r)
+{
+	F32 d = 0.f;
+	F32 t;
+	
+	if ((min-origin).magVecSquared() < r &&
+		(max-origin).magVecSquared() < r)
+	{
+		return 2;
+	}
+
+	for (U32 i = 0; i < 3; i++)
+	{
+		if (origin.mV[i] < min.mV[i])
+		{
+			t = min.mV[i] - origin.mV[i];
+			d += t*t;
+		}
+		else if (origin.mV[i] > max.mV[i])
+		{
+			t = origin.mV[i] - max.mV[i];
+			d += t*t;
+		}
+
+		if (d > r)
+		{
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
+{
+	return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
+{
+	F32 d = 0.f;
+	F32 t;
+	
+	LLVector4a origina;
+	origina.load3(origin.mV);
+
+	LLVector4a v;
+	v.setSub(min, origina);
+	
+	if (v.dot3(v) < r)
+	{
+		v.setSub(max, origina);
+		if (v.dot3(v) < r)
+		{
+			return 2;
+		}
+	}
+
+
+	for (U32 i = 0; i < 3; i++)
+	{
+		if (origin.mV[i] < min[i])
+		{
+			t = min[i] - origin.mV[i];
+			d += t*t;
+		}
+		else if (origin.mV[i] > max[i])
+		{
+			t = origin.mV[i] - max[i];
+			d += t*t;
+		}
+
+		if (d > r)
+		{
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+//-----------------------------------------------------------------------------------
+//class LLViewerOctreeEntry definitions
+//-----------------------------------------------------------------------------------
+LLViewerOctreeEntry::LLViewerOctreeEntry() : mGroup(NULL)
+{
+	mPositionGroup.clear();
+	mExtents[0].clear();
+	mExtents[1].clear();
+	mBinRadius = 0.f;
+	mBinIndex = -1;
+
+	for(S32 i = 0; i < NUM_DATA_TYPE; i++)
+	{
+		mData[i] = NULL;
+	}
+}
+
+LLViewerOctreeEntry::~LLViewerOctreeEntry()
+{
+	llassert(!mGroup);
+}
+
+void LLViewerOctreeEntry::addData(LLViewerOctreeEntryData* data)
+{
+	//llassert(mData[data->getDataType()] == NULL);	
+	llassert(data != NULL);
+
+	mData[data->getDataType()] = data;
+}
+
+void LLViewerOctreeEntry::removeData(LLViewerOctreeEntryData* data)
+{
+	//llassert(data->getDataType() != LLVOCACHEENTRY); //can not remove VOCache entry
+
+	if(!mData[data->getDataType()])
+	{
+		return;
+	}
+
+	mData[data->getDataType()] = NULL;
+	
+	if(mGroup != NULL && !mData[LLDRAWABLE])
+	{
+		LLviewerOctreeGroup* group = mGroup;
+		mGroup = NULL;
+		group->removeFromGroup(data);
+
+		llassert(mBinIndex == -1);				
+	}
+}
+
+//called by group handleDestruction() ONLY when group is destroyed by octree.
+void LLViewerOctreeEntry::nullGroup()
+{
+	mGroup = NULL;
+}
+
+void LLViewerOctreeEntry::setGroup(LLviewerOctreeGroup* group)
+{
+	if(mGroup == group)
+	{
+		return;
+	}
+
+	if(mGroup)
+	{
+		LLviewerOctreeGroup* group = mGroup;
+		mGroup = NULL;
+		group->removeFromGroup(this);
+
+		llassert(mBinIndex == -1);
+	}
+
+	mGroup = group;
+}
+
+//-----------------------------------------------------------------------------------
+//class LLViewerOctreeEntryData definitions
+//-----------------------------------------------------------------------------------
+LLViewerOctreeEntryData::~LLViewerOctreeEntryData()
+{
+	if(mEntry)
+	{
+		mEntry->removeData(this);
+	}
+}
+
+LLViewerOctreeEntryData::LLViewerOctreeEntryData(LLViewerOctreeEntry::eEntryDataType_t data_type)
+	: mDataType(data_type),
+	  mEntry(NULL)
+{
+}
+
+//virtual
+void LLViewerOctreeEntryData::setOctreeEntry(LLViewerOctreeEntry* entry)
+{
+	if(mEntry.notNull())
+	{
+		return; 
+	}
+
+	if(!entry)
+	{
+		mEntry = new LLViewerOctreeEntry();
+	}
+	else
+	{
+		mEntry = entry;
+	}
+	mEntry->addData(this);
+}
+
+void LLViewerOctreeEntryData::setSpatialExtents(const LLVector3& min, const LLVector3& max)
+{ 
+	mEntry->mExtents[0].load3(min.mV); 
+	mEntry->mExtents[1].load3(max.mV);
+}
+
+void LLViewerOctreeEntryData::setSpatialExtents(const LLVector4a& min, const LLVector4a& max)
+{ 
+	mEntry->mExtents[0] = min; 
+	mEntry->mExtents[1] = max;
+}
+
+void LLViewerOctreeEntryData::setPositionGroup(const LLVector4a& pos)
+{
+	mEntry->mPositionGroup = pos;
+}
+
+const LLVector4a* LLViewerOctreeEntryData::getSpatialExtents() const 
+{
+	return mEntry->getSpatialExtents();
+}
+
+//virtual
+void LLViewerOctreeEntryData::setGroup(LLviewerOctreeGroup* group)
+{
+	mEntry->setGroup(group);
+}
+
+void LLViewerOctreeEntryData::shift(const LLVector4a &shift_vector)
+{
+	mEntry->mExtents[0].add(shift_vector);
+	mEntry->mExtents[1].add(shift_vector);
+	mEntry->mPositionGroup.add(shift_vector);
+}
+
+LLviewerOctreeGroup* LLViewerOctreeEntryData::getGroup()const        
+{
+	return mEntry.notNull() ? mEntry->mGroup : NULL;
+}
+
+const LLVector4a& LLViewerOctreeEntryData::getPositionGroup() const  
+{
+	return mEntry->getPositionGroup();
+}	
+
+//virtual
+bool LLViewerOctreeEntryData::isVisible() const
+{
+	if(mEntry)
+	{
+		return mEntry->mVisible == sCurVisible;
+	}
+	return false;
+}
+
+//virtual
+bool LLViewerOctreeEntryData::isRecentlyVisible() const
+{
+	if(!mEntry)
+	{
+		return false;
+	}
+
+	if(isVisible())
+	{
+		return true;
+	}
+	if(getGroup() && getGroup()->isRecentlyVisible())
+	{
+		setVisible();
+		return true;
+	}
+
+	return (sCurVisible - mEntry->mVisible < getMinVisFrameRange());
+}
+
+void LLViewerOctreeEntryData::setVisible() const
+{
+	if(mEntry)
+	{
+		mEntry->mVisible = sCurVisible;
+	}
+}
+
+//-----------------------------------------------------------------------------------
+//class LLviewerOctreeGroup definitions
+//-----------------------------------------------------------------------------------
+
+LLviewerOctreeGroup::~LLviewerOctreeGroup()
+{
+}
+
+LLviewerOctreeGroup::LLviewerOctreeGroup(OctreeNode* node) :
+	mOctreeNode(node),
+	mState(CLEAN)
+{
+	LLVector4a tmp;
+	tmp.splat(0.f);
+	mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = 
+		mObjectExtents[0] = mObjectExtents[1] = tmp;
+	
+	mBounds[0] = node->getCenter();
+	mBounds[1] = node->getSize();
+
+	mOctreeNode->addListener(this);
+}
+
+bool LLviewerOctreeGroup::removeFromGroup(LLViewerOctreeEntryData* data)
+{
+	return removeFromGroup(data->getEntry());
+}
+
+bool LLviewerOctreeGroup::removeFromGroup(LLViewerOctreeEntry* entry)
+{
+	llassert(entry != NULL);
+	llassert(!entry->getGroup());
+
+	unbound();
+	if (mOctreeNode)
+	{
+		if (!mOctreeNode->remove(entry))
+		{
+			OCT_ERRS << "Could not remove LLVOCacheEntry from LLVOCacheOctreeGroup" << llendl;
+			return false;
+		}
+	}
+	setState(OBJECT_DIRTY);
+
+	return true;
+}
+
+//virtual 
+void LLviewerOctreeGroup::unbound()
+{
+	if (isDirty())
+	{
+		return;
+	}
+
+	setState(DIRTY);
+	
+	//all the parent nodes need to rebound this child
+	if (mOctreeNode)
+	{
+		OctreeNode* parent = (OctreeNode*) mOctreeNode->getParent();
+		while (parent != NULL)
+		{
+			LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) parent->getListener(0);
+			if (!group || group->isDirty())
+			{
+				return;
+			}
+			
+			group->setState(DIRTY);
+			parent = (OctreeNode*) parent->getParent();
+		}
+	}
+}
+	
+//virtual 
+void LLviewerOctreeGroup::rebound()
+{
+	if (!isDirty())
+	{	
+		return;
+	}
+	
+	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
+	{
+		LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) mOctreeNode->getChild(0)->getListener(0);
+		group->rebound();
+		
+		//copy single child's bounding box
+		mBounds[0] = group->mBounds[0];
+		mBounds[1] = group->mBounds[1];
+		mExtents[0] = group->mExtents[0];
+		mExtents[1] = group->mExtents[1];
+		
+		group->setState(SKIP_FRUSTUM_CHECK);
+	}
+	else if (mOctreeNode->isLeaf())
+	{ //copy object bounding box if this is a leaf
+		boundObjects(TRUE, mExtents[0], mExtents[1]);
+		mBounds[0] = mObjectBounds[0];
+		mBounds[1] = mObjectBounds[1];
+	}
+	else
+	{
+		LLVector4a& newMin = mExtents[0];
+		LLVector4a& newMax = mExtents[1];
+		LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) mOctreeNode->getChild(0)->getListener(0);
+		group->clearState(SKIP_FRUSTUM_CHECK);
+		group->rebound();
+		//initialize to first child
+		newMin = group->mExtents[0];
+		newMax = group->mExtents[1];
+
+		//first, rebound children
+		for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
+		{
+			group = (LLviewerOctreeGroup*) mOctreeNode->getChild(i)->getListener(0);
+			group->clearState(SKIP_FRUSTUM_CHECK);
+			group->rebound();
+			const LLVector4a& max = group->mExtents[1];
+			const LLVector4a& min = group->mExtents[0];
+
+			newMax.setMax(newMax, max);
+			newMin.setMin(newMin, min);
+		}
+
+		boundObjects(FALSE, newMin, newMax);
+		
+		mBounds[0].setAdd(newMin, newMax);
+		mBounds[0].mul(0.5f);
+		mBounds[1].setSub(newMax, newMin);
+		mBounds[1].mul(0.5f);
+	}
+	
+	clearState(DIRTY);
+
+	return;
+}
+
+//virtual 
+void LLviewerOctreeGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* obj)
+{
+	obj->setGroup(this);	
+	unbound();
+	setState(OBJECT_DIRTY);
+}
+	
+//virtual 
+void LLviewerOctreeGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* obj)
+{
+	obj->setGroup(NULL);
+	unbound();
+	setState(OBJECT_DIRTY);
+}
+	
+//virtual 
+void LLviewerOctreeGroup::handleDestruction(const TreeNode* node)
+{
+	for (OctreeNode::element_iter i = mOctreeNode->getDataBegin(); i != mOctreeNode->getDataEnd(); ++i)
+	{
+		LLViewerOctreeEntry* obj = *i;
+		if (obj && obj->getGroup() == this)
+		{
+			obj->nullGroup();
+		}
+	}
+}
+	
+//virtual 
+void LLviewerOctreeGroup::handleStateChange(const TreeNode* node)
+{
+	//drop bounding box upon state change
+	if (mOctreeNode != node)
+	{
+		mOctreeNode = (OctreeNode*) node;
+	}
+	unbound();
+}
+	
+//virtual 
+void LLviewerOctreeGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)
+{
+	llerrs << "can not access here. It is an abstract class." << llendl;
+
+	//((LLviewerOctreeGroup*)child->getListener(0))->unbound();
+}
+	
+//virtual 
+void LLviewerOctreeGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNode* child)
+{
+	unbound();
+}
+
+LLviewerOctreeGroup* LLviewerOctreeGroup::getParent()
+{
+	if(!mOctreeNode)
+	{
+		return NULL;
+	}
+	
+	OctreeNode* parent = mOctreeNode->getOctParent();
+
+	if (parent)
+	{
+		return (LLviewerOctreeGroup*) parent->getListener(0);
+	}
+
+	return NULL;
+}
+
+//virtual 
+bool LLviewerOctreeGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
+{
+	const OctreeNode* node = mOctreeNode;
+
+	if (node->isEmpty())
+	{	//don't do anything if there are no objects
+		if (empty && mOctreeNode->getParent())
+		{	//only root is allowed to be empty
+			OCT_ERRS << "Empty leaf found in octree." << llendl;
+		}
+		return false;
+	}
+
+	LLVector4a& newMin = mObjectExtents[0];
+	LLVector4a& newMax = mObjectExtents[1];
+	
+	if (hasState(OBJECT_DIRTY))
+	{ //calculate new bounding box
+		clearState(OBJECT_DIRTY);
+
+		//initialize bounding box to first element
+		OctreeNode::const_element_iter i = node->getDataBegin();
+		LLViewerOctreeEntry* entry = *i;
+		const LLVector4a* minMax = entry->getSpatialExtents();
+
+		newMin = minMax[0];
+		newMax = minMax[1];
+
+		for (++i; i != node->getDataEnd(); ++i)
+		{
+			entry = *i;
+			minMax = entry->getSpatialExtents();
+			
+			update_min_max(newMin, newMax, minMax[0]);
+			update_min_max(newMin, newMax, minMax[1]);
+		}
+		
+		mObjectBounds[0].setAdd(newMin, newMax);
+		mObjectBounds[0].mul(0.5f);
+		mObjectBounds[1].setSub(newMax, newMin);
+		mObjectBounds[1].mul(0.5f);
+	}
+	
+	if (empty)
+	{
+		minOut = newMin;
+		maxOut = newMax;
+	}
+	else
+	{
+		minOut.setMin(minOut, newMin);
+		maxOut.setMax(maxOut, newMax);
+	}
+		
+	return TRUE;
+}
+
+//virtual 
+BOOL LLviewerOctreeGroup::isVisible() const
+{
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------------
+//class LLViewerOctreeCull definitions
+//-----------------------------------------------------------------------------------
+
+//virtual 
+bool LLViewerOctreeCull::earlyFail(LLviewerOctreeGroup* group)
+{	
+	return false;
+}
+	
+//virtual 
+void LLViewerOctreeCull::traverse(const OctreeNode* n)
+{
+	LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) n->getListener(0);
+
+	if (earlyFail(group))
+	{
+		return;
+	}
+		
+	if (mRes == 2 || 
+		(mRes && group->hasState(LLviewerOctreeGroup::SKIP_FRUSTUM_CHECK)))
+	{	//fully in, just add everything
+		OctreeTraveler::traverse(n);
+	}
+	else
+	{
+		mRes = frustumCheck(group);
+				
+		if (mRes)
+		{ //at least partially in, run on down
+			OctreeTraveler::traverse(n);
+		}
+
+		mRes = 0;
+	}
+}
+	
+S32 LLViewerOctreeCull::AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+}
+
+S32 LLViewerOctreeCull::AABBSphereIntersectGroupExtents(const LLviewerOctreeGroup* group)
+{
+	return AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist);
+}
+
+S32 LLViewerOctreeCull::AABBInFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+}
+
+S32 LLViewerOctreeCull::AABBSphereIntersectObjectExtents(const LLviewerOctreeGroup* group)
+{
+	return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist);
+}
+
+S32 LLViewerOctreeCull::AABBInFrustumGroupBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+}
+
+S32 LLViewerOctreeCull::AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+}
+
+//virtual 
+bool LLViewerOctreeCull::checkObjects(const OctreeNode* branch, const LLviewerOctreeGroup* group)
+{
+	if (branch->getElementCount() == 0) //no elements
+	{
+		return false;
+	}
+	else if (branch->getChildCount() == 0) //leaf state, already checked tightest bounding box
+	{
+		return true;
+	}
+	else if (mRes == 1 && !frustumCheckObjects(group)) //no objects in frustum
+	{
+		return false;
+	}
+		
+	return true;
+}
+
+//virtual 
+void LLViewerOctreeCull::preprocess(LLviewerOctreeGroup* group)
+{		
+}
+	
+//virtual 
+void LLViewerOctreeCull::processGroup(LLviewerOctreeGroup* group)
+{
+}
+	
+//virtual 
+void LLViewerOctreeCull::visit(const OctreeNode* branch) 
+{	
+	LLviewerOctreeGroup* group = (LLviewerOctreeGroup*) branch->getListener(0);
+
+	preprocess(group);
+		
+	if (checkObjects(branch, group))
+	{
+		processGroup(group);
+	}
+}
+
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
new file mode 100644
index 0000000000..c063e96ea5
--- /dev/null
+++ b/indra/newview/llvieweroctree.h
@@ -0,0 +1,274 @@
+/** 
+ * @file llvieweroctree.h
+ * @brief LLViewerObjectOctree.cpp header file, defining all supporting classes.
+ *
+ * $LicenseInfo:firstyear=2002&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_VIEWEROCTREE_H
+#define LL_VIEWEROCTREE_H
+
+#include <vector>
+#include <map>
+
+#include "v2math.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "m4math.h"
+#include "llvector4a.h"
+#include "llquaternion.h"
+#include "lloctree.h"
+#include "llcamera.h"
+
+class LLViewerOctreeEntryData;
+class LLviewerOctreeGroup;
+class LLViewerOctreeEntry;
+
+typedef LLOctreeListener<LLViewerOctreeEntry>	OctreeListener;
+typedef LLTreeNode<LLViewerOctreeEntry>			TreeNode;
+typedef LLOctreeNode<LLViewerOctreeEntry>		OctreeNode;
+typedef LLOctreeRoot<LLViewerOctreeEntry>		OctreeRoot;
+typedef LLOctreeTraveler<LLViewerOctreeEntry>	OctreeTraveler;
+
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad);
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared);
+
+S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
+S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);
+
+//defines data needed for octree of an entry
+LL_ALIGN_PREFIX(16)
+class LLViewerOctreeEntry : public LLRefCount
+{
+	friend class LLViewerOctreeEntryData;
+
+public:
+	typedef enum
+	{
+		LLDRAWABLE = 0,
+		LLVOCACHEENTRY,
+		NUM_DATA_TYPE
+	}eEntryDataType_t;
+
+	~LLViewerOctreeEntry();
+public:
+	LLViewerOctreeEntry();
+	
+	void nullGroup(); //called by group handleDestruction() only
+	void setGroup(LLviewerOctreeGroup* group);
+	void removeData(LLViewerOctreeEntryData* data);
+
+	LLViewerOctreeEntryData* getData(U32 data_type)const {return mData[data_type];}
+	bool                     hasData(U32 data_type)const {return mData[data_type] != NULL;}
+
+	LLViewerOctreeEntryData* getDrawable() const {return mData[LLDRAWABLE];}
+	bool                     hasDrawable() const {return mData[LLDRAWABLE] != NULL;}
+	LLViewerOctreeEntryData* getVOCacheEntry() const {return mData[LLVOCACHEENTRY];}
+	bool                     hasVOCacheEntry() const {return mData[LLVOCACHEENTRY] != NULL;}
+
+	const LLVector4a* getSpatialExtents() const {return mExtents;} 
+	const LLVector4a& getPositionGroup() const  {return mPositionGroup;}	
+	LLviewerOctreeGroup* getGroup()const        {return mGroup;}
+	
+	F32  getBinRadius() const                   {return mBinRadius;}
+	S32	 getBinIndex() const			        {return mBinIndex; }
+	void setBinIndex(S32 index) const	        {mBinIndex = index; }
+
+private:
+	void addData(LLViewerOctreeEntryData* data);			
+
+private:
+	LLViewerOctreeEntryData*    mData[NUM_DATA_TYPE]; //do not use LLPointer here.
+	LLviewerOctreeGroup*        mGroup;
+
+	//aligned members
+	LL_ALIGN_16(LLVector4a		mExtents[2]);
+	LL_ALIGN_16(LLVector4a		mPositionGroup);
+	F32				            mBinRadius;
+	mutable S32		            mBinIndex;
+	mutable U32		            mVisible;	
+
+} LL_ALIGN_POSTFIX(16);
+
+//defines an abstract class for entry data
+LL_ALIGN_PREFIX(16)
+class LLViewerOctreeEntryData : public LLRefCount
+{
+protected:
+	~LLViewerOctreeEntryData();
+
+public:
+	LLViewerOctreeEntryData(const LLViewerOctreeEntryData& rhs)
+	{
+		*this = rhs;
+	}
+	LLViewerOctreeEntryData(LLViewerOctreeEntry::eEntryDataType_t data_type);
+	
+	LLViewerOctreeEntry::eEntryDataType_t getDataType() const {return mDataType;}
+	LLViewerOctreeEntry* getEntry() {return mEntry;}
+	
+	virtual void setOctreeEntry(LLViewerOctreeEntry* entry);
+
+	virtual S32  getMinVisFrameRange()const = 0;
+
+	F32                  getBinRadius() const   {return mEntry->getBinRadius();}
+	const LLVector4a*    getSpatialExtents() const;
+	LLviewerOctreeGroup* getGroup()const;
+	const LLVector4a&    getPositionGroup() const;
+
+	void setBinRadius(F32 rad)  {mEntry->mBinRadius = rad;}
+	void setSpatialExtents(const LLVector3& min, const LLVector3& max);
+	void setSpatialExtents(const LLVector4a& min, const LLVector4a& max);
+	void setPositionGroup(const LLVector4a& pos);
+	
+	virtual void setGroup(LLviewerOctreeGroup* group);
+	void         shift(const LLVector4a &shift_vector);
+
+	U32          getVisible() const {return mEntry ? mEntry->mVisible : 0;}
+	void         setVisible() const;
+	virtual bool isVisible() const;
+	virtual bool isRecentlyVisible() const;	
+	
+	static S32 getCurrentFrame() { return sCurVisible; }
+
+protected:
+	LLVector4a& getGroupPosition()  {return mEntry->mPositionGroup;}
+	void        initVisible(U32 visible) {mEntry->mVisible = visible;}
+
+	static void incrementVisible() {sCurVisible++;}
+protected:
+	LLPointer<LLViewerOctreeEntry>        mEntry;
+	LLViewerOctreeEntry::eEntryDataType_t mDataType;
+	static  U32                           sCurVisible; // Counter for what value of mVisible means currently visible
+}LL_ALIGN_POSTFIX(16);
+
+
+//defines an octree group for an octree node, which contains multiple entries.
+LL_ALIGN_PREFIX(16)
+class LLviewerOctreeGroup : public LLOctreeListener<LLViewerOctreeEntry>
+{
+	friend class LLViewerOctreeCull;
+protected:
+	~LLviewerOctreeGroup();
+
+public:
+	enum
+	{
+		CLEAN              = 0x00000000,
+		DIRTY              = 0x00000001,
+		OBJECT_DIRTY       = 0x00000002,
+		SKIP_FRUSTUM_CHECK = 0x00000004,
+		INVALID_STATE      = 0x00000008,
+	};
+
+public:
+	LLviewerOctreeGroup(OctreeNode* node);
+	LLviewerOctreeGroup(const LLviewerOctreeGroup& rhs)
+	{
+		*this = rhs;
+	}
+
+	void* operator new(size_t size)
+	{
+		return ll_aligned_malloc_16(size);
+	}
+
+	void operator delete(void* ptr)
+	{
+		ll_aligned_free_16(ptr);
+	}
+
+	bool removeFromGroup(LLViewerOctreeEntryData* data);
+	bool removeFromGroup(LLViewerOctreeEntry* entry);
+
+	virtual void unbound();
+	virtual void rebound();
+
+	virtual BOOL isVisible() const;
+	virtual BOOL isRecentlyVisible() const = 0;
+
+	U32  getState()				   {return mState; }
+	bool isDirty() const           {return mState & DIRTY;}
+	bool hasState(U32 state) const {return mState & state;}
+	void setState(U32 state)       {mState |= state;}
+	void clearState(U32 state)     {mState &= ~state;}	
+
+	//LISTENER FUNCTIONS
+	virtual void handleInsertion(const TreeNode* node, LLViewerOctreeEntry* obj);
+	virtual void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* obj);
+	virtual void handleDestruction(const TreeNode* node);
+	virtual void handleStateChange(const TreeNode* node);
+	virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
+	virtual void handleChildRemoval(const OctreeNode* parent, const OctreeNode* child);
+
+	OctreeNode*          getOctreeNode() {return mOctreeNode;}
+	LLviewerOctreeGroup* getParent();
+
+	const LLVector4a* getBounds() const        {return mBounds;}
+	const LLVector4a* getExtents() const       {return mExtents;}
+	const LLVector4a* getObjectBounds() const  {return mObjectBounds;}
+	const LLVector4a* getObjectExtents() const {return mObjectExtents;}
+
+private:
+	virtual bool boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut);	
+	
+protected:
+	U32         mState;
+	OctreeNode* mOctreeNode;
+	
+	LL_ALIGN_16(LLVector4a mBounds[2]);       // bounding box (center, size) of this node and all its children (tight fit to objects)
+	LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node
+	LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
+	LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node
+
+}LL_ALIGN_POSTFIX(16);
+
+class LLViewerOctreeCull : public OctreeTraveler
+{
+public:
+	LLViewerOctreeCull(LLCamera* camera)
+		: mCamera(camera), mRes(0) { }
+
+	virtual bool earlyFail(LLviewerOctreeGroup* group);
+	virtual void traverse(const OctreeNode* n);
+	
+	S32 AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group);
+	S32 AABBSphereIntersectGroupExtents(const LLviewerOctreeGroup* group);
+	S32 AABBInFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group);
+	S32 AABBSphereIntersectObjectExtents(const LLviewerOctreeGroup* group);
+	S32 AABBInFrustumGroupBounds(const LLviewerOctreeGroup* group);
+	S32 AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group);
+	
+	virtual S32 frustumCheck(const LLviewerOctreeGroup* group) = 0;
+	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group) = 0;
+
+	virtual bool checkObjects(const OctreeNode* branch, const LLviewerOctreeGroup* group);
+	virtual void preprocess(LLviewerOctreeGroup* group);
+	virtual void processGroup(LLviewerOctreeGroup* group);
+	virtual void visit(const OctreeNode* branch);
+	
+protected:
+	LLCamera *mCamera;
+	S32 mRes;
+};
+
+#endif
\ No newline at end of file
diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index 6bd9f66b9c..8acdc08b00 100644
--- a/indra/newview/llviewerpartsim.cpp
+++ b/indra/newview/llviewerpartsim.cpp
@@ -151,8 +151,8 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 &center_agent, const F32 bo
 
 	if (group != NULL)
 	{
-		LLVector3 center(group->mOctreeNode->getCenter().getF32ptr());
-		LLVector3 size(group->mOctreeNode->getSize().getF32ptr());
+		LLVector3 center(group->getOctreeNode()->getCenter().getF32ptr());
+		LLVector3 size(group->getOctreeNode()->getSize().getF32ptr());
 		size += LLVector3(0.01f, 0.01f, 0.01f);
 		mMinObjPos = center - size;
 		mMaxObjPos = center + size;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 31e3820a21..15c95aa30a 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -70,6 +70,7 @@
 #include "stringize.h"
 #include "llviewercontrol.h"
 #include "llsdserialize.h"
+#include "llvieweroctree.h"
 
 #ifdef LL_WINDOWS
 	#pragma warning(disable:4355)
@@ -133,7 +134,14 @@ public:
 	// Misc
 	LLVLComposition *mCompositionp;		// Composition layer for the surface
 
-	LLVOCacheEntry::vocache_entry_map_t		mCacheMap;
+	LLVOCacheEntry::vocache_entry_map_t	mCacheMap; //all cached entries
+	LLVOCacheEntry::vocache_entry_set_t mActiveSet; //all active entries;
+	LLVOCacheEntry::vocache_entry_set_t mWaitingSet; //entries waiting for LLDrawable to be generated.
+	LLVOCacheEntry::vocache_entry_set_t mVisibleEntries; //visible root entries of a linked set.
+	std::set< LLPointer<LLVOCacheEntry> > mDummyEntries; //dummy vo cache entries, for LLSpatialBridge use.
+	std::set< LLSpatialGroup* >         mVisibleGroups; //visible llspatialgroup
+	LLVOCachePartition*                 mVOCachePartition;
+
 	// time?
 	// LRU info?
 
@@ -291,7 +299,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mCacheLoaded(FALSE),
 	mCacheDirty(FALSE),
 	mReleaseNotesRequested(FALSE),
-	mCapabilitiesReceived(false)
+	mCapabilitiesReceived(false),
+	mDead(FALSE)
 {
 	mWidth = region_width_meters;
 	mImpl->mOriginGlobal = from_region_handle(handle); 
@@ -323,17 +332,20 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 
 	//create object partitions
 	//MUST MATCH declaration of eObjectPartitions
-	mImpl->mObjectPartition.push_back(new LLHUDPartition());		//PARTITION_HUD
-	mImpl->mObjectPartition.push_back(new LLTerrainPartition());	//PARTITION_TERRAIN
-	mImpl->mObjectPartition.push_back(new LLVoidWaterPartition());	//PARTITION_VOIDWATER
-	mImpl->mObjectPartition.push_back(new LLWaterPartition());		//PARTITION_WATER
-	mImpl->mObjectPartition.push_back(new LLTreePartition());		//PARTITION_TREE
-	mImpl->mObjectPartition.push_back(new LLParticlePartition());	//PARTITION_PARTICLE
-	mImpl->mObjectPartition.push_back(new LLGrassPartition());		//PARTITION_GRASS
-	mImpl->mObjectPartition.push_back(new LLVolumePartition());	//PARTITION_VOLUME
-	mImpl->mObjectPartition.push_back(new LLBridgePartition());	//PARTITION_BRIDGE
-	mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE
+	mImpl->mObjectPartition.push_back(new LLHUDPartition(this));		//PARTITION_HUD
+	mImpl->mObjectPartition.push_back(new LLTerrainPartition(this));	//PARTITION_TERRAIN
+	mImpl->mObjectPartition.push_back(new LLVoidWaterPartition(this));	//PARTITION_VOIDWATER
+	mImpl->mObjectPartition.push_back(new LLWaterPartition(this));		//PARTITION_WATER
+	mImpl->mObjectPartition.push_back(new LLTreePartition(this));		//PARTITION_TREE
+	mImpl->mObjectPartition.push_back(new LLParticlePartition(this));	//PARTITION_PARTICLE
+	mImpl->mObjectPartition.push_back(new LLGrassPartition(this));		//PARTITION_GRASS
+	mImpl->mObjectPartition.push_back(new LLVolumePartition(this));	//PARTITION_VOLUME
+	mImpl->mObjectPartition.push_back(new LLBridgePartition(this));	//PARTITION_BRIDGE
+	mImpl->mObjectPartition.push_back(new LLHUDParticlePartition(this));//PARTITION_HUD_PARTICLE
+	mImpl->mObjectPartition.push_back(new LLVOCachePartition(this)); //PARTITION_VO_CACHE
 	mImpl->mObjectPartition.push_back(NULL);						//PARTITION_NONE
+
+	mImpl->mVOCachePartition = (LLVOCachePartition*)getSpatialPartition(PARTITION_VO_CACHE);
 }
 
 
@@ -354,6 +366,12 @@ void LLViewerRegion::initStats()
 
 LLViewerRegion::~LLViewerRegion() 
 {
+	mDead = TRUE;
+	mImpl->mActiveSet.clear();
+	mImpl->mVisibleEntries.clear();
+	mImpl->mVisibleGroups.clear();
+	mImpl->mWaitingSet.clear();
+
 	gVLManager.cleanupData(this);
 	// Can't do this on destruction, because the neighbor pointers might be invalid.
 	// This should be reference counted...
@@ -437,10 +455,6 @@ void LLViewerRegion::saveObjectCache()
 		mCacheDirty = FALSE;
 	}
 
-	for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter)
-	{
-		delete iter->second;
-	}
 	mImpl->mCacheMap.clear();
 }
 
@@ -718,8 +732,199 @@ void LLViewerRegion::dirtyHeights()
 	}
 }
 
+void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry)
+{
+	LLPointer<LLViewerOctreeEntry> oct_entry;
+	U32 state = LLVOCacheEntry::INACTIVE;
+
+	if(old_entry)
+	{
+		oct_entry = old_entry->getEntry();
+		state = old_entry->getState();		
+
+		while(old_entry->getNumOfChildren() > 0)
+		{
+			new_entry->addChild(old_entry->getNextChild());
+		}
+
+		killCacheEntry(old_entry);
+	}
+
+	mImpl->mCacheMap[new_entry->getLocalID()] = new_entry;
+	if(oct_entry.notNull())
+	{
+		new_entry->setOctreeEntry(oct_entry);
+	}
+
+	if(state == LLVOCacheEntry::ACTIVE)
+	{
+		llassert(new_entry->getEntry()->hasDrawable());
+		mImpl->mActiveSet.insert(new_entry);
+	}
+	else if(state == LLVOCacheEntry::WAITING)
+	{
+		mImpl->mWaitingSet.insert(new_entry);
+	}
+	else if(old_entry && oct_entry)
+	{
+		addToVOCacheTree(new_entry);
+	}
+	new_entry->setState(state);
+}
+
+//physically delete the cache entry
+void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry)
+{	
+	if(!entry)
+	{
+		return;
+	}
+
+	//1, remove from active list and waiting list
+	if(entry->isState(LLVOCacheEntry::ACTIVE))
+	{
+		mImpl->mActiveSet.erase(entry);
+	}
+	else if(entry->isState(LLVOCacheEntry::WAITING))
+	{
+		mImpl->mWaitingSet.erase(entry);
+	}	
+
+	//2, kill LLViewerObject if exists
+	//this should be done by the rendering pipeline automatically.
+
+	//3, remove from mVOCachePartition
+	if(entry->isState(LLVOCacheEntry::INACTIVE) && entry->getEntry())
+	{
+		removeFromVOCacheTree(entry);
+	}
+
+	entry->setState(LLVOCacheEntry::INACTIVE);
+	//4, remove from mCacheMap, real deletion
+	mImpl->mCacheMap.erase(entry->getLocalID());
+}
+
+//physically delete the cache entry	
+void LLViewerRegion::killCacheEntry(U32 local_id) 
+{
+	killCacheEntry(getCacheEntry(local_id));
+}
+
+U32 LLViewerRegion::getNumOfActiveCachedObjects() const
+{
+	return  mImpl->mActiveSet.size();
+}
+
+void LLViewerRegion::addActiveCacheEntry(LLVOCacheEntry* entry)
+{
+	if(!entry || mDead)
+	{
+		return;
+	}
+
+	if(entry->isState(LLVOCacheEntry::WAITING))
+	{
+		mImpl->mWaitingSet.erase(entry);
+	}
+
+	entry->setState(LLVOCacheEntry::ACTIVE);
+	entry->setVisible();
+
+	llassert(entry->getEntry()->hasDrawable());
+	mImpl->mActiveSet.insert(entry);
+}
+
+void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep)
+{
+	if(mDead)
+	{
+		return;
+	}
+	if(entry->isDummy())
+	{
+		mImpl->mDummyEntries.insert(entry); //keep a copy to prevent from being deleted.
+		addToVOCacheTree(entry);
+	}
+	else if(!drawablep->getParent()) //root node
+	{
+		addToVOCacheTree(entry);
+		mImpl->mVisibleEntries.erase(entry);
+	}
+	else //child node
+	{
+		LLViewerOctreeEntry* parent_oct_entry = drawablep->getParent()->getEntry();
+		if(parent_oct_entry && parent_oct_entry->hasVOCacheEntry())
+		{
+			LLVOCacheEntry* parent = (LLVOCacheEntry*)parent_oct_entry->getVOCacheEntry();
+			parent->addChild(entry);
+		}
+	}
+
+	mImpl->mActiveSet.erase(entry);
+	mImpl->mWaitingSet.erase(entry);
+	entry->setState(LLVOCacheEntry::INACTIVE);
+}
+
+void LLViewerRegion::addVisibleGroup(LLSpatialGroup* group)
+{
+	if(mDead || group->isEmpty() || group->isDead())
+	{
+		return;
+	}
+
+	mImpl->mVisibleGroups.insert(group);
+}
+
+void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry)
+{
+	static BOOL vo_cache_culling_enabled = gSavedSettings.getBOOL("ObjectCacheViewCullingEnabled");
+
+	if(mDead || !entry || !entry->getEntry())
+	{
+		return;
+	}
+	llassert(!entry->getGroup());
+
+	mImpl->mVOCachePartition->addEntry(entry->getEntry());
+}
+
+void LLViewerRegion::removeFromVOCacheTree(LLVOCacheEntry* entry)
+{
+	if(mDead || !entry || !entry->getEntry())
+	{
+		return;
+	}
+
+	mImpl->mVOCachePartition->removeEntry(entry->getEntry());
+}
+
+//add the visible root entry of a linked set
+void LLViewerRegion::addVisibleCacheEntry(LLVOCacheEntry* entry)
+{
+	if(mDead || !entry || !entry->getNumOfChildren())
+	{
+		return; //no child entries
+	}
+
+	mImpl->mVisibleEntries.insert(entry);
+}
+
+void LLViewerRegion::clearVisibleGroup(LLSpatialGroup* group)
+{
+	if(mDead)
+	{
+		return;
+	}
+
+	llassert(!group->getOctreeNode() || group->isEmpty());
+
+	mImpl->mVisibleGroups.erase(group);
+}
+
 BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 {
+	LLTimer update_timer;
+
 	// did_update returns TRUE if we did at least one significant update
 	BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time);
 	
@@ -729,9 +934,168 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 		mParcelOverlay->idleUpdate();
 	}
 
+	if(update_timer.getElapsedTimeF32() > max_update_time)
+	{
+		return did_update;
+	}
+
+	//kill invisible objects
+	std::vector<LLDrawable*> delete_list;
+	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin();
+		iter != mImpl->mActiveSet.end(); ++iter)
+	{
+		if(!(*iter)->isRecentlyVisible())
+		{
+			killObject((*iter), delete_list);
+		}
+	}
+	for(S32 i = 0; i < delete_list.size(); i++)
+	{
+		gObjectList.killObject(delete_list[i]->getVObj());
+	}
+	delete_list.clear();
+
+	bool timeout = false;
+	S32 new_object_count = 64; //minimum number of new objects to be added
+	//add childrens of visible objects to the rendering pipeline
+	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();)
+	{
+		LLVOCacheEntry* entry = *iter;				
+		LLVOCacheEntry* child = entry->getNextChild();
+		while(child != NULL)
+		{
+			if(child->isState(LLVOCacheEntry::INACTIVE))
+			{
+				addNewObject(child);
+				
+				if(new_object_count-- < 0 && update_timer.getElapsedTimeF32() > max_update_time)
+				{
+					timeout = true;
+					break;
+				}
+			}
+			child = entry->getNextChild();
+		}
+		if(!child)
+		{
+			if(entry->isDummy())
+			{
+				mImpl->mDummyEntries.erase(entry);
+			}
+
+			iter = mImpl->mVisibleEntries.erase(iter);
+		}
+		else
+		{
+			break; //timeout
+		}
+	}
+	if(timeout)
+	{
+		mImpl->mVisibleGroups.clear();
+		return did_update;
+	}
+
+	//add objects in the visible groups to the rendering pipeline
+	std::set< LLSpatialGroup* >::iterator group_iter = mImpl->mVisibleGroups.begin();
+	while(group_iter != mImpl->mVisibleGroups.end())
+	{
+		LLSpatialGroup* group = *group_iter;
+		if(!group->getOctreeNode() || group->isEmpty())
+		{
+			mImpl->mVisibleGroups.erase(group_iter);
+			group_iter = mImpl->mVisibleGroups.begin();
+			continue;
+		}
+
+		std::vector<LLViewerOctreeEntry*> entry_list;
+		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+		{
+			//group data contents could change during creating new objects, so copy all contents first.
+			entry_list.push_back(*i);
+		}
+		
+		for(S32 i = 0; i < entry_list.size(); i++)
+		{
+			LLViewerOctreeEntry* entry = entry_list[i];
+			if(entry && entry->hasVOCacheEntry())
+			{
+				LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)entry->getVOCacheEntry();
+				if(vo_entry->isDummy())
+				{
+					addVisibleCacheEntry(vo_entry); //for LLSpatialBridge.
+				}
+				else if(vo_entry->isState(LLVOCacheEntry::INACTIVE))
+				{
+					addNewObject(vo_entry);
+					if(new_object_count-- < 0 && update_timer.getElapsedTimeF32() > max_update_time)
+					{
+						timeout = true;
+						break;
+					}
+				}
+			}
+		}
+		entry_list.clear();
+
+		if(timeout)
+		{
+			break;
+		}
+		mImpl->mVisibleGroups.erase(group);
+		group_iter = mImpl->mVisibleGroups.begin();
+	}
+	mImpl->mVisibleGroups.clear();
+
 	return did_update;
 }
 
+void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list)
+{
+	//kill the object.
+	LLDrawable* drawablep = (LLDrawable*)entry->getEntry()->getDrawable();
+	llassert(drawablep);
+
+	if(!drawablep->getParent())
+	{
+		LLViewerObject::const_child_list_t& child_list = drawablep->getVObj()->getChildren();
+		for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+			iter != child_list.end(); iter++)
+		{
+			LLViewerObject* child = *iter;
+			if(child->mDrawable->isRecentlyVisible())
+			{
+				//set the parent group visible if any of its children visible.
+				drawablep->getSpatialGroup()->setVisible();
+				return;
+			}
+		}
+		delete_list.push_back(drawablep);				
+	}				
+}
+
+LLViewerObject* LLViewerRegion::addNewObject(LLVOCacheEntry* entry)
+{
+	LLViewerObject* obj = NULL;
+	if(!entry->getEntry()->hasDrawable()) //not added to the rendering pipeline yet
+	{
+		//add the object
+		obj = gObjectList.processObjectUpdateFromCache(entry, this);
+		if(obj)
+		{
+			if(!entry->isState(LLVOCacheEntry::ACTIVE))
+			{
+				mImpl->mWaitingSet.insert(entry);
+				entry->setState(LLVOCacheEntry::WAITING);
+			}
+		}
+	}
+	else
+	{
+		llerrs << "Object is already created." << llendl;
+	}
+	return obj;
+}
 
 // As above, but forcibly do the update.
 void LLViewerRegion::forceUpdate()
@@ -1191,8 +1555,9 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 {
 	U32 local_id = objectp->getLocalID();
 	U32 crc = objectp->getCRC();
+	eCacheUpdateResult result;
 
-	LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL);
+	LLVOCacheEntry* entry = getCacheEntry(local_id);
 
 	if (entry)
 	{
@@ -1201,41 +1566,79 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 		{
 			// Record a hit
 			entry->recordDupe();
-			return CACHE_UPDATE_DUPE;
+			result = CACHE_UPDATE_DUPE;
 		}
+		else
+		{
+			// Update the cache entry
+			LLPointer<LLVOCacheEntry> new_entry = new LLVOCacheEntry(local_id, crc, dp);
+			replaceCacheEntry(entry, new_entry);
+			entry = new_entry;
 
-		// Update the cache entry
-		mImpl->mCacheMap.erase(local_id);
-		delete entry;
+			result = CACHE_UPDATE_CHANGED;
+		}
+	}
+	else
+	{
+		// 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;
-		return CACHE_UPDATE_CHANGED;
 	}
 
-	// we haven't seen this object before
-
-	// Create new entry and add to map
-	eCacheUpdateResult result = CACHE_UPDATE_ADDED;
-	if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
+	if(objectp->mDrawable.notNull() && !entry->getEntry())
 	{
-		delete mImpl->mCacheMap.begin()->second ;
-		mImpl->mCacheMap.erase(mImpl->mCacheMap.begin());
-		result = CACHE_UPDATE_REPLACED;
-		
+		entry->setOctreeEntry(objectp->mDrawable->getEntry());
+	}
+	if(entry->getEntry() && entry->getEntry()->hasDrawable() && entry->isState(LLVOCacheEntry::INACTIVE))
+	{
+		addActiveCacheEntry(entry);
 	}
-	entry = new LLVOCacheEntry(local_id, crc, dp);
 
-	mImpl->mCacheMap[local_id] = entry;
 	return result;
 }
 
+LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id)
+{
+	static BOOL vo_cache_culling_enabled = gSavedSettings.getBOOL("ObjectCacheViewCullingEnabled");
+
+	if(!vo_cache_culling_enabled)
+	{
+		return NULL;
+	}
+
+	LLVOCacheEntry* entry = getCacheEntry(local_id);
+	removeFromVOCacheTree(entry);
+
+	return entry;
+}
+
+LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id)
+{
+	LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.find(local_id);
+	if(iter != mImpl->mCacheMap.end())
+	{
+		return iter->second;
+	}
+	return NULL;
+}
+
 // Get data packer for this object, if we have cached data
 // AND the CRC matches. JC
 LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
 {
 	//llassert(mCacheLoaded);  This assert failes often, changing to early-out -- davep, 2010/10/18
 
-	LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL);
+	LLVOCacheEntry* entry = getCacheEntry(local_id);
 
 	if (entry)
 	{
@@ -1244,20 +1647,21 @@ LLDataPacker *LLViewerRegion::getDP(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;
+
 			return entry->getDP(crc);
 		}
 		else
 		{
 			// llinfos << "CRC miss for " << local_id << llendl;
-		cache_miss_type = CACHE_MISS_TYPE_CRC;
+			cache_miss_type = CACHE_MISS_TYPE_CRC;
 			mCacheMissCRC.put(local_id);
 		}
 	}
 	else
 	{
 		// llinfos << "Cache miss for " << local_id << llendl;
-	cache_miss_type = CACHE_MISS_TYPE_FULL;
+		cache_miss_type = CACHE_MISS_TYPE_FULL;
 		mCacheMissFull.put(local_id);
 	}
 
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index c9fffaf30e..17654a8bc7 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -66,7 +66,8 @@ class LLDataPacker;
 class LLDataPackerBinaryBuffer;
 class LLHost;
 class LLBBox;
-
+class LLSpatialGroup;
+class LLDrawable;
 class LLViewerRegionImpl;
 
 class LLViewerRegion: public LLCapabilityProvider // implements this interface
@@ -85,6 +86,7 @@ public:
 		PARTITION_VOLUME,
 		PARTITION_BRIDGE,
 		PARTITION_HUD_PARTICLE,
+		PARTITION_VO_CACHE,
 		PARTITION_NONE,
 		NUM_PARTITIONS
 	} eObjectPartitions;
@@ -216,6 +218,12 @@ public:
 	F32	getWidth() const						{ return mWidth; }
 
 	BOOL idleUpdate(F32 max_update_time);
+	void addVisibleGroup(LLSpatialGroup* group);
+	void addVisibleCacheEntry(LLVOCacheEntry* entry);
+	void addActiveCacheEntry(LLVOCacheEntry* entry);
+	void removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep);	
+	void killCacheEntry(U32 local_id); //physically delete the cache entry	
+	void clearVisibleGroup(LLSpatialGroup* group);
 
 	// Like idleUpdate, but forces everything to complete regardless of
 	// how long it takes.
@@ -305,7 +313,8 @@ public:
 	} eCacheUpdateResult;
 
 	// handle a full update message
-	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
+	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);	
+	LLVOCacheEntry* getCacheEntryForOctree(U32 local_id);
 	LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);
 	void requestCacheMisses();
 	void addCacheMissFull(const U32 local_id);
@@ -322,6 +331,7 @@ public:
     virtual std::string getDescription() const;
 	std::string getHttpUrl() const { return mHttpUrl ;}
 
+	U32 getNumOfActiveCachedObjects() const;
 	LLSpatialPartition* getSpatialPartition(U32 type);
 
 	bool objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const;
@@ -331,6 +341,15 @@ public:
 	void getNeighboringRegions( std::vector<LLViewerRegion*>& uniqueRegions );
 	void getNeighboringRegionsStatus( std::vector<S32>& regions );
 	
+private:
+	void addToVOCacheTree(LLVOCacheEntry* entry);
+	LLViewerObject* addNewObject(LLVOCacheEntry* entry);
+	void killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list);
+	LLVOCacheEntry* getCacheEntry(U32 local_id);
+	void removeFromVOCacheTree(LLVOCacheEntry* entry);
+	void replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry);
+	void killCacheEntry(LLVOCacheEntry* entry); //physically delete the cache entry	
+
 public:
 	struct CompareDistance
 	{
@@ -408,18 +427,17 @@ private:
 	// Maps local ids to cache entries.
 	// Regions can have order 10,000 objects, so assume
 	// a structure of size 2^14 = 16,000
-	BOOL									mCacheLoaded;
-	BOOL                                    mCacheDirty;
+	BOOL	mCacheLoaded;
+	BOOL    mCacheDirty;
+	BOOL	mAlive;					// can become false if circuit disconnects
+	BOOL	mCapabilitiesReceived;
+	BOOL    mReleaseNotesRequested;
+	BOOL    mDead;  //if true, this region is in the process of deleting.
 
 	LLDynamicArray<U32>						mCacheMissFull;
 	LLDynamicArray<U32>						mCacheMissCRC;
-
-	bool	mAlive;					// can become false if circuit disconnects
-	bool	mCapabilitiesReceived;
-	caps_received_signal_t mCapabilitiesReceivedSignal;
-
-	BOOL mReleaseNotesRequested;
 	
+	caps_received_signal_t mCapabilitiesReceivedSignal;		
 	LLSD mSimulatorFeatures;
 };
 
diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp
index 91e485d01b..2d5292b5f3 100644
--- a/indra/newview/llviewerstatsrecorder.cpp
+++ b/indra/newview/llviewerstatsrecorder.cpp
@@ -220,7 +220,7 @@ void LLViewerStatsRecorder::writeToLog( F32 interval )
 		}
 		else
 		{
-			llwarns << "Couldn't open " << STATS_FILE_NAME << " for logging." << llendl;
+			//llwarns << "Couldn't open " << STATS_FILE_NAME << " for logging." << llendl;
 			return;
 		}
 	}
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index fd892db3d3..a11653b77d 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -808,8 +808,10 @@ U32  LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys,
 		updateMeshTextures();
 
 		// unpack the texture UUIDs to the texture slots
-		retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num);
-
+		if(mesgsys != NULL)
+		{
+			retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num);
+		}
 		// need to trigger a few operations to get the avatar to use the new bakes
 		for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
 		{
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 7db19c5c1b..17e0ef3bdb 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -29,6 +29,8 @@
 #include "llerror.h"
 #include "llregionhandle.h"
 #include "llviewercontrol.h"
+#include "llviewerobjectlist.h"
+#include "lldrawable.h"
 
 BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) 
 {
@@ -46,12 +48,13 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
 //---------------------------------------------------------------------------
 
 LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp)
-	:
+	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(local_id),
 	mCRC(crc),
 	mHitCount(0),
 	mDupeCount(0),
-	mCRCChangeCount(0)
+	mCRCChangeCount(0),
+	mState(INACTIVE)
 {
 	mBuffer = new U8[dp.getBufferSize()];
 	mDP.assignBuffer(mBuffer, dp.getBufferSize());
@@ -59,19 +62,22 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &
 }
 
 LLVOCacheEntry::LLVOCacheEntry()
-	:
+	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY),
 	mLocalID(0),
 	mCRC(0),
 	mHitCount(0),
 	mDupeCount(0),
 	mCRCChangeCount(0),
-	mBuffer(NULL)
+	mBuffer(NULL),
+	mState(INACTIVE)
 {
 	mDP.assignBuffer(mBuffer, 0);
 }
 
 LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
-	: mBuffer(NULL)
+	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
+	mBuffer(NULL),
+	mState(INACTIVE)
 {
 	S32 size = -1;
 	BOOL success;
@@ -138,8 +144,57 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 LLVOCacheEntry::~LLVOCacheEntry()
 {
 	mDP.freeBuffer();
+	//llassert(mState == INACTIVE);
 }
 
+//virtual 
+void LLVOCacheEntry::setOctreeEntry(LLViewerOctreeEntry* entry)
+{
+	if(!entry && mDP.getBufferSize() > 0)
+	{
+		LLUUID fullid;
+		mDP.reset();
+		mDP.unpackUUID(fullid, "ID");
+		mDP.reset();
+
+		LLViewerObject* obj = gObjectList.findObject(fullid);
+		if(obj && obj->mDrawable)
+		{
+			entry = obj->mDrawable->getEntry();
+		}
+	}
+
+	LLViewerOctreeEntryData::setOctreeEntry(entry);
+}
+
+//virtual 
+S32  LLVOCacheEntry::getMinVisFrameRange()const
+{
+	const S32 MIN_RANGE = 128; //frames
+
+	return MIN_RANGE;
+}
+
+void LLVOCacheEntry::addChild(LLVOCacheEntry* entry)
+{
+	llassert(entry != NULL);
+
+	mChildrenList.push_back(entry);
+}
+	
+LLVOCacheEntry* LLVOCacheEntry::getNextChild()
+{
+	S32 size = mChildrenList.size();
+	if(!size)
+	{
+		return NULL;
+	}
+
+	LLVOCacheEntry* entry = mChildrenList[size - 1];
+	mChildrenList.pop_back(); //remove the entry;
+
+	return entry;
+}
 
 // New CRC means the object has changed.
 void LLVOCacheEntry::assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp)
@@ -170,6 +225,16 @@ LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc)
 	return &mDP;
 }
 
+LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP()
+{
+	if (mDP.getBufferSize() == 0)
+	{
+		//llinfos << "Not getting cache entry, invalid!" << llendl;
+		return NULL;
+	}
+	
+	return &mDP;
+}
 
 void LLVOCacheEntry::recordHit()
 {
@@ -625,11 +690,10 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 				{
 					for (S32 i = 0; i < num_entries; i++)
 					{
-						LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file);
+						LLPointer<LLVOCacheEntry> entry = new LLVOCacheEntry(&apr_file);
 						if (!entry->getLocalID())
 						{
 							llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
-							delete entry ;
 							success = false ;
 							break ;
 						}
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 14e3b4c793..85538e8043 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -31,34 +31,57 @@
 #include "lldatapacker.h"
 #include "lldlinked.h"
 #include "lldir.h"
-
+#include "llvieweroctree.h"
 
 //---------------------------------------------------------------------------
 // Cache entries
 class LLVOCacheEntry;
 
-class LLVOCacheEntry
+class LLVOCacheEntry : public LLViewerOctreeEntryData
 {
+public:
+	enum
+	{
+		INACTIVE = 0,
+		WAITING,
+		ACTIVE
+	};
+
+protected:
+	~LLVOCacheEntry();
 public:
 	LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp);
 	LLVOCacheEntry(LLAPRFile* apr_file);
-	LLVOCacheEntry();
-	~LLVOCacheEntry();
+	LLVOCacheEntry();	
+
+	void setState(U32 state) {mState = state;}
+	bool isState(U32 state)  {return mState == state;}
+	U32  getState() const    {return mState;}
 
 	U32 getLocalID() const			{ return mLocalID; }
 	U32 getCRC() const				{ return mCRC; }
 	S32 getHitCount() const			{ return mHitCount; }
 	S32 getCRCChangeCount() const	{ return mCRCChangeCount; }
+	S32 getMinVisFrameRange()const;
 
 	void dump() const;
 	BOOL writeToFile(LLAPRFile* apr_file) const;
 	void assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp);
 	LLDataPackerBinaryBuffer *getDP(U32 crc);
+	LLDataPackerBinaryBuffer *getDP();
 	void recordHit();
 	void recordDupe() { mDupeCount++; }
+	
+	/*virtual*/ void setOctreeEntry(LLViewerOctreeEntry* entry);
+
+	void addChild(LLVOCacheEntry* entry);
+	LLVOCacheEntry* getNextChild();
+	S32 getNumOfChildren() {return mChildrenList.size();}
+	bool isDummy() {return !mBuffer;}
 
 public:
-	typedef std::map<U32, LLVOCacheEntry*>	vocache_entry_map_t;
+	typedef std::map<U32, LLPointer<LLVOCacheEntry> >	vocache_entry_map_t;
+	typedef std::set<LLVOCacheEntry*>                   vocache_entry_set_t;
 
 protected:
 	U32							mLocalID;
@@ -68,6 +91,9 @@ protected:
 	S32							mCRCChangeCount;
 	LLDataPackerBinaryBuffer	mDP;
 	U8							*mBuffer;
+
+	U32                         mState;
+	std::vector<LLVOCacheEntry*> mChildrenList; //children entries in a linked set.
 };
 
 //
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 4dca87652d..d378ed2577 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -603,8 +603,8 @@ U32 LLVOGrass::getPartitionType() const
 	return LLViewerRegion::PARTITION_GRASS;
 }
 
-LLGrassPartition::LLGrassPartition()
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB)
+LLGrassPartition::LLGrassPartition(LLViewerRegion* regionp)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB, regionp)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_GRASS;
 	mPartitionType = LLViewerRegion::PARTITION_GRASS;
@@ -624,9 +624,9 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count
 	LLViewerCamera* camera = LLViewerCamera::getInstance();
 	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
-		LLDrawable* drawablep = *i;
+		LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable();
 		
-		if (drawablep->isDead())
+		if (!drawablep || drawablep->isDead())
 		{
 			continue;
 		}
@@ -738,8 +738,10 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group)
 			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), 
 				//facep->getTexture(),
 				buffer, fullbright); 
-			info->mExtents[0] = group->mObjectExtents[0];
-			info->mExtents[1] = group->mObjectExtents[1];
+
+			const LLVector4a* exts = group->getObjectExtents();
+			info->mExtents[0] = exts[0];
+			info->mExtents[1] = exts[1];
 			info->mVSize = vsize;
 			draw_vec.push_back(info);
 			//for alpha sorting
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index fa34a6f1f5..29c78f85f2 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -489,8 +489,8 @@ U32 LLVOPartGroup::getPartitionType() const
 	return LLViewerRegion::PARTITION_PARTICLE; 
 }
 
-LLParticlePartition::LLParticlePartition()
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB)
+LLParticlePartition::LLParticlePartition(LLViewerRegion* regionp)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB, regionp)
 {
 	mRenderPass = LLRenderPass::PASS_ALPHA;
 	mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
@@ -499,8 +499,8 @@ LLParticlePartition::LLParticlePartition()
 	mLODPeriod = 1;
 }
 
-LLHUDParticlePartition::LLHUDParticlePartition() :
-	LLParticlePartition()
+LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) :
+	LLParticlePartition(regionp)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_HUD_PARTICLES;
 	mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE;
@@ -510,7 +510,7 @@ static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VBO("Particle VBO");
 
 void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
 {
-	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY))
+	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
 		return;
 	}
@@ -558,9 +558,9 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 	LLViewerCamera* camera = LLViewerCamera::getInstance();
 	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
-		LLDrawable* drawablep = *i;
+		LLDrawable* drawablep = (LLDrawable*)(*i)->getDrawable();
 		
-		if (drawablep->isDead())
+		if (!drawablep || drawablep->isDead())
 		{
 			continue;
 		}
@@ -699,8 +699,10 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), 
 				//facep->getTexture(),
 				buffer, fullbright); 
-			info->mExtents[0] = group->mObjectExtents[0];
-			info->mExtents[1] = group->mObjectExtents[1];
+
+			const LLVector4a* exts = group->getObjectExtents();
+			info->mExtents[0] = exts[0];
+			info->mExtents[1] = exts[1];
 			info->mVSize = vsize;
 			draw_vec.push_back(info);
 			//for alpha sorting
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index cb905d02da..d5b3f2fd14 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -1058,8 +1058,8 @@ U32 LLVOSurfacePatch::getPartitionType() const
 	return LLViewerRegion::PARTITION_TERRAIN; 
 }
 
-LLTerrainPartition::LLTerrainPartition()
-: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB)
+LLTerrainPartition::LLTerrainPartition(LLViewerRegion* regionp)
+: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW_ARB, regionp)
 {
 	mOcclusionEnabled = FALSE;
 	mInfiniteFarClip = TRUE;
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 6687ce432f..fe1ef10f7f 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -1290,8 +1290,8 @@ U32 LLVOTree::getPartitionType() const
 	return LLViewerRegion::PARTITION_TREE; 
 }
 
-LLTreePartition::LLTreePartition()
-: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB)
+LLTreePartition::LLTreePartition(LLViewerRegion* regionp)
+: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB, regionp)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_TREE;
 	mPartitionType = LLViewerRegion::PARTITION_TREE;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 813fa72cc3..51a3ace61b 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3912,8 +3912,8 @@ U32 LLVOVolume::getPartitionType() const
 	return LLViewerRegion::PARTITION_VOLUME;
 }
 
-LLVolumePartition::LLVolumePartition()
-: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB)
+LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp)
+: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB, regionp)
 {
 	mLODPeriod = 32;
 	mDepthMask = FALSE;
@@ -3923,8 +3923,8 @@ LLVolumePartition::LLVolumePartition()
 	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 }
 
-LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep)
-: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK)
+LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep, LLViewerRegion* regionp)
+: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK, regionp)
 {
 	mDepthMask = FALSE;
 	mLODPeriod = 32;
@@ -4146,9 +4146,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	group->mLastUpdateViewAngle = group->mViewAngle;
 
-	if (!group->isState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY))
+	if (!group->hasState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::ALPHA_DIRTY))
 	{
-		if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)
+		if (group->hasState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)
 		{
 			rebuildMesh(group);
 		}
@@ -4186,7 +4186,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	group->mSurfaceArea = 0;
 	
 	//cache object box size since it might be used for determining visibility
-	group->mObjectBoxSize = group->mObjectBounds[1].getLength3().getF32();
+	const LLVector4a* bounds = group->getObjectBounds();
+	group->mObjectBoxSize = bounds[1].getLength3().getF32();
 
 	group->clearDrawMap();
 
@@ -4213,9 +4214,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		//get all the faces into a list
 		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 		{
-			LLDrawable* drawablep = *drawable_iter;
+			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
 		
-			if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
+			if (!drawablep || drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
 			{
 				continue;
 			}
@@ -4619,8 +4620,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		//drawables have been rebuilt, clear rebuild status
 		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 		{
-			LLDrawable* drawablep = *drawable_iter;
-			drawablep->clearState(LLDrawable::REBUILD_ALL);
+			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
+			if(drawablep)
+			{
+				drawablep->clearState(LLDrawable::REBUILD_ALL);
+			}
 		}
 	}
 
@@ -4646,7 +4650,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
 	llassert(group);
-	if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY))
+	if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY))
 	{
 		LLFastTimer ftm(FTM_REBUILD_VOLUME_VB);
 		LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers
@@ -4659,9 +4663,9 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 
 		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 		{
-			LLDrawable* drawablep = *drawable_iter;
+			LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
 
-			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
+			if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
 			{
 				LLVOVolume* vobj = drawablep->getVOVolume();
 				vobj->preRebuild();
@@ -4727,7 +4731,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 			llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; 
 			for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 			{
-				LLDrawable* drawablep = *drawable_iter;
+				LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
+				if(!drawablep)
+				{
+					continue;
+				}
 				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 				{
 					LLFace* face = drawablep->getFace(i);
@@ -5200,9 +5208,9 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 
 	for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 	{
-		LLDrawable* drawablep = *drawable_iter;
+		LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
 		
-		if (drawablep->isDead())
+		if (!drawablep || drawablep->isDead())
 		{
 			continue;
 		}
@@ -5240,7 +5248,7 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 	group->mBufferUsage = usage;
 }
 
-LLHUDPartition::LLHUDPartition()
+LLHUDPartition::LLHUDPartition(LLViewerRegion* regionp) : LLBridgePartition(regionp)
 {
 	mPartitionType = LLViewerRegion::PARTITION_HUD;
 	mDrawableType = LLPipeline::RENDER_TYPE_HUD;
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index e8a1c3d1d6..50e7ed7bb5 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -298,15 +298,15 @@ U32 LLVOVoidWater::getPartitionType() const
 	return LLViewerRegion::PARTITION_VOIDWATER;
 }
 
-LLWaterPartition::LLWaterPartition()
-: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB)
+LLWaterPartition::LLWaterPartition(LLViewerRegion* regionp)
+: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB, regionp)
 {
 	mInfiniteFarClip = TRUE;
 	mDrawableType = LLPipeline::RENDER_TYPE_WATER;
 	mPartitionType = LLViewerRegion::PARTITION_WATER;
 }
 
-LLVoidWaterPartition::LLVoidWaterPartition()
+LLVoidWaterPartition::LLVoidWaterPartition(LLViewerRegion* regionp) : LLWaterPartition(regionp)
 {
 	mOcclusionEnabled = FALSE;
 	mDrawableType = LLPipeline::RENDER_TYPE_VOIDWATER;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 9e495c46b1..0a622997f7 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -133,6 +133,9 @@ void LLWorld::destroyClass()
 	{
 		mEdgeWaterObjects[i] = NULL;
 	}
+
+	//make all visible drawbles invisible.
+	LLDrawable::incrementVisible();
 }
 
 
@@ -599,7 +602,8 @@ void LLWorld::updateVisibilities()
 		if (part)
 		{
 			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
-			if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+			const LLVector4a* bounds = group->getBounds();
+			if (LLViewerCamera::getInstance()->AABBInFrustum(bounds[0], bounds[1]))
 			{
 				mCulledRegionList.erase(curiter);
 				mVisibleRegionList.push_back(regionp);
@@ -622,7 +626,8 @@ void LLWorld::updateVisibilities()
 		if (part)
 		{
 			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
-			if (LLViewerCamera::getInstance()->AABBInFrustum(group->mBounds[0], group->mBounds[1]))
+			const LLVector4a* bounds = group->getBounds();
+			if (LLViewerCamera::getInstance()->AABBInFrustum(bounds[0], bounds[1]))
 			{
 				regionp->calculateCameraDistance();
 				regionp->getLand().updatePatchVisibilities(gAgent);
@@ -644,8 +649,8 @@ void LLWorld::updateVisibilities()
 void LLWorld::updateRegions(F32 max_update_time)
 {
 	LLTimer update_timer;
-	BOOL did_one = FALSE;
-	
+	BOOL did_one = FALSE;	
+
 	// Perform idle time updates for the regions (and associated surfaces)
 	for (region_list_t::iterator iter = mRegionList.begin();
 		 iter != mRegionList.end(); ++iter)
@@ -660,6 +665,13 @@ void LLWorld::updateRegions(F32 max_update_time)
 			did_one = TRUE;
 		}
 	}
+
+	mNumOfActiveCachedObjects = 0;
+	for (region_list_t::iterator iter = mRegionList.begin();
+		 iter != mRegionList.end(); ++iter)
+	{
+		mNumOfActiveCachedObjects += (*iter)->getNumOfActiveCachedObjects();
+	}
 }
 
 void LLWorld::updateParticles()
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index f350009d10..8187142b2b 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -144,6 +144,7 @@ public:
 	U64 getSpaceTimeUSec() const;
 
 	void getInfo(LLSD& info);
+	U32  getNumOfActiveCachedObjects() const {return mNumOfActiveCachedObjects;}
 
 public:
 	typedef std::list<LLViewerRegion*> region_list_t;
@@ -181,7 +182,7 @@ private:
 	S32 mLastPacketsIn;
 	S32 mLastPacketsOut;
 	S32 mLastPacketsLost;
-
+	U32 mNumOfActiveCachedObjects;
 	U64 mSpaceTimeUSec;
 
 	BOOL mClassicCloudsEnabled;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 4582de805f..e06577c512 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1378,18 +1378,18 @@ S32 LLPipeline::setLightingDetail(S32 level)
 	return mLightingDetail;
 }
 
-class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
+class LLOctreeDirtyTexture : public OctreeTraveler
 {
 public:
 	const std::set<LLViewerFetchedTexture*>& mTextures;
 
 	LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { }
 
-	virtual void visit(const LLOctreeNode<LLDrawable>* node)
+	virtual void visit(const OctreeNode* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 
-		if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty())
+		if (!group->hasState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty())
 		{
 			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
 			{
@@ -1578,11 +1578,9 @@ void LLPipeline::addPool(LLDrawPool *new_poolp)
 
 void LLPipeline::allocDrawable(LLViewerObject *vobj)
 {
-	LLDrawable *drawable = new LLDrawable();
+	LLDrawable *drawable = new LLDrawable(vobj);
 	vobj->mDrawable = drawable;
 	
-	drawable->mVObjp     = vobj;
-	
 	//encompass completely sheared objects by taking 
 	//the most extreme point possible (<1,1,0.5>)
 	drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length());
@@ -2006,7 +2004,7 @@ void check_references(LLSpatialGroup* group, LLDrawable* drawable)
 {
 	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
-		if (drawable == *i)
+		if (drawable == (LLDrawable*)(*i)->getDrawable())
 		{
 			llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl;
 		}
@@ -2028,8 +2026,11 @@ void check_references(LLSpatialGroup* group, LLFace* face)
 {
 	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
-		LLDrawable* drawable = *i;
-		check_references(drawable, face);
+		LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable();
+		if(drawable)
+		{
+			check_references(drawable, face);
+		}
 	}			
 }
 
@@ -2351,6 +2352,10 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 				{
 					part->cull(camera);
 				}
+				else if(part->mPartitionType == LLViewerRegion::PARTITION_VO_CACHE)
+				{
+					part->cull(camera);
+				}
 			}
 		}
 	}
@@ -2420,15 +2425,20 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 		return;
 	}
 
+	const LLVector4a* bounds = group->getBounds();
 	if (sMinRenderSize > 0.f && 
-			llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize)
+			llmax(llmax(bounds[1][0], bounds[1][1]), bounds[1][2]) < sMinRenderSize)
 	{
 		return;
 	}
 
 	assertInitialized();
 	
-	if (!group->mSpatialPartition->mRenderByGroup)
+	if(group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_VO_CACHE)
+	{
+		group->mSpatialPartition->mRegionp->addVisibleGroup(group);
+	}
+	else if (!group->mSpatialPartition->mRenderByGroup)
 	{ //render by drawable
 		sCull->pushDrawableGroup(group);
 	}
@@ -2980,14 +2990,14 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
 
 		if (priority)
 		{
-			if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
+			if (!group->hasState(LLSpatialGroup::IN_BUILD_Q1))
 			{
 				llassert_always(!mGroupQ1Locked);
 
 				mGroupQ1.push_back(group);
 				group->setState(LLSpatialGroup::IN_BUILD_Q1);
 
-				if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
+				if (group->hasState(LLSpatialGroup::IN_BUILD_Q2))
 				{
 					LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
 					if (iter != mGroupQ2.end())
@@ -2998,7 +3008,7 @@ void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
 				}
 			}
 		}
-		else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
+		else if (!group->hasState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
 		{
 			llassert_always(!mGroupQ2Locked);
 			mGroupQ2.push_back(group);
@@ -3073,7 +3083,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 			group->setVisible();
 			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 			{
-				markVisible(*i, camera);
+				markVisible((LLDrawable*)(*i)->getDrawable(), camera);
 			}
 
 			if (!sDelayVBUpdate)
@@ -3160,8 +3170,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 	{
 		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 		{
-			LLDrawable* drawablep = *i;
-			stateSort(drawablep, camera);
+			stateSort((LLDrawable*)(*i)->getDrawable(), camera);
 		}
 
 		if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
@@ -3280,7 +3289,10 @@ void forAllDrawables(LLCullResult::sg_iterator begin,
 	{
 		for (LLSpatialGroup::element_iter j = (*i)->getDataBegin(); j != (*i)->getDataEnd(); ++j)
 		{
-			func(*j);	
+			if((*j)->hasDrawable())
+			{
+				func((LLDrawable*)(*j)->getDrawable());	
+			}
 		}
 	}
 }
@@ -3508,7 +3520,7 @@ void LLPipeline::postSort(LLCamera& camera)
 			continue;
 		}
 
-		if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
+		if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY))
 		{ //no way this group is going to be drawable without a rebuild
 			group->rebuildGeom();
 		}
-- 
cgit v1.2.3


From 9bc8028ab52ef5d56fa8a3915d927b5a050d8ead Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 16 Oct 2012 11:40:02 -0600
Subject: Some minor performance tuning-up for SH-3333.

---
 indra/newview/llviewerregion.cpp | 2 +-
 indra/newview/llvocache.cpp      | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 15c95aa30a..0c0522d32f 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1066,7 +1066,7 @@ void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>&
 			if(child->mDrawable->isRecentlyVisible())
 			{
 				//set the parent group visible if any of its children visible.
-				drawablep->getSpatialGroup()->setVisible();
+				((LLViewerOctreeEntryData*)drawablep)->setVisible();
 				return;
 			}
 		}
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 17e0ef3bdb..236ce11c7e 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -170,7 +170,7 @@ void LLVOCacheEntry::setOctreeEntry(LLViewerOctreeEntry* entry)
 //virtual 
 S32  LLVOCacheEntry::getMinVisFrameRange()const
 {
-	const S32 MIN_RANGE = 128; //frames
+	const S32 MIN_RANGE = 64; //frames
 
 	return MIN_RANGE;
 }
-- 
cgit v1.2.3


From 6c7167b1f2363ab9412c4ded3b22c829018f6e45 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Fri, 19 Oct 2012 17:00:29 -0600
Subject: fix a gTextureTimer bug: it starts too early.

---
 indra/newview/lltexturefetch.cpp | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index f2caa01644..338cb8d70f 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1919,6 +1919,10 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 		}
 		mOriginFetchSource = mFetchSource;
 	}
+
+	//reset the texture timer.
+	gTextureTimer.reset();
+	gTextureTimer.pause();
 }
 
 LLTextureFetch::~LLTextureFetch()
-- 
cgit v1.2.3


From 87097e546fa9e160264400f6d9d79d536abbb2fa Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 25 Oct 2012 17:00:34 -0600
Subject: more for SH-3333: avoid repeatedly creating/killing a same object
 from object cache due to occlusion culling.

---
 indra/newview/llvocache.cpp | 47 +++++++++++++++++++++++++++++++++++++++------
 indra/newview/llvocache.h   |  4 +++-
 2 files changed, 44 insertions(+), 7 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 236ce11c7e..fbab5c60e3 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -54,7 +54,9 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &
 	mHitCount(0),
 	mDupeCount(0),
 	mCRCChangeCount(0),
-	mState(INACTIVE)
+	mState(INACTIVE),
+	mRepeatedVisCounter(0),
+	mVisFrameRange(64)
 {
 	mBuffer = new U8[dp.getBufferSize()];
 	mDP.assignBuffer(mBuffer, dp.getBufferSize());
@@ -69,7 +71,9 @@ LLVOCacheEntry::LLVOCacheEntry()
 	mDupeCount(0),
 	mCRCChangeCount(0),
 	mBuffer(NULL),
-	mState(INACTIVE)
+	mState(INACTIVE),
+	mRepeatedVisCounter(0),
+	mVisFrameRange(64)
 {
 	mDP.assignBuffer(mBuffer, 0);
 }
@@ -77,7 +81,9 @@ LLVOCacheEntry::LLVOCacheEntry()
 LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
 	mBuffer(NULL),
-	mState(INACTIVE)
+	mState(INACTIVE),
+	mRepeatedVisCounter(0),
+	mVisFrameRange(64)
 {
 	S32 size = -1;
 	BOOL success;
@@ -167,12 +173,41 @@ void LLVOCacheEntry::setOctreeEntry(LLViewerOctreeEntry* entry)
 	LLViewerOctreeEntryData::setOctreeEntry(entry);
 }
 
+void LLVOCacheEntry::setState(U32 state)
+{
+	mState = state;
+
+	if(mState == ACTIVE)
+	{
+		const S32 MIN_REAVTIVE_INTERVAL = 20;
+		U32 last_visible = getVisible();
+		
+		setVisible();
+
+		if(getVisible() - last_visible < MIN_REAVTIVE_INTERVAL + mVisFrameRange)
+		{
+			mRepeatedVisCounter++;
+		}
+		else
+		{
+			mRepeatedVisCounter = 0;
+			mVisFrameRange = 64;
+		}
+
+		if(mRepeatedVisCounter > 2) 
+		{
+			//if repeatedly becomes visible immediately after invisible, enlarge the visible frame range
+
+			mRepeatedVisCounter = 0;
+			mVisFrameRange *= 2;
+		}
+	}
+}
+
 //virtual 
 S32  LLVOCacheEntry::getMinVisFrameRange()const
 {
-	const S32 MIN_RANGE = 64; //frames
-
-	return MIN_RANGE;
+	return mVisFrameRange;
 }
 
 void LLVOCacheEntry::addChild(LLVOCacheEntry* entry)
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 85538e8043..2228e3e43b 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -54,7 +54,7 @@ public:
 	LLVOCacheEntry(LLAPRFile* apr_file);
 	LLVOCacheEntry();	
 
-	void setState(U32 state) {mState = state;}
+	void setState(U32 state);
 	bool isState(U32 state)  {return mState == state;}
 	U32  getState() const    {return mState;}
 
@@ -92,6 +92,8 @@ protected:
 	LLDataPackerBinaryBuffer	mDP;
 	U8							*mBuffer;
 
+	S32                         mVisFrameRange;
+	S32                         mRepeatedVisCounter; //number of repeatedly visible within a short time.
 	U32                         mState;
 	std::vector<LLVOCacheEntry*> mChildrenList; //children entries in a linked set.
 };
-- 
cgit v1.2.3


From 09591242f90fa9b24a0be2aad02e91041ac0fcc7 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 25 Oct 2012 18:20:36 -0600
Subject: avoid redundant object creation.

---
 indra/newview/llviewerobjectlist.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index a1db1f7237..d41eee5926 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -338,8 +338,10 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*
 				objectp->updateRegion(regionp); // for LLVOAvatar
 			}
 		}
-
-		//return TRUE; //already loaded.
+		else
+		{
+			return objectp; //already loaded.
+		}
 	}
 
 	bool justCreated = false;
-- 
cgit v1.2.3


From e35a220bf7dd47132174c81181d5f59fb0d54c5d Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Mon, 29 Oct 2012 17:13:15 -0600
Subject: for SH-3459: interesting store object bounding information in viewer
 cache

---
 indra/newview/llvocache.cpp | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index fbab5c60e3..f389867484 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -89,6 +89,8 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 	BOOL success;
 
 	mDP.assignBuffer(mBuffer, 0);
+	setOctreeEntry(NULL);
+
 	success = check_read(apr_file, &mLocalID, sizeof(U32));
 	if(success)
 	{
@@ -107,6 +109,21 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32));
 	}
 	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));
 
@@ -144,6 +161,7 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 		mDupeCount = 0;
 		mCRCChangeCount = 0;
 		mBuffer = NULL;
+		mEntry = NULL;
 	}
 }
 
@@ -289,6 +307,11 @@ void LLVOCacheEntry::dump() const
 
 BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 {
+	if(!mEntry)
+	{
+		return FALSE;
+	}
+
 	BOOL success;
 	success = check_write(apr_file, (void*)&mLocalID, sizeof(U32));
 	if(success)
@@ -308,6 +331,17 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32));
 	}
 	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));
-- 
cgit v1.2.3


From 5ae116f89b8459963ccb6ae9125d94ffaa79025e Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 31 Oct 2012 17:05:53 -0600
Subject: for SH-3471: create a simplified version of octree for object cache
 entries.

---
 indra/newview/llspatialpartition.cpp | 108 ++++++----------------
 indra/newview/llspatialpartition.h   |  49 ++--------
 indra/newview/llvieweroctree.cpp     |  48 +++++++++-
 indra/newview/llvieweroctree.h       |  39 +++++++-
 indra/newview/llviewerregion.cpp     | 174 ++++++++++++++++++++++++-----------
 indra/newview/llviewerregion.h       |  14 ++-
 indra/newview/llvocache.cpp          |  77 ++++++++++++++++
 indra/newview/llvocache.h            |  13 +++
 indra/newview/pipeline.cpp           |  20 ++--
 9 files changed, 346 insertions(+), 196 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index debb790c58..e9ece331d1 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -264,11 +264,7 @@ LLSpatialGroup::~LLSpatialGroup()
 	{
 		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
 	}*/
-	if(isVisible())
-	{
-		mSpatialPartition->mRegionp->clearVisibleGroup(this);
-	}
-
+	
 	if (gDebugGL)
 	{
 		gPipeline.checkReferences(this);
@@ -434,16 +430,6 @@ BOOL LLSpatialGroup::isRecentlyVisible() const
 	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < MIN_VIS_FRAME_RANGE ;
 }
 
-BOOL LLSpatialGroup::isVisible() const
-{
-	return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
-}
-
-void LLSpatialGroup::setVisible()
-{
-	mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame();
-}
-
 void LLSpatialGroup::validate()
 {
 	ll_assert_aligned(this,64);
@@ -1165,12 +1151,6 @@ BOOL LLSpatialGroup::changeLOD()
 
 void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry)
 {
-	if(mSpatialPartition->isVOCachePartition())
-	{
-		LLviewerOctreeGroup::handleInsertion(node, entry);
-		return;
-	}
-		
 	addObject((LLDrawable*)entry->getDrawable());
 	unbound();
 	setState(OBJECT_DIRTY);
@@ -1178,10 +1158,7 @@ void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry*
 
 void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry)
 {
-	if(!mSpatialPartition->isVOCachePartition())
-	{
-		removeObject((LLDrawable*)entry->getDrawable(), TRUE);
-	}
+	removeObject((LLDrawable*)entry->getDrawable(), TRUE);
 	LLviewerOctreeGroup::handleRemoval(node, entry);
 }
 
@@ -1189,12 +1166,6 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 {
 	setState(DEAD);
 
-	if(mSpatialPartition->isVOCachePartition())
-	{
-		LLviewerOctreeGroup::handleDestruction(node);
-		return;
-	}
-
 	for (element_iter i = getDataBegin(); i != getDataEnd(); ++i)
 	{
 		LLViewerOctreeEntry* entry = *i;
@@ -1510,8 +1481,9 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 //==============================================
 
 LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage, LLViewerRegion* regionp)
-: mRenderByGroup(render_by_group), mBridge(NULL), mRegionp(regionp)
+: mRenderByGroup(render_by_group), mBridge(NULL)
 {
+	mRegionp = regionp;
 	mOcclusionEnabled = TRUE;
 	mDrawableType = 0;
 	mPartitionType = LLViewerRegion::PARTITION_NONE;
@@ -1521,27 +1493,14 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32
 	mBufferUsage = buffer_usage;
 	mDepthMask = FALSE;
 	mSlopRatio = 0.25f;
-	mInfiniteFarClip = FALSE;
-	mVisitedTime = 0;
-
-	LLVector4a center, size;
-	center.splat(0.f);
-	size.splat(1.f);
+	mInfiniteFarClip = FALSE;	
 
-	mOctree = new OctreeRoot(center,size, NULL);
 	new LLSpatialGroup(mOctree, this);
 }
 
 
 LLSpatialPartition::~LLSpatialPartition()
-{
-	delete mOctree;
-	mOctree = NULL;
-}
-
-BOOL LLSpatialPartition::isVOCachePartition() const
-{
-	return mPartitionType == LLViewerRegion::PARTITION_VO_CACHE;
+{	
 }
 
 LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
@@ -2050,12 +2009,7 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
-	bool is_vo_cache_part = (mPartitionType == LLViewerRegion::PARTITION_VO_CACHE);
-	
-	if(is_vo_cache_part && mVisitedTime == LLViewerOctreeEntryData::getCurrentFrame())
-	{
-		return 0; //no need to visit more than once per frame
-	}		
+	llassert(results != NULL && for_select);
 
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
@@ -2070,19 +2024,34 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	((LLSpatialGroup*)mOctree->getListener(0))->validate();
 #endif
 
+	LLOctreeSelect selecter(&camera, results);
+	selecter.traverse(mOctree);
 	
-	if (for_select && !is_vo_cache_part)
+	return 0;
+}
+
+S32 LLSpatialPartition::cull(LLCamera &camera)
+{
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
+#endif
 	{
-		LLOctreeSelect selecter(&camera, results);
-		selecter.traverse(mOctree);
+		LLFastTimer ftm(FTM_CULL_REBOUND);		
+		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
+		group->rebound();
 	}
-	else if (LLPipeline::sShadowRender && !is_vo_cache_part)
+
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->validate();
+#endif
+
+	if (LLPipeline::sShadowRender)
 	{
 		LLFastTimer ftm(FTM_FRUSTUM_CULL);
 		LLOctreeCullShadow culler(&camera);
 		culler.traverse(mOctree);
 	}
-	else if ((mInfiniteFarClip || !LLPipeline::sUseFarClip) && !is_vo_cache_part)
+	else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
 	{
 		LLFastTimer ftm(FTM_FRUSTUM_CULL);		
 		LLOctreeCullNoFarClip culler(&camera);
@@ -2090,11 +2059,6 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 	}
 	else
 	{
-		if(is_vo_cache_part)
-		{
-			mVisitedTime = LLViewerOctreeEntryData::getCurrentFrame();
-		}
-
 		LLFastTimer ftm(FTM_FRUSTUM_CULL);		
 		LLOctreeCull culler(&camera);
 		culler.traverse(mOctree);
@@ -4663,21 +4627,3 @@ void LLCullResult::assertDrawMapsEmpty()
 	}
 }
 
-LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp) : LLSpatialPartition(0, FALSE, 0, regionp)
-{
-	mPartitionType = LLViewerRegion::PARTITION_VO_CACHE;
-}
-
-void LLVOCachePartition::addEntry(LLViewerOctreeEntry* entry)
-{
-	llassert(entry->hasVOCacheEntry());
-
-	mOctree->insert(entry);
-}
-	
-void LLVOCachePartition::removeEntry(LLViewerOctreeEntry* entry)
-{
-	entry->getVOCacheEntry()->setGroup(NULL);
-
-	llassert(!entry->getGroup());
-}
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index dd189d751d..079c0f58f0 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -45,6 +45,7 @@
 #define SG_STATE_INHERIT_MASK (OCCLUDED)
 #define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY)
 
+class LLViewerOctreePartition;
 class LLSpatialPartition;
 class LLSpatialBridge;
 class LLSpatialGroup;
@@ -225,10 +226,7 @@ public:
 	typedef std::map<U32, drawmap_elem_t > draw_map_t;	
 	typedef std::vector<LLPointer<LLVertexBuffer> > buffer_list_t;
 	typedef std::map<LLFace*, buffer_list_t> buffer_texture_map_t;
-	typedef std::map<U32, buffer_texture_map_t> buffer_map_t;
-
-	typedef LLOctreeNode<LLViewerOctreeEntry>::element_iter element_iter;
-	typedef LLOctreeNode<LLViewerOctreeEntry>::element_list element_list;
+	typedef std::map<U32, buffer_texture_map_t> buffer_map_t;	
 
 	struct CompareDistanceGreater
 	{
@@ -308,9 +306,7 @@ public:
 	BOOL addObject(LLDrawable *drawablep);
 	BOOL removeObject(LLDrawable *drawablep, BOOL from_octree = FALSE);
 	BOOL updateInGroup(LLDrawable *drawablep, BOOL immediate = FALSE); // Update position if it's in the group
-	BOOL isVisible() const;
 	BOOL isRecentlyVisible() const;
-	void setVisible();
 	void shift(const LLVector4a &offset);
 	void checkOcclusion(); //read back last occlusion query (if any)
 	void doOcclusion(LLCamera* camera); //issue occlusion query
@@ -325,14 +321,7 @@ public:
 
 	void setState(U32 state)       {mState |= state;}
 	void dirtyGeom() { setState(GEOM_DIRTY); }
-	void dirtyMesh() { setState(MESH_DIRTY); }
-
-	//octree wrappers to make code more readable
-	element_list& getData() { return mOctreeNode->getData(); }
-	element_iter getDataBegin() { return mOctreeNode->getDataBegin(); }
-	element_iter getDataEnd() { return mOctreeNode->getDataEnd(); }
-	U32 getElementCount() const { return mOctreeNode->getElementCount(); }
-	bool isEmpty() const { return mOctreeNode->isEmpty(); }
+	void dirtyMesh() { setState(MESH_DIRTY); }		
 
 	void drawObjectBox(LLColor4 col);
 
@@ -404,8 +393,7 @@ public:
 
 	U32 mBufferUsage;
 	draw_map_t mDrawMap;
-	
-	S32 mVisible[LLViewerCamera::NUM_CAMERAS];
+		
 	F32 mDistance;
 	F32 mDepth;
 	F32 mLastUpdateDistance;
@@ -428,7 +416,7 @@ public:
 	virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage);
 };
 
-class LLSpatialPartition: public LLGeometryManager
+class LLSpatialPartition: public LLViewerOctreePartition, public LLGeometryManager
 {
 public:
 	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage, LLViewerRegion* regionp);
@@ -458,7 +446,8 @@ public:
 	virtual void rebuildMesh(LLSpatialGroup* group);
 
 	BOOL visibleObjectsInFrustum(LLCamera& camera);
-	S32 cull(LLCamera &camera, std::vector<LLDrawable *>* results = NULL, BOOL for_select = FALSE); // Cull on arbitrary frustum
+	/*virtual*/ S32 cull(LLCamera &camera); // Cull on arbitrary frustum
+	S32 cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select); // Cull on arbitrary frustum
 	
 	BOOL isVisible(const LLVector3& v);
 	bool isHUDPartition() ;
@@ -473,26 +462,21 @@ public:
 	void resetVertexBuffers();
 	BOOL isOcclusionEnabled();
 	BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax);
-	BOOL isVOCachePartition() const;
-
+	
 public:
-	OctreeNode*      mOctree;
 	LLSpatialBridge* mBridge; // NULL for non-LLSpatialBridge instances, otherwise, mBridge == this
 							// use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe
 							// to call asBridge() from the destructor
 	BOOL mOcclusionEnabled; // if TRUE, occlusion culling is performed
 	BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
 	U32 mBufferUsage;
+	U32   mDrawableType;
 	const BOOL mRenderByGroup;
 	U32 mLODSeed;
 	U32 mLODPeriod;	//number of frames between LOD updates for a given spatial group (staggered by mLODSeed)
 	U32 mVertexDataMask;
 	F32 mSlopRatio; //percentage distance must change before drawables receive LOD update (default is 0.25);
-	BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering
-	U32 mDrawableType;
-	U32 mPartitionType;
-	U32 mVisitedTime;
-	LLViewerRegion* mRegionp; // the region this partition belongs to.
+	BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering	
 };
 
 // class for creating bridges between spatial partitions
@@ -638,19 +622,6 @@ public:
 	LLVoidWaterPartition(LLViewerRegion* regionp);
 };
 
-//spatial partition for hole and edge water (implemented in LLVOWater.cpp)
-class LLVOCachePartition : public LLSpatialPartition
-{
-public:
-	LLVOCachePartition(LLViewerRegion* regionp);
-
-	void addEntry(LLViewerOctreeEntry* entry);
-	void removeEntry(LLViewerOctreeEntry* entry);
-
-	virtual void getGeometry(LLSpatialGroup* group) {  }
-	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count) { }
-};
-
 //spatial partition for terrain (impelmented in LLVOSurfacePatch.cpp)
 class LLTerrainPartition : public LLSpatialPartition
 {
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 05f977036c..143f2a6819 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -26,6 +26,7 @@
 
 #include "llviewerprecompiledheaders.h"
 #include "llvieweroctree.h"
+#include "llviewerregion.h"
 
 //-----------------------------------------------------------------------------------
 //static variables definitions
@@ -324,6 +325,10 @@ void LLViewerOctreeEntryData::setVisible() const
 
 LLviewerOctreeGroup::~LLviewerOctreeGroup()
 {
+	if(LLViewerRegion::sCurRegionp && isVisible())
+	{
+		LLViewerRegion::sCurRegionp->clearVisibleGroup(this);
+	}
 }
 
 LLviewerOctreeGroup::LLviewerOctreeGroup(OctreeNode* node) :
@@ -482,8 +487,10 @@ void LLviewerOctreeGroup::handleDestruction(const TreeNode* node)
 		if (obj && obj->getGroup() == this)
 		{
 			obj->nullGroup();
+			//obj->setGroup(NULL);
 		}
 	}
+	mOctreeNode = NULL;
 }
 	
 //virtual 
@@ -500,8 +507,17 @@ void LLviewerOctreeGroup::handleStateChange(const TreeNode* node)
 //virtual 
 void LLviewerOctreeGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child)
 {
-	llerrs << "can not access here. It is an abstract class." << llendl;
+	if (child->getListenerCount() == 0)
+	{
+		new LLviewerOctreeGroup(child);
+	}
+	else
+	{
+		OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl;
+	}
 
+	unbound();
+	
 	//((LLviewerOctreeGroup*)child->getListener(0))->unbound();
 }
 	
@@ -589,7 +605,35 @@ bool LLviewerOctreeGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4
 //virtual 
 BOOL LLviewerOctreeGroup::isVisible() const
 {
-	return TRUE;
+	return mVisible[LLViewerCamera::sCurCameraID] >= LLViewerOctreeEntryData::getCurrentFrame() ? TRUE : FALSE;
+}
+
+//virtual 
+BOOL LLviewerOctreeGroup::isRecentlyVisible() const 
+{
+	return FALSE;
+}
+
+void LLviewerOctreeGroup::setVisible()
+{
+	mVisible[LLViewerCamera::sCurCameraID] = LLViewerOctreeEntryData::getCurrentFrame();
+}
+//-----------------------------------------------------------------------------------
+//class LLViewerOctreePartition definitions
+//-----------------------------------------------------------------------------------
+LLViewerOctreePartition::LLViewerOctreePartition() : mRegionp(NULL)
+{
+	LLVector4a center, size;
+	center.splat(0.f);
+	size.splat(1.f);
+
+	mOctree = new OctreeRoot(center,size, NULL);
+}
+	
+LLViewerOctreePartition::~LLViewerOctreePartition()
+{
+	delete mOctree;
+	mOctree = NULL;
 }
 
 //-----------------------------------------------------------------------------------
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index c063e96ea5..498ec3e75d 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -37,8 +37,9 @@
 #include "llvector4a.h"
 #include "llquaternion.h"
 #include "lloctree.h"
-#include "llcamera.h"
+#include "llviewercamera.h"
 
+class LLViewerRegion;
 class LLViewerOctreeEntryData;
 class LLviewerOctreeGroup;
 class LLViewerOctreeEntry;
@@ -181,6 +182,9 @@ public:
 	};
 
 public:
+	typedef LLOctreeNode<LLViewerOctreeEntry>::element_iter element_iter;
+	typedef LLOctreeNode<LLViewerOctreeEntry>::element_list element_list;
+
 	LLviewerOctreeGroup(OctreeNode* node);
 	LLviewerOctreeGroup(const LLviewerOctreeGroup& rhs)
 	{
@@ -203,8 +207,10 @@ public:
 	virtual void unbound();
 	virtual void rebound();
 
-	virtual BOOL isVisible() const;
-	virtual BOOL isRecentlyVisible() const = 0;
+	void setVisible();
+	BOOL isVisible() const;
+	virtual BOOL isRecentlyVisible() const;
+	bool isEmpty() const { return mOctreeNode->isEmpty(); }
 
 	U32  getState()				   {return mState; }
 	bool isDirty() const           {return mState & DIRTY;}
@@ -228,20 +234,43 @@ public:
 	const LLVector4a* getObjectBounds() const  {return mObjectBounds;}
 	const LLVector4a* getObjectExtents() const {return mObjectExtents;}
 
+	//octree wrappers to make code more readable
+	element_list& getData() { return mOctreeNode->getData(); }
+	element_iter getDataBegin() { return mOctreeNode->getDataBegin(); }
+	element_iter getDataEnd() { return mOctreeNode->getDataEnd(); }
+	U32 getElementCount() const { return mOctreeNode->getElementCount(); }	
+
 private:
 	virtual bool boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut);	
 	
 protected:
 	U32         mState;
-	OctreeNode* mOctreeNode;
-	
+	OctreeNode* mOctreeNode;	
+
 	LL_ALIGN_16(LLVector4a mBounds[2]);       // bounding box (center, size) of this node and all its children (tight fit to objects)
 	LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node
 	LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
 	LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node
 
+public:
+	S32         mVisible[LLViewerCamera::NUM_CAMERAS];
 }LL_ALIGN_POSTFIX(16);
 
+class LLViewerOctreePartition
+{
+public:
+	LLViewerOctreePartition();
+	virtual ~LLViewerOctreePartition();
+
+	// Cull on arbitrary frustum
+	virtual S32 cull(LLCamera &camera) = 0;
+
+public:	
+	U32              mPartitionType;
+	OctreeNode*      mOctree;
+	LLViewerRegion*  mRegionp; // the region this partition belongs to.
+};
+
 class LLViewerOctreeCull : public OctreeTraveler
 {
 public:
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 0c0522d32f..1adab15d70 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -86,6 +86,8 @@ const F32 CAP_REQUEST_TIMEOUT = 18;
 // Even though we gave up on login, keep trying for caps after we are logged in:
 const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;
 
+LLViewerRegion* LLViewerRegion::sCurRegionp = NULL;
+
 typedef std::map<std::string, std::string> CapabilityMap;
 
 class LLViewerRegionImpl {
@@ -139,7 +141,7 @@ public:
 	LLVOCacheEntry::vocache_entry_set_t mWaitingSet; //entries waiting for LLDrawable to be generated.
 	LLVOCacheEntry::vocache_entry_set_t mVisibleEntries; //visible root entries of a linked set.
 	std::set< LLPointer<LLVOCacheEntry> > mDummyEntries; //dummy vo cache entries, for LLSpatialBridge use.
-	std::set< LLSpatialGroup* >         mVisibleGroups; //visible llspatialgroup
+	std::set< LLviewerOctreeGroup* >      mVisibleGroups; //visible llspatialgroup
 	LLVOCachePartition*                 mVOCachePartition;
 
 	// time?
@@ -165,7 +167,7 @@ public:
 	LLCapabilityListener mCapabilityListener;
 
 	//spatial partitions for objects in this region
-	std::vector<LLSpatialPartition*> mObjectPartition;
+	std::vector<LLViewerOctreePartition*> mObjectPartition;
 };
 
 // support for secondlife:///app/region/{REGION} SLapps
@@ -345,7 +347,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mImpl->mObjectPartition.push_back(new LLVOCachePartition(this)); //PARTITION_VO_CACHE
 	mImpl->mObjectPartition.push_back(NULL);						//PARTITION_NONE
 
-	mImpl->mVOCachePartition = (LLVOCachePartition*)getSpatialPartition(PARTITION_VO_CACHE);
+	mImpl->mVOCachePartition = getVOCachePartition();
 }
 
 
@@ -384,12 +386,12 @@ LLViewerRegion::~LLViewerRegion()
 	delete mParcelOverlay;
 	delete mImpl->mLandp;
 	delete mImpl->mEventPoll;
-	LLHTTPSender::clearSender(mImpl->mHost);
-	
-	saveObjectCache();
+	LLHTTPSender::clearSender(mImpl->mHost);	
 
 	std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer());
 
+	saveObjectCache();
+
 	delete mImpl;
 	mImpl = NULL;
 }
@@ -865,13 +867,13 @@ void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* d
 	entry->setState(LLVOCacheEntry::INACTIVE);
 }
 
-void LLViewerRegion::addVisibleGroup(LLSpatialGroup* group)
+void LLViewerRegion::addVisibleGroup(LLviewerOctreeGroup* group)
 {
-	if(mDead || group->isEmpty() || group->isDead())
+	if(mDead || group->isEmpty())
 	{
 		return;
 	}
-
+	group->setVisible();
 	mImpl->mVisibleGroups.insert(group);
 }
 
@@ -909,7 +911,7 @@ void LLViewerRegion::addVisibleCacheEntry(LLVOCacheEntry* entry)
 	mImpl->mVisibleEntries.insert(entry);
 }
 
-void LLViewerRegion::clearVisibleGroup(LLSpatialGroup* group)
+void LLViewerRegion::clearVisibleGroup(LLviewerOctreeGroup* group)
 {
 	if(mDead)
 	{
@@ -920,44 +922,18 @@ void LLViewerRegion::clearVisibleGroup(LLSpatialGroup* group)
 
 	mImpl->mVisibleGroups.erase(group);
 }
-
-BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
-{
-	LLTimer update_timer;
-
-	// did_update returns TRUE if we did at least one significant update
-	BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time);
 	
-	if (mParcelOverlay)
-	{
-		// Hopefully not a significant time sink...
-		mParcelOverlay->idleUpdate();
-	}
-
-	if(update_timer.getElapsedTimeF32() > max_update_time)
-	{
-		return did_update;
-	}
-
-	//kill invisible objects
-	std::vector<LLDrawable*> delete_list;
-	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin();
-		iter != mImpl->mActiveSet.end(); ++iter)
-	{
-		if(!(*iter)->isRecentlyVisible())
-		{
-			killObject((*iter), delete_list);
-		}
-	}
-	for(S32 i = 0; i < delete_list.size(); i++)
+//return time left
+F32 LLViewerRegion::addLinkedSetChildren(F32 max_time, S32& max_num_objects)
+{
+	if(mImpl->mVisibleEntries.empty())
 	{
-		gObjectList.killObject(delete_list[i]->getVObj());
+		return max_time;
 	}
-	delete_list.clear();
 
+	LLTimer update_timer;
 	bool timeout = false;
-	S32 new_object_count = 64; //minimum number of new objects to be added
-	//add childrens of visible objects to the rendering pipeline
+
 	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();)
 	{
 		LLVOCacheEntry* entry = *iter;				
@@ -968,9 +944,9 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 			{
 				addNewObject(child);
 				
-				if(new_object_count-- < 0 && update_timer.getElapsedTimeF32() > max_update_time)
+				if(max_num_objects-- < 0 && update_timer.getElapsedTimeF32() > max_time)
 				{
-					timeout = true;
+					timeout = true; //timeout
 					break;
 				}
 			}
@@ -982,7 +958,10 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 			{
 				mImpl->mDummyEntries.erase(entry);
 			}
-
+		}
+		
+		if(!timeout)
+		{
 			iter = mImpl->mVisibleEntries.erase(iter);
 		}
 		else
@@ -990,17 +969,28 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 			break; //timeout
 		}
 	}
+
 	if(timeout)
 	{
-		mImpl->mVisibleGroups.clear();
-		return did_update;
+		return -1.f;
 	}
+	return max_time - update_timer.getElapsedTimeF32(); //time left
+}
 
-	//add objects in the visible groups to the rendering pipeline
-	std::set< LLSpatialGroup* >::iterator group_iter = mImpl->mVisibleGroups.begin();
+F32 LLViewerRegion::addVisibleObjects(F32 max_time, S32& max_num_objects)
+{
+	if(mImpl->mVisibleGroups.empty())
+	{
+		return max_time;
+	}
+
+	LLTimer update_timer;
+	bool timeout = false;
+
+	std::set< LLviewerOctreeGroup* >::iterator group_iter = mImpl->mVisibleGroups.begin();
 	while(group_iter != mImpl->mVisibleGroups.end())
 	{
-		LLSpatialGroup* group = *group_iter;
+		LLviewerOctreeGroup* group = *group_iter;
 		if(!group->getOctreeNode() || group->isEmpty())
 		{
 			mImpl->mVisibleGroups.erase(group_iter);
@@ -1009,7 +999,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 		}
 
 		std::vector<LLViewerOctreeEntry*> entry_list;
-		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+		for (LLviewerOctreeGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 		{
 			//group data contents could change during creating new objects, so copy all contents first.
 			entry_list.push_back(*i);
@@ -1028,7 +1018,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 				else if(vo_entry->isState(LLVOCacheEntry::INACTIVE))
 				{
 					addNewObject(vo_entry);
-					if(new_object_count-- < 0 && update_timer.getElapsedTimeF32() > max_update_time)
+					if(max_num_objects-- < 0 && update_timer.getElapsedTimeF32() > max_time)
 					{
 						timeout = true;
 						break;
@@ -1044,12 +1034,75 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 		}
 		mImpl->mVisibleGroups.erase(group);
 		group_iter = mImpl->mVisibleGroups.begin();
+	}	
+
+	if(timeout)
+	{
+		return -1.0f;
 	}
-	mImpl->mVisibleGroups.clear();
+	return max_time - update_timer.getElapsedTimeF32();
+}
+
+BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
+{
+	LLTimer update_timer;
 
+	// did_update returns TRUE if we did at least one significant update
+	BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time);
+	
+	if (mParcelOverlay)
+	{
+		// Hopefully not a significant time sink...
+		mParcelOverlay->idleUpdate();
+	}
+
+	max_update_time -= update_timer.getElapsedTimeF32();
+	if(max_update_time < 0.f)
+	{
+		return did_update;
+	}
+
+	sCurRegionp = this;
+
+	//kill invisible objects
+	max_update_time = killInvisibleObjects(max_update_time);
+
+	S32 new_object_count = 64; //minimum number of new objects to be added
+	
+	//add childrens of visible objects to the rendering pipeline
+	max_update_time = addLinkedSetChildren(max_update_time, new_object_count);
+
+	//add objects in the visible groups to the rendering pipeline
+	if(max_update_time > 0.f)
+	{
+		addVisibleObjects(max_update_time, new_object_count);
+	}
+
+	mImpl->mVisibleGroups.clear();
+	sCurRegionp = NULL;
 	return did_update;
 }
 
+F32 LLViewerRegion::killInvisibleObjects(F32 max_time)
+{
+	std::vector<LLDrawable*> delete_list;
+	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin();
+		iter != mImpl->mActiveSet.end(); ++iter)
+	{
+		if(!(*iter)->isRecentlyVisible())
+		{
+			killObject((*iter), delete_list);
+		}
+	}
+	for(S32 i = 0; i < delete_list.size(); i++)
+	{
+		gObjectList.killObject(delete_list[i]->getVObj());
+	}
+	delete_list.clear();
+
+	return max_time;
+}
+
 void LLViewerRegion::killObject(LLVOCacheEntry* entry, std::vector<LLDrawable*>& delete_list)
 {
 	//kill the object.
@@ -2189,9 +2242,18 @@ void LLViewerRegion::logActiveCapabilities() const
 
 LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type)
 {
-	if (type < mImpl->mObjectPartition.size())
+	if (type < mImpl->mObjectPartition.size() && type < PARTITION_VO_CACHE)
+	{
+		return (LLSpatialPartition*)mImpl->mObjectPartition[type];
+	}
+	return NULL;
+}
+
+LLVOCachePartition* LLViewerRegion::getVOCachePartition()
+{
+	if(PARTITION_VO_CACHE < mImpl->mObjectPartition.size())
 	{
-		return mImpl->mObjectPartition[type];
+		return (LLVOCachePartition*)mImpl->mObjectPartition[PARTITION_VO_CACHE];
 	}
 	return NULL;
 }
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 17654a8bc7..86d3ee0d8c 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -69,6 +69,8 @@ class LLBBox;
 class LLSpatialGroup;
 class LLDrawable;
 class LLViewerRegionImpl;
+class LLviewerOctreeGroup;
+class LLVOCachePartition;
 
 class LLViewerRegion: public LLCapabilityProvider // implements this interface
 {
@@ -85,7 +87,7 @@ public:
 		PARTITION_GRASS,
 		PARTITION_VOLUME,
 		PARTITION_BRIDGE,
-		PARTITION_HUD_PARTICLE,
+		PARTITION_HUD_PARTICLE,		
 		PARTITION_VO_CACHE,
 		PARTITION_NONE,
 		NUM_PARTITIONS
@@ -218,12 +220,12 @@ public:
 	F32	getWidth() const						{ return mWidth; }
 
 	BOOL idleUpdate(F32 max_update_time);
-	void addVisibleGroup(LLSpatialGroup* group);
+	void addVisibleGroup(LLviewerOctreeGroup* group);
 	void addVisibleCacheEntry(LLVOCacheEntry* entry);
 	void addActiveCacheEntry(LLVOCacheEntry* entry);
 	void removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* drawablep);	
 	void killCacheEntry(U32 local_id); //physically delete the cache entry	
-	void clearVisibleGroup(LLSpatialGroup* group);
+	void clearVisibleGroup(LLviewerOctreeGroup* group);
 
 	// Like idleUpdate, but forces everything to complete regardless of
 	// how long it takes.
@@ -333,6 +335,7 @@ public:
 
 	U32 getNumOfActiveCachedObjects() const;
 	LLSpatialPartition* getSpatialPartition(U32 type);
+	LLVOCachePartition* getVOCachePartition();
 
 	bool objectIsReturnable(const LLVector3& pos, const std::vector<LLBBox>& boxes) const;
 	bool childrenObjectReturnable( const std::vector<LLBBox>& boxes ) const;
@@ -350,6 +353,10 @@ private:
 	void replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry);
 	void killCacheEntry(LLVOCacheEntry* entry); //physically delete the cache entry	
 
+	F32 killInvisibleObjects(F32 max_time);
+	F32 addLinkedSetChildren(F32 max_time, S32& max_num_objects);
+	F32 addVisibleObjects(F32 max_time, S32& max_num_objects);
+
 public:
 	struct CompareDistance
 	{
@@ -384,6 +391,7 @@ public:
 	LLDynamicArray<U32> mMapAvatars;
 	LLDynamicArray<LLUUID> mMapAvatarIDs;
 
+	static LLViewerRegion* sCurRegionp;
 private:
 	LLViewerRegionImpl * mImpl;
 
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index f389867484..d4938fd216 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -31,6 +31,7 @@
 #include "llviewercontrol.h"
 #include "llviewerobjectlist.h"
 #include "lldrawable.h"
+#include "llviewerregion.h"
 
 BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) 
 {
@@ -355,6 +356,82 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 	return success ;
 }
 
+//-------------------------------------------------------------------
+//LLVOCachePartition
+//-------------------------------------------------------------------
+LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp)
+{
+	mRegionp = regionp;
+	mPartitionType = LLViewerRegion::PARTITION_VO_CACHE;
+	mVisitedTime = 0;
+
+	new LLviewerOctreeGroup(mOctree);
+}
+
+void LLVOCachePartition::addEntry(LLViewerOctreeEntry* entry)
+{
+	llassert(entry->hasVOCacheEntry());
+
+	mOctree->insert(entry);
+}
+	
+void LLVOCachePartition::removeEntry(LLViewerOctreeEntry* entry)
+{
+	entry->getVOCacheEntry()->setGroup(NULL);
+
+	llassert(!entry->getGroup());
+}
+	
+class LLVOCacheOctreeCull : public LLViewerOctreeCull
+{
+public:
+	LLVOCacheOctreeCull(LLCamera* camera, LLViewerRegion* regionp) : LLViewerOctreeCull(camera), mRegionp(regionp) {}
+
+	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)
+	{
+		S32 res = AABBInFrustumNoFarClipGroupBounds(group);
+		if (res != 0)
+		{
+			res = llmin(res, AABBSphereIntersectGroupExtents(group));
+		}
+		return res;
+	}
+
+	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)
+	{
+		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
+		if (res != 0)
+		{
+			res = llmin(res, AABBSphereIntersectObjectExtents(group));
+		}
+		return res;
+	}
+
+	virtual void processGroup(LLviewerOctreeGroup* base_group)
+	{
+		mRegionp->addVisibleGroup(base_group);
+	}
+
+private:
+	LLViewerRegion* mRegionp;
+};
+
+S32 LLVOCachePartition::cull(LLCamera &camera)
+{
+	if(mVisitedTime == LLViewerOctreeEntryData::getCurrentFrame())
+	{
+		return 0; //already visited.
+	}
+	mVisitedTime = LLViewerOctreeEntryData::getCurrentFrame();
+
+	((LLviewerOctreeGroup*)mOctree->getListener(0))->rebound();
+		
+	LLVOCacheOctreeCull culler(&camera, mRegionp);
+	culler.traverse(mOctree);
+
+	return 0;
+}
+
 //-------------------------------------------------------------------
 //LLVOCache
 //-------------------------------------------------------------------
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 2228e3e43b..675c12a3eb 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -98,6 +98,19 @@ protected:
 	std::vector<LLVOCacheEntry*> mChildrenList; //children entries in a linked set.
 };
 
+class LLVOCachePartition : public LLViewerOctreePartition
+{
+public:
+	LLVOCachePartition(LLViewerRegion* regionp);
+
+	void addEntry(LLViewerOctreeEntry* entry);
+	void removeEntry(LLViewerOctreeEntry* entry);
+	/*virtual*/ S32 cull(LLCamera &camera);
+
+private:
+	U32 mVisitedTime;
+};
+
 //
 //Note: LLVOCache is not thread-safe
 //
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e06577c512..850714f676 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -86,6 +86,7 @@
 #include "llviewerregion.h" // for audio debugging.
 #include "llviewerwindow.h" // For getSpinAxis
 #include "llvoavatarself.h"
+#include "llvocache.h"
 #include "llvoground.h"
 #include "llvosky.h"
 #include "llvotree.h"
@@ -2352,12 +2353,15 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 				{
 					part->cull(camera);
 				}
-				else if(part->mPartitionType == LLViewerRegion::PARTITION_VO_CACHE)
-				{
-					part->cull(camera);
-				}
 			}
 		}
+
+		//scan the VO Cache tree
+		LLVOCachePartition* vo_part = region->getVOCachePartition();
+		if(vo_part)
+		{
+			vo_part->cull(camera);
+		}
 	}
 
 	if (bound_shader)
@@ -2433,12 +2437,8 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 	}
 
 	assertInitialized();
-	
-	if(group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_VO_CACHE)
-	{
-		group->mSpatialPartition->mRegionp->addVisibleGroup(group);
-	}
-	else if (!group->mSpatialPartition->mRenderByGroup)
+		
+	if (!group->mSpatialPartition->mRenderByGroup)
 	{ //render by drawable
 		sCull->pushDrawableGroup(group);
 	}
-- 
cgit v1.2.3


From 8e6341b9194b1fb27d92d8f5e6739390ac882941 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 1 Nov 2012 17:05:26 -0600
Subject: more for SH-3459: interesting store object bounding information in
 viewer cache

---
 indra/newview/llvocache.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index d4938fd216..db6aa9cd00 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -110,6 +110,17 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32));
 	}
 	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));
@@ -332,6 +343,17 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32));
 	}
 	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]);
-- 
cgit v1.2.3


From c2859e4663c405950b6f433270ae558852330c76 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 8 Nov 2012 21:36:47 -0700
Subject: for SH-3472: prioritize object loading

---
 indra/newview/lldrawable.cpp         |  17 +-
 indra/newview/llviewerobjectlist.cpp |  85 +++++-----
 indra/newview/llviewerobjectlist.h   |   2 +-
 indra/newview/llvieweroctree.cpp     |   9 +-
 indra/newview/llvieweroctree.h       |   8 +-
 indra/newview/llviewerregion.cpp     | 317 ++++++++++++++++++++++-------------
 indra/newview/llviewerregion.h       |   6 +-
 indra/newview/llvocache.cpp          | 136 +++++++++++----
 indra/newview/llvocache.h            |  69 ++++++--
 9 files changed, 423 insertions(+), 226 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index e29551e83c..c782fbfe7e 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -470,7 +470,13 @@ void LLDrawable::makeActive()
 		}
 		updatePartition();
 	}
-
+	else if (!isRoot() && !mParent->isActive()) //this should not happen, but occasionally it does...
+	{
+		mParent->makeActive();
+		//NOTE: linked set will now NEVER become static
+		mParent->setState(LLDrawable::ACTIVE_CHILD);
+	}
+	
 	llassert(isAvatar() || isRoot() || mParent->isActive());
 }
 
@@ -1093,6 +1099,11 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat
 	{
 		part->put(this);
 	}
+
+	if(mDrawable->getEntry()->hasVOCacheEntry())
+	{
+		((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry())->setBridgeChild();
+	}
 }
 
 LLSpatialBridge::~LLSpatialBridge()
@@ -1470,9 +1481,9 @@ void LLSpatialBridge::cleanupReferences()
 		dummy_entry = new LLVOCacheEntry();
 		dummy_entry->setOctreeEntry(mEntry);
 		dummy_entry->addChild((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry());
-		llassert(!mDrawable->getParent());
+		//llassert(!mDrawable->getParent());
 		
-		mDrawable->mParent = this;
+		//mDrawable->mParent = this;
 	}
 
 	LLDrawable::cleanupReferences();
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index d41eee5926..f3552e2c2b 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -376,7 +376,7 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*
 void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 											 void **user_data,
 											 const EObjectUpdateType update_type,
-											 bool cached, bool compressed)
+											 bool compressed)
 {
 	LLFastTimer t(FTM_PROCESS_OBJECTS);	
 	
@@ -395,7 +395,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
 
 	// I don't think this case is ever hit.  TODO* Test this.
-	if (!cached && !compressed && update_type != OUT_FULL)
+	if (!compressed && update_type != OUT_FULL)
 	{
 		//llinfos << "TEST: !cached && !compressed && update_type != OUT_FULL" << llendl;
 		gTerseObjectUpdates += num_objects;
@@ -439,7 +439,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 
 	U8 compressed_dpbuffer[2048];
 	LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048);
-	LLDataPacker *cached_dpp = NULL;
 	LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance();
 
 	for (i = 0; i < num_objects; i++)
@@ -449,34 +448,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 		BOOL justCreated = FALSE;
 		S32	msg_size = 0;
 
-		if (cached)
-		{
-			U32 id;
-			U32 crc;
-			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i);
-			mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, 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;
-			cached_dpp = regionp->getDP(id, crc, cache_miss_type);
-			if (cached_dpp)
-			{
-				// Cache Hit.
-				cached_dpp->reset();
-				cached_dpp->unpackUUID(fullid, "ID");
-				cached_dpp->unpackU32(local_id, "LocalID");
-				cached_dpp->unpackU8(pcode, "PCode");
-			}
-			else
-			{
-				// Cache Miss.
-				recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size);
-
-				continue; // no data packer, skip this object
-			}
-		}
-		else if (compressed)
+		if (compressed)
 		{
 			S32	uncompressed_length = 2048;
 			compressed_dp.reset();			
@@ -575,9 +547,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 					continue;
 				}
 			}
-			else if (cached) // Cache hit only?
-			{
-			}
 			else
 			{
 				if (update_type != OUT_FULL)
@@ -610,7 +579,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			}
 			justCreated = TRUE;
 			mNumNewObjects++;
-			sCacheHitRate.addValue(cached ? 100.f : 0.f);
+			sCacheHitRate.addValue(0.f);
 
 		}
 
@@ -641,11 +610,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 				}
 			}
 		}
-		else if (cached) // Cache hit only?
-		{
-			objectp->mLocalID = local_id;
-			processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated);
-		}
 		else
 		{
 			if (update_type == OUT_FULL)
@@ -668,14 +632,51 @@ void LLViewerObjectList::processCompressedObjectUpdate(LLMessageSystem *mesgsys,
 											 void **user_data,
 											 const EObjectUpdateType update_type)
 {
-	processObjectUpdate(mesgsys, user_data, update_type, false, true);
+	processObjectUpdate(mesgsys, user_data, update_type, true);
 }
 
 void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,
 											 void **user_data,
 											 const EObjectUpdateType update_type)
 {
-	processObjectUpdate(mesgsys, user_data, update_type, true, false);
+	//processObjectUpdate(mesgsys, user_data, update_type, true, false);
+
+	S32 num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
+	gFullObjectUpdates += num_objects;
+
+	U64 region_handle;
+	mesgsys->getU64Fast(_PREHASH_RegionData, _PREHASH_RegionHandle, region_handle);	
+	LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(region_handle);
+	if (!regionp)
+	{
+		llwarns << "Object update from unknown region! " << region_handle << llendl;
+		return;
+	}
+
+	LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance();
+
+	for (S32 i = 0; i < num_objects; i++)
+	{
+		S32	msg_size = 0;
+		U32 id;
+		U32 crc;
+		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i);
+		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, 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))
+		{
+			// Cache Miss.
+			recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size);
+
+			continue; // no data packer, skip this object
+		}
+		sCacheHitRate.addValue(100.f);
+	}
+
+	return;
 }	
 
 void LLViewerObjectList::dirtyAllObjectInventory()
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 1476f44215..17c8c86ff5 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -83,7 +83,7 @@ public:
 	void processUpdateCore(LLViewerObject* objectp, void** data, U32 block, const EObjectUpdateType update_type, 
 		                   LLDataPacker* dpp, bool justCreated, bool from_cache = false);
 	LLViewerObject* processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp);
-	void processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type, bool cached=false, bool compressed=false);
+	void processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type, bool compressed=false);
 	void processCompressedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type);
 	void processCachedObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type);
 	void updateApparentAngles(LLAgent &agent);
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 143f2a6819..b6e0674a95 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -126,13 +126,14 @@ S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LL
 //-----------------------------------------------------------------------------------
 //class LLViewerOctreeEntry definitions
 //-----------------------------------------------------------------------------------
-LLViewerOctreeEntry::LLViewerOctreeEntry() : mGroup(NULL)
+LLViewerOctreeEntry::LLViewerOctreeEntry() 
+	: mGroup(NULL),
+	  mBinRadius(0.f),
+	  mBinIndex(-1)
 {
 	mPositionGroup.clear();
 	mExtents[0].clear();
-	mExtents[1].clear();
-	mBinRadius = 0.f;
-	mBinIndex = -1;
+	mExtents[1].clear();	
 
 	for(S32 i = 0; i < NUM_DATA_TYPE; i++)
 	{
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index 498ec3e75d..b89014119c 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -135,7 +135,7 @@ public:
 	const LLVector4a*    getSpatialExtents() const;
 	LLviewerOctreeGroup* getGroup()const;
 	const LLVector4a&    getPositionGroup() const;
-
+	
 	void setBinRadius(F32 rad)  {mEntry->mBinRadius = rad;}
 	void setSpatialExtents(const LLVector3& min, const LLVector3& max);
 	void setSpatialExtents(const LLVector4a& min, const LLVector4a& max);
@@ -247,9 +247,9 @@ protected:
 	U32         mState;
 	OctreeNode* mOctreeNode;	
 
-	LL_ALIGN_16(LLVector4a mBounds[2]);       // bounding box (center, size) of this node and all its children (tight fit to objects)
-	LL_ALIGN_16(LLVector4a mObjectBounds[2]); // bounding box (center, size) of objects in this node
-	LL_ALIGN_16(LLVector4a mExtents[2]); // extents (min, max) of this node and all its children
+	LL_ALIGN_16(LLVector4a mBounds[2]);        // bounding box (center, size) of this node and all its children (tight fit to objects)
+	LL_ALIGN_16(LLVector4a mObjectBounds[2]);  // bounding box (center, size) of objects in this node
+	LL_ALIGN_16(LLVector4a mExtents[2]);       // extents (min, max) of this node and all its children
 	LL_ALIGN_16(LLVector4a mObjectExtents[2]); // extents (min, max) of objects in this node
 
 public:
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 1adab15d70..24bd68825b 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -100,6 +100,8 @@ public:
 			mSeedCapMaxAttemptsBeforeLogin(MAX_SEED_CAP_ATTEMPTS_BEFORE_LOGIN),
 			mSeedCapAttempts(0),
 			mHttpResponderID(0),
+			mLastCameraUpdate(0),
+			mLastCameraOrigin(),
 		    // I'd prefer to set the LLCapabilityListener name to match the region
 		    // name -- it's disappointing that's not available at construction time.
 		    // We could instead store an LLCapabilityListener*, making
@@ -136,13 +138,14 @@ public:
 	// Misc
 	LLVLComposition *mCompositionp;		// Composition layer for the surface
 
-	LLVOCacheEntry::vocache_entry_map_t	mCacheMap; //all cached entries
-	LLVOCacheEntry::vocache_entry_set_t mActiveSet; //all active entries;
-	LLVOCacheEntry::vocache_entry_set_t mWaitingSet; //entries waiting for LLDrawable to be generated.
-	LLVOCacheEntry::vocache_entry_set_t mVisibleEntries; //visible root entries of a linked set.
+	LLVOCacheEntry::vocache_entry_map_t	  mCacheMap; //all cached entries
+	LLVOCacheEntry::vocache_entry_set_t   mActiveSet; //all active entries;
+	LLVOCacheEntry::vocache_entry_set_t   mWaitingSet; //entries waiting for LLDrawable to be generated.	
 	std::set< LLPointer<LLVOCacheEntry> > mDummyEntries; //dummy vo cache entries, for LLSpatialBridge use.
-	std::set< LLviewerOctreeGroup* >      mVisibleGroups; //visible llspatialgroup
-	LLVOCachePartition*                 mVOCachePartition;
+	std::set< LLviewerOctreeGroup* >      mVisibleGroups; //visible groupa
+	LLVOCachePartition*                   mVOCachePartition;
+	LLVOCacheEntry::vocache_entry_set_t   mVisibleEntries; //must-be-created visible entries wait for objects creation.	
+	LLVOCacheEntry::vocache_entry_priority_list_t mWaitingList; //transient list storing sorted visible entries waiting for object creation.
 
 	// time?
 	// LRU info?
@@ -168,6 +171,9 @@ public:
 
 	//spatial partitions for objects in this region
 	std::vector<LLViewerOctreePartition*> mObjectPartition;
+
+	LLVector3 mLastCameraOrigin;
+	U32       mLastCameraUpdate;
 };
 
 // support for secondlife:///app/region/{REGION} SLapps
@@ -736,27 +742,16 @@ void LLViewerRegion::dirtyHeights()
 
 void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry)
 {
-	LLPointer<LLViewerOctreeEntry> oct_entry;
 	U32 state = LLVOCacheEntry::INACTIVE;
 
 	if(old_entry)
 	{
-		oct_entry = old_entry->getEntry();
+		new_entry->copy(old_entry);
 		state = old_entry->getState();		
-
-		while(old_entry->getNumOfChildren() > 0)
-		{
-			new_entry->addChild(old_entry->getNextChild());
-		}
-
 		killCacheEntry(old_entry);
 	}
 
 	mImpl->mCacheMap[new_entry->getLocalID()] = new_entry;
-	if(oct_entry.notNull())
-	{
-		new_entry->setOctreeEntry(oct_entry);
-	}
 
 	if(state == LLVOCacheEntry::ACTIVE)
 	{
@@ -767,7 +762,7 @@ void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry
 	{
 		mImpl->mWaitingSet.insert(new_entry);
 	}
-	else if(old_entry && oct_entry)
+	else if(old_entry && new_entry->getEntry())
 	{
 		addToVOCacheTree(new_entry);
 	}
@@ -790,19 +785,23 @@ void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry)
 	else if(entry->isState(LLVOCacheEntry::WAITING))
 	{
 		mImpl->mWaitingSet.erase(entry);
-	}	
-
-	//2, kill LLViewerObject if exists
-	//this should be done by the rendering pipeline automatically.
-
-	//3, remove from mVOCachePartition
-	if(entry->isState(LLVOCacheEntry::INACTIVE) && entry->getEntry())
+	}
+	else if(entry->isState(LLVOCacheEntry::IN_QUEUE))
 	{
+		mImpl->mVisibleEntries.erase(entry);
+	}
+	else if(entry->isState(LLVOCacheEntry::INACTIVE))
+	{
+		//remove from mVOCachePartition
 		removeFromVOCacheTree(entry);
 	}
 
+	//kill LLViewerObject if exists
+	//this should be done by the rendering pipeline automatically.
+	
 	entry->setState(LLVOCacheEntry::INACTIVE);
-	//4, remove from mCacheMap, real deletion
+	
+	//remove from mCacheMap, real deletion
 	mImpl->mCacheMap.erase(entry->getLocalID());
 }
 
@@ -885,7 +884,10 @@ void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry)
 	{
 		return;
 	}
-	llassert(!entry->getGroup());
+	if(entry->getGroup()) //already in octree.
+	{
+		return;
+	}
 
 	mImpl->mVOCachePartition->addEntry(entry->getEntry());
 }
@@ -896,18 +898,31 @@ void LLViewerRegion::removeFromVOCacheTree(LLVOCacheEntry* entry)
 	{
 		return;
 	}
+	if(!entry->getGroup())
+	{
+		return;
+	}
 
 	mImpl->mVOCachePartition->removeEntry(entry->getEntry());
 }
 
-//add the visible root entry of a linked set
+//add the visible entries
 void LLViewerRegion::addVisibleCacheEntry(LLVOCacheEntry* entry)
 {
-	if(mDead || !entry || !entry->getNumOfChildren())
+	if(mDead || !entry)
 	{
-		return; //no child entries
+		return; 
 	}
 
+	if(entry->isState(LLVOCacheEntry::IN_QUEUE))
+	{
+		return;
+	}
+
+	if(entry->isState(LLVOCacheEntry::INACTIVE))
+	{
+		entry->setState(LLVOCacheEntry::IN_QUEUE);
+	}
 	mImpl->mVisibleEntries.insert(entry);
 }
 
@@ -922,124 +937,148 @@ void LLViewerRegion::clearVisibleGroup(LLviewerOctreeGroup* group)
 
 	mImpl->mVisibleGroups.erase(group);
 }
-	
-//return time left
-F32 LLViewerRegion::addLinkedSetChildren(F32 max_time, S32& max_num_objects)
+
+F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
 {
-	if(mImpl->mVisibleEntries.empty())
+	if(mImpl->mVisibleGroups.empty() && mImpl->mVisibleEntries.empty())
 	{
 		return max_time;
 	}
 
 	LLTimer update_timer;
-	bool timeout = false;
+
+	const LLVector3 camera_origin = LLViewerCamera::getInstance()->getOrigin();
+	const U32 cur_frame = LLViewerOctreeEntryData::getCurrentFrame();
+	bool needs_update = ((cur_frame - mImpl->mLastCameraUpdate) > 5) && ((camera_origin - mImpl->mLastCameraOrigin).lengthSquared() > 10.f);	
+
+	//process visible entries
+	max_time *= 0.5f; //only use up to half available time to update entries.
 
 	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();)
 	{
-		LLVOCacheEntry* entry = *iter;				
-		LLVOCacheEntry* child = entry->getNextChild();
-		while(child != NULL)
+		LLVOCacheEntry* vo_entry = *iter;
+		vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate);
+
+		if(vo_entry->getState() < LLVOCacheEntry::WAITING && !vo_entry->isDummy())
+		{			
+			mImpl->mWaitingList.insert(vo_entry);
+		}
+
+		LLVOCacheEntry* child;
+		S32 num_child = vo_entry->getNumOfChildren();
+		S32 num_done = 0;
+		for(S32 i = 0; i < num_child; i++)
 		{
-			if(child->isState(LLVOCacheEntry::INACTIVE))
+			child = vo_entry->getChild(i);
+			if(child->getState() < LLVOCacheEntry::WAITING)
 			{
-				addNewObject(child);
-				
-				if(max_num_objects-- < 0 && update_timer.getElapsedTimeF32() > max_time)
-				{
-					timeout = true; //timeout
-					break;
-				}
+				child->setSceneContribution(vo_entry->getSceneContribution());
+				mImpl->mWaitingList.insert(child);
 			}
-			child = entry->getNextChild();
-		}
-		if(!child)
-		{
-			if(entry->isDummy())
+			else
 			{
-				mImpl->mDummyEntries.erase(entry);
+				num_done++;
 			}
 		}
-		
-		if(!timeout)
+		if(num_done == num_child)
 		{
-			iter = mImpl->mVisibleEntries.erase(iter);
+			vo_entry->clearChildrenList();
+		}
+
+		if(!vo_entry->getNumOfChildren())
+		{
+			if(vo_entry->isDummy())
+			{
+				mImpl->mDummyEntries.erase(vo_entry);
+				iter = mImpl->mVisibleEntries.erase(iter);
+			}
+			else if(vo_entry->getState() >= LLVOCacheEntry::WAITING)
+			{
+				iter = mImpl->mVisibleEntries.erase(iter);
+			}
+			else
+			{
+				++iter;
+			}
 		}
 		else
 		{
-			break; //timeout
+			++iter;
 		}
-	}
 
-	if(timeout)
-	{
-		return -1.f;
-	}
-	return max_time - update_timer.getElapsedTimeF32(); //time left
-}
-
-F32 LLViewerRegion::addVisibleObjects(F32 max_time, S32& max_num_objects)
-{
-	if(mImpl->mVisibleGroups.empty())
-	{
-		return max_time;
+		//if(update_timer.getElapsedTimeF32() > max_time)
+		//{
+		//	break;
+		//}
 	}
 
-	LLTimer update_timer;
-	bool timeout = false;
-
+	//process visible groups
 	std::set< LLviewerOctreeGroup* >::iterator group_iter = mImpl->mVisibleGroups.begin();
-	while(group_iter != mImpl->mVisibleGroups.end())
+	for(; group_iter != mImpl->mVisibleGroups.end(); ++group_iter)
 	{
 		LLviewerOctreeGroup* group = *group_iter;
 		if(!group->getOctreeNode() || group->isEmpty())
 		{
-			mImpl->mVisibleGroups.erase(group_iter);
-			group_iter = mImpl->mVisibleGroups.begin();
 			continue;
 		}
 
-		std::vector<LLViewerOctreeEntry*> entry_list;
 		for (LLviewerOctreeGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 		{
-			//group data contents could change during creating new objects, so copy all contents first.
-			entry_list.push_back(*i);
-		}
-		
-		for(S32 i = 0; i < entry_list.size(); i++)
-		{
-			LLViewerOctreeEntry* entry = entry_list[i];
-			if(entry && entry->hasVOCacheEntry())
+			if((*i)->hasVOCacheEntry())
 			{
-				LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)entry->getVOCacheEntry();
+				LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry();
 				if(vo_entry->isDummy())
 				{
 					addVisibleCacheEntry(vo_entry); //for LLSpatialBridge.
+					continue;
 				}
-				else if(vo_entry->isState(LLVOCacheEntry::INACTIVE))
-				{
-					addNewObject(vo_entry);
-					if(max_num_objects-- < 0 && update_timer.getElapsedTimeF32() > max_time)
-					{
-						timeout = true;
-						break;
-					}
-				}
+
+				vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate);				
+				mImpl->mWaitingList.insert(vo_entry);
 			}
 		}
-		entry_list.clear();
 
-		if(timeout)
-		{
-			break;
-		}
-		mImpl->mVisibleGroups.erase(group);
-		group_iter = mImpl->mVisibleGroups.begin();
-	}	
+		//if(update_timer.getElapsedTimeF32() > max_time)
+		//{
+		//	break;
+		//}
+	}
+	mImpl->mVisibleGroups.clear();
+
+	if(needs_update)
+	{
+		mImpl->mLastCameraOrigin = camera_origin;
+		mImpl->mLastCameraUpdate = cur_frame;
+	}
+
+	return 2.0f * max_time - update_timer.getElapsedTimeF32();
+}
+
+F32 LLViewerRegion::createVisibleObjects(F32 max_time)
+{
+	if(mImpl->mWaitingList.empty())
+	{
+		return max_time;
+	}
 
-	if(timeout)
+	LLTimer update_timer;
+	S32 max_num_objects = 64; //minimum number of new objects to be added
+	for(LLVOCacheEntry::vocache_entry_priority_list_t::iterator iter = mImpl->mWaitingList.begin();
+		iter != mImpl->mWaitingList.end(); ++iter)
 	{
-		return -1.0f;
+		LLVOCacheEntry* vo_entry = *iter;
+			
+		if(vo_entry->getState() < LLVOCacheEntry::WAITING)
+		{
+			addNewObject(vo_entry);
+			if(max_num_objects-- < 0 && update_timer.getElapsedTimeF32() > max_time)
+			{
+				break;
+			}
+		}
 	}
+	mImpl->mWaitingList.clear();
+
 	return max_time - update_timer.getElapsedTimeF32();
 }
 
@@ -1057,7 +1096,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 	}
 
 	max_update_time -= update_timer.getElapsedTimeF32();
-	if(max_update_time < 0.f)
+	if(max_update_time < 0.f || mImpl->mCacheMap.empty())
 	{
 		return did_update;
 	}
@@ -1065,20 +1104,14 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 	sCurRegionp = this;
 
 	//kill invisible objects
-	max_update_time = killInvisibleObjects(max_update_time);
-
-	S32 new_object_count = 64; //minimum number of new objects to be added
+	max_update_time = killInvisibleObjects(max_update_time);	
 	
-	//add childrens of visible objects to the rendering pipeline
-	max_update_time = addLinkedSetChildren(max_update_time, new_object_count);
-
-	//add objects in the visible groups to the rendering pipeline
-	if(max_update_time > 0.f)
-	{
-		addVisibleObjects(max_update_time, new_object_count);
-	}
+	max_update_time = updateVisibleEntries(max_update_time);
+	createVisibleObjects(max_update_time);
 
 	mImpl->mVisibleGroups.clear();
+	mImpl->mWaitingList.clear();
+
 	sCurRegionp = NULL;
 	return did_update;
 }
@@ -1687,7 +1720,7 @@ LLVOCacheEntry* LLViewerRegion::getCacheEntry(U32 local_id)
 
 // Get data packer for this object, if we have cached data
 // AND the CRC matches. JC
-LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
+bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
 {
 	//llassert(mCacheLoaded);  This assert failes often, changing to early-out -- davep, 2010/10/18
 
@@ -1702,7 +1735,51 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
 			entry->recordHit();
 			cache_miss_type = CACHE_MISS_TYPE_NONE;
 
-			return entry->getDP(crc);
+			if(entry->getGroup() || !entry->isState(LLVOCacheEntry::INACTIVE))
+			{
+				return true;
+			}
+
+			addVisibleCacheEntry(entry);
+#if 0
+			if(entry->isBridgeChild()) //bridge child
+			{
+				addVisibleCacheEntry(entry);
+			}
+			else
+			{
+				U32 parent_id = entry->getParentID();
+				if(parent_id > 0) //has parent
+				{
+					LLVOCacheEntry* parent = getCacheEntry(parent_id);
+				
+					if(parent) //parent cached
+					{
+						parent->addChild(entry);
+
+						if(parent->isState(LLVOCacheEntry::INACTIVE))
+						{
+							//addToVOCacheTree(parent);
+							addVisibleCacheEntry(parent);
+						}
+						else //parent visible
+						{
+							addVisibleCacheEntry(parent);
+						}
+					}
+					else //parent not cached. This should not happen, but just in case...
+					{
+						addVisibleCacheEntry(entry);
+					}
+				}
+				else //root node
+				{
+					//addToVOCacheTree(entry);
+					addVisibleCacheEntry(entry);
+				}
+			}
+#endif
+			return true;
 		}
 		else
 		{
@@ -1718,7 +1795,7 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
 		mCacheMissFull.put(local_id);
 	}
 
-	return NULL;
+	return false;
 }
 
 void LLViewerRegion::addCacheMissFull(const U32 local_id)
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 86d3ee0d8c..9a47227f1c 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -317,7 +317,7 @@ public:
 	// handle a full update message
 	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);	
 	LLVOCacheEntry* getCacheEntryForOctree(U32 local_id);
-	LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);
+	bool probeCache(U32 local_id, U32 crc, U8 &cache_miss_type);
 	void requestCacheMisses();
 	void addCacheMissFull(const U32 local_id);
 
@@ -354,8 +354,8 @@ private:
 	void killCacheEntry(LLVOCacheEntry* entry); //physically delete the cache entry	
 
 	F32 killInvisibleObjects(F32 max_time);
-	F32 addLinkedSetChildren(F32 max_time, S32& max_num_objects);
-	F32 addVisibleObjects(F32 max_time, S32& max_num_objects);
+	F32 createVisibleObjects(F32 max_time);
+	F32 updateVisibleEntries(F32 max_time); //update visible entries
 
 public:
 	struct CompareDistance
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index db6aa9cd00..ec8585852b 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -32,6 +32,7 @@
 #include "llviewerobjectlist.h"
 #include "lldrawable.h"
 #include "llviewerregion.h"
+#include "pipeline.h"
 
 BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) 
 {
@@ -57,11 +58,24 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &
 	mCRCChangeCount(0),
 	mState(INACTIVE),
 	mRepeatedVisCounter(0),
-	mVisFrameRange(64)
+	mVisFrameRange(64),
+	mSceneContrib(0.f)
 {
 	mBuffer = new U8[dp.getBufferSize()];
 	mDP.assignBuffer(mBuffer, dp.getBufferSize());
 	mDP = dp;
+
+	if(dp.getBufferSize() > 0)
+	{
+		U32 parent_id = 0;
+		dp.reset();
+		dp.unpackU32(parent_id, "ParentID");
+		dp.reset();
+		if(parent_id > 0)
+		{
+			mState |= CHILD; //is a child
+		}
+	}
 }
 
 LLVOCacheEntry::LLVOCacheEntry()
@@ -74,7 +88,8 @@ LLVOCacheEntry::LLVOCacheEntry()
 	mBuffer(NULL),
 	mState(INACTIVE),
 	mRepeatedVisCounter(0),
-	mVisFrameRange(64)
+	mVisFrameRange(64),
+	mSceneContrib(0.f)
 {
 	mDP.assignBuffer(mBuffer, 0);
 }
@@ -84,7 +99,8 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 	mBuffer(NULL),
 	mState(INACTIVE),
 	mRepeatedVisCounter(0),
-	mVisFrameRange(64)
+	mVisFrameRange(64),
+	mSceneContrib(0.f)
 {
 	S32 size = -1;
 	BOOL success;
@@ -110,6 +126,10 @@ 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);
@@ -174,6 +194,7 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 		mCRCChangeCount = 0;
 		mBuffer = NULL;
 		mEntry = NULL;
+		mState = 0;
 	}
 }
 
@@ -203,11 +224,40 @@ void LLVOCacheEntry::setOctreeEntry(LLViewerOctreeEntry* entry)
 	LLViewerOctreeEntryData::setOctreeEntry(entry);
 }
 
+void LLVOCacheEntry::setBridgeChild()
+{
+	mState |= BRIDGE_CHILD;
+}
+	
+void LLVOCacheEntry::clearBridgeChild()
+{
+	mState &= ~BRIDGE_CHILD;
+}
+
+void LLVOCacheEntry::copy(LLVOCacheEntry* entry)
+{
+	//copy LLViewerOctreeEntry
+	LLViewerOctreeEntry* oct_entry = entry->getEntry();
+	if(!oct_entry)
+	{
+		setOctreeEntry(oct_entry);
+	}
+
+	//copy children
+	S32 num_children = entry->getNumOfChildren();
+	for(S32 i = 0; i < num_children; i++)
+	{
+		addChild(entry->getChild(i));
+	}
+}
+
 void LLVOCacheEntry::setState(U32 state)
 {
-	mState = state;
+	mState &= 0xffff0000; //clear the low 16 bits
+	state &= 0x0000ffff;  //clear the high 16 bits;
+	mState |= state;
 
-	if(mState == ACTIVE)
+	if(getState() == ACTIVE)
 	{
 		const S32 MIN_REAVTIVE_INTERVAL = 20;
 		U32 last_visible = getVisible();
@@ -247,37 +297,6 @@ void LLVOCacheEntry::addChild(LLVOCacheEntry* entry)
 	mChildrenList.push_back(entry);
 }
 	
-LLVOCacheEntry* LLVOCacheEntry::getNextChild()
-{
-	S32 size = mChildrenList.size();
-	if(!size)
-	{
-		return NULL;
-	}
-
-	LLVOCacheEntry* entry = mChildrenList[size - 1];
-	mChildrenList.pop_back(); //remove the entry;
-
-	return entry;
-}
-
-// New CRC means the object has changed.
-void LLVOCacheEntry::assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp)
-{
-	if (  (mCRC != crc)
-		||(mDP.getBufferSize() == 0))
-	{
-		mCRC = crc;
-		mHitCount = 0;
-		mCRCChangeCount++;
-
-		mDP.freeBuffer();
-		mBuffer = new U8[dp.getBufferSize()];
-		mDP.assignBuffer(mBuffer, dp.getBufferSize());
-		mDP = dp;
-	}
-}
-
 LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc)
 {
 	if (  (mCRC != crc)
@@ -343,6 +362,11 @@ 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]);
@@ -378,6 +402,46 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 	return success ;
 }
 
+void LLVOCacheEntry::calcSceneContribution(const LLVector3& camera_origin, bool needs_update, U32 last_update)
+{
+	if(!needs_update && getVisible() >= last_update)
+	{
+		return; //no need to update
+	}
+
+	const LLVector4a& center = getPositionGroup();
+	
+	LLVector4a origin;
+	origin.load3(camera_origin.mV);
+
+	LLVector4a lookAt;
+	lookAt.setSub(center, origin);
+	F32 squared_dist = lookAt.dot3(lookAt).getF32();
+
+	F32 rad = getBinRadius();
+	mSceneContrib = rad * rad / squared_dist;
+
+	setVisible();
+}
+
+U32 LLVOCacheEntry::getParentID()
+{
+	if(!(mState & CHILD))
+	{
+		return 0; //not a child
+	}
+
+	U32 parent_id = 0;
+	LLDataPackerBinaryBuffer* dp = getDP();
+	if(dp)
+	{
+		dp->reset();
+		dp->unpackU32(parent_id, "ParentID");
+		dp->reset();
+	}
+	return parent_id;
+}
+
 //-------------------------------------------------------------------
 //LLVOCachePartition
 //-------------------------------------------------------------------
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 675c12a3eb..ded29dd990 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -36,17 +36,47 @@
 //---------------------------------------------------------------------------
 // Cache entries
 class LLVOCacheEntry;
+class LLCamera;
 
 class LLVOCacheEntry : public LLViewerOctreeEntryData
 {
 public:
 	enum
 	{
-		INACTIVE = 0,
-		WAITING,
-		ACTIVE
+		INACTIVE = 0x00000000,     //not visible
+		IN_QUEUE = 0x00000001,     //in visible queue, object to be created
+		WAITING  = 0x00000002,     //object creation request sent
+		ACTIVE   = 0x00000004      //object created, and in rendering pipeline.
 	};
 
+	enum
+	{
+		CHILD        = 0x00010000, //has parent
+		BRIDGE_CHILD = 0x00020000  //is a child of a spatial bridge.
+	};
+
+	struct CompareVOCacheEntry
+	{
+		bool operator()(const LLVOCacheEntry* const& lhs, const LLVOCacheEntry* const& rhs)
+		{
+			F32 lpa = lhs->getSceneContribution();
+			F32 rpa = rhs->getSceneContribution();
+
+			//larger pixel area first
+			if(lpa > rpa)		
+			{
+				return true;
+			}
+			else if(lpa < rpa)
+			{
+				return false;
+			}
+			else
+			{
+				return lhs < rhs;
+			}			
+		}
+	};
 protected:
 	~LLVOCacheEntry();
 public:
@@ -55,33 +85,45 @@ public:
 	LLVOCacheEntry();	
 
 	void setState(U32 state);
-	bool isState(U32 state)  {return mState == state;}
-	U32  getState() const    {return mState;}
+	bool isState(U32 state)   {return (mState & 0xffff) == state;}
+	U32  getState() const     {return (mState & 0xffff);}
+	U32  getFullState() const {return mState;}
+
+	void setBridgeChild();  
+	void clearBridgeChild(); 
+	bool isBridgeChild()     {return mState & BRIDGE_CHILD;}
 
 	U32 getLocalID() const			{ return mLocalID; }
 	U32 getCRC() const				{ return mCRC; }
 	S32 getHitCount() const			{ return mHitCount; }
 	S32 getCRCChangeCount() const	{ return mCRCChangeCount; }
-	S32 getMinVisFrameRange()const;
+	S32 getMinVisFrameRange()const;	
+	U32 getParentID();
+
+	void calcSceneContribution(const LLVector3& camera_origin, bool needs_update, U32 last_update);
+	void setSceneContribution(F32 scene_contrib) {mSceneContrib = scene_contrib;}
+	F32 getSceneContribution() const             { return mSceneContrib;}
 
 	void dump() const;
 	BOOL writeToFile(LLAPRFile* apr_file) const;
-	void assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp);
 	LLDataPackerBinaryBuffer *getDP(U32 crc);
 	LLDataPackerBinaryBuffer *getDP();
 	void recordHit();
 	void recordDupe() { mDupeCount++; }
 	
+	void copy(LLVOCacheEntry* entry); //copy variables 
 	/*virtual*/ void setOctreeEntry(LLViewerOctreeEntry* entry);
 
 	void addChild(LLVOCacheEntry* entry);
-	LLVOCacheEntry* getNextChild();
-	S32 getNumOfChildren() {return mChildrenList.size();}
-	bool isDummy() {return !mBuffer;}
+	LLVOCacheEntry* getChild(S32 i) {return mChildrenList[i];}
+	S32  getNumOfChildren()         {return mChildrenList.size();}
+	void clearChildrenList()        {mChildrenList.clear();}
+	bool isDummy()                  {return !mBuffer;}	
 
 public:
-	typedef std::map<U32, LLPointer<LLVOCacheEntry> >	vocache_entry_map_t;
-	typedef std::set<LLVOCacheEntry*>                   vocache_entry_set_t;
+	typedef std::map<U32, LLPointer<LLVOCacheEntry> >	   vocache_entry_map_t;
+	typedef std::set<LLVOCacheEntry*>                      vocache_entry_set_t;
+	typedef std::set<LLVOCacheEntry*, CompareVOCacheEntry> vocache_entry_priority_list_t;	
 
 protected:
 	U32							mLocalID;
@@ -92,9 +134,10 @@ protected:
 	LLDataPackerBinaryBuffer	mDP;
 	U8							*mBuffer;
 
+	F32                         mSceneContrib; //projected scene contributuion of this object.
 	S32                         mVisFrameRange;
 	S32                         mRepeatedVisCounter; //number of repeatedly visible within a short time.
-	U32                         mState;
+	U32                         mState; //high 16 bits reserved for special use.
 	std::vector<LLVOCacheEntry*> mChildrenList; //children entries in a linked set.
 };
 
-- 
cgit v1.2.3


From ed3d96069a5ecce17974812dbc9ab65ff8a6db4f Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Mon, 19 Nov 2012 22:22:54 -0700
Subject: for SH-3352: Create pixel shader to accumulate frame-to-frame
 absolute pixel differences

---
 .../class1/interface/twotexturecompareF.glsl       | 42 ++++++++++++++++++++++
 .../class1/interface/twotexturecompareV.glsl       | 41 +++++++++++++++++++++
 indra/newview/llviewershadermgr.cpp                | 18 ++++++++++
 indra/newview/llviewershadermgr.h                  |  2 ++
 4 files changed, 103 insertions(+)
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/twotexturecompareV.glsl

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
new file mode 100644
index 0000000000..ec5f18e9bd
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -0,0 +1,42 @@
+/** 
+ * @file twotexturecompareF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2D tex0;
+uniform sampler2D tex1;
+
+VARYING vec2 vary_texcoord0;
+VARYING vec2 vary_texcoord1;
+
+void main() 
+{
+	frag_color = texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy);
+	frag_color[3] = 1.f;
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareV.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareV.glsl
new file mode 100644
index 0000000000..67c6674f0c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareV.glsl
@@ -0,0 +1,41 @@
+/** 
+ * @file twotexturecompareV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+ 
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+ATTRIBUTE vec2 texcoord1;
+
+VARYING vec2 vary_texcoord0;
+VARYING vec2 vary_texcoord1;
+
+void main()
+{
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+	vary_texcoord0 = texcoord0;
+	vary_texcoord1 = texcoord1;
+}
+
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 4b0e0598f6..5295573709 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -78,6 +78,7 @@ LLGLSLShader	gGlowCombineProgram;
 LLGLSLShader	gSplatTextureRectProgram;
 LLGLSLShader	gGlowCombineFXAAProgram;
 LLGLSLShader	gTwoTextureAddProgram;
+LLGLSLShader	gTwoTextureCompareProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
 LLGLSLShader	gClipProgram;
@@ -672,6 +673,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gSplatTextureRectProgram.unload();
 	gGlowCombineFXAAProgram.unload();
 	gTwoTextureAddProgram.unload();
+	gTwoTextureCompareProgram.unload();
 	gOneTextureNoColorProgram.unload();
 	gSolidColorProgram.unload();
 
@@ -2706,6 +2708,22 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		}
 	}
 
+	if (success)
+	{
+		gTwoTextureCompareProgram.mName = "Two Texture Compare Shader";
+		gTwoTextureCompareProgram.mShaderFiles.clear();
+		gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareV.glsl", GL_VERTEX_SHADER_ARB));
+		gTwoTextureCompareProgram.mShaderFiles.push_back(make_pair("interface/twotexturecompareF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gTwoTextureCompareProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gTwoTextureCompareProgram.createShader(NULL, NULL);
+		if (success)
+		{
+			gTwoTextureCompareProgram.bind();
+			gTwoTextureCompareProgram.uniform1i("tex0", 0);
+			gTwoTextureCompareProgram.uniform1i("tex1", 1);
+		}
+	}
+
 	if (success)
 	{
 		gOneTextureNoColorProgram.mName = "One Texture No Color Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index d6dd645e8c..8a706daa8f 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -233,6 +233,8 @@ extern LLGLSLShader			gAlphaMaskProgram;
 
 //output tex0[tc0] + tex1[tc1]
 extern LLGLSLShader			gTwoTextureAddProgram;
+//output tex0[tc0] - tex1[tc1]
+extern LLGLSLShader			gTwoTextureCompareProgram;
 						
 extern LLGLSLShader			gOneTextureNoColorProgram;
 
-- 
cgit v1.2.3


From c180fe2ae2b5d2e00149f9902717e02ed7042143 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Mon, 19 Nov 2012 22:28:12 -0700
Subject: for SH-3561: capture the frame buffer contents and compare pixel
 differences between frames.

---
 indra/llui/llui.cpp                                |  28 +-
 indra/llui/llui.h                                  |   4 +-
 indra/newview/CMakeLists.txt                       |   2 +
 indra/newview/app_settings/settings.xml            |  14 +-
 indra/newview/lldebugview.cpp                      |  10 +-
 indra/newview/llscenemonitor.cpp                   | 358 +++++++++++++++++++++
 indra/newview/llscenemonitor.h                     |  87 +++++
 indra/newview/llviewerdisplay.cpp                  |   8 +
 indra/newview/llviewermenu.cpp                     |  10 +-
 indra/newview/llviewertexture.cpp                  |   6 +
 indra/newview/llviewertexture.h                    |   1 +
 indra/newview/llvoavatar.cpp                       |   6 +
 indra/newview/llworld.cpp                          |   4 +-
 indra/newview/skins/default/xui/en/menu_viewer.xml |  10 +
 14 files changed, 536 insertions(+), 12 deletions(-)
 create mode 100644 indra/newview/llscenemonitor.cpp
 create mode 100644 indra/newview/llscenemonitor.h

(limited to 'indra')

diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index 87bf518aa1..1dac622f32 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -724,9 +724,14 @@ void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LL
 	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color, uv_rect );
 }
 
-void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect)
+void gl_draw_scaled_target(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* target, const LLColor4& color, const LLRectf& uv_rect)
 {
-	if (NULL == image)
+	gl_draw_scaled_rotated_image(x, y, width, height, 0.f, NULL, color, uv_rect, target);
+}
+
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLTexture* image, const LLColor4& color, const LLRectf& uv_rect, LLRenderTarget* target)
+{
+	if (!image && !target)
 	{
 		llwarns << "image == NULL; aborting function" << llendl;
 		return;
@@ -734,8 +739,14 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 
 	LLGLSUIDefault gls_ui;
 
-
-	gGL.getTexUnit(0)->bind(image, true);
+	if(image != NULL)
+	{
+		gGL.getTexUnit(0)->bind(image, true);
+	}
+	else
+	{
+		gGL.getTexUnit(0)->bind(target);
+	}
 
 	gGL.color4fv(color.mV);
 
@@ -788,7 +799,14 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre
 
 		LLMatrix3 quat(0.f, 0.f, degrees*DEG_TO_RAD);
 		
-		gGL.getTexUnit(0)->bind(image, true);
+		if(image != NULL)
+		{
+			gGL.getTexUnit(0)->bind(image, true);
+		}
+		else
+		{
+			gGL.getTexUnit(0)->bind(target);
+		}
 
 		gGL.color4fv(color.mV);
 		
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 28e84fa444..d3c88cfb5f 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -58,6 +58,7 @@ class LLUUID;
 class LLWindow;
 class LLView;
 class LLHelp;
+class LLRenderTarget;
 
 // UI colors
 extern const LLColor4 UI_VERTEX_COLOR;
@@ -93,8 +94,9 @@ void gl_washer_segment_2d(F32 outer_radius, F32 inner_radius, F32 start_radians,
 
 void gl_draw_image(S32 x, S32 y, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_target(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* target, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
-void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
+void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees,LLTexture* image, const LLColor4& color = UI_VERTEX_COLOR, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), LLRenderTarget* target = NULL);
 void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border_height, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTexture* image, const LLColor4 &color, BOOL solid_color = FALSE, const LLRectf& uv_rect = LLRectf(0.f, 1.f, 1.f, 0.f), const LLRectf& scale_rect = LLRectf(0.f, 1.f, 1.f, 0.f));
 
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index c81ade6937..377075ffd5 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -459,6 +459,7 @@ set(viewer_SOURCE_FILES
     llremoteparcelrequest.cpp
     llsavedsettingsglue.cpp
     llsaveoutfitcombobtn.cpp
+	llscenemonitor.cpp
     llsceneview.cpp
     llscreenchannel.cpp
     llscriptfloater.cpp
@@ -1025,6 +1026,7 @@ set(viewer_HEADER_FILES
     llrootview.h
     llsavedsettingsglue.h
     llsaveoutfitcombobtn.h
+	llscenemonitor.h
     llsceneview.h
     llscreenchannel.h
     llscriptfloater.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 13c95c2381..c6cfe3b616 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9469,6 +9469,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>SceneLoadingMonitorEnabled</key>
+    <map>
+      <key>Comment</key>
+      <string>Enabled scene loading monitor if set</string>
+      <key>Persist</key>
+      <integer>0</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>ScriptHelpFollowsCursor</key>
     <map>
       <key>Comment</key>
@@ -10864,7 +10875,7 @@
       <key>Type</key>
       <string>F32</string>
       <key>Value</key>
-      <integer>0.0</integer>
+      <real>0.0</real>
     </map>
     <key>TextureFetchUpdateSkipLowPriority</key>
     <map>
@@ -12492,6 +12503,7 @@
       <key>Type</key>
       <string>LLSD</string>
       <key>Value</key>
+      <array />
     </map>
     <key>VFSOldSize</key>
     <map>
diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp
index aeecf054b8..86f0213282 100644
--- a/indra/newview/lldebugview.cpp
+++ b/indra/newview/lldebugview.cpp
@@ -40,7 +40,7 @@
 #include "llsceneview.h"
 #include "llviewertexture.h"
 #include "llfloaterreg.h"
-
+#include "llscenemonitor.h"
 //
 // Globals
 //
@@ -66,6 +66,7 @@ LLDebugView::~LLDebugView()
 	gDebugView = NULL;
 	gTextureView = NULL;
 	gSceneView = NULL;
+	gSceneMonitorView = NULL;
 }
 
 void LLDebugView::init()
@@ -98,6 +99,13 @@ void LLDebugView::init()
 	gSceneView->setVisible(FALSE);
 	addChild(gSceneView);
 	gSceneView->setRect(rect);
+
+	gSceneMonitorView = new LLSceneMonitorView(r);
+	gSceneMonitorView->setFollowsTop();
+	gSceneMonitorView->setFollowsLeft();
+	gSceneMonitorView->setVisible(FALSE);
+	addChild(gSceneMonitorView);
+	gSceneMonitorView->setRect(rect);
 	
 	r.setLeftTopAndSize(25, rect.getHeight() - 50, (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f), 
 									 (S32) (gViewerWindow->getWindowRectScaled().getHeight() * 0.75f));
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
new file mode 100644
index 0000000000..8597767c61
--- /dev/null
+++ b/indra/newview/llscenemonitor.cpp
@@ -0,0 +1,358 @@
+/** 
+ * @file llscenemonitor.cpp
+ * @brief monitor the scene loading process.
+ *
+ * $LicenseInfo:firstyear=2003&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 "llrendertarget.h"
+#include "llscenemonitor.h"
+#include "llviewerwindow.h"
+#include "llviewerdisplay.h"
+#include "llviewercontrol.h"
+#include "llviewershadermgr.h"
+#include "llui.h"
+#include "llstartup.h"
+#include "llappviewer.h"
+#include "llwindow.h"
+#include "llpointer.h"
+
+LLSceneMonitorView* gSceneMonitorView = NULL;
+
+LLSceneMonitor::LLSceneMonitor() : mEnabled(false), mDiff(NULL), mNeedsUpdateDiff(FALSE)
+{
+	mFrames[0] = NULL;
+	mFrames[1] = NULL;
+}
+
+LLSceneMonitor::~LLSceneMonitor()
+{
+	destroyClass();
+}
+
+void LLSceneMonitor::destroyClass()
+{
+	reset();
+}
+
+void LLSceneMonitor::reset()
+{
+	delete mFrames[0];
+	delete mFrames[1];
+	delete mDiff;
+
+	mFrames[0] = NULL;
+	mFrames[1] = NULL;
+	mDiff = NULL;
+}
+
+void LLSceneMonitor::setEnabled(bool enabled)
+{
+	if(enabled == (bool)gSavedSettings.getBOOL("SceneLoadingMonitorEnabled"))
+	{
+		return;
+	}
+	gSavedSettings.setBOOL("SceneLoadingMonitorEnabled", enabled);
+}
+
+bool LLSceneMonitor::preCapture()
+{
+	static LLCachedControl<bool> enabled(gSavedSettings,"SceneLoadingMonitorEnabled");
+	static LLFrameTimer timer;	
+
+	mCurTarget = NULL;
+	if (!LLGLSLShader::sNoFixedFunction)
+	{
+		return false;
+	}
+	if(mEnabled != (BOOL)enabled)
+	{
+		if(mEnabled)
+		{
+			reset();
+			unfreezeScene();
+		}
+		else
+		{
+			freezeScene();
+		}
+
+		mEnabled = (BOOL)enabled;
+	}
+
+	if(!mEnabled)
+	{
+		return false;
+	}
+
+	if (LLStartUp::getStartupState() < STATE_STARTED)
+	{
+		return false;
+	}
+
+	if(LLAppViewer::instance()->logoutRequestSent())
+	{
+		return false;
+	}
+
+	if(gWindowResized || gHeadlessClient || gTeleportDisplay || gRestoreGL || gDisconnected)
+	{
+		return false;
+	}
+
+	if (   !gViewerWindow->getActive()
+		|| !gViewerWindow->getWindow()->getVisible() 
+		|| gViewerWindow->getWindow()->getMinimized() )
+	{
+		return false;
+	}
+
+	if(timer.getElapsedTimeF32() < 1.0f)
+	{
+		return false;
+	}
+	timer.reset();
+	
+	S32 width = gViewerWindow->getWorldViewWidthRaw();
+	S32 height = gViewerWindow->getWorldViewHeightRaw();
+	
+	if(!mFrames[0])
+	{
+		mFrames[0] = new LLRenderTarget();
+		mFrames[0]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true);
+		gGL.getTexUnit(0)->bind(mFrames[0]);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+		mCurTarget = mFrames[0];
+	}
+	else if(!mFrames[1])
+	{
+		mFrames[1] = new LLRenderTarget();
+		mFrames[1]->allocate(width, height, GL_RGB, false, false, LLTexUnit::TT_TEXTURE, true);
+		gGL.getTexUnit(0)->bind(mFrames[1]);
+		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+		mCurTarget = mFrames[1];
+	}
+	else //swap
+	{
+		mCurTarget = mFrames[0];
+		mFrames[0] = mFrames[1];
+		mFrames[1] = mCurTarget;
+	}
+	
+	if(mCurTarget->getWidth() != width || mCurTarget->getHeight() != height) //size changed
+	{
+		mCurTarget->resize(width, height, GL_RGB);
+	}
+
+	return true;
+}
+
+void LLSceneMonitor::postCapture()
+{
+	mCurTarget = NULL;
+	mNeedsUpdateDiff = TRUE;
+}
+
+void LLSceneMonitor::freezeAvatar(LLCharacter* avatarp)
+{
+	mAvatarPauseHandles.push_back(avatarp->requestPause());
+}
+
+void LLSceneMonitor::freezeScene()
+{
+	//freeze all avatars
+	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
+		iter != LLCharacter::sInstances.end(); ++iter)
+	{
+		freezeAvatar((LLCharacter*)(*iter));
+	}
+
+	// freeze everything else
+	gSavedSettings.setBOOL("FreezeTime", TRUE);
+}
+
+void LLSceneMonitor::unfreezeScene()
+{
+	//thaw all avatars
+	mAvatarPauseHandles.clear();
+
+	// thaw everything else
+	gSavedSettings.setBOOL("FreezeTime", FALSE);
+}
+
+LLRenderTarget* LLSceneMonitor::getDiffTarget() const 
+{
+	return mDiff;
+}
+
+void LLSceneMonitor::capture()
+{
+	static U32 count = 0;
+	if(count == gFrameCount)
+	{
+		return;
+	}
+	count = gFrameCount;
+
+	preCapture();
+
+	if(!mCurTarget)
+	{
+		return;
+	}
+	
+	U32 old_FBO = LLRenderTarget::sCurFBO;
+
+	gGL.getTexUnit(0)->bind(mCurTarget);
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); //point to the main frame buffer.
+		
+	glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, mCurTarget->getWidth(), mCurTarget->getHeight()); //copy the content
+	
+	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);		
+	glBindFramebuffer(GL_FRAMEBUFFER, old_FBO);
+
+	postCapture();
+}
+
+void LLSceneMonitor::compare()
+{
+	if(!mNeedsUpdateDiff)
+	{
+		return;
+	}
+
+	if(!mFrames[0] || !mFrames[1])
+	{
+		return;
+	}
+	if(mFrames[0]->getWidth() != mFrames[1]->getWidth() || mFrames[0]->getHeight() != mFrames[1]->getHeight())
+	{
+		return; //size does not match
+	}
+
+	if (!LLGLSLShader::sNoFixedFunction)
+	{
+		return;
+	}
+
+	S32 width = mFrames[0]->getWidth();
+	S32 height = mFrames[0]->getHeight();
+	if(!mDiff)
+	{
+		mDiff = new LLRenderTarget();
+		mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true);
+	}
+	else if(mDiff->getWidth() != width || mDiff->getHeight() != height)
+	{
+		mDiff->resize(width, height, GL_RGBA);
+	}
+	mDiff->bindTarget();
+	mDiff->clear();
+
+	gTwoTextureCompareProgram.bind();
+	
+	gGL.getTexUnit(0)->activate();
+	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(0)->bind(mFrames[0]);
+	gGL.getTexUnit(0)->activate();
+
+	gGL.getTexUnit(1)->activate();
+	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(1)->bind(mFrames[1]);
+	gGL.getTexUnit(1)->activate();	
+			
+	gl_rect_2d_simple_tex(width, height);
+	
+	gGL.flush();
+	mDiff->flush();
+
+	gTwoTextureCompareProgram.unbind();
+	
+	gGL.getTexUnit(0)->disable();
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(1)->disable();
+	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
+
+	mNeedsUpdateDiff = FALSE;
+}
+
+//-------------------------------------------------------------------------------------------------------------
+//definition of class LLSceneMonitorView
+//-------------------------------------------------------------------------------------------------------------
+LLSceneMonitorView::LLSceneMonitorView(const LLRect& rect)
+	:	LLFloater(LLSD())
+{
+	setRect(rect);
+	setVisible(FALSE);
+	
+	setCanMinimize(false);
+	setCanClose(true);
+}
+
+void LLSceneMonitorView::onClickCloseBtn()
+{
+	setVisible(false);	
+}
+
+void LLSceneMonitorView::setVisible(BOOL visible)
+{
+	if(visible != (BOOL)LLSceneMonitor::getInstance()->isEnabled())
+	{
+		LLSceneMonitor::getInstance()->setEnabled(visible);
+	}
+
+	LLView::setVisible(visible);
+}
+
+void LLSceneMonitorView::draw()
+{
+	if (!LLGLSLShader::sNoFixedFunction)
+	{
+		return;
+	}
+	LLRenderTarget* target = LLSceneMonitor::getInstance()->getDiffTarget();
+	if(!target)
+	{
+		return;
+	}
+
+	S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.75f);
+	S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f);
+	
+	LLRect new_rect;
+	new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
+	setRect(new_rect);
+
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
+	
+	gl_draw_scaled_target(0, 0, getRect().getWidth(), getRect().getHeight(), target);//, LLColor4(0.f, 0.f, 0.f, 0.25f));
+
+	LLView::draw();
+}
+
diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h
new file mode 100644
index 0000000000..941039cefd
--- /dev/null
+++ b/indra/newview/llscenemonitor.h
@@ -0,0 +1,87 @@
+/** 
+ * @file llscenemonitor.h
+ * @brief monitor the process of scene loading
+ *
+ * $LicenseInfo:firstyear=2003&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_LLSCENE_MONITOR_H
+#define LL_LLSCENE_MONITOR_H
+
+#include "llsingleton.h"
+#include "llmath.h"
+#include "llfloater.h"
+#include "llcharacter.h"
+
+class LLCharacter;
+class LLRenderTarget;
+
+class LLSceneMonitor :  public LLSingleton<LLSceneMonitor>
+{
+public:
+	LLSceneMonitor();
+	~LLSceneMonitor();
+
+	void destroyClass();
+	
+	void freezeAvatar(LLCharacter* avatarp);
+	void setEnabled(bool enabled);
+
+	void capture(); //capture the main frame buffer
+	void compare(); //compare the stored two buffers.	
+
+	LLRenderTarget* getDiffTarget() const;
+	bool isEnabled()const {return mEnabled;}
+	
+private:
+	void freezeScene();
+	void unfreezeScene();
+	void reset();
+	bool preCapture();
+	void postCapture();
+	
+private:
+	BOOL mEnabled;
+	BOOL mNeedsUpdateDiff;
+	LLRenderTarget* mFrames[2];
+	LLRenderTarget* mDiff;
+	LLRenderTarget* mCurTarget;
+
+	std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
+};
+
+class LLSceneMonitorView : public LLFloater
+{
+public:
+	LLSceneMonitorView(const LLRect& rect);
+
+	virtual void draw();
+	virtual void setVisible(BOOL visible);
+
+protected:
+	virtual void onClickCloseBtn();
+};
+
+extern LLSceneMonitorView* gSceneMonitorView;
+
+#endif
+
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index ffeea2f4df..c12144df6f 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -77,6 +77,7 @@
 #include "llwlparammanager.h"
 #include "llwaterparammanager.h"
 #include "llpostprocess.h"
+#include "llscenemonitor.h"
 
 extern LLPointer<LLViewerTexture> gStartTexture;
 extern bool gShiftFrame;
@@ -989,6 +990,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		LLPipeline::sUnderWaterRender = FALSE;
 
+		{
+			//capture the frame buffer.
+			LLSceneMonitor::getInstance()->capture();
+		}
+
 		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI");
 		if (!for_snapshot)
 		{
@@ -1403,6 +1409,8 @@ void render_ui_2d()
 	//  Menu overlays, HUD, etc
 	gViewerWindow->setup2DRender();
 
+	LLSceneMonitor::getInstance()->compare();
+
 	F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
 	S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 4ec498dc33..4dfcf1efce 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -121,6 +121,7 @@
 #include "llwindow.h"
 #include "llpathfindingmanager.h"
 #include "boost/unordered_map.hpp"
+#include "llscenemonitor.h"
 
 using namespace LLVOAvatarDefines;
 
@@ -528,7 +529,10 @@ class LLAdvancedToggleConsole : public view_listener_t
 		{
 			toggle_visibility( (void*)gSceneView);
 		}
-
+		else if ("scene monitor" == console_type)
+		{
+			toggle_visibility( (void*)gSceneMonitorView);
+		}
 #if MEM_TRACK_MEM
 		else if ("memory view" == console_type)
 		{
@@ -556,9 +560,9 @@ class LLAdvancedCheckConsole : public view_listener_t
 		{
 			new_value = LLFloaterReg::instanceVisible("fast_timers");
 		}
-		else if ("scene view" == console_type)
+		else if ("scene monitor" == console_type)
 		{
-			new_value = get_visibility( (void*) gSceneView);
+			new_value = get_visibility( (void*) gSceneMonitorView);
 		}
 #if MEM_TRACK_MEM
 		else if ("memory view" == console_type)
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index b0f8f60d1e..45b6bf2828 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -953,6 +953,12 @@ void LLViewerTexture::setCachedRawImage(S32 discard_level, LLImageRaw* imageraw)
 	//nothing here.
 }
 
+BOOL LLViewerTexture::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
+{
+	llassert(mGLTexturep.notNull()) ;
+	return mGLTexturep->setSubImageFromFrameBuffer(fb_x, fb_y, x_pos, y_pos, width, height);
+}
+
 void LLViewerTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes)
 {
 	llassert(mGLTexturep.notNull()) ;
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 2ea9a07e9a..7095e97b39 100755
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -211,6 +211,7 @@ public:
 	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLViewerTexture::OTHER);
 	virtual void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
 
+	BOOL       setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
 	void       setFilteringOption(LLTexUnit::eTextureFilterOptions option);
 	void       setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
 	void       setAddressMode(LLTexUnit::eTextureAddressMode mode);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index d366455a62..1fab3b68d5 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -102,6 +102,7 @@
 
 #include "lldebugmessagebox.h"
 #include "llsdutil.h"
+#include "llscenemonitor.h"
 
 extern F32 SPEED_ADJUST_MAX;
 extern F32 SPEED_ADJUST_MAX_SEC;
@@ -771,6 +772,11 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mLastPelvisToFoot = 0.0f;
 	mPelvisFixup = 0.0f;
 	mLastPelvisFixup = 0.0f;
+
+	if(LLSceneMonitor::getInstance()->isEnabled())
+	{
+		LLSceneMonitor::getInstance()->freezeAvatar((LLCharacter*)this);
+	}
 }
 
 std::string LLVOAvatar::avString() const
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 0a622997f7..aed2835e4a 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -55,7 +55,7 @@
 #include "message.h"
 #include "pipeline.h"
 #include "llappviewer.h"		// for do_disconnect()
-
+#include "llscenemonitor.h"
 #include <deque>
 #include <queue>
 #include <map>
@@ -136,6 +136,8 @@ void LLWorld::destroyClass()
 
 	//make all visible drawbles invisible.
 	LLDrawable::incrementVisible();
+
+	LLSceneMonitor::getInstance()->destroyClass();
 }
 
 
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index c6d9f9ef8f..7923cc9f62 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1981,6 +1981,16 @@
                function="Advanced.ToggleConsole"
                parameter="scene view" />
             </menu_item_check>
+            <menu_item_check
+                 label="Scene Loading Monitor"
+                 name="Scene Loading Monitor">
+              <menu_item_check.on_check
+               function="Advanced.CheckConsole"
+               parameter="scene monitor" />
+              <menu_item_check.on_click
+               function="Advanced.ToggleConsole"
+               parameter="scene monitor" />
+            </menu_item_check>
             <menu_item_call
               enabled="false"
               visible="false"
-- 
cgit v1.2.3


From 551411247b8e4701e4768f61717b644750af83a7 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 20 Nov 2012 21:37:04 -0700
Subject: fix a crash caused by object cache for SH-3333.

---
 indra/newview/llviewerregion.cpp |  2 +-
 indra/newview/llvocache.cpp      | 12 ++++++------
 indra/newview/llvocache.h        |  2 +-
 3 files changed, 8 insertions(+), 8 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 24bd68825b..e275b44e92 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -746,7 +746,7 @@ void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry
 
 	if(old_entry)
 	{
-		new_entry->copy(old_entry);
+		old_entry->copyTo(new_entry);
 		state = old_entry->getState();		
 		killCacheEntry(old_entry);
 	}
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index ec8585852b..8ea79dbae6 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -234,20 +234,20 @@ void LLVOCacheEntry::clearBridgeChild()
 	mState &= ~BRIDGE_CHILD;
 }
 
-void LLVOCacheEntry::copy(LLVOCacheEntry* entry)
+void LLVOCacheEntry::copyTo(LLVOCacheEntry* new_entry)
 {
 	//copy LLViewerOctreeEntry
-	LLViewerOctreeEntry* oct_entry = entry->getEntry();
-	if(!oct_entry)
+	if(mEntry.notNull())
 	{
-		setOctreeEntry(oct_entry);
+		new_entry->setOctreeEntry(mEntry);
+		mEntry = NULL;
 	}
 
 	//copy children
-	S32 num_children = entry->getNumOfChildren();
+	S32 num_children = getNumOfChildren();
 	for(S32 i = 0; i < num_children; i++)
 	{
-		addChild(entry->getChild(i));
+		new_entry->addChild(getChild(i));
 	}
 }
 
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index ded29dd990..4d058ffdac 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -111,7 +111,7 @@ public:
 	void recordHit();
 	void recordDupe() { mDupeCount++; }
 	
-	void copy(LLVOCacheEntry* entry); //copy variables 
+	void copyTo(LLVOCacheEntry* new_entry); //copy variables 
 	/*virtual*/ void setOctreeEntry(LLViewerOctreeEntry* entry);
 
 	void addChild(LLVOCacheEntry* entry);
-- 
cgit v1.2.3


From ced00c47328f69a5426e6c69dce59c8f29856c51 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 20 Nov 2012 21:37:53 -0700
Subject: more for SH-3352: Create pixel shader to accumulate frame-to-frame
 absolute pixel differences

---
 .../shaders/class1/interface/twotexturecompareF.glsl        | 13 +++++++++++++
 1 file changed, 13 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
index ec5f18e9bd..92aa7602a4 100644
--- a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -38,5 +38,18 @@ VARYING vec2 vary_texcoord1;
 void main() 
 {
 	frag_color = texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy);
+	
+	if(frag_color[0] < 0.f)
+	{
+		frag_color[0] = -frag_color[0];
+	}
+	if(frag_color[1] < 0.f)
+	{
+		frag_color[1] = -frag_color[1];
+	}
+	if(frag_color[2] < 0.f)
+	{
+		frag_color[2] = -frag_color[2];
+	}
 	frag_color[3] = 1.f;
 }
-- 
cgit v1.2.3


From 6ae6abae26200c80a15d2e2d899ae6970602ff04 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 21 Nov 2012 13:29:15 -0700
Subject: more for SH-3571: display frame-to-frame pixel differences on screen

---
 indra/newview/app_settings/settings.xml            |  2 +-
 .../class1/interface/twotexturecompareF.glsl       |  2 +-
 indra/newview/llscenemonitor.cpp                   | 43 +++++++++++-----------
 indra/newview/llscenemonitor.h                     |  4 +-
 indra/newview/llviewerdisplay.cpp                  |  9 ++++-
 5 files changed, 33 insertions(+), 27 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index c6cfe3b616..7fc7a7ad3b 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9474,7 +9474,7 @@
       <key>Comment</key>
       <string>Enabled scene loading monitor if set</string>
       <key>Persist</key>
-      <integer>0</integer>
+      <integer>1</integer>
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
index 92aa7602a4..336ca21b96 100644
--- a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -51,5 +51,5 @@ void main()
 	{
 		frag_color[2] = -frag_color[2];
 	}
-	frag_color[3] = 1.f;
+	frag_color[3] = 0.95f;
 }
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 8597767c61..0730281d85 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -39,7 +39,12 @@
 
 LLSceneMonitorView* gSceneMonitorView = NULL;
 
-LLSceneMonitor::LLSceneMonitor() : mEnabled(false), mDiff(NULL), mNeedsUpdateDiff(FALSE)
+LLSceneMonitor::LLSceneMonitor() : 
+	mEnabled(FALSE), 
+	mDiff(NULL), 
+	mCurTarget(NULL), 
+	mNeedsUpdateDiff(FALSE), 
+	mDebugViewerVisible(FALSE)
 {
 	mFrames[0] = NULL;
 	mFrames[1] = NULL;
@@ -66,18 +71,14 @@ void LLSceneMonitor::reset()
 	mDiff = NULL;
 }
 
-void LLSceneMonitor::setEnabled(bool enabled)
+void LLSceneMonitor::setDebugViewerVisible(BOOL visible) 
 {
-	if(enabled == (bool)gSavedSettings.getBOOL("SceneLoadingMonitorEnabled"))
-	{
-		return;
-	}
-	gSavedSettings.setBOOL("SceneLoadingMonitorEnabled", enabled);
+	mDebugViewerVisible = visible;
 }
 
 bool LLSceneMonitor::preCapture()
 {
-	static LLCachedControl<bool> enabled(gSavedSettings,"SceneLoadingMonitorEnabled");
+	static LLCachedControl<bool> monitor_enabled(gSavedSettings,"SceneLoadingMonitorEnabled");
 	static LLFrameTimer timer;	
 
 	mCurTarget = NULL;
@@ -85,7 +86,9 @@ bool LLSceneMonitor::preCapture()
 	{
 		return false;
 	}
-	if(mEnabled != (BOOL)enabled)
+
+	BOOL enabled = (BOOL)monitor_enabled || mDebugViewerVisible;
+	if(mEnabled != enabled)
 	{
 		if(mEnabled)
 		{
@@ -97,7 +100,7 @@ bool LLSceneMonitor::preCapture()
 			freezeScene();
 		}
 
-		mEnabled = (BOOL)enabled;
+		mEnabled = enabled;
 	}
 
 	if(!mEnabled)
@@ -260,8 +263,8 @@ void LLSceneMonitor::compare()
 		return;
 	}
 
-	S32 width = mFrames[0]->getWidth();
-	S32 height = mFrames[0]->getHeight();
+	S32 width = gViewerWindow->getWindowWidthRaw();
+	S32 height = gViewerWindow->getWindowHeightRaw();
 	if(!mDiff)
 	{
 		mDiff = new LLRenderTarget();
@@ -288,7 +291,6 @@ void LLSceneMonitor::compare()
 			
 	gl_rect_2d_simple_tex(width, height);
 	
-	gGL.flush();
 	mDiff->flush();
 
 	gTwoTextureCompareProgram.unbind();
@@ -321,10 +323,7 @@ void LLSceneMonitorView::onClickCloseBtn()
 
 void LLSceneMonitorView::setVisible(BOOL visible)
 {
-	if(visible != (BOOL)LLSceneMonitor::getInstance()->isEnabled())
-	{
-		LLSceneMonitor::getInstance()->setEnabled(visible);
-	}
+	LLSceneMonitor::getInstance()->setDebugViewerVisible(visible);
 
 	LLView::setVisible(visible);
 }
@@ -341,17 +340,17 @@ void LLSceneMonitorView::draw()
 		return;
 	}
 
-	S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.75f);
-	S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f);
+	S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f);
+	S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f);
 	
 	LLRect new_rect;
 	new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
 	setRect(new_rect);
 
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
+	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	//gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
 	
-	gl_draw_scaled_target(0, 0, getRect().getWidth(), getRect().getHeight(), target);//, LLColor4(0.f, 0.f, 0.f, 0.25f));
+	gl_draw_scaled_target(0, 0, getRect().getWidth(), getRect().getHeight(), target);
 
 	LLView::draw();
 }
diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h
index 941039cefd..648429f97b 100644
--- a/indra/newview/llscenemonitor.h
+++ b/indra/newview/llscenemonitor.h
@@ -44,7 +44,7 @@ public:
 	void destroyClass();
 	
 	void freezeAvatar(LLCharacter* avatarp);
-	void setEnabled(bool enabled);
+	void setDebugViewerVisible(BOOL visible);
 
 	void capture(); //capture the main frame buffer
 	void compare(); //compare the stored two buffers.	
@@ -62,6 +62,8 @@ private:
 private:
 	BOOL mEnabled;
 	BOOL mNeedsUpdateDiff;
+	BOOL mDebugViewerVisible;
+
 	LLRenderTarget* mFrames[2];
 	LLRenderTarget* mDiff;
 	LLRenderTarget* mCurTarget;
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index c12144df6f..270ab26149 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1228,6 +1228,13 @@ void render_ui(F32 zoom_factor, int subfield)
 		glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
 	}
 	
+	{
+		gGL.pushMatrix();
+		gViewerWindow->setup2DRender();
+		LLSceneMonitor::getInstance()->compare();
+		gGL.popMatrix();
+	}
+
 	{
 		BOOL to_texture = gPipeline.canUseVertexShaders() &&
 							LLPipeline::sRenderGlow;
@@ -1409,8 +1416,6 @@ void render_ui_2d()
 	//  Menu overlays, HUD, etc
 	gViewerWindow->setup2DRender();
 
-	LLSceneMonitor::getInstance()->compare();
-
 	F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
 	S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
 
-- 
cgit v1.2.3


From 21409a3aaaef71102195d65fc35cebdb5d941a26 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Fri, 30 Nov 2012 22:50:06 -0700
Subject: for SH-3350 and SH-3353: Report frame-to-frame visual deltas as an
 LLStat

---
 .../class1/interface/onetexturefilterF.glsl        |  49 ++++++
 .../class1/interface/onetexturefilterV.glsl        |  38 +++++
 .../class1/interface/twotexturecompareF.glsl       |  16 +-
 indra/newview/llscenemonitor.cpp                   | 188 ++++++++++++++-------
 indra/newview/llscenemonitor.h                     |  17 +-
 indra/newview/llspatialpartition.cpp               |  22 ++-
 indra/newview/llspatialpartition.h                 |   2 +
 indra/newview/llviewershadermgr.cpp                |  17 ++
 indra/newview/llviewershadermgr.h                  |   4 +-
 indra/newview/pipeline.cpp                         |   5 +-
 10 files changed, 271 insertions(+), 87 deletions(-)
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl

(limited to 'indra')

diff --git a/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl
new file mode 100644
index 0000000000..f1400c9b44
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterF.glsl
@@ -0,0 +1,49 @@
+/** 
+ * @file onetexturefilterF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2D tex0;
+uniform float tolerance;
+
+VARYING vec2 vary_texcoord0;
+
+void main() 
+{
+	frag_color = texture2D(tex0, vary_texcoord0.xy);
+	
+	if(frag_color[0] + frag_color[1] + frag_color[2] < tolerance)
+	{
+		discard;
+	}
+	else
+	{		
+		frag_color[3] = 0.95f;	
+	}	
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl
new file mode 100644
index 0000000000..a33ef7e92c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/onetexturefilterV.glsl
@@ -0,0 +1,38 @@
+/** 
+ * @file onetexturefilterV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+ 
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec2 vary_texcoord0;
+
+void main()
+{
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+	vary_texcoord0 = texcoord0;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
index 336ca21b96..050114b37e 100644
--- a/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -37,19 +37,5 @@ VARYING vec2 vary_texcoord1;
 
 void main() 
 {
-	frag_color = texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy);
-	
-	if(frag_color[0] < 0.f)
-	{
-		frag_color[0] = -frag_color[0];
-	}
-	if(frag_color[1] < 0.f)
-	{
-		frag_color[1] = -frag_color[1];
-	}
-	if(frag_color[2] < 0.f)
-	{
-		frag_color[2] = -frag_color[2];
-	}
-	frag_color[3] = 0.95f;
+	frag_color = abs(texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy));
 }
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 0730281d85..adeada04ca 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -36,18 +36,24 @@
 #include "llappviewer.h"
 #include "llwindow.h"
 #include "llpointer.h"
+#include "llspatialpartition.h"
 
 LLSceneMonitorView* gSceneMonitorView = NULL;
 
 LLSceneMonitor::LLSceneMonitor() : 
 	mEnabled(FALSE), 
-	mDiff(NULL), 
+	mDiff(NULL),
+	mDiffResult(0.f),
+	mDiffTolerance(0.1f),
 	mCurTarget(NULL), 
-	mNeedsUpdateDiff(FALSE), 
-	mDebugViewerVisible(FALSE)
+	mNeedsUpdateDiff(FALSE),
+	mHasNewDiff(FALSE),
+	mHasNewQueryResult(FALSE),
+	mDebugViewerVisible(FALSE),
+	mQueryObject(0)
 {
 	mFrames[0] = NULL;
-	mFrames[1] = NULL;
+	mFrames[1] = NULL;	
 }
 
 LLSceneMonitor::~LLSceneMonitor()
@@ -69,6 +75,15 @@ void LLSceneMonitor::reset()
 	mFrames[0] = NULL;
 	mFrames[1] = NULL;
 	mDiff = NULL;
+	mCurTarget = NULL;
+
+	unfreezeScene();
+
+	if(mQueryObject > 0)
+	{
+		release_occlusion_query_object_name(mQueryObject);
+		mQueryObject = 0;
+	}
 }
 
 void LLSceneMonitor::setDebugViewerVisible(BOOL visible) 
@@ -108,28 +123,6 @@ bool LLSceneMonitor::preCapture()
 		return false;
 	}
 
-	if (LLStartUp::getStartupState() < STATE_STARTED)
-	{
-		return false;
-	}
-
-	if(LLAppViewer::instance()->logoutRequestSent())
-	{
-		return false;
-	}
-
-	if(gWindowResized || gHeadlessClient || gTeleportDisplay || gRestoreGL || gDisconnected)
-	{
-		return false;
-	}
-
-	if (   !gViewerWindow->getActive()
-		|| !gViewerWindow->getWindow()->getVisible() 
-		|| gViewerWindow->getWindow()->getMinimized() )
-	{
-		return false;
-	}
-
 	if(timer.getElapsedTimeF32() < 1.0f)
 	{
 		return false;
@@ -174,12 +167,6 @@ bool LLSceneMonitor::preCapture()
 	return true;
 }
 
-void LLSceneMonitor::postCapture()
-{
-	mCurTarget = NULL;
-	mNeedsUpdateDiff = TRUE;
-}
-
 void LLSceneMonitor::freezeAvatar(LLCharacter* avatarp)
 {
 	mAvatarPauseHandles.push_back(avatarp->requestPause());
@@ -207,19 +194,14 @@ void LLSceneMonitor::unfreezeScene()
 	gSavedSettings.setBOOL("FreezeTime", FALSE);
 }
 
-LLRenderTarget* LLSceneMonitor::getDiffTarget() const 
-{
-	return mDiff;
-}
-
 void LLSceneMonitor::capture()
 {
-	static U32 count = 0;
-	if(count == gFrameCount)
+	static U32 last_capture_time = 0;
+	if(last_capture_time == gFrameCount)
 	{
 		return;
 	}
-	count = gFrameCount;
+	last_capture_time = gFrameCount;
 
 	preCapture();
 
@@ -239,7 +221,8 @@ void LLSceneMonitor::capture()
 	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);		
 	glBindFramebuffer(GL_FRAMEBUFFER, old_FBO);
 
-	postCapture();
+	mCurTarget = NULL;
+	mNeedsUpdateDiff = TRUE;
 }
 
 void LLSceneMonitor::compare()
@@ -248,6 +231,7 @@ void LLSceneMonitor::compare()
 	{
 		return;
 	}
+	mNeedsUpdateDiff = FALSE;
 
 	if(!mFrames[0] || !mFrames[1])
 	{
@@ -258,11 +242,6 @@ void LLSceneMonitor::compare()
 		return; //size does not match
 	}
 
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		return;
-	}
-
 	S32 width = gViewerWindow->getWindowWidthRaw();
 	S32 height = gViewerWindow->getWindowHeightRaw();
 	if(!mDiff)
@@ -274,9 +253,10 @@ void LLSceneMonitor::compare()
 	{
 		mDiff->resize(width, height, GL_RGBA);
 	}
+
 	mDiff->bindTarget();
 	mDiff->clear();
-
+	
 	gTwoTextureCompareProgram.bind();
 	
 	gGL.getTexUnit(0)->activate();
@@ -288,21 +268,108 @@ void LLSceneMonitor::compare()
 	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->bind(mFrames[1]);
 	gGL.getTexUnit(1)->activate();	
-			
+	
 	gl_rect_2d_simple_tex(width, height);
 	
-	mDiff->flush();
+	mDiff->flush();	
 
 	gTwoTextureCompareProgram.unbind();
-	
+
 	gGL.getTexUnit(0)->disable();
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(1)->disable();
 	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
 
-	mNeedsUpdateDiff = FALSE;
+	mHasNewDiff = TRUE;
+	
+	//send out the query request.
+	queryDiff();
+}
+
+void LLSceneMonitor::queryDiff()
+{
+	if(mDebugViewerVisible)
+	{
+		return;
+	}
+
+	calcDiffAggregate();
+}
+
+//calculate Diff aggregate information in GPU, and enable gl occlusion query to capture it.
+void LLSceneMonitor::calcDiffAggregate()
+{
+	if(!mHasNewDiff && !mDebugViewerVisible)
+	{
+		return;
+	}	
+
+	if(!mQueryObject)
+	{
+		mQueryObject = get_new_occlusion_query_object_name();
+	}
+
+	LLGLDepthTest depth(true, false, GL_ALWAYS);
+	if(!mDebugViewerVisible)
+	{
+		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+	}
+
+	LLGLSLShader* cur_shader = NULL;
+	
+	cur_shader = LLGLSLShader::sCurBoundShaderPtr;
+	gOneTextureFilterProgram.bind();
+	gOneTextureFilterProgram.uniform1f("tolerance", mDiffTolerance);
+
+	if(mHasNewDiff)
+	{
+		glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mQueryObject);
+	}
+
+	gl_draw_scaled_target(0, 0, mDiff->getWidth() * 0.5f, mDiff->getHeight() * 0.5f, mDiff);
+
+	if(mHasNewDiff)
+	{
+		glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+		mHasNewDiff = FALSE;	
+		mHasNewQueryResult = TRUE;
+	}
+		
+	gOneTextureFilterProgram.unbind();
+	
+	if(cur_shader != NULL)
+	{
+		cur_shader->bind();
+	}
+	
+	if(!mDebugViewerVisible)
+	{
+		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+	}	
 }
 
+void LLSceneMonitor::fetchQueryResult()
+{
+	if(!mHasNewQueryResult)
+	{
+		return;
+	}
+	mHasNewQueryResult = FALSE;
+
+	GLuint available = 0;
+	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+	if(!available)
+	{
+		return;
+	}
+
+	GLuint count = 0;
+	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_ARB, &count);
+	
+	mDiffResult = count * 0.5f / (mDiff->getWidth() * mDiff->getHeight() * 0.25f);
+
+	//llinfos << count << " : " << mDiffResult << llendl;
+}
 //-------------------------------------------------------------------------------------------------------------
 //definition of class LLSceneMonitorView
 //-------------------------------------------------------------------------------------------------------------
@@ -330,27 +397,26 @@ void LLSceneMonitorView::setVisible(BOOL visible)
 
 void LLSceneMonitorView::draw()
 {
-	if (!LLGLSLShader::sNoFixedFunction)
-	{
-		return;
-	}
-	LLRenderTarget* target = LLSceneMonitor::getInstance()->getDiffTarget();
+	const LLRenderTarget* target = LLSceneMonitor::getInstance()->getDiffTarget();
 	if(!target)
 	{
 		return;
 	}
 
-	S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f);
-	S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f);
+	S32 height = target->getHeight() * 0.5f;
+	S32 width = target->getWidth() * 0.5f;
+	//S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f);
+	//S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f);
 	
 	LLRect new_rect;
 	new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
 	setRect(new_rect);
 
-	//gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	//gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
+	//draw background
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.f, 0.f, 0.f, 0.25f));
 	
-	gl_draw_scaled_target(0, 0, getRect().getWidth(), getRect().getHeight(), target);
+	LLSceneMonitor::getInstance()->calcDiffAggregate();
 
 	LLView::draw();
 }
diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h
index 648429f97b..db5ac3eeef 100644
--- a/indra/newview/llscenemonitor.h
+++ b/indra/newview/llscenemonitor.h
@@ -48,8 +48,14 @@ public:
 
 	void capture(); //capture the main frame buffer
 	void compare(); //compare the stored two buffers.	
+	void queryDiff();	
+	void fetchQueryResult();
+	void calcDiffAggregate();
+	void setDiffTolerance(F32 tol) {mDiffTolerance = tol;}
 
-	LLRenderTarget* getDiffTarget() const;
+	const LLRenderTarget* getDiffTarget() const {return mDiff;}
+	F32  getDiffTolerance() const {return mDiffTolerance;}
+	F32  getDiffResult() const { return mDiffResult;}
 	bool isEnabled()const {return mEnabled;}
 	
 private:
@@ -57,17 +63,22 @@ private:
 	void unfreezeScene();
 	void reset();
 	bool preCapture();
-	void postCapture();
-	
+
 private:
 	BOOL mEnabled;
 	BOOL mNeedsUpdateDiff;
+	BOOL mHasNewDiff;
+	BOOL mHasNewQueryResult;
 	BOOL mDebugViewerVisible;
 
 	LLRenderTarget* mFrames[2];
 	LLRenderTarget* mDiff;
 	LLRenderTarget* mCurTarget;
 
+	GLuint  mQueryObject; //used for glQuery
+	F32     mDiffResult;  //aggregate results of mDiff.
+	F32     mDiffTolerance; //pixels are filtered out when R+G+B < mDiffTolerance
+
 	std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
 };
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index e9ece331d1..b7694074a5 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -126,6 +126,16 @@ protected:
 
 static LLOcclusionQueryPool sQueryPool;
 
+GLuint get_new_occlusion_query_object_name()
+{
+	return sQueryPool.allocate();
+}
+
+void release_occlusion_query_object_name(GLuint name)
+{
+	sQueryPool.release(name);
+}
+
 //static counter for frame to switch LOD on
 
 void sg_assert(BOOL expr)
@@ -283,7 +293,7 @@ LLSpatialGroup::~LLSpatialGroup()
 		{
 			if (mOcclusionQuery[i])
 			{
-				sQueryPool.release(mOcclusionQuery[i]);
+				release_occlusion_query_object_name(mOcclusionQuery[i]);
 			}
 		}
 	}
@@ -879,7 +889,7 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
 
 				if ((state & DISCARD_QUERY) && mOcclusionQuery[i])
 				{
-					sQueryPool.release(mOcclusionQuery[i]);
+					release_occlusion_query_object_name(mOcclusionQuery[i]);
 					mOcclusionQuery[i] = 0;
 				}
 			}
@@ -890,7 +900,7 @@ void LLSpatialGroup::setOcclusionState(U32 state, S32 mode)
 		mOcclusionState[LLViewerCamera::sCurCameraID] |= state;
 		if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
 		{
-			sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+			release_occlusion_query_object_name(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 			mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
 		}
 	}
@@ -1237,7 +1247,7 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)
 		{
 			if (mOcclusionQuery[i])
 			{
-				sQueryPool.release(mOcclusionQuery[i]);
+				release_occlusion_query_object_name(mOcclusionQuery[i]);
 				mOcclusionQuery[i] = 0;
 			}
 		}
@@ -1318,7 +1328,7 @@ void LLSpatialGroup::checkOcclusion()
 				}
 				else if (mOcclusionQuery[LLViewerCamera::sCurCameraID])
 				{ //delete the query to avoid holding onto hundreds of pending queries
-					sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+					release_occlusion_query_object_name(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 					mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0;
 				}
 				
@@ -1390,7 +1400,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 					if (!mOcclusionQuery[LLViewerCamera::sCurCameraID])
 					{
 						LLFastTimer t(FTM_OCCLUSION_ALLOCATE);
-						mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
+						mOcclusionQuery[LLViewerCamera::sCurCameraID] = get_new_occlusion_query_object_name();
 					}
 
 					// Depth clamp all water to avoid it being culled as a result of being
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 079c0f58f0..57e986fb80 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -58,6 +58,8 @@ void pushVerts(LLFace* face, U32 mask);
 // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
 U32 get_box_fan_indices(LLCamera* camera, const LLVector4a& center);
 U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center);
+GLuint get_new_occlusion_query_object_name();
+void release_occlusion_query_object_name(GLuint name);
 
 class LLDrawInfo : public LLRefCount 
 {
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 5295573709..1aa36eafee 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -79,6 +79,7 @@ LLGLSLShader	gSplatTextureRectProgram;
 LLGLSLShader	gGlowCombineFXAAProgram;
 LLGLSLShader	gTwoTextureAddProgram;
 LLGLSLShader	gTwoTextureCompareProgram;
+LLGLSLShader	gOneTextureFilterProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
 LLGLSLShader	gClipProgram;
@@ -674,6 +675,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gGlowCombineFXAAProgram.unload();
 	gTwoTextureAddProgram.unload();
 	gTwoTextureCompareProgram.unload();
+	gOneTextureFilterProgram.unload();
 	gOneTextureNoColorProgram.unload();
 	gSolidColorProgram.unload();
 
@@ -2724,6 +2726,21 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		}
 	}
 
+	if (success)
+	{
+		gOneTextureFilterProgram.mName = "One Texture Filter Shader";
+		gOneTextureFilterProgram.mShaderFiles.clear();
+		gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterV.glsl", GL_VERTEX_SHADER_ARB));
+		gOneTextureFilterProgram.mShaderFiles.push_back(make_pair("interface/onetexturefilterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gOneTextureFilterProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gOneTextureFilterProgram.createShader(NULL, NULL);
+		if (success)
+		{
+			gOneTextureFilterProgram.bind();
+			gOneTextureFilterProgram.uniform1i("tex0", 0);
+		}
+	}
+
 	if (success)
 	{
 		gOneTextureNoColorProgram.mName = "One Texture No Color Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 8a706daa8f..3e7c615f23 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -235,7 +235,9 @@ extern LLGLSLShader			gAlphaMaskProgram;
 extern LLGLSLShader			gTwoTextureAddProgram;
 //output tex0[tc0] - tex1[tc1]
 extern LLGLSLShader			gTwoTextureCompareProgram;
-						
+//discard some fragments based on user-set color tolerance
+extern LLGLSLShader			gOneTextureFilterProgram;
+
 extern LLGLSLShader			gOneTextureNoColorProgram;
 
 //object shaders
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 850714f676..d8af7a5cfb 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -112,6 +112,7 @@
 #include "llfloaterpathfindingconsole.h"
 #include "llfloaterpathfindingcharacters.h"
 #include "llpathfindingpathtool.h"
+#include "llscenemonitor.h"
 
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
@@ -3161,7 +3162,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 		}
 	}
 		
-	postSort(camera);	
+	postSort(camera);
+
+	LLSceneMonitor::getInstance()->fetchQueryResult();
 }
 
 void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
-- 
cgit v1.2.3


From 0270ce079c2090cd25244516648ac1691db00a0d Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Sun, 2 Dec 2012 22:12:43 -0700
Subject: more for SH-3350, add debug texts

---
 indra/newview/llscenemonitor.cpp | 43 ++++++++++++++++++++++++++++++++++------
 indra/newview/llscenemonitor.h   |  5 +++++
 2 files changed, 42 insertions(+), 6 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index adeada04ca..43f9e9208b 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -40,6 +40,18 @@
 
 LLSceneMonitorView* gSceneMonitorView = NULL;
 
+//
+//The procedures of monitoring when the scene finishes loading visually, 
+//i.e., no pixel differences among frames, are:
+//1, freeze all dynamic objects and avatars;
+//2, (?) disable all sky and water;
+//3, capture frames periodically, by calling "capture()";
+//4, compute pixel differences between two latest captured frames, by calling "compare()", results are stored at mDiff;
+//5, compute the number of pixels in mDiff above some tolerance threshold in GPU, by calling "queryDiff() -> calcDiffAggregate()";
+//6, use gl occlusion query to fetch the result from GPU, by calling "fetchQueryResult()";
+//END.
+//
+
 LLSceneMonitor::LLSceneMonitor() : 
 	mEnabled(FALSE), 
 	mDiff(NULL),
@@ -50,7 +62,9 @@ LLSceneMonitor::LLSceneMonitor() :
 	mHasNewDiff(FALSE),
 	mHasNewQueryResult(FALSE),
 	mDebugViewerVisible(FALSE),
-	mQueryObject(0)
+	mQueryObject(0),
+	mSamplingTime(1.0f),
+	mDiffPixelRatio(0.5f)
 {
 	mFrames[0] = NULL;
 	mFrames[1] = NULL;	
@@ -123,7 +137,7 @@ bool LLSceneMonitor::preCapture()
 		return false;
 	}
 
-	if(timer.getElapsedTimeF32() < 1.0f)
+	if(timer.getElapsedTimeF32() < mSamplingTime)
 	{
 		return false;
 	}
@@ -326,7 +340,7 @@ void LLSceneMonitor::calcDiffAggregate()
 		glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mQueryObject);
 	}
 
-	gl_draw_scaled_target(0, 0, mDiff->getWidth() * 0.5f, mDiff->getHeight() * 0.5f, mDiff);
+	gl_draw_scaled_target(0, 0, mDiff->getWidth() * mDiffPixelRatio, mDiff->getHeight() * mDiffPixelRatio, mDiff);
 
 	if(mHasNewDiff)
 	{
@@ -366,7 +380,7 @@ void LLSceneMonitor::fetchQueryResult()
 	GLuint count = 0;
 	glGetQueryObjectuivARB(mQueryObject, GL_QUERY_RESULT_ARB, &count);
 	
-	mDiffResult = count * 0.5f / (mDiff->getWidth() * mDiff->getHeight() * 0.25f);
+	mDiffResult = count * 0.5f / (mDiff->getWidth() * mDiff->getHeight() * mDiffPixelRatio * mDiffPixelRatio); //0.5 -> (front face + back face)
 
 	//llinfos << count << " : " << mDiffResult << llendl;
 }
@@ -403,8 +417,9 @@ void LLSceneMonitorView::draw()
 		return;
 	}
 
-	S32 height = target->getHeight() * 0.5f;
-	S32 width = target->getWidth() * 0.5f;
+	F32 ratio = LLSceneMonitor::getInstance()->getDiffPixelRatio();
+	S32 height = target->getHeight() * ratio;
+	S32 width = target->getWidth() * ratio;
 	//S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f);
 	//S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f);
 	
@@ -418,6 +433,22 @@ void LLSceneMonitorView::draw()
 	
 	LLSceneMonitor::getInstance()->calcDiffAggregate();
 
+	//show some texts
+	LLColor4 color = LLColor4::white;
+	S32 line_height = LLFontGL::getFontMonospace()->getLineHeight();
+
+	S32 lines = 0;
+	std::string num_str = llformat("Frame difference: %.6f", LLSceneMonitor::getInstance()->getDiffResult());
+	LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP);
+	lines++;
+
+	num_str = llformat("Pixel tolerance: (R+G+B) < %.4f", LLSceneMonitor::getInstance()->getDiffTolerance());
+	LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP);
+	lines++;
+
+	num_str = llformat("Sampling time: %.3f seconds", LLSceneMonitor::getInstance()->getSamplingTime());
+	LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, 5, getRect().getHeight() - line_height * lines, color, LLFontGL::LEFT, LLFontGL::TOP);
+
 	LLView::draw();
 }
 
diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h
index db5ac3eeef..ce25467a21 100644
--- a/indra/newview/llscenemonitor.h
+++ b/indra/newview/llscenemonitor.h
@@ -56,6 +56,8 @@ public:
 	const LLRenderTarget* getDiffTarget() const {return mDiff;}
 	F32  getDiffTolerance() const {return mDiffTolerance;}
 	F32  getDiffResult() const { return mDiffResult;}
+	F32  getSamplingTime() const { return mSamplingTime;}
+	F32  getDiffPixelRatio() const { return mDiffPixelRatio;}
 	bool isEnabled()const {return mEnabled;}
 	
 private:
@@ -79,6 +81,9 @@ private:
 	F32     mDiffResult;  //aggregate results of mDiff.
 	F32     mDiffTolerance; //pixels are filtered out when R+G+B < mDiffTolerance
 
+	F32     mSamplingTime; //time interval to capture frames, in seconds
+	F32     mDiffPixelRatio; //ratio of pixels used for comparison against the original mDiff size along one dimension
+
 	std::vector<LLAnimPauseRequest> mAvatarPauseHandles;
 };
 
-- 
cgit v1.2.3


From f2bf13b87768c97ec6a36a183013413bf4b905f0 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 12 Dec 2012 11:00:24 -0700
Subject: fix for SH-3622: crash on LLViewerRegion::updateVisibleEntries

---
 indra/newview/llviewerregion.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index e275b44e92..ab692308b0 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -777,25 +777,25 @@ void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry)
 		return;
 	}
 
-	//1, remove from active list and waiting list
+	//remove from active list and waiting list
 	if(entry->isState(LLVOCacheEntry::ACTIVE))
 	{
 		mImpl->mActiveSet.erase(entry);
 	}
-	else if(entry->isState(LLVOCacheEntry::WAITING))
-	{
-		mImpl->mWaitingSet.erase(entry);
-	}
-	else if(entry->isState(LLVOCacheEntry::IN_QUEUE))
-	{
-		mImpl->mVisibleEntries.erase(entry);
-	}
-	else if(entry->isState(LLVOCacheEntry::INACTIVE))
+	else
 	{
+		if(entry->isState(LLVOCacheEntry::WAITING))
+		{
+			mImpl->mWaitingSet.erase(entry);
+		}
+		
 		//remove from mVOCachePartition
 		removeFromVOCacheTree(entry);
 	}
 
+	//remove from the forced visible list
+	mImpl->mVisibleEntries.erase(entry);
+
 	//kill LLViewerObject if exists
 	//this should be done by the rendering pipeline automatically.
 	
-- 
cgit v1.2.3


From 834a956a70bb49f1a242681bd611df4bbb7e4cc8 Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@lindenlab.com>
Date: Thu, 13 Dec 2012 15:43:10 -0800
Subject: We now handle local_id=0 in KillObject as a prefix to deleted
 local_id's. This is the real viewer-side work that was the motivation for
 MAINT-2123. Reviewed with Bao.

---
 indra/newview/llappviewer.cpp        |  5 ---
 indra/newview/llviewermessage.cpp    | 80 ++++++++++++++++++------------------
 indra/newview/llviewerobjectlist.cpp | 12 +-----
 indra/newview/llviewerobjectlist.h   |  1 -
 4 files changed, 40 insertions(+), 58 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index bffa1708ec..777fe4b8f1 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4267,11 +4267,6 @@ void LLAppViewer::idle()
 				llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl;
 				gObjectList.mNumDeadObjectUpdates = 0;
 			}
-			if (gObjectList.mNumUnknownKills)
-			{
-				llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl;
-				gObjectList.mNumUnknownKills = 0;
-			}
 			if (gObjectList.mNumUnknownUpdates)
 			{
 				llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 67d400af2d..62d4e779d0 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4483,40 +4483,42 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_
 
 static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Kill Objects");
 
+const U32 KILLOBJECT_DELETE_OPCODE = 0;
+
 
 void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 {
 	LLFastTimer t(FTM_PROCESS_OBJECTS);
 
-	LLUUID		id;
-	U32			local_id;
-	S32			i = 0;
-	S32			num_objects;
-
-	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
+	LLUUID id;
 
-	mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
+	U32 ip = mesgsys->getSenderIP();
+	U32 port = mesgsys->getSenderPort();
 	LLViewerRegion* regionp = NULL;
-	bool remove_from_cache = !local_id; //if the first local id is 0, physically remove all objects from VO cache.
-	if(remove_from_cache)
 	{
-		i++;
-
-		LLHost host(gMessageSystem->getSenderIP(), gMessageSystem->getSenderPort());
+		LLHost host(ip, port);
 		regionp = LLWorld::getInstance()->getRegion(host);
 	}
-	for (; i < num_objects; i++)
+
+	bool delete_object = false;
+	S32	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
+	for (S32 i = 0; i < num_objects; ++i)
 	{
+		U32	local_id;
 		mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i);
+		if (local_id == KILLOBJECT_DELETE_OPCODE)
+		{
+			// This local_id is invalid, but was sent by the server to flag
+			// all subsequent local_id's as objects that were actually deleted
+			// rather than unsubscribed from interestlist.
+			delete_object = true;
+			continue;
+		}
 
-		LLViewerObjectList::getUUIDFromLocal(id,
-											local_id,
-											gMessageSystem->getSenderIP(),
-											gMessageSystem->getSenderPort());
+		LLViewerObjectList::getUUIDFromLocal(id, local_id, ip, port); 
 		if (id == LLUUID::null)
 		{
 			LL_DEBUGS("Messaging") << "Unknown kill for local " << local_id << LL_ENDL;
-			gObjectList.mNumUnknownKills++;
 			continue;
 		}
 		else
@@ -4524,39 +4526,35 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 			LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL;
 		}
 
-		// ...don't kill the avatar
-		if (!(id == gAgentID))
+		if (id == gAgentID)
 		{
-			LLViewerObject *objectp = gObjectList.findObject(id);
-			if (objectp)
-			{
-				// Display green bubble on kill
-				if ( gShowObjectUpdates )
-				{
-					LLColor4 color(0.f,1.f,0.f,1.f);
-					gPipeline.addDebugBlip(objectp->getPositionAgent(), color);
-				}
-
-				// Do the kill
-				gObjectList.killObject(objectp);
-			}
-			//else
-			//{
-			//	LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL;
-			//	gObjectList.mNumUnknownKills++;
-			//}
+			// never kill our avatar
+			continue;
+		}
 
-			if(remove_from_cache)
+		LLViewerObject *objectp = gObjectList.findObject(id);
+		if (objectp)
+		{
+			// Display green bubble on kill
+			if ( gShowObjectUpdates )
 			{
-				regionp->killCacheEntry(local_id);
+				LLColor4 color(0.f,1.f,0.f,1.f);
+				gPipeline.addDebugBlip(objectp->getPositionAgent(), color);
 			}
+
+			// Do the kill
+			gObjectList.killObject(objectp);
+		}
+
+		if(delete_object)
+		{
+			regionp->killCacheEntry(local_id);
 		}
 
 		// We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab,
         // which is using the object, release the mouse capture correctly when the object dies.
         // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical().
 		LLSelectMgr::getInstance()->removeObjectFromSelections(id);
-
 	}
 }
 
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index f3552e2c2b..5b2214f3b3 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -107,7 +107,6 @@ LLViewerObjectList::LLViewerObjectList()
 	mNumNewObjects = 0;
 	mWasPaused = FALSE;
 	mNumDeadObjectUpdates = 0;
-	mNumUnknownKills = 0;
 	mNumUnknownUpdates = 0;
 }
 
@@ -1342,16 +1341,7 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
 
 	if (objectp)
 	{
-		if (objectp->isDead())
-		{
-			// This object is already dead.  Don't need to do more.
-			return TRUE;
-		}
-		else
-		{
-			objectp->markDead();
-		}
-
+		objectp->markDead(); // does the right thing if object already dead
 		return TRUE;
 	}
 
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 17c8c86ff5..3b26df7de6 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -191,7 +191,6 @@ public:
 
 	S32 mNumUnknownUpdates;
 	S32 mNumDeadObjectUpdates;
-	S32 mNumUnknownKills;
 	S32 mNumDeadObjects;
 protected:
 	std::vector<U64>	mOrphanParents;	// LocalID/ip,port of orphaned objects
-- 
cgit v1.2.3


From e1247d631f24065a31d9668915cb8bc84f3abc7f Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 18 Dec 2012 14:36:46 -0700
Subject: fix for SH-3619: some objects are missing

---
 indra/llmath/llcamera.cpp        | 50 ++++++++++++++++++--
 indra/llmath/llcamera.h          |  8 +++-
 indra/newview/lldrawable.cpp     | 13 ------
 indra/newview/llvieweroctree.cpp | 50 ++++++++++++++++++--
 indra/newview/llvieweroctree.h   | 19 ++++++--
 indra/newview/llviewerregion.cpp | 98 ++++++++++++----------------------------
 indra/newview/llviewerregion.h   |  1 +
 indra/newview/llvocache.cpp      | 49 ++++++++++----------
 indra/newview/llvocache.h        |  2 -
 indra/newview/llworld.cpp        |  1 +
 10 files changed, 168 insertions(+), 123 deletions(-)

(limited to 'indra')

diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index 22ba26f99b..6551b52462 100644
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -161,7 +161,7 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
 
 // ---------------- test methods  ---------------- 
 
-S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius) 
+S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius, const LLPlane* planes) 
 {
 	static const LLVector4a scaler[] = {
 		LLVector4a(-1,-1,-1),
@@ -174,6 +174,12 @@ S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
 		LLVector4a( 1, 1, 1)
 	};
 
+	if(!planes)
+	{
+		//use agent space
+		planes = mAgentPlanes;
+	}
+
 	U8 mask = 0;
 	bool result = false;
 	LLVector4a rscale, maxp, minp;
@@ -183,7 +189,7 @@ S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
 		mask = mPlaneMask[i];
 		if (mask != 0xff)
 		{
-			const LLPlane& p(mAgentPlanes[i]);
+			const LLPlane& p(planes[i]);
 			p.getAt<3>(d);
 			rscale.setMul(radius, scaler[mask]);
 			minp.setSub(center, rscale);
@@ -204,8 +210,14 @@ S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
 	return result?1:2;
 }
 
+//exactly same as the function AABBInFrustum(...)
+//except uses mRegionPlanes instead of mAgentPlanes.
+S32 LLCamera::AABBInRegionFrustum(const LLVector4a& center, const LLVector4a& radius) 
+{
+	return AABBInFrustum(center, radius, mRegionPlanes);
+}
 
-S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius) 
+S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius, const LLPlane* planes) 
 {
 	static const LLVector4a scaler[] = {
 		LLVector4a(-1,-1,-1),
@@ -218,6 +230,12 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a&
 		LLVector4a( 1, 1, 1)
 	};
 
+	if(!planes)
+	{
+		//use agent space
+		planes = mAgentPlanes;
+	}
+
 	U8 mask = 0;
 	bool result = false;
 	LLVector4a rscale, maxp, minp;
@@ -227,7 +245,7 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a&
 		mask = mPlaneMask[i];
 		if ((i != 5) && (mask != 0xff))
 		{
-			const LLPlane& p(mAgentPlanes[i]);
+			const LLPlane& p(planes[i]);
 			p.getAt<3>(d);
 			rscale.setMul(radius, scaler[mask]);
 			minp.setSub(center, rscale);
@@ -248,6 +266,13 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a&
 	return result?1:2;
 }
 
+//exactly same as the function AABBInFrustumNoFarClip(...)
+//except uses mRegionPlanes instead of mAgentPlanes.
+S32 LLCamera::AABBInRegionFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius) 
+{
+	return AABBInFrustumNoFarClip(center, radius, mRegionPlanes);
+}
+
 int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius) 
 {
 	LLVector3 dist = sphere_center-mFrustCenter;
@@ -584,6 +609,23 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
 	}
 }
 
+//calculate regional planes from mAgentPlanes.
+//vector "shift" is the vector of the region origin in the agent space.
+void LLCamera::calcRegionFrustumPlanes(const LLVector3& shift) 
+{
+	F32 d;
+	LLVector3 n;
+	for(S32 i = 0 ; i < 7; i++)
+	{
+		if (mPlaneMask[i] != 0xff)
+		{
+			n.setVec(mAgentPlanes[i][0], mAgentPlanes[i][1], mAgentPlanes[i][2]);
+			d = mAgentPlanes[i][3] - n * shift;
+			mRegionPlanes[i].setVec(n, d);
+		}
+	}
+}
+
 void LLCamera::calculateFrustumPlanes(F32 left, F32 right, F32 top, F32 bottom)
 {
 	LLVector3 a, b, c;
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 0b591be622..898d73ed7e 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -109,6 +109,7 @@ public:
 
 private:
 	LL_ALIGN_16(LLPlane mAgentPlanes[7]);  //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+	LL_ALIGN_16(LLPlane mRegionPlanes[7]);  //frustum planes in a local region space, derived from mAgentPlanes
 	U8 mPlaneMask[8];         // 8 for alignment	
 	
 	F32 mView;					// angle between top and bottom frustum planes in radians.
@@ -178,6 +179,7 @@ public:
 	// Return number of bytes copied.
 	size_t readFrustumFromBuffer(const char *buffer);
 	void calcAgentFrustumPlanes(LLVector3* frust);
+	void calcRegionFrustumPlanes(const LLVector3& shift); //calculate regional planes from mAgentPlanes.
 	void ignoreAgentFrustumPlane(S32 idx);
 
 	// Returns 1 if partly in, 2 if fully in.
@@ -186,8 +188,10 @@ public:
 	S32 sphereInFrustum(const LLVector3 &center, const F32 radius) const;
 	S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
 	S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
-	S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
-	S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
+	S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius, const LLPlane* planes = NULL);
+	S32 AABBInRegionFrustum(const LLVector4a& center, const LLVector4a& radius);
+	S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius, const LLPlane* planes = NULL);
+	S32 AABBInRegionFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
 
 	//does a quick 'n dirty sphere-sphere check
 	S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius); 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index c782fbfe7e..1b7a98ba54 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1473,19 +1473,6 @@ void LLSpatialBridge::shiftPos(const LLVector4a& vec)
 
 void LLSpatialBridge::cleanupReferences()
 {	
-	LLPointer<LLVOCacheEntry> dummy_entry;
-	if (mDrawable && mDrawable->isDead() && mDrawable->getEntry()->hasVOCacheEntry())
-	{
-		//create a dummy entry to insert the entire LLSpatialBridge to the vo_cache partition so it can be reloaded.
-
-		dummy_entry = new LLVOCacheEntry();
-		dummy_entry->setOctreeEntry(mEntry);
-		dummy_entry->addChild((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry());
-		//llassert(!mDrawable->getParent());
-		
-		//mDrawable->mParent = this;
-	}
-
 	LLDrawable::cleanupReferences();
 	if (mDrawable)
 	{
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index b6e0674a95..7f502a6c51 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -675,6 +675,8 @@ void LLViewerOctreeCull::traverse(const OctreeNode* n)
 	}
 }
 	
+//------------------------------------------
+//agent space group culling
 S32 LLViewerOctreeCull::AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group)
 {
 	return mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
@@ -685,6 +687,14 @@ S32 LLViewerOctreeCull::AABBSphereIntersectGroupExtents(const LLviewerOctreeGrou
 	return AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist);
 }
 
+S32 LLViewerOctreeCull::AABBInFrustumGroupBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+}
+//------------------------------------------
+
+//------------------------------------------
+//agent space object set culling
 S32 LLViewerOctreeCull::AABBInFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group)
 {
 	return mCamera->AABBInFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
@@ -695,15 +705,47 @@ S32 LLViewerOctreeCull::AABBSphereIntersectObjectExtents(const LLviewerOctreeGro
 	return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist);
 }
 
-S32 LLViewerOctreeCull::AABBInFrustumGroupBounds(const LLviewerOctreeGroup* group)
+S32 LLViewerOctreeCull::AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group)
 {
-	return mCamera->AABBInFrustum(group->mBounds[0], group->mBounds[1]);
+	return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
 }
+//------------------------------------------
 
-S32 LLViewerOctreeCull::AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group)
+//------------------------------------------
+//local regional space group culling
+S32 LLViewerOctreeCull::AABBInRegionFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group)
 {
-	return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+	return mCamera->AABBInRegionFrustumNoFarClip(group->mBounds[0], group->mBounds[1]);
+}
+
+S32 LLViewerOctreeCull::AABBInRegionFrustumGroupBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInRegionFrustum(group->mBounds[0], group->mBounds[1]);
+}
+
+S32 LLViewerOctreeCull::AABBRegionSphereIntersectGroupExtents(const LLviewerOctreeGroup* group, const LLVector3& shift)
+{
+	return AABBSphereIntersect(group->mExtents[0], group->mExtents[1], mCamera->getOrigin() - shift, mCamera->mFrustumCornerDist);
+}
+//------------------------------------------
+
+//------------------------------------------
+//local regional space object culling
+S32 LLViewerOctreeCull::AABBInRegionFrustumObjectBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInRegionFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+}
+
+S32 LLViewerOctreeCull::AABBInRegionFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInRegionFrustumNoFarClip(group->mObjectBounds[0], group->mObjectBounds[1]);
+}
+
+S32 LLViewerOctreeCull::AABBRegionSphereIntersectObjectExtents(const LLviewerOctreeGroup* group, const LLVector3& shift)
+{
+	return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin() - shift, mCamera->mFrustumCornerDist);
 }
+//------------------------------------------
 
 //virtual 
 bool LLViewerOctreeCull::checkObjects(const OctreeNode* branch, const LLviewerOctreeGroup* group)
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index b89014119c..f6ad3ac327 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -280,13 +280,26 @@ public:
 	virtual bool earlyFail(LLviewerOctreeGroup* group);
 	virtual void traverse(const OctreeNode* n);
 	
-	S32 AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group);
+	//agent space group cull
+	S32 AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group);	
 	S32 AABBSphereIntersectGroupExtents(const LLviewerOctreeGroup* group);
-	S32 AABBInFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group);
-	S32 AABBSphereIntersectObjectExtents(const LLviewerOctreeGroup* group);
 	S32 AABBInFrustumGroupBounds(const LLviewerOctreeGroup* group);
+
+	//agent space object set cull
+	S32 AABBInFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group);
+	S32 AABBSphereIntersectObjectExtents(const LLviewerOctreeGroup* group);	
 	S32 AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group);
 	
+	//local region space group cull
+	S32 AABBInRegionFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group);
+	S32 AABBInRegionFrustumGroupBounds(const LLviewerOctreeGroup* group);
+	S32 AABBRegionSphereIntersectGroupExtents(const LLviewerOctreeGroup* group, const LLVector3& shift);
+
+	//local region space object set cull
+	S32 AABBInRegionFrustumNoFarClipObjectBounds(const LLviewerOctreeGroup* group);
+	S32 AABBInRegionFrustumObjectBounds(const LLviewerOctreeGroup* group);
+	S32 AABBRegionSphereIntersectObjectExtents(const LLviewerOctreeGroup* group, const LLVector3& shift);	
+	
 	virtual S32 frustumCheck(const LLviewerOctreeGroup* group) = 0;
 	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group) = 0;
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index ab692308b0..33e8348660 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -87,6 +87,7 @@ const F32 CAP_REQUEST_TIMEOUT = 18;
 const S32 MAX_CAP_REQUEST_ATTEMPTS = 30;
 
 LLViewerRegion* LLViewerRegion::sCurRegionp = NULL;
+BOOL LLViewerRegion::sVOCacheCullingEnabled = FALSE;
 
 typedef std::map<std::string, std::string> CapabilityMap;
 
@@ -141,7 +142,6 @@ public:
 	LLVOCacheEntry::vocache_entry_map_t	  mCacheMap; //all cached entries
 	LLVOCacheEntry::vocache_entry_set_t   mActiveSet; //all active entries;
 	LLVOCacheEntry::vocache_entry_set_t   mWaitingSet; //entries waiting for LLDrawable to be generated.	
-	std::set< LLPointer<LLVOCacheEntry> > mDummyEntries; //dummy vo cache entries, for LLSpatialBridge use.
 	std::set< LLviewerOctreeGroup* >      mVisibleGroups; //visible groupa
 	LLVOCachePartition*                   mVOCachePartition;
 	LLVOCacheEntry::vocache_entry_set_t   mVisibleEntries; //must-be-created visible entries wait for objects creation.	
@@ -841,17 +841,8 @@ void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* d
 	{
 		return;
 	}
-	if(entry->isDummy())
-	{
-		mImpl->mDummyEntries.insert(entry); //keep a copy to prevent from being deleted.
-		addToVOCacheTree(entry);
-	}
-	else if(!drawablep->getParent()) //root node
-	{
-		addToVOCacheTree(entry);
-		mImpl->mVisibleEntries.erase(entry);
-	}
-	else //child node
+
+	if(drawablep->getParent()) //child object
 	{
 		LLViewerOctreeEntry* parent_oct_entry = drawablep->getParent()->getEntry();
 		if(parent_oct_entry && parent_oct_entry->hasVOCacheEntry())
@@ -860,7 +851,19 @@ void LLViewerRegion::removeActiveCacheEntry(LLVOCacheEntry* entry, LLDrawable* d
 			parent->addChild(entry);
 		}
 	}
+	else //insert to vo cache tree.
+	{
+		//shift to the local regional space from agent space
+		const LLVector3 pos = drawablep->getVObj()->getPositionRegion();
+		LLVector4a vec(pos[0], pos[1], pos[2]);
+		LLVector4a shift; 
+		shift.setSub(vec, entry->getPositionGroup());
+		entry->shift(shift);
+		
+		addToVOCacheTree(entry);
+	}
 
+	mImpl->mVisibleEntries.erase(entry);
 	mImpl->mActiveSet.erase(entry);
 	mImpl->mWaitingSet.erase(entry);
 	entry->setState(LLVOCacheEntry::INACTIVE);
@@ -878,7 +881,10 @@ void LLViewerRegion::addVisibleGroup(LLviewerOctreeGroup* group)
 
 void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry)
 {
-	static BOOL vo_cache_culling_enabled = gSavedSettings.getBOOL("ObjectCacheViewCullingEnabled");
+	if(!sVOCacheCullingEnabled)
+	{
+		return;
+	}
 
 	if(mDead || !entry || !entry->getEntry())
 	{
@@ -954,12 +960,13 @@ F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
 	//process visible entries
 	max_time *= 0.5f; //only use up to half available time to update entries.
 
+#if 1
 	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mVisibleEntries.begin(); iter != mImpl->mVisibleEntries.end();)
 	{
 		LLVOCacheEntry* vo_entry = *iter;
 		vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate);
 
-		if(vo_entry->getState() < LLVOCacheEntry::WAITING && !vo_entry->isDummy())
+		if(vo_entry->getState() < LLVOCacheEntry::WAITING)
 		{			
 			mImpl->mWaitingList.insert(vo_entry);
 		}
@@ -987,12 +994,7 @@ F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
 
 		if(!vo_entry->getNumOfChildren())
 		{
-			if(vo_entry->isDummy())
-			{
-				mImpl->mDummyEntries.erase(vo_entry);
-				iter = mImpl->mVisibleEntries.erase(iter);
-			}
-			else if(vo_entry->getState() >= LLVOCacheEntry::WAITING)
+			if(vo_entry->getState() >= LLVOCacheEntry::WAITING)
 			{
 				iter = mImpl->mVisibleEntries.erase(iter);
 			}
@@ -1011,6 +1013,7 @@ F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
 		//	break;
 		//}
 	}
+#endif
 
 	//process visible groups
 	std::set< LLviewerOctreeGroup* >::iterator group_iter = mImpl->mVisibleGroups.begin();
@@ -1027,11 +1030,6 @@ F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
 			if((*i)->hasVOCacheEntry())
 			{
 				LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry();
-				if(vo_entry->isDummy())
-				{
-					addVisibleCacheEntry(vo_entry); //for LLSpatialBridge.
-					continue;
-				}
 
 				vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate);				
 				mImpl->mWaitingList.insert(vo_entry);
@@ -1118,6 +1116,11 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 
 F32 LLViewerRegion::killInvisibleObjects(F32 max_time)
 {
+	if(!sVOCacheCullingEnabled)
+	{
+		return max_time;
+	}
+
 	std::vector<LLDrawable*> delete_list;
 	for(LLVOCacheEntry::vocache_entry_set_t::iterator iter = mImpl->mActiveSet.begin();
 		iter != mImpl->mActiveSet.end(); ++iter)
@@ -1695,13 +1698,6 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 
 LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id)
 {
-	static BOOL vo_cache_culling_enabled = gSavedSettings.getBOOL("ObjectCacheViewCullingEnabled");
-
-	if(!vo_cache_culling_enabled)
-	{
-		return NULL;
-	}
-
 	LLVOCacheEntry* entry = getCacheEntry(local_id);
 	removeFromVOCacheTree(entry);
 
@@ -1741,44 +1737,6 @@ bool LLViewerRegion::probeCache(U32 local_id, U32 crc, U8 &cache_miss_type)
 			}
 
 			addVisibleCacheEntry(entry);
-#if 0
-			if(entry->isBridgeChild()) //bridge child
-			{
-				addVisibleCacheEntry(entry);
-			}
-			else
-			{
-				U32 parent_id = entry->getParentID();
-				if(parent_id > 0) //has parent
-				{
-					LLVOCacheEntry* parent = getCacheEntry(parent_id);
-				
-					if(parent) //parent cached
-					{
-						parent->addChild(entry);
-
-						if(parent->isState(LLVOCacheEntry::INACTIVE))
-						{
-							//addToVOCacheTree(parent);
-							addVisibleCacheEntry(parent);
-						}
-						else //parent visible
-						{
-							addVisibleCacheEntry(parent);
-						}
-					}
-					else //parent not cached. This should not happen, but just in case...
-					{
-						addVisibleCacheEntry(entry);
-					}
-				}
-				else //root node
-				{
-					//addToVOCacheTree(entry);
-					addVisibleCacheEntry(entry);
-				}
-			}
-#endif
 			return true;
 		}
 		else
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 9a47227f1c..dbc59cee8f 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -392,6 +392,7 @@ public:
 	LLDynamicArray<LLUUID> mMapAvatarIDs;
 
 	static LLViewerRegion* sCurRegionp;
+	static BOOL sVOCacheCullingEnabled; //vo cache culling enabled or not.
 private:
 	LLViewerRegionImpl * mImpl;
 
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 8ea79dbae6..59645fdbe9 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -424,24 +424,6 @@ void LLVOCacheEntry::calcSceneContribution(const LLVector3& camera_origin, bool
 	setVisible();
 }
 
-U32 LLVOCacheEntry::getParentID()
-{
-	if(!(mState & CHILD))
-	{
-		return 0; //not a child
-	}
-
-	U32 parent_id = 0;
-	LLDataPackerBinaryBuffer* dp = getDP();
-	if(dp)
-	{
-		dp->reset();
-		dp->unpackU32(parent_id, "ParentID");
-		dp->reset();
-	}
-	return parent_id;
-}
-
 //-------------------------------------------------------------------
 //LLVOCachePartition
 //-------------------------------------------------------------------
@@ -471,24 +453,31 @@ void LLVOCachePartition::removeEntry(LLViewerOctreeEntry* entry)
 class LLVOCacheOctreeCull : public LLViewerOctreeCull
 {
 public:
-	LLVOCacheOctreeCull(LLCamera* camera, LLViewerRegion* regionp) : LLViewerOctreeCull(camera), mRegionp(regionp) {}
+	LLVOCacheOctreeCull(LLCamera* camera, LLViewerRegion* regionp, const LLVector3& shift) : LLViewerOctreeCull(camera), mRegionp(regionp) 
+	{
+		mLocalShift = shift;
+	}
 
 	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)
 	{
-		S32 res = AABBInFrustumNoFarClipGroupBounds(group);
+		//S32 res = AABBInRegionFrustumGroupBounds(group);
+		
+		S32 res = AABBInRegionFrustumNoFarClipGroupBounds(group);
 		if (res != 0)
 		{
-			res = llmin(res, AABBSphereIntersectGroupExtents(group));
+			res = llmin(res, AABBRegionSphereIntersectGroupExtents(group, mLocalShift));
 		}
 		return res;
 	}
 
 	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)
 	{
-		S32 res = AABBInFrustumNoFarClipObjectBounds(group);
+		//S32 res = AABBInRegionFrustumObjectBounds(group);
+
+		S32 res = AABBInRegionFrustumNoFarClipObjectBounds(group);
 		if (res != 0)
 		{
-			res = llmin(res, AABBSphereIntersectObjectExtents(group));
+			res = llmin(res, AABBRegionSphereIntersectObjectExtents(group, mLocalShift));
 		}
 		return res;
 	}
@@ -500,10 +489,16 @@ public:
 
 private:
 	LLViewerRegion* mRegionp;
+	LLVector3       mLocalShift; //shift vector from agent space to local region space.
 };
 
 S32 LLVOCachePartition::cull(LLCamera &camera)
 {
+	if(!LLViewerRegion::sVOCacheCullingEnabled)
+	{
+		return 0;
+	}
+
 	if(mVisitedTime == LLViewerOctreeEntryData::getCurrentFrame())
 	{
 		return 0; //already visited.
@@ -511,8 +506,12 @@ S32 LLVOCachePartition::cull(LLCamera &camera)
 	mVisitedTime = LLViewerOctreeEntryData::getCurrentFrame();
 
 	((LLviewerOctreeGroup*)mOctree->getListener(0))->rebound();
-		
-	LLVOCacheOctreeCull culler(&camera, mRegionp);
+
+	//localize the camera
+	LLVector3 region_agent = mRegionp->getOriginAgent();
+	camera.calcRegionFrustumPlanes(region_agent);
+
+	LLVOCacheOctreeCull culler(&camera, mRegionp, region_agent);
 	culler.traverse(mOctree);
 
 	return 0;
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 4d058ffdac..f5cc5d2f75 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -98,7 +98,6 @@ public:
 	S32 getHitCount() const			{ return mHitCount; }
 	S32 getCRCChangeCount() const	{ return mCRCChangeCount; }
 	S32 getMinVisFrameRange()const;	
-	U32 getParentID();
 
 	void calcSceneContribution(const LLVector3& camera_origin, bool needs_update, U32 last_update);
 	void setSceneContribution(F32 scene_contrib) {mSceneContrib = scene_contrib;}
@@ -118,7 +117,6 @@ public:
 	LLVOCacheEntry* getChild(S32 i) {return mChildrenList[i];}
 	S32  getNumOfChildren()         {return mChildrenList.size();}
 	void clearChildrenList()        {mChildrenList.clear();}
-	bool isDummy()                  {return !mBuffer;}	
 
 public:
 	typedef std::map<U32, LLPointer<LLVOCacheEntry> >	   vocache_entry_map_t;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index aed2835e4a..7a7d6a7b43 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -110,6 +110,7 @@ LLWorld::LLWorld() :
 	gGL.getTexUnit(0)->bind(mDefaultWaterTexturep);
 	mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
+	LLViewerRegion::sVOCacheCullingEnabled = (BOOL)gSavedSettings.getBOOL("ObjectCacheViewCullingEnabled");
 }
 
 
-- 
cgit v1.2.3


From 4e22f3e3ef15e24d7e9e0ad156e60d4cd1b2d5c9 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 18 Dec 2012 23:16:50 -0700
Subject: fix for SH-3624: Object deletion does not work

---
 indra/newview/lldrawable.cpp         |  5 -----
 indra/newview/llviewerobject.cpp     | 16 ++++++++++++++++
 indra/newview/llviewerobject.h       |  1 +
 indra/newview/llviewerobjectlist.cpp |  3 ++-
 indra/newview/llviewerobjectlist.h   |  2 +-
 indra/newview/llviewerregion.cpp     |  6 +++++-
 indra/newview/llvocache.cpp          | 22 ----------------------
 indra/newview/llvocache.h            | 18 ++++++++----------
 8 files changed, 33 insertions(+), 40 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 1b7a98ba54..3c68ac231e 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1099,11 +1099,6 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat
 	{
 		part->put(this);
 	}
-
-	if(mDrawable->getEntry()->hasVOCacheEntry())
-	{
-		((LLVOCacheEntry*)mDrawable->getEntry()->getVOCacheEntry())->setBridgeChild();
-	}
 }
 
 LLSpatialBridge::~LLSpatialBridge()
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index dbccb2a4d9..2aa0e15fc3 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -323,6 +323,22 @@ 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)
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 02b4f84785..74b86600d4 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -132,6 +132,7 @@ public:
 	BOOL isDead() const									{return mDead;}
 	BOOL isOrphaned() const								{ return mOrphaned; }
 	BOOL isParticleSource() const;
+	void EnableToCacheTree(bool enabled);
 
 	virtual LLVOAvatar* asAvatar();
 
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 5b2214f3b3..6e7ce103b5 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1326,7 +1326,7 @@ void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
 	}
 }
 
-BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
+BOOL LLViewerObjectList::killObject(LLViewerObject *objectp, bool cache_enabled)
 {
 	// 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.
@@ -1341,6 +1341,7 @@ BOOL LLViewerObjectList::killObject(LLViewerObject *objectp)
 
 	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;
 	}
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 3b26df7de6..0e2b34cb34 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -72,7 +72,7 @@ public:
 
 	LLViewerObject *replaceObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); // TomY: hack to switch VO instances on the fly
 	
-	BOOL killObject(LLViewerObject *objectp);
+	BOOL killObject(LLViewerObject *objectp, bool cache_enabled = false);
 	void killObjects(LLViewerRegion *regionp); // Kill all objects owned by a particular region.
 	void killAllObjects();
 	void removeDrawable(LLDrawable* drawablep);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 33e8348660..c4b6cacae2 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -894,6 +894,10 @@ 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());
 }
@@ -1132,7 +1136,7 @@ F32 LLViewerRegion::killInvisibleObjects(F32 max_time)
 	}
 	for(S32 i = 0; i < delete_list.size(); i++)
 	{
-		gObjectList.killObject(delete_list[i]->getVObj());
+		gObjectList.killObject(delete_list[i]->getVObj(), true);
 	}
 	delete_list.clear();
 
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 59645fdbe9..86cfbb1d74 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -64,18 +64,6 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &
 	mBuffer = new U8[dp.getBufferSize()];
 	mDP.assignBuffer(mBuffer, dp.getBufferSize());
 	mDP = dp;
-
-	if(dp.getBufferSize() > 0)
-	{
-		U32 parent_id = 0;
-		dp.reset();
-		dp.unpackU32(parent_id, "ParentID");
-		dp.reset();
-		if(parent_id > 0)
-		{
-			mState |= CHILD; //is a child
-		}
-	}
 }
 
 LLVOCacheEntry::LLVOCacheEntry()
@@ -224,16 +212,6 @@ void LLVOCacheEntry::setOctreeEntry(LLViewerOctreeEntry* entry)
 	LLViewerOctreeEntryData::setOctreeEntry(entry);
 }
 
-void LLVOCacheEntry::setBridgeChild()
-{
-	mState |= BRIDGE_CHILD;
-}
-	
-void LLVOCacheEntry::clearBridgeChild()
-{
-	mState &= ~BRIDGE_CHILD;
-}
-
 void LLVOCacheEntry::copyTo(LLVOCacheEntry* new_entry)
 {
 	//copy LLViewerOctreeEntry
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index f5cc5d2f75..c631e12739 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -51,8 +51,7 @@ public:
 
 	enum
 	{
-		CHILD        = 0x00010000, //has parent
-		BRIDGE_CHILD = 0x00020000  //is a child of a spatial bridge.
+		ADD_TO_CACHE_TREE = 0x00010000, //has parent
 	};
 
 	struct CompareVOCacheEntry
@@ -85,14 +84,13 @@ public:
 	LLVOCacheEntry();	
 
 	void setState(U32 state);
-	bool isState(U32 state)   {return (mState & 0xffff) == state;}
-	U32  getState() const     {return (mState & 0xffff);}
-	U32  getFullState() const {return mState;}
-
-	void setBridgeChild();  
-	void clearBridgeChild(); 
-	bool isBridgeChild()     {return mState & BRIDGE_CHILD;}
-
+	void clearState(U32 state) {mState &= ~state;}
+	void addState(U32 state)   {mState |= state;}
+	bool isState(U32 state)    {return (mState & 0xffff) == state;}
+	bool hasState(U32 state)   {return mState & state;}
+	U32  getState() const      {return (mState & 0xffff);}
+	U32  getFullState() const  {return mState;}
+	
 	U32 getLocalID() const			{ return mLocalID; }
 	U32 getCRC() const				{ return mCRC; }
 	S32 getHitCount() const			{ return mHitCount; }
-- 
cgit v1.2.3


From 1fbd45672fcb1e5bfc194712fc7d0d4847a651cd Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 19 Dec 2012 23:21:31 -0700
Subject: fix for SH-3640: Can not edit objects

---
 indra/newview/llscenemonitor.cpp  | 6 ++++++
 indra/newview/llscenemonitor.h    | 1 +
 indra/newview/llviewerdisplay.cpp | 2 ++
 3 files changed, 9 insertions(+)

(limited to 'indra')

diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 43f9e9208b..4872200f24 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -211,6 +211,7 @@ void LLSceneMonitor::unfreezeScene()
 void LLSceneMonitor::capture()
 {
 	static U32 last_capture_time = 0;
+
 	if(last_capture_time == gFrameCount)
 	{
 		return;
@@ -239,6 +240,11 @@ void LLSceneMonitor::capture()
 	mNeedsUpdateDiff = TRUE;
 }
 
+bool LLSceneMonitor::needsUpdate() const
+{
+	return mNeedsUpdateDiff;
+}
+
 void LLSceneMonitor::compare()
 {
 	if(!mNeedsUpdateDiff)
diff --git a/indra/newview/llscenemonitor.h b/indra/newview/llscenemonitor.h
index ce25467a21..02e3d57d46 100644
--- a/indra/newview/llscenemonitor.h
+++ b/indra/newview/llscenemonitor.h
@@ -59,6 +59,7 @@ public:
 	F32  getSamplingTime() const { return mSamplingTime;}
 	F32  getDiffPixelRatio() const { return mDiffPixelRatio;}
 	bool isEnabled()const {return mEnabled;}
+	bool needsUpdate() const;
 	
 private:
 	void freezeScene();
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 270ab26149..31b2220fc8 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1228,10 +1228,12 @@ void render_ui(F32 zoom_factor, int subfield)
 		glh_set_current_modelview(glh_copy_matrix(gGLLastModelView));
 	}
 	
+	if(LLSceneMonitor::getInstance()->needsUpdate())
 	{
 		gGL.pushMatrix();
 		gViewerWindow->setup2DRender();
 		LLSceneMonitor::getInstance()->compare();
+		gViewerWindow->setup3DRender();
 		gGL.popMatrix();
 	}
 
-- 
cgit v1.2.3


From 7cc37d949e9319a5b60641ff8453a0fed763d817 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 9 Jan 2013 22:43:10 -0700
Subject: fix the merge errors from the changeset 3eadda9666cf

---
 indra/newview/lldrawable.cpp         | 16 ++++++++++------
 indra/newview/llspatialpartition.cpp |  2 --
 indra/newview/llviewerobjectlist.cpp |  6 ++----
 indra/newview/llvieweroctree.cpp     |  9 +++++++++
 indra/newview/llvieweroctree.h       | 15 +++++++++++++--
 5 files changed, 34 insertions(+), 14 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index d91c7b0e1a..ba970671af 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1009,13 +1009,15 @@ bool LLDrawable::isRecentlyVisible() const
 
 void LLDrawable::setGroup(LLviewerOctreeGroup *groupp)
 {
-    //precondition: mGroupp MUST be null or DEAD or mGroupp MUST NOT contain this
-	llassert(!getGroup() || getGroup()->isDead() || !getGroup()->hasElement(this));
+	LLSpatialGroup* cur_groupp = (LLSpatialGroup*)getGroup();
+    
+	//precondition: mGroupp MUST be null or DEAD or mGroupp MUST NOT contain this
+	//llassert(!cur_groupp || cur_groupp->isDead() || !cur_groupp->hasElement(this));
 
 	//precondition: groupp MUST be null or groupp MUST contain this
-	llassert(!groupp || groupp->hasElement(this));
+	llassert(!groupp || (LLSpatialGroup*)groupp->hasElement(this));
 
-	if (getGroup() != groupp && getVOVolume())
+	if (cur_groupp != groupp && getVOVolume())
 	{ //NULL out vertex buffer references for volumes on spatial group change to maintain
 		//requirement that every face vertex buffer is either NULL or points to a vertex buffer
 		//contained by its drawable's spatial group
@@ -1031,8 +1033,8 @@ void LLDrawable::setGroup(LLviewerOctreeGroup *groupp)
 
 	//postcondition: if next group is NULL, previous group must be dead OR NULL OR binIndex must be -1
 	//postcondition: if next group is NOT NULL, binIndex must not be -1
-	llassert(groupp == NULL ? (getGroup() == NULL || getGroup()->isDead()) || getBinIndex() == -1 :
-							getBinIndex() != -1);
+	//llassert(groupp == NULL ? (cur_groupp == NULL || cur_groupp->isDead()) || (!getEntry() || getEntry()->getBinIndex() == -1) :
+	//						(getEntry() && getEntry()->getBinIndex() != -1));
 
 	LLViewerOctreeEntryData::setGroup(groupp);
 }
@@ -1498,6 +1500,8 @@ void LLSpatialBridge::cleanupReferences()
 				{
 					drawable->setGroup(NULL);				
 				}
+			}
+		}
 
 		LLDrawable* drawablep = mDrawable;
 		mDrawable = NULL;
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index bcafe2e008..0e2109c4af 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1549,8 +1549,6 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 		drawablep->setGroup(NULL);
 	}
 
-	drawablep->setSpatialGroup(NULL);
-
 	assert_octree_valid(mOctree);
 	
 	return TRUE;
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 0543d11644..0335cd769b 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -356,7 +356,7 @@ LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry*
 		}
 		justCreated = true;
 		mNumNewObjects++;
-		sCacheHitRate.addValue(100.f);
+		sCacheHitRate.sample(100.f);
 	}
 
 	if (objectp->isDead())
@@ -578,8 +578,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			}
 			justCreated = TRUE;
 			mNumNewObjects++;
-			sCacheHitRate.sample(cached ? 100.f : 0.f);
-
 		}
 
 
@@ -672,7 +670,7 @@ void LLViewerObjectList::processCachedObjectUpdate(LLMessageSystem *mesgsys,
 
 			continue; // no data packer, skip this object
 		}
-		sCacheHitRate.addValue(100.f);
+		sCacheHitRate.sample(100.f);
 	}
 
 	return;
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 7f502a6c51..cfa24c32ed 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -347,6 +347,15 @@ LLviewerOctreeGroup::LLviewerOctreeGroup(OctreeNode* node) :
 	mOctreeNode->addListener(this);
 }
 
+bool LLviewerOctreeGroup::hasElement(LLViewerOctreeEntryData* data) 
+{ 
+	if(!data->getEntry())
+	{
+		return false;
+	}
+	return std::find(getDataBegin(), getDataEnd(), data->getEntry()) != getDataEnd(); 
+}
+
 bool LLviewerOctreeGroup::removeFromGroup(LLViewerOctreeEntryData* data)
 {
 	return removeFromGroup(data->getEntry());
diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index f6ad3ac327..5bcaeb85da 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -94,6 +94,16 @@ public:
 	S32	 getBinIndex() const			        {return mBinIndex; }
 	void setBinIndex(S32 index) const	        {mBinIndex = index; }
 
+	void* operator new(size_t size)
+	{
+		return ll_aligned_malloc_16(size);
+	}
+
+	void operator delete(void* ptr)
+	{
+		ll_aligned_free_16(ptr);
+	}
+
 private:
 	void addData(LLViewerOctreeEntryData* data);			
 
@@ -238,8 +248,9 @@ public:
 	element_list& getData() { return mOctreeNode->getData(); }
 	element_iter getDataBegin() { return mOctreeNode->getDataBegin(); }
 	element_iter getDataEnd() { return mOctreeNode->getDataEnd(); }
-	U32 getElementCount() const { return mOctreeNode->getElementCount(); }	
-
+	U32 getElementCount() const { return mOctreeNode->getElementCount(); }
+	bool hasElement(LLViewerOctreeEntryData* data);
+	
 private:
 	virtual bool boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut);	
 	
-- 
cgit v1.2.3


From c539004c7ebec31d7e61209e7110ec96c867aaa6 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 9 Jan 2013 23:37:22 -0700
Subject: fix a type casting error.

---
 indra/newview/llfasttimerview.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp
index 32ed662548..ba298ed819 100644
--- a/indra/newview/llfasttimerview.cpp
+++ b/indra/newview/llfasttimerview.cpp
@@ -514,7 +514,7 @@ void LLFastTimerView::draw()
 			else
 			{
 				ms = LLUnit<LLUnits::Seconds, F64>(frame_recording.getPeriodMean(*idp));
-				calls = (S32)frame_recording.getPeriodMean((F32)idp->callCount());
+				calls = (S32)frame_recording.getPeriodMean(idp->callCount());
 			}
 
 			if (mDisplayCalls)
-- 
cgit v1.2.3


From 0c3df70dffdc6b19abaa91bfd14f2d08a66e95dd Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 9 Jan 2013 23:15:32 -0800
Subject: added newline to fix gcc builds

---
 indra/newview/llvieweroctree.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'indra')

diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h
index 5bcaeb85da..a35c551949 100644
--- a/indra/newview/llvieweroctree.h
+++ b/indra/newview/llvieweroctree.h
@@ -324,4 +324,4 @@ protected:
 	S32 mRes;
 };
 
-#endif
\ No newline at end of file
+#endif
-- 
cgit v1.2.3


From 840540be186904b1e711d79dede0c771c967950c Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 10 Jan 2013 18:42:39 -0800
Subject: SH-3405 WIP convert existing stats to lltrace system fixed gcc errors
 in llscenemonitor.cpp

---
 indra/newview/llscenemonitor.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
index 4872200f24..189697dcf0 100644
--- a/indra/newview/llscenemonitor.cpp
+++ b/indra/newview/llscenemonitor.cpp
@@ -346,7 +346,7 @@ void LLSceneMonitor::calcDiffAggregate()
 		glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mQueryObject);
 	}
 
-	gl_draw_scaled_target(0, 0, mDiff->getWidth() * mDiffPixelRatio, mDiff->getHeight() * mDiffPixelRatio, mDiff);
+	gl_draw_scaled_target(0, 0, S32(mDiff->getWidth() * mDiffPixelRatio), S32(mDiff->getHeight() * mDiffPixelRatio), mDiff);
 
 	if(mHasNewDiff)
 	{
@@ -424,8 +424,8 @@ void LLSceneMonitorView::draw()
 	}
 
 	F32 ratio = LLSceneMonitor::getInstance()->getDiffPixelRatio();
-	S32 height = target->getHeight() * ratio;
-	S32 width = target->getWidth() * ratio;
+	S32 height = (S32)(target->getHeight() * ratio);
+	S32 width = (S32)(target->getWidth() * ratio);
 	//S32 height = (S32) (gViewerWindow->getWindowRectScaled().getHeight()*0.5f);
 	//S32 width = (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.5f);
 	
-- 
cgit v1.2.3