diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index 22ba26f99b20d178f22fae7c5e4c5589470700e5..6551b52462cb0621212bf2e0b19f6da08eaad9e6 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 0b591be622e453915809b3e557caeb04310a937c..898d73ed7ee05e7a6d8730281b91dfc4460befbc 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -109,6 +109,7 @@ class LLCamera
 
 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 @@ class LLCamera
 	// 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 @@ class LLCamera
 	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/llui/llui.cpp b/indra/llui/llui.cpp
index 6d2bc1837cee68b895c284830e45bbbcbf600b28..6a87977718644ff1556bf6b4d3d364f0c3610acd 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 c5a12d2b315ec4febfc42468ac23f59d593b4b8f..90a4617c4e521c1f87bff887fe3909243433f6db 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 ebc8e4572aff55409e408e0d69e6450a9895a551..16d82d5a0a63d9a01f11d2b6a309442bbeaef6f3 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -462,6 +462,7 @@ set(viewer_SOURCE_FILES
     llremoteparcelrequest.cpp
     llsavedsettingsglue.cpp
     llsaveoutfitcombobtn.cpp
+	llscenemonitor.cpp
     llsceneview.cpp
     llscreenchannel.cpp
     llscriptfloater.cpp
@@ -586,6 +587,7 @@ set(viewer_SOURCE_FILES
     llviewernetwork.cpp
     llviewerobject.cpp
     llviewerobjectlist.cpp
+	llvieweroctree.cpp
     llviewerparcelmedia.cpp
     llviewerparcelmediaautoplay.cpp
     llviewerparcelmgr.cpp
@@ -1028,6 +1030,7 @@ set(viewer_HEADER_FILES
     llrootview.h
     llsavedsettingsglue.h
     llsaveoutfitcombobtn.h
+	llscenemonitor.h
     llsceneview.h
     llscreenchannel.h
     llscriptfloater.h
@@ -1152,6 +1155,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 557a698d6daf9fc2727428a128cfe370742a04e5..5c0e8d858e2dce771a00049a0f34636b6bc8a476 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6389,6 +6389,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>
@@ -9447,6 +9458,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>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>ScriptHelpFollowsCursor</key>
     <map>
       <key>Comment</key>
@@ -10853,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 +12514,7 @@
       <key>Type</key>
       <string>LLSD</string>
       <key>Value</key>
+      <array />
     </map>
     <key>VFSOldSize</key>
     <map>
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 0000000000000000000000000000000000000000..f1400c9b44f5688acffaca57a3cdf7f8ce0d8dce
--- /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 0000000000000000000000000000000000000000..a33ef7e92c18e457decf2f7cd286b336eff01dce
--- /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
new file mode 100644
index 0000000000000000000000000000000000000000..050114b37e0e4b41a853d6f3b4a644cb202fe2b7
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/twotexturecompareF.glsl
@@ -0,0 +1,41 @@
+/** 
+ * @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 = abs(texture2D(tex0, vary_texcoord0.xy) - texture2D(tex1, vary_texcoord0.xy));
+}
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 0000000000000000000000000000000000000000..67c6674f0cec4a66c8c8e342c59998298101865a
--- /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/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 86a241fa588e45a42585d1dc9bf76fa4a9d1367d..3d7770c765e187067a6e25e6e13fea9c0868b969 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3749,7 +3749,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;
 }
@@ -4333,11 +4333,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/lldebugview.cpp b/indra/newview/lldebugview.cpp
index aeecf054b8ba5245c1f0cf800bd39057a355e90f..86f0213282b33fdcadf4eeb0f5d40c6bec3296d6 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/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 6ef437cefb7609eb8134139cde5a27ac80efb215..ba970671afc1822a23cf78bc7942467b4db141e2 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;
@@ -76,7 +77,6 @@ LLTrace::MemStat	LLDrawable::sMemStat("LLDrawable");
 //
 
 // static
-U32 LLDrawable::sCurVisible = 0;
 U32 LLDrawable::sNumZombieDrawables = 0;
 F32 LLDrawable::sCurPixelAngle = 0;
 LLDynamicArrayPtr<LLPointer<LLDrawable> > LLDrawable::sDeadList;
@@ -86,33 +86,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
@@ -156,6 +182,7 @@ void LLDrawable::markDead()
 		llwarns << "Warning!  Marking dead multiple times!" << llendl;
 		return;
 	}
+	setState(DEAD);
 
 	if (mSpatialBridge)
 	{
@@ -165,8 +192,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);
 }
@@ -220,6 +246,8 @@ void LLDrawable::cleanupReferences()
 	
 	gPipeline.unlinkDrawable(this);
 	
+	removeFromOctree();
+
 	{
 		LLFastTimer t(FTM_DEREF_DRAWABLE);
 		// Cleanup references to other objects
@@ -228,6 +256,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()
 {
 	/*
@@ -428,7 +471,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());
 }
 
@@ -717,7 +766,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 		LLVOVolume* volume = getVOVolume();
 		if (volume)
 		{
-			if (getSpatialGroup())
+			if (getGroup())
 			{
 				pos.set(getPositionGroup().getF32ptr());
 			}
@@ -835,9 +884,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)
 	{
@@ -845,9 +892,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);
@@ -859,40 +904,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);
 	}
 }
 
@@ -901,11 +930,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));
 	}
 }
 
@@ -939,26 +968,56 @@ 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
 {
-	//precondition: mSpatialGroupp MUST be null or DEAD or mSpatialGroupp MUST NOT contain this
-	llassert(!mSpatialGroupp || mSpatialGroupp->isDead() || !mSpatialGroupp->hasElement(this));
-
-	//precondition: groupp MUST be null or groupp MUST contain this
-	llassert(!groupp || groupp->hasElement(this));
+	//currently visible or visible in the previous frame.
+	bool vis = LLViewerOctreeEntryData::isRecentlyVisible();
 
-/*if (mSpatialGroupp && (groupp != mSpatialGroupp))
+	if(!vis)
 	{
-		mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY);
-	}*/
+		LLviewerOctreeGroup* group = getGroup();
+		if (group && group->isRecentlyVisible())
+		{
+			LLViewerOctreeEntryData::setVisible();
+			vis = TRUE ;
+		}
+	}
+
+	return vis ;
+}
+
+void LLDrawable::setGroup(LLviewerOctreeGroup *groupp)
+{
+	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 || (LLSpatialGroup*)groupp->hasElement(this));
 
-	if (mSpatialGroupp != 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
@@ -974,10 +1033,10 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *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 ? (mSpatialGroupp == NULL || mSpatialGroupp->isDead()) || getBinIndex() == -1 :
-							getBinIndex() != -1);
+	//llassert(groupp == NULL ? (cur_groupp == NULL || cur_groupp->isDead()) || (!getEntry() || getEntry()->getBinIndex() == -1) :
+	//						(getEntry() && getEntry()->getBinIndex() != -1));
 
-	mSpatialGroupp = groupp;
+	LLViewerOctreeEntryData::setGroup(groupp);
 }
 
 LLSpatialPartition* LLDrawable::getSpatialPartition()
@@ -996,11 +1055,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();
@@ -1019,89 +1078,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;
 	
@@ -1122,10 +1118,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
@@ -1147,8 +1146,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;
@@ -1160,7 +1160,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];
@@ -1182,12 +1182,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;
@@ -1200,19 +1197,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)
@@ -1247,7 +1246,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
@@ -1282,21 +1281,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);
 	}
@@ -1340,7 +1339,7 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 			}
 
 			if (!group ||
-				LLDrawable::getCurrentFrame() - av->mVisible > 1 ||
+				LLDrawable::getCurrentFrame() - av->getVisible() > 1 ||
 				impostor ||
 				!loaded)
 			{
@@ -1354,16 +1353,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 && 
@@ -1478,9 +1478,7 @@ 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()
@@ -1488,11 +1486,8 @@ void LLSpatialBridge::cleanupReferences()
 	LLDrawable::cleanupReferences();
 	if (mDrawable)
 	{
-		/*
+		mDrawable->setGroup(NULL);
 		
-		DON'T DO THIS -- this should happen through octree destruction
-
-			mDrawable->setSpatialGroup(NULL);
 		if (mDrawable->getVObj())
 		{
 			LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
@@ -1503,10 +1498,10 @@ void LLSpatialBridge::cleanupReferences()
 				LLDrawable* drawable = child->mDrawable;					
 				if (drawable)
 				{
-						drawable->setSpatialGroup(NULL);
-					}
+					drawable->setGroup(NULL);				
 				}
-		}*/
+			}
+		}
 
 		LLDrawable* drawablep = mDrawable;
 		mDrawable = NULL;
@@ -1575,8 +1570,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;
@@ -1584,8 +1579,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 c22cce246be7901e9bf559797537de60645ca214..161f550bb6aed9933c529997583a24360ac61422 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;
@@ -60,11 +61,11 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;
 // All data for new renderer goes into this class.
 LL_ALIGN_PREFIX(16)
 class LLDrawable 
-:	public LLRefCount,
-	public LLTrace::MemTrackable<LLDrawable, 16>
+:	public LLViewerOctreeEntryData,
+	public LLTrace::MemTrackable<LLDrawable>
 {
 public:
-	LLDrawable(const LLDrawable& rhs)
+	LLDrawable(const LLDrawable& rhs) : LLViewerOctreeEntryData(rhs)
 	{
 		*this = rhs;
 	}
@@ -77,7 +78,7 @@ class LLDrawable
 
 	static void initClass();
 
-	LLDrawable()				{ init(); }
+	LLDrawable(LLViewerObject *vobj, bool new_entry = false);
 	
 	void markDead();			// Mark this drawable as dead
 	BOOL isDead() const			{ return isState(DEAD); }
@@ -85,11 +86,9 @@ class LLDrawable
 
 	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; }
@@ -102,16 +101,12 @@ class LLDrawable
 	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; }
@@ -142,7 +137,7 @@ class LLDrawable
 	void                setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep);
 	void				mergeFaces(LLDrawable* src);
 
-	void init();
+	void init(bool new_entry);
 	void destroy();
 
 	void update();
@@ -173,8 +168,12 @@ class LLDrawable
 	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;
@@ -184,11 +183,6 @@ class LLDrawable
 	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; }
@@ -197,10 +191,14 @@ class LLDrawable
 	// 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();
@@ -285,10 +283,6 @@ class LLDrawable
 		ACTIVE_CHILD	= 0x40000000,
 	} EDrawableFlags;
 
-private: //aligned members
-	LL_ALIGN_16(LLVector4a		mExtents[2]);
-	LL_ALIGN_16(LLVector4a		mPositionGroup);
-	
 public:
 	LLXformMatrix       mXform;
 
@@ -297,12 +291,6 @@ class LLDrawable
 
 	F32				mDistanceWRTCamera;
 
-	static S32 getCurrentFrame() { return sCurVisible; }
-	static S32 getMinVisFrameRange();
-
-	void setSpatialBridge(LLSpatialBridge* bridge) { mSpatialBridge = (LLDrawable*) bridge; }
-	LLSpatialBridge* getSpatialBridge() { return (LLSpatialBridge*) (LLDrawable*) mSpatialBridge; }
-	
 	static F32 sCurPixelAngle; //current pixels per radian
 	static LLTrace::MemStat sMemStat;
 
@@ -313,18 +301,13 @@ class LLDrawable
 	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
 	static U32					sNumZombieDrawables;
 	static LLDynamicArrayPtr<LLPointer<LLDrawable> > sDeadList;
 } LL_ALIGN_POSTFIX(16);
diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..189697dcf01ca142bee29afc927d808c828cbef2
--- /dev/null
+++ b/indra/newview/llscenemonitor.cpp
@@ -0,0 +1,460 @@
+/** 
+ * @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"
+#include "llspatialpartition.h"
+
+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),
+	mDiffResult(0.f),
+	mDiffTolerance(0.1f),
+	mCurTarget(NULL), 
+	mNeedsUpdateDiff(FALSE),
+	mHasNewDiff(FALSE),
+	mHasNewQueryResult(FALSE),
+	mDebugViewerVisible(FALSE),
+	mQueryObject(0),
+	mSamplingTime(1.0f),
+	mDiffPixelRatio(0.5f)
+{
+	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;
+	mCurTarget = NULL;
+
+	unfreezeScene();
+
+	if(mQueryObject > 0)
+	{
+		release_occlusion_query_object_name(mQueryObject);
+		mQueryObject = 0;
+	}
+}
+
+void LLSceneMonitor::setDebugViewerVisible(BOOL visible) 
+{
+	mDebugViewerVisible = visible;
+}
+
+bool LLSceneMonitor::preCapture()
+{
+	static LLCachedControl<bool> monitor_enabled(gSavedSettings,"SceneLoadingMonitorEnabled");
+	static LLFrameTimer timer;	
+
+	mCurTarget = NULL;
+	if (!LLGLSLShader::sNoFixedFunction)
+	{
+		return false;
+	}
+
+	BOOL enabled = (BOOL)monitor_enabled || mDebugViewerVisible;
+	if(mEnabled != enabled)
+	{
+		if(mEnabled)
+		{
+			reset();
+			unfreezeScene();
+		}
+		else
+		{
+			freezeScene();
+		}
+
+		mEnabled = enabled;
+	}
+
+	if(!mEnabled)
+	{
+		return false;
+	}
+
+	if(timer.getElapsedTimeF32() < mSamplingTime)
+	{
+		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::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);
+}
+
+void LLSceneMonitor::capture()
+{
+	static U32 last_capture_time = 0;
+
+	if(last_capture_time == gFrameCount)
+	{
+		return;
+	}
+	last_capture_time = 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);
+
+	mCurTarget = NULL;
+	mNeedsUpdateDiff = TRUE;
+}
+
+bool LLSceneMonitor::needsUpdate() const
+{
+	return mNeedsUpdateDiff;
+}
+
+void LLSceneMonitor::compare()
+{
+	if(!mNeedsUpdateDiff)
+	{
+		return;
+	}
+	mNeedsUpdateDiff = FALSE;
+
+	if(!mFrames[0] || !mFrames[1])
+	{
+		return;
+	}
+	if(mFrames[0]->getWidth() != mFrames[1]->getWidth() || mFrames[0]->getHeight() != mFrames[1]->getHeight())
+	{
+		return; //size does not match
+	}
+
+	S32 width = gViewerWindow->getWindowWidthRaw();
+	S32 height = gViewerWindow->getWindowHeightRaw();
+	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);
+	
+	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);
+
+	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, S32(mDiff->getWidth() * mDiffPixelRatio), S32(mDiff->getHeight() * mDiffPixelRatio), 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() * mDiffPixelRatio * mDiffPixelRatio); //0.5 -> (front face + back face)
+
+	//llinfos << count << " : " << mDiffResult << llendl;
+}
+//-------------------------------------------------------------------------------------------------------------
+//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)
+{
+	LLSceneMonitor::getInstance()->setDebugViewerVisible(visible);
+
+	LLView::setVisible(visible);
+}
+
+void LLSceneMonitorView::draw()
+{
+	const LLRenderTarget* target = LLSceneMonitor::getInstance()->getDiffTarget();
+	if(!target)
+	{
+		return;
+	}
+
+	F32 ratio = LLSceneMonitor::getInstance()->getDiffPixelRatio();
+	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);
+	
+	LLRect new_rect;
+	new_rect.setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height);
+	setRect(new_rect);
+
+	//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));
+	
+	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
new file mode 100644
index 0000000000000000000000000000000000000000..02e3d57d46d58d801f8f0861483d7b476f114326
--- /dev/null
+++ b/indra/newview/llscenemonitor.h
@@ -0,0 +1,106 @@
+/** 
+ * @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 setDebugViewerVisible(BOOL visible);
+
+	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;}
+
+	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;}
+	bool needsUpdate() const;
+	
+private:
+	void freezeScene();
+	void unfreezeScene();
+	void reset();
+	bool preCapture();
+
+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
+
+	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;
+};
+
+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/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 88fb609d1c629fd4669d350f4a371bb476c49958..0e2109c4afe2b9d3dd38e281184f31be6d622ec2 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -126,106 +126,28 @@ class LLOcclusionQueryPool : public LLGLNamePool
 
 static LLOcclusionQueryPool sQueryPool;
 
-//static counter for frame to switch LOD on
-
-void sg_assert(BOOL expr)
-{
-#if LL_OCTREE_PARANOIA_CHECK
-	if (!expr)
-	{
-		llerrs << "Octree invalid!" << llendl;
-	}
-#endif
-}
-
-S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
+GLuint get_new_occlusion_query_object_name()
 {
-	return AABBSphereIntersectR2(min, max, origin, rad*rad);
+	return sQueryPool.allocate();
 }
 
-S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &r)
+void release_occlusion_query_object_name(GLuint name)
 {
-	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;
+	sQueryPool.release(name);
 }
 
+//static counter for frame to switch LOD on
 
-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)
+void sg_assert(BOOL expr)
 {
-	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 LL_OCTREE_PARANOIA_CHECK
+	if (!expr)
 	{
-		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;
-		}
+		llerrs << "Octree invalid!" << llendl;
 	}
-
-	return 1;
+#endif
 }
 
-
 typedef enum
 {
 	b000 = 0x00,
@@ -352,13 +274,13 @@ LLSpatialGroup::~LLSpatialGroup()
 	{
 		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
 	}*/
-
+	
 	if (gDebugGL)
 	{
 		gPipeline.checkReferences(this);
 	}
 
-	if (isState(DEAD))
+	if (hasState(DEAD))
 	{
 		sZombieGroups--;
 	}
@@ -371,7 +293,7 @@ LLSpatialGroup::~LLSpatialGroup()
 		{
 			if (mOcclusionQuery[i])
 			{
-				sQueryPool.release(mOcclusionQuery[i]);
+				release_occlusion_query_object_name(mOcclusionQuery[i]);
 			}
 		}
 	}
@@ -514,17 +436,8 @@ BOOL LLSpatialGroup::isHUDGroup()
 
 BOOL LLSpatialGroup::isRecentlyVisible() const
 {
-	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < LLDrawable::getMinVisFrameRange() ;
-}
-
-BOOL LLSpatialGroup::isVisible() const
-{
-	return mVisible[LLViewerCamera::sCurCameraID] >= LLDrawable::getCurrentFrame() ? TRUE : FALSE;
-}
-
-void LLSpatialGroup::setVisible()
-{
-	mVisible[LLViewerCamera::sCurCameraID] = LLDrawable::getCurrentFrame();
+	const S32 MIN_VIS_FRAME_RANGE = 2;
+	return (LLDrawable::getCurrentFrame() - mVisible[LLViewerCamera::sCurCameraID]) < MIN_VIS_FRAME_RANGE ;
 }
 
 void LLSpatialGroup::validate()
@@ -619,7 +532,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 +546,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 +576,7 @@ void LLSpatialGroup::rebuildGeom()
 	{
 		mSpatialPartition->rebuildGeom(this);
 
-		if (isState(LLSpatialGroup::MESH_DIRTY))
+		if (hasState(LLSpatialGroup::MESH_DIRTY))
 		{
 			gPipeline.markMeshDirty(this);
 		}
@@ -686,7 +598,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 +663,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 +686,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 +745,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 +758,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 +792,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 +805,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 +839,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 +855,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);
 		}
 	}
 };
@@ -1093,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;
 				}
 			}
@@ -1104,19 +900,19 @@ 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;
 		}
 	}
 }
 
-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 +920,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 +962,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 +985,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 +1023,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 +1054,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 +1131,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 +1159,36 @@ 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);
+	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);
+	removeObject((LLDrawable*)entry->getDrawable(), TRUE);
+	LLviewerOctreeGroup::handleRemoval(node, entry);
 }
 
 void LLSpatialGroup::handleDestruction(const TreeNode* node)
 {
 	setState(DEAD);
-	
+
 	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 +1210,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 +1226,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);
@@ -1467,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;
 			}
 		}
@@ -1476,7 +1256,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 +1272,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");
 
@@ -1607,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;
 				}
 				
@@ -1679,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
@@ -1769,9 +1490,10 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 
 //==============================================
 
-LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage)
+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;
 	mPartitionType = LLViewerRegion::PARTITION_NONE;
@@ -1781,37 +1503,32 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32
 	mBufferUsage = buffer_usage;
 	mDepthMask = FALSE;
 	mSlopRatio = 0.25f;
-	mInfiniteFarClip = FALSE;
+	mInfiniteFarClip = FALSE;	
 
-	LLVector4a center, size;
-	center.splat(0.f);
-	size.splat(1.f);
-
-	mOctree = new LLSpatialGroup::OctreeRoot(center,size,
-											NULL);
 	new LLSpatialGroup(mOctree, this);
 }
 
 
 LLSpatialPartition::~LLSpatialPartition()
-{
-	delete mOctree;
-	mOctree = NULL;
+{	
 }
 
-
 LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 {
 	drawablep->updateSpatialExtents();
 
 	//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,11 +1546,9 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 	}
 	else
 	{
-		drawablep->setSpatialGroup(NULL);
+		drawablep->setGroup(NULL);
 	}
 
-	drawablep->setSpatialGroup(NULL);
-
 	assert_octree_valid(mOctree);
 	
 	return TRUE;
@@ -1883,13 +1598,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); 
 	}
@@ -1901,17 +1616,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))
 		{
@@ -1921,79 +1636,30 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 		
 		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)
 		{
@@ -2001,21 +1667,6 @@ class LLOctreeCull : public LLSpatialGroup::OctreeTraveler
 		}
 		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
@@ -2024,14 +1675,14 @@ class LLOctreeCullNoFarClip : public LLOctreeCull
 	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;
 	}
 };
@@ -2042,14 +1693,14 @@ class LLOctreeCullShadow : public LLOctreeCull
 	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);
 	}
 };
 
@@ -2059,9 +1710,11 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 	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))
 		{
@@ -2071,7 +1724,7 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 		return false;
 	}
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* n)
+	virtual void traverse(const OctreeNode* n)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0);
 
@@ -2080,10 +1733,10 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 			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
 		{  
@@ -2091,31 +1744,35 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 				
 			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]);
 		}
 	}
 
@@ -2130,10 +1787,12 @@ class LLOctreeCullDetectVisible: public LLOctreeCullShadow
 	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)))
 		{
@@ -2143,9 +1802,9 @@ class LLOctreeCullDetectVisible: public LLOctreeCullShadow
 		return false;
 	}
 
-	virtual void processGroup(LLSpatialGroup* group)
+	virtual void processGroup(LLviewerOctreeGroup* base_group)
 	{
-		if (group->isVisible())
+		if (base_group->isVisible())
 		{
 			mResult = TRUE;
 		}
@@ -2160,17 +1819,21 @@ class LLOctreeSelect : public LLOctreeCull
 	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())
@@ -2283,17 +1946,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);
@@ -2352,6 +2019,8 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera)
 
 S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select)
 {
+	llassert(results != NULL && for_select);
+
 #if LL_OCTREE_PARANOIA_CHECK
 	((LLSpatialGroup*)mOctree->getListener(0))->checkStates();
 #endif
@@ -2365,13 +2034,28 @@ 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)
+	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)
+
+#if LL_OCTREE_PARANOIA_CHECK
+	((LLSpatialGroup*)mOctree->getListener(0))->validate();
+#endif
+
+	if (LLPipeline::sShadowRender)
 	{
 		LLFastTimer ftm(FTM_FRUSTUM_CULL);
 		LLOctreeCullShadow culler(&camera);
@@ -2404,9 +2088,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)
 	{
@@ -2531,7 +2216,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]);
 	}
 }
 
@@ -2595,13 +2281,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();
@@ -2659,9 +2351,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);
@@ -2677,7 +2370,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)
@@ -3444,9 +3139,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 )
 		{
@@ -4003,17 +3702,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();
@@ -4053,17 +3753,17 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 		}
 	}
 
-	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();
@@ -4073,15 +3773,20 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			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);			
@@ -4203,17 +3908,18 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 };
 
 
-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();
@@ -4231,23 +3937,24 @@ class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
 		}
 	}
 
-	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);
 
@@ -4258,19 +3965,23 @@ class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
 		}
 	}
 
-	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);			
 		}
 	}
@@ -4282,7 +3993,7 @@ void LLSpatialPartition::renderIntersectingBBoxes(LLCamera* camera)
 	pusher.traverse(mOctree);
 }
 
-class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
+class LLOctreeStateCheck : public OctreeTraveler
 {
 public:
 	U32 mInheritedMask[LLViewerCamera::NUM_CAMERAS];
@@ -4295,7 +4006,7 @@ class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
 		}
 	}
 
-	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	virtual void traverse(const OctreeNode* node)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 		
@@ -4322,7 +4033,7 @@ class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
 	}
 	
 
-	virtual void visit(const LLOctreeNode<LLDrawable>* state)
+	virtual void visit(const OctreeNode* state)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
 
@@ -4334,7 +4045,7 @@ class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
 			}
 		}
 
-		if (group->isState(LLSpatialGroup::DIRTY))
+		if (group->hasState(LLSpatialGroup::DIRTY))
 		{
 			assert_parent_state(group, LLSpatialGroup::DIRTY);
 		}
@@ -4345,7 +4056,7 @@ class LLOctreeStateCheck : public LLOctreeTraveler<LLDrawable>
 		LLSpatialGroup* parent = group->getParent();
 		while (parent)
 		{
-			if (!parent->isState(state))
+			if (!parent->hasState(state))
 			{
 				llerrs << "Spatial group failed parent state check." << llendl;
 			}
@@ -4460,7 +4171,7 @@ BOOL LLSpatialPartition::isVisible(const LLVector3& v)
 	return TRUE;
 }
 
-class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
+class LLOctreeIntersect : public OctreeTraveler
 {
 public:
 	LLVector3 mStart;
@@ -4487,21 +4198,21 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 	{
 	}
 	
-	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);
@@ -4509,8 +4220,9 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 			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;
@@ -4537,8 +4249,9 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 		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;
 
@@ -4932,5 +4645,3 @@ void LLCullResult::assertDrawMapsEmpty()
 	}
 }
 
-
-
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index b1706d9d35130dbb75970c09c64761d6688ae2dd..a2e2bf45d666a347b371c278864ce3cb164e4df4 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -45,22 +45,21 @@
 #define SG_STATE_INHERIT_MASK (OCCLUDED)
 #define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY)
 
+class LLViewerOctreePartition;
 class LLSpatialPartition;
 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
 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 
 {
@@ -192,13 +191,13 @@ class LLDrawInfo : public LLRefCount
 };
 
 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;
 	}
@@ -229,16 +228,7 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	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 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 std::map<U32, buffer_texture_map_t> buffer_map_t;	
 
 	struct CompareDistanceGreater
 	{
@@ -275,18 +265,15 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 
 	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 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	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,18 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	
 	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,28 +321,18 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	void rebuildGeom();
 	void rebuildMesh();
 
+	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(); }
-	bool hasElement(LLDrawable* drawablep) { return std::find(mOctreeNode->getDataBegin(), mOctreeNode->getDataEnd(), drawablep) != mOctreeNode->getDataEnd(); }
-
-	U32 getElementCount() const { return mOctreeNode->getElementCount(); }
-	bool isEmpty() const { return mOctreeNode->isEmpty(); }
+	void dirtyMesh() { setState(MESH_DIRTY); }		
 
 	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
 //-------------------
@@ -386,21 +354,6 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 
 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);
 
@@ -421,7 +374,6 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 protected:
 	virtual ~LLSpatialGroup();
 
-	U32 mState;
 	U32 mOcclusionState[LLViewerCamera::NUM_CAMERAS];
 	U32 mOcclusionIssued[LLViewerCamera::NUM_CAMERAS];
 
@@ -436,7 +388,6 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node
 
 	F32 mBuilt;
-	OctreeNode* mOctreeNode;
 	LLSpatialPartition* mSpatialPartition;
 	
 	LLPointer<LLVertexBuffer> mVertexBuffer;
@@ -444,8 +395,7 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 
 	U32 mBufferUsage;
 	draw_map_t mDrawMap;
-	
-	S32 mVisible[LLViewerCamera::NUM_CAMERAS];
+		
 	F32 mDistance;
 	F32 mDepth;
 	F32 mLastUpdateDistance;
@@ -468,10 +418,10 @@ class LLGeometryManager
 	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);
+	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage, LLViewerRegion* regionp);
 	virtual ~LLSpatialPartition();
 
 	LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE);
@@ -498,7 +448,8 @@ class LLSpatialPartition: public LLGeometryManager
 	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() ;
@@ -513,23 +464,21 @@ class LLSpatialPartition: public LLGeometryManager
 	void resetVertexBuffers();
 	BOOL isOcclusionEnabled();
 	BOOL getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax);
-
+	
 public:
-	LLSpatialGroup::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;
+	BOOL mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering	
 };
 
 // class for creating bridges between spatial partitions
@@ -541,7 +490,7 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition
 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();
 
@@ -564,7 +513,7 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition
 
 };
 
-class LLCullResult 
+class LLCullResult
 {
 public:
 	LLCullResult();
@@ -663,7 +612,7 @@ class LLCullResult
 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) { }
 };
@@ -672,14 +621,14 @@ class LLWaterPartition : public LLSpatialPartition
 class LLVoidWaterPartition : public LLWaterPartition
 {
 public:
-	LLVoidWaterPartition();
+	LLVoidWaterPartition(LLViewerRegion* regionp);
 };
 
 //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);
 };
@@ -688,7 +637,7 @@ class LLTerrainPartition : public LLSpatialPartition
 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) { }
 
@@ -698,7 +647,7 @@ class LLTreePartition : public LLSpatialPartition
 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);
@@ -710,14 +659,14 @@ class LLParticlePartition : public LLSpatialPartition
 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:
@@ -747,7 +696,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); }
@@ -758,7 +707,7 @@ class LLVolumePartition : public LLSpatialPartition, public LLVolumeGeometryMana
 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); }
@@ -768,7 +717,7 @@ class LLVolumeBridge : public LLSpatialBridge, public LLVolumeGeometryManager
 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);
 };
@@ -777,7 +726,7 @@ class LLHUDBridge : public LLVolumeBridge
 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) {  }
 };
@@ -785,7 +734,7 @@ class LLBridgePartition : public LLSpatialPartition
 class LLHUDPartition : public LLBridgePartition
 {
 public:
-	LLHUDPartition();
+	LLHUDPartition(LLViewerRegion* regionp);
 	virtual void shift(const LLVector4a &offset);
 };
 
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index d62101d1599eff3a1973de4da830618e8c465af4..fba636e8ef9e122b85f07dad46629a64c37e7fc2 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -2358,6 +2358,10 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	mHttpMetricsHeaders = new LLCore::HttpHeaders;
 	mHttpMetricsHeaders->mHeaders.push_back("Content-Type: application/llsd+xml");
 	mHttpPolicyClass = LLAppViewer::instance()->getAppCoreHttp().getPolicyDefault();
+
+	//reset the texture timer.
+	gTextureTimer.reset();
+	gTextureTimer.pause();
 }
 
 LLTextureFetch::~LLTextureFetch()
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 1d54e50bb90cc5f8f80b6dab4a5ab94c6b13dac0..7a6351c880f3ecd56c9b6687f6ff9b235b5788e9 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"
@@ -517,6 +519,9 @@ void LLGLTexMemBar::draw()
 	LLUnit<LLUnits::Bytes, F32> total_texture_downloaded = gTotalTextureData;
 	LLUnit<LLUnits::Bytes, F32> total_object_downloaded = gTotalObjectData;
 	U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests() ;
+	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);
@@ -549,9 +554,11 @@ void LLGLTexMemBar::draw()
 	U32 cache_read(0U), cache_write(0U), res_wait(0U);
 	LLAppViewer::getTextureFetch()->getStateStats(&cache_read, &cache_write, &res_wait);
 	
-	text = llformat("Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d Cread: %u Cwrite: %u Rwait: %u",
+	text = llformat("Net Tot Tex: %.1f MB Tot Obj: %.1f MB #Objs/#Cached: %d/%d Tot Htp: %d Cread: %u Cwrite: %u Rwait: %u",
 					total_texture_downloaded.value(),
 					total_object_downloaded.value(),
+					total_objects, 
+					total_active_cached_objects,
 					total_http_requests,
 					cache_read,
 					cache_write,
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 41a08398bbded75e4fba368aa2b77452bfa16672..fe83f80caa69696aa8a59e0a236d9202799101aa 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;
@@ -991,6 +992,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)
 		{
@@ -1224,6 +1230,15 @@ 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();
+	}
+
 	{
 		BOOL to_texture = gPipeline.canUseVertexShaders() &&
 							LLPipeline::sRenderGlow;
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 3ca410cf73293f7ee00874e2da8b4b5ad2fca9ab..9a0cb432bec272a2d3d69d1b6f227fe82dc804fb 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -122,6 +122,7 @@
 #include "llwindow.h"
 #include "llpathfindingmanager.h"
 #include "boost/unordered_map.hpp"
+#include "llscenemonitor.h"
 
 using namespace LLVOAvatarDefines;
 
@@ -529,7 +530,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)
 		{
@@ -557,9 +561,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/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 6da93f0653ac0ada79e1b0bb865269460fce857f..7a2025ed5bccbe96a0ab40efb9d75aa19984200a 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4483,30 +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;
-	S32			num_objects;
+	LLUUID id;
 
-	num_objects = mesgsys->getNumberOfBlocksFast(_PREHASH_ObjectData);
+	U32 ip = mesgsys->getSenderIP();
+	U32 port = mesgsys->getSenderPort();
+	LLViewerRegion* regionp = NULL;
+	{
+		LLHost host(ip, port);
+		regionp = LLWorld::getInstance()->getRegion(host);
+	}
 
-	for (i = 0; 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
@@ -4514,34 +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);
-				}
+			// never kill our avatar
+			continue;
+		}
 
-				// Do the kill
-				gObjectList.killObject(objectp);
-			}
-			else
+		LLViewerObject *objectp = gObjectList.findObject(id);
+		if (objectp)
+		{
+			// Display green bubble on kill
+			if ( gShowObjectUpdates )
 			{
-				LL_WARNS("Messaging") << "Object in UUID lookup, but not on object list in kill!" << LL_ENDL;
-				gObjectList.mNumUnknownKills++;
+				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/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 61dc66065c7bd64fe775e58a49ea2be1c9009d30..f5f5bdffbd432dfadc0bc5c4e213536f09a4f722 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
 
@@ -326,6 +327,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)
@@ -348,7 +365,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();
 			}
@@ -889,10 +906,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
 		{
@@ -918,11 +936,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.
@@ -1695,13 +1716,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;
 
@@ -1729,10 +1753,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);
 
@@ -1808,9 +1843,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
@@ -1848,10 +1892,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())
@@ -1872,8 +1927,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);
@@ -1957,7 +2022,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 
 	new_rot.normQuat();
 
-	if (sPingInterpolate)
+	if (sPingInterpolate && mesgsys != NULL)
 	{ 
 		LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mesgsys->getSender());
 		if (cdp)
@@ -1980,16 +2045,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/llviewerobject.h b/indra/newview/llviewerobject.h
index bdff88f8ca7efcd9fe5e5f6dae170060ce2fdb66..20254bfe02cc1322138791a43d74d9151aa341f3 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -136,6 +136,7 @@ class LLViewerObject
 	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 fc3b7e794237d11e36835a1294f0e2a2a0cf9fae..0335cd769b9a976bed0b088c7b3ea29e0ca4ff70 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;
@@ -106,7 +107,6 @@ LLViewerObjectList::LLViewerObjectList()
 	mNumNewObjects = 0;
 	mWasPaused = FALSE;
 	mNumDeadObjectUpdates = 0;
-	mNumUnknownKills = 0;
 	mNumUnknownUpdates = 0;
 }
 
@@ -228,9 +228,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 +260,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,10 +294,88 @@ 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
+			}
+		}
+		else
+		{
+			return objectp; //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.sample(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,
-											 bool cached, bool compressed)
+											 bool compressed)
 {
 	LLFastTimer t(FTM_PROCESS_OBJECTS);	
 	
@@ -299,7 +394,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;
@@ -343,7 +438,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++)
@@ -353,43 +447,10 @@ 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();
-
-			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);
@@ -485,9 +546,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 					continue;
 				}
 			}
-			else if (cached) // Cache hit only?
-			{
-			}
 			else
 			{
 				if (update_type != OUT_FULL)
@@ -520,8 +578,6 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			}
 			justCreated = TRUE;
 			mNumNewObjects++;
-			sCacheHitRate.sample(cached ? 100.f : 0.f);
-
 		}
 
 
@@ -540,16 +596,17 @@ 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?
-		{
-			objectp->mLocalID = local_id;
-			processUpdateCore(objectp, user_data, i, update_type, cached_dpp, justCreated);
-		}
 		else
 		{
 			if (update_type == OUT_FULL)
@@ -572,14 +629,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.sample(100.f);
+	}
+
+	return;
 }	
 
 void LLViewerObjectList::dirtyAllObjectInventory()
@@ -1230,7 +1324,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.
@@ -1245,16 +1339,8 @@ 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->EnableToCacheTree(cache_enabled); //enable to add to VO cache tree if set.
+		objectp->markDead(); // does the right thing if object already dead
 		return TRUE;
 	}
 
@@ -1890,7 +1976,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 9a36b66302a7c90da3bb031ac3490880e24dc4c9..b92be61faefd2cfc53c54ad8bf9e64004c90416c 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,12 +66,13 @@ class LLViewerObjectList
 	
 	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);
 
 	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);
@@ -78,8 +80,10 @@ class LLViewerObjectList
 	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 processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, EObjectUpdateType update_type, bool cached=false, bool compressed=false);
+	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 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);
@@ -188,7 +192,6 @@ class LLViewerObjectList
 
 	S32 mNumUnknownUpdates;
 	S32 mNumDeadObjectUpdates;
-	S32 mNumUnknownKills;
 	S32 mNumDeadObjects;
 protected:
 	std::vector<U64>	mOrphanParents;	// LocalID/ip,port of orphaned objects
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cfa24c32edf1c11bf3727f3343dab2be0b84e6ff
--- /dev/null
+++ b/indra/newview/llvieweroctree.cpp
@@ -0,0 +1,800 @@
+/** 
+ * @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"
+#include "llviewerregion.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),
+	  mBinRadius(0.f),
+	  mBinIndex(-1)
+{
+	mPositionGroup.clear();
+	mExtents[0].clear();
+	mExtents[1].clear();	
+
+	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()
+{
+	if(LLViewerRegion::sCurRegionp && isVisible())
+	{
+		LLViewerRegion::sCurRegionp->clearVisibleGroup(this);
+	}
+}
+
+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::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());
+}
+
+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();
+			//obj->setGroup(NULL);
+		}
+	}
+	mOctreeNode = NULL;
+}
+	
+//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)
+{
+	if (child->getListenerCount() == 0)
+	{
+		new LLviewerOctreeGroup(child);
+	}
+	else
+	{
+		OCT_ERRS << "LLSpatialGroup redundancy detected." << llendl;
+	}
+
+	unbound();
+	
+	//((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 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;
+}
+
+//-----------------------------------------------------------------------------------
+//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;
+	}
+}
+	
+//------------------------------------------
+//agent space group culling
+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::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]);
+}
+
+S32 LLViewerOctreeCull::AABBSphereIntersectObjectExtents(const LLviewerOctreeGroup* group)
+{
+	return AABBSphereIntersect(group->mObjectExtents[0], group->mObjectExtents[1], mCamera->getOrigin(), mCamera->mFrustumCornerDist);
+}
+
+S32 LLViewerOctreeCull::AABBInFrustumObjectBounds(const LLviewerOctreeGroup* group)
+{
+	return mCamera->AABBInFrustum(group->mObjectBounds[0], group->mObjectBounds[1]);
+}
+//------------------------------------------
+
+//------------------------------------------
+//local regional space group culling
+S32 LLViewerOctreeCull::AABBInRegionFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group)
+{
+	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)
+{
+	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 0000000000000000000000000000000000000000..a35c551949fdb1a5c20da703e2e12883fd15d826
--- /dev/null
+++ b/indra/newview/llvieweroctree.h
@@ -0,0 +1,327 @@
+/** 
+ * @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 "llviewercamera.h"
+
+class LLViewerRegion;
+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; }
+
+	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);			
+
+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:
+	typedef LLOctreeNode<LLViewerOctreeEntry>::element_iter element_iter;
+	typedef LLOctreeNode<LLViewerOctreeEntry>::element_list element_list;
+
+	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();
+
+	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;}
+	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;}
+
+	//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 hasElement(LLViewerOctreeEntryData* data);
+	
+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
+
+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:
+	LLViewerOctreeCull(LLCamera* camera)
+		: mCamera(camera), mRes(0) { }
+
+	virtual bool earlyFail(LLviewerOctreeGroup* group);
+	virtual void traverse(const OctreeNode* n);
+	
+	//agent space group cull
+	S32 AABBInFrustumNoFarClipGroupBounds(const LLviewerOctreeGroup* group);	
+	S32 AABBSphereIntersectGroupExtents(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;
+
+	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
diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index 6bd9f66b9c482e564ac34dbcb4434aefdfe84971..8acdc08b0025d258648de851fcb0ce16866fff2a 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 7e81e9714ffa02140b0f894a9cb001f09eefaa2e..7d2e08c1c6948237e424cdb21f932b4090c0c348 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)
@@ -85,6 +86,9 @@ 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;
+BOOL LLViewerRegion::sVOCacheCullingEnabled = FALSE;
+
 typedef std::map<std::string, std::string> CapabilityMap;
 
 class LLViewerRegionImpl {
@@ -97,6 +101,8 @@ class LLViewerRegionImpl {
 			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
@@ -133,7 +139,14 @@ class LLViewerRegionImpl {
 	// 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.	
+	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?
 
@@ -157,7 +170,10 @@ class LLViewerRegionImpl {
 	LLCapabilityListener mCapabilityListener;
 
 	//spatial partitions for objects in this region
-	std::vector<LLSpatialPartition*> mObjectPartition;
+	std::vector<LLViewerOctreePartition*> mObjectPartition;
+
+	LLVector3 mLastCameraOrigin;
+	U32       mLastCameraUpdate;
 };
 
 // support for secondlife:///app/region/{REGION} SLapps
@@ -292,7 +308,8 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mReleaseNotesRequested(FALSE),
 	mCapabilitiesReceived(false),
 	mBitsReceived(0.f),
-	mPacketsReceived(0.f)
+	mPacketsReceived(0.f),
+	mDead(FALSE)
 {
 	mWidth = region_width_meters;
 	mImpl->mOriginGlobal = from_region_handle(handle); 
@@ -324,17 +341,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 = getVOCachePartition();
 }
 
 
@@ -355,6 +375,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...
@@ -367,12 +393,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;
 }
@@ -438,10 +464,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();
 }
 
@@ -719,8 +741,354 @@ void LLViewerRegion::dirtyHeights()
 	}
 }
 
+void LLViewerRegion::replaceCacheEntry(LLVOCacheEntry* old_entry, LLVOCacheEntry* new_entry)
+{
+	U32 state = LLVOCacheEntry::INACTIVE;
+
+	if(old_entry)
+	{
+		old_entry->copyTo(new_entry);
+		state = old_entry->getState();		
+		killCacheEntry(old_entry);
+	}
+
+	mImpl->mCacheMap[new_entry->getLocalID()] = new_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 && new_entry->getEntry())
+	{
+		addToVOCacheTree(new_entry);
+	}
+	new_entry->setState(state);
+}
+
+//physically delete the cache entry
+void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry)
+{	
+	if(!entry)
+	{
+		return;
+	}
+
+	//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);
+		}
+		
+		//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.
+	
+	entry->setState(LLVOCacheEntry::INACTIVE);
+	
+	//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(drawablep->getParent()) //child object
+	{
+		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);
+		}
+	}
+	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);
+}
+
+void LLViewerRegion::addVisibleGroup(LLviewerOctreeGroup* group)
+{
+	if(mDead || group->isEmpty())
+	{
+		return;
+	}
+	group->setVisible();
+	mImpl->mVisibleGroups.insert(group);
+}
+
+void LLViewerRegion::addToVOCacheTree(LLVOCacheEntry* entry)
+{
+	if(!sVOCacheCullingEnabled)
+	{
+		return;
+	}
+
+	if(mDead || !entry || !entry->getEntry())
+	{
+		return;
+	}
+	if(entry->getGroup()) //already in octree.
+	{
+		return;
+	}
+	if(!entry->hasState(LLVOCacheEntry::ADD_TO_CACHE_TREE))
+	{
+		return; //can not add to vo cache tree.
+	}
+
+	mImpl->mVOCachePartition->addEntry(entry->getEntry());
+}
+
+void LLViewerRegion::removeFromVOCacheTree(LLVOCacheEntry* entry)
+{
+	if(mDead || !entry || !entry->getEntry())
+	{
+		return;
+	}
+	if(!entry->getGroup())
+	{
+		return;
+	}
+
+	mImpl->mVOCachePartition->removeEntry(entry->getEntry());
+}
+
+//add the visible entries
+void LLViewerRegion::addVisibleCacheEntry(LLVOCacheEntry* entry)
+{
+	if(mDead || !entry)
+	{
+		return; 
+	}
+
+	if(entry->isState(LLVOCacheEntry::IN_QUEUE))
+	{
+		return;
+	}
+
+	if(entry->isState(LLVOCacheEntry::INACTIVE))
+	{
+		entry->setState(LLVOCacheEntry::IN_QUEUE);
+	}
+	mImpl->mVisibleEntries.insert(entry);
+}
+
+void LLViewerRegion::clearVisibleGroup(LLviewerOctreeGroup* group)
+{
+	if(mDead)
+	{
+		return;
+	}
+
+	llassert(!group->getOctreeNode() || group->isEmpty());
+
+	mImpl->mVisibleGroups.erase(group);
+}
+
+F32 LLViewerRegion::updateVisibleEntries(F32 max_time)
+{
+	if(mImpl->mVisibleGroups.empty() && mImpl->mVisibleEntries.empty())
+	{
+		return max_time;
+	}
+
+	LLTimer update_timer;
+
+	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.
+
+#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)
+		{			
+			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++)
+		{
+			child = vo_entry->getChild(i);
+			if(child->getState() < LLVOCacheEntry::WAITING)
+			{
+				child->setSceneContribution(vo_entry->getSceneContribution());
+				mImpl->mWaitingList.insert(child);
+			}
+			else
+			{
+				num_done++;
+			}
+		}
+		if(num_done == num_child)
+		{
+			vo_entry->clearChildrenList();
+		}
+
+		if(!vo_entry->getNumOfChildren())
+		{
+			if(vo_entry->getState() >= LLVOCacheEntry::WAITING)
+			{
+				iter = mImpl->mVisibleEntries.erase(iter);
+			}
+			else
+			{
+				++iter;
+			}
+		}
+		else
+		{
+			++iter;
+		}
+
+		//if(update_timer.getElapsedTimeF32() > max_time)
+		//{
+		//	break;
+		//}
+	}
+#endif
+
+	//process visible groups
+	std::set< LLviewerOctreeGroup* >::iterator group_iter = mImpl->mVisibleGroups.begin();
+	for(; group_iter != mImpl->mVisibleGroups.end(); ++group_iter)
+	{
+		LLviewerOctreeGroup* group = *group_iter;
+		if(!group->getOctreeNode() || group->isEmpty())
+		{
+			continue;
+		}
+
+		for (LLviewerOctreeGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+		{
+			if((*i)->hasVOCacheEntry())
+			{
+				LLVOCacheEntry* vo_entry = (LLVOCacheEntry*)(*i)->getVOCacheEntry();
+
+				vo_entry->calcSceneContribution(camera_origin, needs_update, mImpl->mLastCameraUpdate);				
+				mImpl->mWaitingList.insert(vo_entry);
+			}
+		}
+
+		//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;
+	}
+
+	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)
+	{
+		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();
+}
+
 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);
 	
@@ -730,9 +1098,98 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time)
 		mParcelOverlay->idleUpdate();
 	}
 
+	max_update_time -= update_timer.getElapsedTimeF32();
+	if(max_update_time < 0.f || mImpl->mCacheMap.empty())
+	{
+		return did_update;
+	}
+
+	sCurRegionp = this;
+
+	//kill invisible objects
+	max_update_time = killInvisibleObjects(max_update_time);	
+	
+	max_update_time = updateVisibleEntries(max_update_time);
+	createVisibleObjects(max_update_time);
+
+	mImpl->mVisibleGroups.clear();
+	mImpl->mWaitingList.clear();
+
+	sCurRegionp = NULL;
 	return did_update;
 }
 
+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)
+	{
+		if(!(*iter)->isRecentlyVisible())
+		{
+			killObject((*iter), delete_list);
+		}
+	}
+	for(S32 i = 0; i < delete_list.size(); i++)
+	{
+		gObjectList.killObject(delete_list[i]->getVObj(), true);
+	}
+	delete_list.clear();
+
+	return max_time;
+}
+
+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.
+				((LLViewerOctreeEntryData*)drawablep)->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 +1648,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 +1659,72 @@ 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)
+{
+	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)
+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
 
-	LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL);
+	LLVOCacheEntry* entry = getCacheEntry(local_id);
 
 	if (entry)
 	{
@@ -1244,24 +1733,31 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type)
 		{
 			// Record a hit
 			entry->recordHit();
-		cache_miss_type = CACHE_MISS_TYPE_NONE;
-			return entry->getDP(crc);
+			cache_miss_type = CACHE_MISS_TYPE_NONE;
+
+			if(entry->getGroup() || !entry->isState(LLVOCacheEntry::INACTIVE))
+			{
+				return true;
+			}
+
+			addVisibleCacheEntry(entry);
+			return true;
 		}
 		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);
 	}
 
-	return NULL;
+	return false;
 }
 
 void LLViewerRegion::addCacheMissFull(const U32 local_id)
@@ -1784,9 +2280,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 756c0dc61fea6dc3201662ee8ef9bc978b1823bb..9252923aa35d5b20ba7609dba8d488e85b1529a0 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -65,8 +65,11 @@ class LLDataPacker;
 class LLDataPackerBinaryBuffer;
 class LLHost;
 class LLBBox;
-
+class LLSpatialGroup;
+class LLDrawable;
 class LLViewerRegionImpl;
+class LLviewerOctreeGroup;
+class LLVOCachePartition;
 
 class LLViewerRegion: public LLCapabilityProvider // implements this interface
 {
@@ -83,7 +86,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 		PARTITION_GRASS,
 		PARTITION_VOLUME,
 		PARTITION_BRIDGE,
-		PARTITION_HUD_PARTICLE,
+		PARTITION_HUD_PARTICLE,		
+		PARTITION_VO_CACHE,
 		PARTITION_NONE,
 		NUM_PARTITIONS
 	} eObjectPartitions;
@@ -215,6 +219,12 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	F32	getWidth() const						{ return mWidth; }
 
 	BOOL idleUpdate(F32 max_update_time);
+	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(LLviewerOctreeGroup* group);
 
 	// Like idleUpdate, but forces everything to complete regardless of
 	// how long it takes.
@@ -304,8 +314,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	} eCacheUpdateResult;
 
 	// handle a full update message
-	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);
-	LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type);
+	eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp);	
+	LLVOCacheEntry* getCacheEntryForOctree(U32 local_id);
+	bool probeCache(U32 local_id, U32 crc, U8 &cache_miss_type);
 	void requestCacheMisses();
 	void addCacheMissFull(const U32 local_id);
 
@@ -321,7 +332,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
     virtual std::string getDescription() const;
 	std::string getHttpUrl() const { return mHttpUrl ;}
 
+	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;
@@ -330,6 +343,19 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	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	
+
+	F32 killInvisibleObjects(F32 max_time);
+	F32 createVisibleObjects(F32 max_time);
+	F32 updateVisibleEntries(F32 max_time); //update visible entries
+
 public:
 	struct CompareDistance
 	{
@@ -363,6 +389,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	LLDynamicArray<U32> mMapAvatars;
 	LLDynamicArray<LLUUID> mMapAvatarIDs;
 
+	static LLViewerRegion* sCurRegionp;
+	static BOOL sVOCacheCullingEnabled; //vo cache culling enabled or not.
 private:
 	LLViewerRegionImpl * mImpl;
 
@@ -406,18 +434,17 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	// 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/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 4b0e0598f651bd249aa32efe53baac3b57a37ac8..1aa36eafee01e80a04adee0332d02e0100799e2b 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -78,6 +78,8 @@ LLGLSLShader	gGlowCombineProgram;
 LLGLSLShader	gSplatTextureRectProgram;
 LLGLSLShader	gGlowCombineFXAAProgram;
 LLGLSLShader	gTwoTextureAddProgram;
+LLGLSLShader	gTwoTextureCompareProgram;
+LLGLSLShader	gOneTextureFilterProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
 LLGLSLShader	gClipProgram;
@@ -672,6 +674,8 @@ void LLViewerShaderMgr::unloadShaders()
 	gSplatTextureRectProgram.unload();
 	gGlowCombineFXAAProgram.unload();
 	gTwoTextureAddProgram.unload();
+	gTwoTextureCompareProgram.unload();
+	gOneTextureFilterProgram.unload();
 	gOneTextureNoColorProgram.unload();
 	gSolidColorProgram.unload();
 
@@ -2706,6 +2710,37 @@ 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)
+	{
+		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 d6dd645e8cc483473a986febaf52dc00be10a24a..3e7c615f239104fe352d990f3a21c15ba2150f96 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -233,7 +233,11 @@ extern LLGLSLShader			gAlphaMaskProgram;
 
 //output tex0[tc0] + tex1[tc1]
 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/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp
index cdb7bde12376838e87141227257bd0e43e7632ad..482f6a77a3f30a179c353d6bba0ab0348f5fc996 100644
--- a/indra/newview/llviewerstatsrecorder.cpp
+++ b/indra/newview/llviewerstatsrecorder.cpp
@@ -223,7 +223,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/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 7a142b481f91ea9b6d544d4a70c4f58cddb87b4d..2680a1cdeb1a57a5770138d7133c65eef4936cf3 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -966,6 +966,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 837d4b21a2810509f005f8e441a5520ca33d30fa..0a9778ce76bea1e85cf3e86cacf9d2ad786480a9 100755
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -212,6 +212,7 @@ class LLViewerTexture : public LLTexture
 	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 f3497145568dcc60ba7a0f614a6116fea7c88ec7..1d43f96fb7f758654485eb60150fe335f1d37206 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/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 7c20e8eae7f26e0d90ff01db0e71e1ae736bcddf..cd033c84bfec1eacd61742d9edaa0d28bbad4d14 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 7db19c5c1b0d6a230af6c160c983ad0a7242258a..86cfbb1d74372881da206c399bc666424bc56cc9 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -29,6 +29,10 @@
 #include "llerror.h"
 #include "llregionhandle.h"
 #include "llviewercontrol.h"
+#include "llviewerobjectlist.h"
+#include "lldrawable.h"
+#include "llviewerregion.h"
+#include "pipeline.h"
 
 BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) 
 {
@@ -46,12 +50,16 @@ 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),
+	mRepeatedVisCounter(0),
+	mVisFrameRange(64),
+	mSceneContrib(0.f)
 {
 	mBuffer = new U8[dp.getBufferSize()];
 	mDP.assignBuffer(mBuffer, dp.getBufferSize());
@@ -59,24 +67,35 @@ 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),
+	mRepeatedVisCounter(0),
+	mVisFrameRange(64),
+	mSceneContrib(0.f)
 {
 	mDP.assignBuffer(mBuffer, 0);
 }
 
 LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
-	: mBuffer(NULL)
+	: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), 
+	mBuffer(NULL),
+	mState(INACTIVE),
+	mRepeatedVisCounter(0),
+	mVisFrameRange(64),
+	mSceneContrib(0.f)
 {
 	S32 size = -1;
 	BOOL success;
 
 	mDP.assignBuffer(mBuffer, 0);
+	setOctreeEntry(NULL);
+
 	success = check_read(apr_file, &mLocalID, sizeof(U32));
 	if(success)
 	{
@@ -95,6 +114,36 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32));
 	}
 	if(success)
+	{
+		success = check_read(apr_file, &mState, sizeof(U32));
+	}
+	if(success)
+	{
+		F32 ext[8];
+		success = check_read(apr_file, (void*)ext, sizeof(F32) * 8);
+
+		LLVector4a exts[2];
+		exts[0].load4a(ext);
+		exts[1].load4a(&ext[4]);
+	
+		setSpatialExtents(exts[0], exts[1]);
+	}
+	if(success)
+	{
+		LLVector4 pos;
+		success = check_read(apr_file, (void*)pos.mV, sizeof(LLVector4));
+
+		LLVector4a pos_;
+		pos_.load4a(pos.mV);
+		setPositionGroup(pos_);
+	}
+	if(success)
+	{
+		F32 rad;
+		success = check_read(apr_file, &rad, sizeof(F32));
+		setBinRadius(rad);
+	}
+	if(success)
 	{
 		success = check_read(apr_file, &size, sizeof(S32));
 
@@ -132,32 +181,100 @@ LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
 		mDupeCount = 0;
 		mCRCChangeCount = 0;
 		mBuffer = NULL;
+		mEntry = NULL;
+		mState = 0;
 	}
 }
 
 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();
 
-// New CRC means the object has changed.
-void LLVOCacheEntry::assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp)
+		LLViewerObject* obj = gObjectList.findObject(fullid);
+		if(obj && obj->mDrawable)
+		{
+			entry = obj->mDrawable->getEntry();
+		}
+	}
+
+	LLViewerOctreeEntryData::setOctreeEntry(entry);
+}
+
+void LLVOCacheEntry::copyTo(LLVOCacheEntry* new_entry)
 {
-	if (  (mCRC != crc)
-		||(mDP.getBufferSize() == 0))
+	//copy LLViewerOctreeEntry
+	if(mEntry.notNull())
 	{
-		mCRC = crc;
-		mHitCount = 0;
-		mCRCChangeCount++;
+		new_entry->setOctreeEntry(mEntry);
+		mEntry = NULL;
+	}
+
+	//copy children
+	S32 num_children = getNumOfChildren();
+	for(S32 i = 0; i < num_children; i++)
+	{
+		new_entry->addChild(getChild(i));
+	}
+}
+
+void LLVOCacheEntry::setState(U32 state)
+{
+	mState &= 0xffff0000; //clear the low 16 bits
+	state &= 0x0000ffff;  //clear the high 16 bits;
+	mState |= state;
 
-		mDP.freeBuffer();
-		mBuffer = new U8[dp.getBufferSize()];
-		mDP.assignBuffer(mBuffer, dp.getBufferSize());
-		mDP = dp;
+	if(getState() == 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
+{
+	return mVisFrameRange;
+}
+
+void LLVOCacheEntry::addChild(LLVOCacheEntry* entry)
+{
+	llassert(entry != NULL);
+
+	mChildrenList.push_back(entry);
+}
+	
 LLDataPackerBinaryBuffer *LLVOCacheEntry::getDP(U32 crc)
 {
 	if (  (mCRC != crc)
@@ -170,6 +287,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()
 {
@@ -189,6 +316,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)
@@ -208,6 +340,33 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32));
 	}
 	if(success)
+	{
+		U32 state = mState & 0xffff0000; //only store the high 16 bits.
+		success = check_write(apr_file, (void*)&state, sizeof(U32));
+	}
+	if(success)
+	{
+		const LLVector4a* exts = getSpatialExtents() ;
+		LLVector4 ext(exts[0][0], exts[0][1], exts[0][2], exts[0][3]);
+		success = check_write(apr_file, ext.mV, sizeof(LLVector4));		
+		if(success)
+		{
+			ext.set(exts[1][0], exts[1][1], exts[1][2], exts[1][3]);
+			success = check_write(apr_file, ext.mV, sizeof(LLVector4));		
+		}
+	}
+	if(success)
+	{
+		const LLVector4a pos_ = getPositionGroup() ;
+		LLVector4 pos(pos_[0], pos_[1], pos_[2], pos_[3]);
+		success = check_write(apr_file, pos.mV, sizeof(LLVector4));		
+	}
+	if(success)
+	{
+		F32 rad = getBinRadius();
+		success = check_write(apr_file, (void*)&rad, sizeof(F32));
+	}
+	if(success)
 	{
 		S32 size = mDP.getBufferSize();
 		success = check_write(apr_file, (void*)&size, sizeof(S32));
@@ -221,6 +380,121 @@ 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();
+}
+
+//-------------------------------------------------------------------
+//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, const LLVector3& shift) : LLViewerOctreeCull(camera), mRegionp(regionp) 
+	{
+		mLocalShift = shift;
+	}
+
+	virtual S32 frustumCheck(const LLviewerOctreeGroup* group)
+	{
+		//S32 res = AABBInRegionFrustumGroupBounds(group);
+		
+		S32 res = AABBInRegionFrustumNoFarClipGroupBounds(group);
+		if (res != 0)
+		{
+			res = llmin(res, AABBRegionSphereIntersectGroupExtents(group, mLocalShift));
+		}
+		return res;
+	}
+
+	virtual S32 frustumCheckObjects(const LLviewerOctreeGroup* group)
+	{
+		//S32 res = AABBInRegionFrustumObjectBounds(group);
+
+		S32 res = AABBInRegionFrustumNoFarClipObjectBounds(group);
+		if (res != 0)
+		{
+			res = llmin(res, AABBRegionSphereIntersectObjectExtents(group, mLocalShift));
+		}
+		return res;
+	}
+
+	virtual void processGroup(LLviewerOctreeGroup* base_group)
+	{
+		mRegionp->addVisibleGroup(base_group);
+	}
+
+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.
+	}
+	mVisitedTime = LLViewerOctreeEntryData::getCurrentFrame();
+
+	((LLviewerOctreeGroup*)mOctree->getListener(0))->rebound();
+
+	//localize the camera
+	LLVector3 region_agent = mRegionp->getOriginAgent();
+	camera.calcRegionFrustumPlanes(region_agent);
+
+	LLVOCacheOctreeCull culler(&camera, mRegionp, region_agent);
+	culler.traverse(mOctree);
+
+	return 0;
+}
+
 //-------------------------------------------------------------------
 //LLVOCache
 //-------------------------------------------------------------------
@@ -625,11 +899,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 14e3b4c79355a94b23827c9b29be224c13a085e7..c631e127390d532a1734fa5f0191b2d0374554f9 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -31,34 +31,95 @@
 #include "lldatapacker.h"
 #include "lldlinked.h"
 #include "lldir.h"
-
+#include "llvieweroctree.h"
 
 //---------------------------------------------------------------------------
 // Cache entries
 class LLVOCacheEntry;
+class LLCamera;
 
-class LLVOCacheEntry
+class LLVOCacheEntry : public LLViewerOctreeEntryData
 {
+public:
+	enum
+	{
+		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
+	{
+		ADD_TO_CACHE_TREE = 0x00010000, //has parent
+	};
+
+	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:
 	LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp);
 	LLVOCacheEntry(LLAPRFile* apr_file);
-	LLVOCacheEntry();
-	~LLVOCacheEntry();
-
+	LLVOCacheEntry();	
+
+	void setState(U32 state);
+	void clearState(U32 state) {mState &= ~state;}
+	void addState(U32 state)   {mState |= state;}
+	bool isState(U32 state)    {return (mState & 0xffff) == state;}
+	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; }
 	S32 getCRCChangeCount() const	{ return mCRCChangeCount; }
+	S32 getMinVisFrameRange()const;	
+
+	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 copyTo(LLVOCacheEntry* new_entry); //copy variables 
+	/*virtual*/ void setOctreeEntry(LLViewerOctreeEntry* entry);
+
+	void addChild(LLVOCacheEntry* entry);
+	LLVOCacheEntry* getChild(S32 i) {return mChildrenList[i];}
+	S32  getNumOfChildren()         {return mChildrenList.size();}
+	void clearChildrenList()        {mChildrenList.clear();}
 
 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;
+	typedef std::set<LLVOCacheEntry*, CompareVOCacheEntry> vocache_entry_priority_list_t;	
 
 protected:
 	U32							mLocalID;
@@ -68,6 +129,25 @@ class LLVOCacheEntry
 	S32							mCRCChangeCount;
 	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; //high 16 bits reserved for special use.
+	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;
 };
 
 //
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 4dca87652da8d7135ceadeb01acc6a0df8d579d7..d378ed25774192c66a60e49bcc3878be7f882576 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 fa34a6f1f56d5558bc86e22cb202b097e0006116..29c78f85f214d25a227140dd05bac292ff8b181a 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 cb905d02da0dd458f2490b45a7490e749943a73f..d5b3f2fd1451c446d9a12a31b5275c9b11417650 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 6687ce432fadaade4b53250b167e49d369312cf5..fe1ef10f7f7374010a658884c7f1d5e5be48ef84 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 78ccbd90c93e1ef61a3dfe96471ab8ce3840ea3e..2056aed0ad6521003ed4e5d612a335eda24610e8 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3933,8 +3933,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;
@@ -3944,8 +3944,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;
@@ -4167,9 +4167,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);
 		}
@@ -4207,7 +4207,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();
 
@@ -4234,9 +4235,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;
 			}
@@ -4640,8 +4641,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);
+			}
 		}
 	}
 
@@ -4667,7 +4671,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
@@ -4680,9 +4684,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();
@@ -4748,7 +4752,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);
@@ -5221,9 +5229,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;
 		}
@@ -5261,7 +5269,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 e8a1c3d1d62124a3dae881803be76bc33a11d4ea..50e7ed7bb5ed3dd0cca42d2f6b9352e7633f8d99 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 126dc599295a7320dd0dec7fdd12575ac8bac655..06e2302b0b334ac737737e2c00374d2f9503f8c1 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>
@@ -110,6 +110,7 @@ LLWorld::LLWorld() :
 	gGL.getTexUnit(0)->bind(mDefaultWaterTexturep);
 	mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
 
+	LLViewerRegion::sVOCacheCullingEnabled = (BOOL)gSavedSettings.getBOOL("ObjectCacheViewCullingEnabled");
 }
 
 
@@ -133,6 +134,11 @@ void LLWorld::destroyClass()
 	{
 		mEdgeWaterObjects[i] = NULL;
 	}
+
+	//make all visible drawbles invisible.
+	LLDrawable::incrementVisible();
+
+	LLSceneMonitor::getInstance()->destroyClass();
 }
 
 
@@ -599,7 +605,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 +629,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 +652,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 +668,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 f350009d100c09f6d10f4b0cc4f1014716f88995..8187142b2ba8fff61954f4402f7f9a7422ee807b 100644
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -144,6 +144,7 @@ class LLWorld : public LLSingleton<LLWorld>
 	U64 getSpaceTimeUSec() const;
 
 	void getInfo(LLSD& info);
+	U32  getNumOfActiveCachedObjects() const {return mNumOfActiveCachedObjects;}
 
 public:
 	typedef std::list<LLViewerRegion*> region_list_t;
@@ -181,7 +182,7 @@ class LLWorld : public LLSingleton<LLWorld>
 	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 b5a81c9fcdd1b5618a62bd849dcd34be9e6e5add..8d3075d1e176641aee3b24c1b748fb427b73c0cd 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"
@@ -111,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
@@ -1410,18 +1412,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)
 			{
@@ -1610,11 +1612,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());
@@ -2038,7 +2038,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;
 		}
@@ -2060,8 +2060,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);
+		}
 	}			
 }
 
@@ -2385,6 +2388,13 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 				}
 			}
 		}
+
+		//scan the VO Cache tree
+		LLVOCachePartition* vo_part = region->getVOCachePartition();
+		if(vo_part)
+		{
+			vo_part->cull(camera);
+		}
 	}
 
 	if (bound_shader)
@@ -2452,14 +2462,15 @@ 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)
 	{ //render by drawable
 		sCull->pushDrawableGroup(group);
@@ -3041,14 +3052,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())
@@ -3059,7 +3070,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);
@@ -3134,7 +3145,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)
@@ -3212,7 +3223,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 		}
 	}
 		
-	postSort(camera);	
+	postSort(camera);
+
+	LLSceneMonitor::getInstance()->fetchQueryResult();
 }
 
 void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
@@ -3221,8 +3234,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)
@@ -3341,7 +3353,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());	
+			}
 		}
 	}
 }
@@ -3569,7 +3584,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();
 		}
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 386d912a2a809a3af2285bdc0707d9262ab45756..8fe955aed840fb73c2aea6bc788b21f0bc319250 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1989,6 +1989,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"