diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 51870515f2ddac78a0d4c33c6132a2e536efdbb0..f5e85aecda460f518eb9b61e0ceacd4c0706886c 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -58,6 +58,7 @@ BOOL LLVertexBuffer::sIBOActive = FALSE;
 U32 LLVertexBuffer::sAllocatedBytes = 0;
 BOOL LLVertexBuffer::sMapped = FALSE;
 BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
+BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
 S32	LLVertexBuffer::sWeight4Loc = -1;
 
 std::vector<U32> LLVertexBuffer::sDeleteList;
@@ -147,7 +148,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 				{ //needs to be enabled
 					glEnableClientState(array[i]);
 				}
-				else if (gDebugGL && glIsEnabled(array[i]))
+				else if (gDebugGL && i > 0 && glIsEnabled(array[i]))
 				{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
 					if (gDebugSession)
 					{
@@ -427,9 +428,9 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 		mUsage = 0;
 	}
 	
-	if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+	if (mUsage == GL_DYNAMIC_DRAW_ARB && sPreferStreamDraw)
 	{
-		mUsage = 0;
+		mUsage = GL_STREAM_DRAW_ARB;
 	}
 
 	//zero out offsets
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index f40f013306b6c1dd851b20ee9c466b2e3ca57722..77c9da2d6c8a42894481f6425b5510710c641cf8 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -92,6 +92,7 @@ class LLVertexBuffer : public LLRefCount
 	static S32	sWeight4Loc;
 
 	static BOOL	sUseStreamDraw;
+	static BOOL	sPreferStreamDraw;
 
 	static void initClass(bool use_vbo);
 	static void cleanupClass();
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index d71b84739c97c24acc253df57bfbe4bee9dfc76d..ec6b942e3e0b5b1fb861b0d0d6f13e7aec762a97 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8810,7 +8810,18 @@
     <key>Value</key>
     <integer>1</integer>
   </map>
-    <key>RenderVolumeLODFactor</key>
+	<key>RenderPreferStreamDraw</key>
+	<map>
+		<key>Comment</key>
+		<string>Use GL_STREAM_DRAW in place of GL_DYNAMIC_DRAW</string>
+		<key>Persist</key>
+		<integer>1</integer>
+		<key>Type</key>
+		<string>Boolean</string>
+		<key>Value</key>
+		<integer>0</integer>
+	</map>
+	<key>RenderVolumeLODFactor</key>
     <map>
       <key>Comment</key>
       <string>Controls level of detail of primitives (multiplier for current screen area when calculated level of detail)</string>
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index cbee800acbfe0f02c6643bdcfae3dd1b05caf990..d370c72a04be37ab366c1fe674717d4210f564e0 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1052,7 +1052,7 @@ BOOL LLDrawable::isVisible() const
 //=======================================
 
 LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 data_mask)
-: LLSpatialPartition(data_mask, render_by_group, FALSE)
+: LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB)
 {
 	mDrawable = root;
 	root->setSpatialBridge(this);
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 5dd1b5ba7e64f08c0b1c3019c5c8aa052f252df2..14775f0f21353a2bb88940d5dd10fd5d33db4449 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -252,11 +252,15 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
 }
 
 
+static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
+
 void LLSpatialGroup::buildOcclusion()
 {
 	if (mOcclusionVerts.isNull())
 	{
-		mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_DYNAMIC_DRAW_ARB);
+
+		mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 
+			LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling.
 		mOcclusionVerts->allocateBuffer(8, 64, true);
 	
 		LLStrider<U16> idx;
@@ -275,40 +279,47 @@ void LLSpatialGroup::buildOcclusion()
 
 	LLStrider<LLVector3> pos;
 	
-	mOcclusionVerts->getVertexStrider(pos);
-
-	LLVector4a* v = (LLVector4a*) pos.get();
-
-	const LLVector4a& c = mBounds[0];
-	const LLVector4a& s = r;
-	
-	static const LLVector4a octant[] =
 	{
-		LLVector4a(-1.f, -1.f, -1.f),
-		LLVector4a(-1.f, -1.f, 1.f),
-		LLVector4a(-1.f, 1.f, -1.f),
-		LLVector4a(-1.f, 1.f, 1.f),
+		LLFastTimer t(FTM_BUILD_OCCLUSION);
+		mOcclusionVerts->getVertexStrider(pos);
+	}
 
-		LLVector4a(1.f, -1.f, -1.f),
-		LLVector4a(1.f, -1.f, 1.f),
-		LLVector4a(1.f, 1.f, -1.f),
-		LLVector4a(1.f, 1.f, 1.f),
-	};
+	{
+		LLVector4a* v = (LLVector4a*) pos.get();
 
-	//vertex positions are encoded so the 3 bits of their vertex index 
-	//correspond to their axis facing, with bit position 3,2,1 matching
-	//axis facing x,y,z, bit set meaning positive facing, bit clear 
-	//meaning negative facing
+		const LLVector4a& c = mBounds[0];
+		const LLVector4a& s = r;
+		
+		static const LLVector4a octant[] =
+		{
+			LLVector4a(-1.f, -1.f, -1.f),
+			LLVector4a(-1.f, -1.f, 1.f),
+			LLVector4a(-1.f, 1.f, -1.f),
+			LLVector4a(-1.f, 1.f, 1.f),
+
+			LLVector4a(1.f, -1.f, -1.f),
+			LLVector4a(1.f, -1.f, 1.f),
+			LLVector4a(1.f, 1.f, -1.f),
+			LLVector4a(1.f, 1.f, 1.f),
+		};
+
+		//vertex positions are encoded so the 3 bits of their vertex index 
+		//correspond to their axis facing, with bit position 3,2,1 matching
+		//axis facing x,y,z, bit set meaning positive facing, bit clear 
+		//meaning negative facing
+		
+		for (S32 i = 0; i < 8; ++i)
+		{
+			LLVector4a p;
+			p.setMul(s, octant[i]);
+			p.add(c);
+			v[i] = p;
+		}
+	}
 	
-	for (S32 i = 0; i < 8; ++i)
 	{
-		LLVector4a p;
-		p.setMul(s, octant[i]);
-		p.add(c);
-		v[i] = p;
+		mOcclusionVerts->setBuffer(0);
 	}
-	
-	mOcclusionVerts->setBuffer(0);
 
 	clearState(LLSpatialGroup::OCCLUSION_DIRTY);
 }
@@ -1189,7 +1200,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	mOctreeNode(node),
 	mSpatialPartition(part),
 	mVertexBuffer(NULL), 
-	mBufferUsage(GL_STATIC_DRAW_ARB),
+	mBufferUsage(part->mBufferUsage),
 	mDistance(0.f),
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
@@ -1616,6 +1627,10 @@ void LLSpatialGroup::checkOcclusion()
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_PUSH_OCCLUSION_VERTS("Push Occlusion");
+static LLFastTimer::DeclareTimer FTM_SET_OCCLUSION_STATE("Occlusion State");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail");
+
 void LLSpatialGroup::doOcclusion(LLCamera* camera)
 {
 	if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1)
@@ -1623,6 +1638,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 		// Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension
 		if (earlyFail(camera, this))
 		{
+			LLFastTimer t(FTM_OCCLUSION_EARLY_FAIL);
 			setOcclusionState(LLSpatialGroup::DISCARD_QUERY);
 			assert_states_valid(this);
 			clearOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
@@ -1664,41 +1680,47 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 					sPendingQueries.insert(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 #endif
 
-					glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
+					{
+						LLFastTimer t(FTM_PUSH_OCCLUSION_VERTS);
+						glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
 					
-					mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
+						mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
 
-					if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
-					{
-						LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
-						if (camera->getOrigin().isExactlyZero())
-						{ //origin is invalid, draw entire box
-							mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
-							mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
-						}
-						else
+						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
 						{
-							mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
-						}
-					}
-					else
-					{
-						if (camera->getOrigin().isExactlyZero())
-						{ //origin is invalid, draw entire box
-							mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
-							mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
+							LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
+							if (camera->getOrigin().isExactlyZero())
+							{ //origin is invalid, draw entire box
+								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
+							}
+							else
+							{
+								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+							}
 						}
 						else
 						{
-							mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+							if (camera->getOrigin().isExactlyZero())
+							{ //origin is invalid, draw entire box
+								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
+							}
+							else
+							{
+								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+							}
 						}
-					}
 
-					glEndQueryARB(mode);
+						glEndQueryARB(mode);
+					}
 				}
 
-				setOcclusionState(LLSpatialGroup::QUERY_PENDING);
-				clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
+				{
+					LLFastTimer t(FTM_SET_OCCLUSION_STATE);
+					setOcclusionState(LLSpatialGroup::QUERY_PENDING);
+					clearOcclusionState(LLSpatialGroup::DISCARD_QUERY);
+				}
 			}
 		}
 	}
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 414036c597eb19986070952ba7fc2214f6760fd9..46aa44b2bb07853e1491e0218a462e9a1364d3ed 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -339,15 +339,6 @@ static bool handleNumpadControlChanged(const LLSD& newvalue)
 	return true;
 }
 
-static bool handleRenderUseVBOChanged(const LLSD& newvalue)
-{
-	if (gPipeline.isInit())
-	{
-		gPipeline.setUseVBO(newvalue.asBoolean());
-	}
-	return true;
-}
-
 static bool handleWLSkyDetailChanged(const LLSD&)
 {
 	if (gSky.mVOWLSkyp.notNull())
@@ -636,8 +627,9 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("MuteVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
 	gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
 	gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
-	gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _2));
+	gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+	gSavedSettings.getControl("RenderPreferStreamDraw")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2));
 	gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _2));
 	gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index d966bd161462e821cbd2fceb3e32eea6b72ee97a..f762f04d8e050be6d952164bf5cf7f41565ffe99 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -360,7 +360,7 @@ U32 LLVOPartGroup::getPartitionType() const
 }
 
 LLParticlePartition::LLParticlePartition()
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK, TRUE, GL_STREAM_DRAW_ARB)
 {
 	mRenderPass = LLRenderPass::PASS_ALPHA;
 	mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 20ca02efda10d527f6da6d0d46470b7dcaca5cfb..1b5aed804f3072a31d7bf10eaa57b4ebfe39f2ea 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -1330,7 +1330,7 @@ U32 LLVOTree::getPartitionType() const
 }
 
 LLTreePartition::LLTreePartition()
-: LLSpatialPartition(0, FALSE, 0)
+: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_TREE;
 	mPartitionType = LLViewerRegion::PARTITION_TREE;
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 9f3ec9cadc5e92358820542731047ed291b21a3e..77875859e99e92924aa24dbfba3d7690b1cb87db 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -289,7 +289,7 @@ U32 LLVOVoidWater::getPartitionType() const
 }
 
 LLWaterPartition::LLWaterPartition()
-: LLSpatialPartition(0, FALSE, 0)
+: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW_ARB)
 {
 	mInfiniteFarClip = TRUE;
 	mDrawableType = LLPipeline::RENDER_TYPE_WATER;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 221960ba0f8ffbc10bbdc8f86c1f6a74e2b0af9c..a8e36df29415d96deb4b8c6cc47f909575913b59 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -383,6 +383,7 @@ void LLPipeline::init()
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
 	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+	LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
 	sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
 	sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
 
@@ -5795,6 +5796,8 @@ void LLPipeline::resetVertexBuffers()
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
 	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+	LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
+	LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable");
 	sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
 	sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
 
@@ -5853,24 +5856,6 @@ void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
 	gGLLastMatrix = NULL;		
 }
 
-void LLPipeline::setUseVBO(BOOL use_vbo)
-{
-	if (use_vbo != LLVertexBuffer::sEnableVBOs)
-	{
-		if (use_vbo)
-		{
-			llinfos << "Enabling VBO." << llendl;
-		}
-		else
-		{ 
-			llinfos << "Disabling VBO." << llendl;
-		}
-		
-		resetVertexBuffers();
-		LLVertexBuffer::initClass(use_vbo);
-	}
-}
-
 void apply_cube_face_rotation(U32 face)
 {
 	switch (face)
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 0eb020605e1e6cba80021c09f468face27a44b96..32ac93388d9c2db5c9ab391124144fee87da1d49 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -119,7 +119,6 @@ class LLPipeline
 	void allocatePhysicsBuffer();
 	
 	void resetVertexBuffers(LLDrawable* drawable);
-	void setUseVBO(BOOL use_vbo);
 	void generateImpostor(LLVOAvatar* avatar);
 	void bindScreenToTexture();
 	void renderBloom(BOOL for_snapshot, F32 zoom_factor = 1.f, int subfield = 0);