diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index c224ab0e9bb20a8c6aefb7517315e1c9cf1a6180..e07ff0015ca51afac78e67326dc1ebeb7732ee14 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -128,9 +128,21 @@ PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB = NULL;
 PFNGLGETBUFFERPOINTERVARBPROC		glGetBufferPointervARB = NULL;
 
 // GL_ARB_map_buffer_range
-PFNGLMAPBUFFERRANGEPROC			glMapBufferRange;
-PFNGLFLUSHMAPPEDBUFFERRANGEPROC	glFlushMappedBufferRange;
-
+PFNGLMAPBUFFERRANGEPROC			glMapBufferRange = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEPROC	glFlushMappedBufferRange = NULL;
+
+// GL_ARB_sync
+PFNGLFENCESYNCPROC				glFenceSync = NULL;
+PFNGLISSYNCPROC					glIsSync = NULL;
+PFNGLDELETESYNCPROC				glDeleteSync = NULL;
+PFNGLCLIENTWAITSYNCPROC			glClientWaitSync = NULL;
+PFNGLWAITSYNCPROC				glWaitSync = NULL;
+PFNGLGETINTEGER64VPROC			glGetInteger64v = NULL;
+PFNGLGETSYNCIVPROC				glGetSynciv = NULL;
+
+// GL_APPLE_flush_buffer_range
+PFNGLBUFFERPARAMETERIAPPLEPROC	glBufferParameteriAPPLE = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL;
 
 // vertex object prototypes
 PFNGLNEWOBJECTBUFFERATIPROC			glNewObjectBufferATI = NULL;
@@ -334,9 +346,10 @@ LLGLManager::LLGLManager() :
 	mHasFramebufferObject(FALSE),
 	mMaxSamples(0),
 	mHasBlendFuncSeparate(FALSE),
-
+	mHasSync(FALSE),
 	mHasVertexBufferObject(FALSE),
 	mHasMapBufferRange(FALSE),
+	mHasFlushBufferRange(FALSE),
 	mHasPBuffer(FALSE),
 	mHasShaderObjects(FALSE),
 	mHasVertexShader(FALSE),
@@ -774,7 +787,9 @@ void LLGLManager::initExtensions()
 	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
 	mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
 	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
+	mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
 	mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
+	mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
 	mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
 	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
 #ifdef GL_ARB_framebuffer_object
@@ -969,6 +984,16 @@ void LLGLManager::initExtensions()
 			mHasVertexBufferObject = FALSE;
 		}
 	}
+	if (mHasSync)
+	{
+		glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync");
+		glIsSync = (PFNGLISSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glIsSync");
+		glDeleteSync = (PFNGLDELETESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteSync");
+		glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glClientWaitSync");
+		glWaitSync = (PFNGLWAITSYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glWaitSync");
+		glGetInteger64v = (PFNGLGETINTEGER64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInteger64v");
+		glGetSynciv = (PFNGLGETSYNCIVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetSynciv");
+	}
 	if (mHasMapBufferRange)
 	{
 		glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glMapBufferRange");
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index d1bee001617b33f0c3447b6571c50cefeff5949b..d736133f3ffc14ba21ec732be273c5338bcf0e76 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -88,7 +88,9 @@ class LLGLManager
 		
 	// ARB Extensions
 	BOOL mHasVertexBufferObject;
+	BOOL mHasSync;
 	BOOL mHasMapBufferRange;
+	BOOL mHasFlushBufferRange;
 	BOOL mHasPBuffer;
 	BOOL mHasShaderObjects;
 	BOOL mHasVertexShader;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index f35f329f002488b8b8ce61cd2149f462b253be47..851a75629e184e60767390c843360156d7d8515a 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -68,6 +68,19 @@ extern PFNGLUNMAPBUFFERARBPROC		glUnmapBufferARB;
 extern PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB;
 extern PFNGLGETBUFFERPOINTERVARBPROC	glGetBufferPointervARB;
 
+// GL_ARB_sync
+extern PFNGLFENCESYNCPROC				glFenceSync;
+extern PFNGLISSYNCPROC					glIsSync;
+extern PFNGLDELETESYNCPROC				glDeleteSync;
+extern PFNGLCLIENTWAITSYNCPROC			glClientWaitSync;
+extern PFNGLWAITSYNCPROC				glWaitSync;
+extern PFNGLGETINTEGER64VPROC			glGetInteger64v;
+extern PFNGLGETSYNCIVPROC				glGetSynciv;
+
+// GL_APPLE_flush_buffer_range
+extern PFNGLBUFFERPARAMETERIAPPLEPROC	glBufferParameteriAPPLE;
+extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
+
 // GL_ARB_map_buffer_range
 extern PFNGLMAPBUFFERRANGEPROC			glMapBufferRange;
 extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC	glFlushMappedBufferRange;
@@ -310,6 +323,19 @@ extern PFNGLUNMAPBUFFERARBPROC		glUnmapBufferARB;
 extern PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB;
 extern PFNGLGETBUFFERPOINTERVARBPROC	glGetBufferPointervARB;
 
+// GL_ARB_sync
+extern PFNGLFENCESYNCPROC				glFenceSync;
+extern PFNGLISSYNCPROC					glIsSync;
+extern PFNGLDELETESYNCPROC				glDeleteSync;
+extern PFNGLCLIENTWAITSYNCPROC			glClientWaitSync;
+extern PFNGLWAITSYNCPROC				glWaitSync;
+extern PFNGLGETINTEGER64VPROC			glGetInteger64v;
+extern PFNGLGETSYNCIVPROC				glGetSynciv;
+
+// GL_APPLE_flush_buffer_range
+extern PFNGLBUFFERPARAMETERIAPPLEPROC	glBufferParameteriAPPLE;
+extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
+
 // GL_ARB_map_buffer_range
 extern PFNGLMAPBUFFERRANGEPROC			glMapBufferRange;
 extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC	glFlushMappedBufferRange;
@@ -519,6 +545,19 @@ extern PFNGLUNMAPBUFFERARBPROC		glUnmapBufferARB;
 extern PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB;
 extern PFNGLGETBUFFERPOINTERVARBPROC	glGetBufferPointervARB;
 
+// GL_ARB_sync
+extern PFNGLFENCESYNCPROC				glFenceSync;
+extern PFNGLISSYNCPROC					glIsSync;
+extern PFNGLDELETESYNCPROC				glDeleteSync;
+extern PFNGLCLIENTWAITSYNCPROC			glClientWaitSync;
+extern PFNGLWAITSYNCPROC				glWaitSync;
+extern PFNGLGETINTEGER64VPROC			glGetInteger64v;
+extern PFNGLGETSYNCIVPROC				glGetSynciv;
+
+// GL_APPLE_flush_buffer_range
+extern PFNGLBUFFERPARAMETERIAPPLEPROC	glBufferParameteriAPPLE;
+extern PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE;
+
 // GL_ARB_map_buffer_range
 extern PFNGLMAPBUFFERRANGEPROC			glMapBufferRange;
 extern PFNGLFLUSHMAPPEDBUFFERRANGEPROC	glFlushMappedBufferRange;
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 4a0b964e616bb06644ed4bbe6b5f011ca2fdb021..82c5efe0ac6f649712ce963bf9a32b71f7c3e914 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -65,6 +65,60 @@ S32	LLVertexBuffer::sWeight4Loc = -1;
 std::vector<U32> LLVertexBuffer::sDeleteList;
 
 
+const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000;  //1 ms
+
+class LLGLSyncFence : public LLGLFence
+{
+public:
+#ifdef GL_ARB_sync
+	GLsync mSync;
+#endif
+	
+	LLGLSyncFence()
+	{
+#ifdef GL_ARB_sync
+		mSync = 0;
+#endif
+	}
+
+	~LLGLSyncFence()
+	{
+#ifdef GL_ARB_sync
+		if (mSync)
+		{
+			glDeleteSync(mSync);
+		}
+#endif
+	}
+
+	void placeFence()
+	{
+#ifdef GL_ARB_sync
+		if (mSync)
+		{
+			glDeleteSync(mSync);
+		}
+		mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+#endif
+	}
+
+	void wait()
+	{
+#ifdef GL_ARB_sync
+		if (mSync)
+		{
+			while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
+			{ //track the number of times we've waited here
+				static S32 waits = 0;
+				waits++;
+			}
+		}
+#endif
+	}
+
+
+};
+
 S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
 {
 	sizeof(LLVector4), // TYPE_VERTEX,
@@ -309,6 +363,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
 		idx);
 	stop_glerror();
+	placeFence();
 }
 
 void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
@@ -340,6 +395,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 	glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
 		((U16*) getIndicesPointer()) + indices_offset);
 	stop_glerror();
+	placeFence();
 }
 
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
@@ -365,6 +421,7 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 	stop_glerror();
 	glDrawArrays(sGLMode[mode], first, count);
 	stop_glerror();
+	placeFence();
 }
 
 //static
@@ -444,9 +501,11 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 	mFilthy(FALSE),
 	mEmpty(TRUE),
 	mResized(FALSE),
-	mDynamicSize(FALSE)
+	mDynamicSize(FALSE),
+	mFence(NULL)
 {
 	LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR);
+	mFence = NULL;
 	if (!sEnableVBOs)
 	{
 		mUsage = 0 ; 
@@ -527,9 +586,40 @@ LLVertexBuffer::~LLVertexBuffer()
 	destroyGLIndices();
 	sCount--;
 
+	if (mFence)
+	{
+		delete mFence;
+	}
+	
+	mFence = NULL;
+
 	llassert_always(!mMappedData && !mMappedIndexData) ;
 };
 
+void LLVertexBuffer::placeFence() const
+{
+	/*if (!mFence && useVBOs())
+	{
+		if (gGLManager.mHasSync)
+		{
+			mFence = new LLGLSyncFence();
+		}
+	}
+
+	if (mFence)
+	{
+		mFence->placeFence();
+	}*/
+}
+
+void LLVertexBuffer::waitFence() const
+{
+	/*if (mFence)
+	{
+		mFence->wait();
+	}*/
+}
+
 //----------------------------------------------------------------------------
 
 void LLVertexBuffer::genBuffer()
@@ -892,17 +982,11 @@ BOOL LLVertexBuffer::useVBOs() const
 {
 	//it's generally ineffective to use VBO for things that are streaming on apple
 		
-#if LL_DARWIN
-	if (!mUsage || mUsage == GL_STREAM_DRAW_ARB)
-	{
-		return FALSE;
-	}
-#else
 	if (!mUsage)
 	{
 		return FALSE;
 	}
-#endif
+
 	return TRUE;
 }
 
@@ -967,8 +1051,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 		
 	if (useVBOs())
 	{
-
-		if (sDisableVBOMapping || gGLManager.mHasMapBufferRange)
+		if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 		{
 			if (count == -1)
 			{
@@ -1008,6 +1091,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES);
 			setBuffer(0, type);
 			mVertexLocked = TRUE;
+			sMappedCount++;
 			stop_glerror();	
 
 			if(sDisableVBOMapping)
@@ -1018,29 +1102,52 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 			else
 			{
 				U8* src = NULL;
-#ifdef GL_ARB_map_buffer_range
+				waitFence();
 				if (gGLManager.mHasMapBufferRange)
 				{
 					if (map_range)
 					{
+#ifdef GL_ARB_map_buffer_range
 						S32 offset = mOffsets[type] + sTypeSize[type]*index;
 						S32 length = (sTypeSize[type]*count+0xF) & ~0xF;
-						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, 
+							GL_MAP_WRITE_BIT | 
+							GL_MAP_FLUSH_EXPLICIT_BIT | 
+							GL_MAP_INVALIDATE_RANGE_BIT | 
+							GL_MAP_UNSYNCHRONIZED_BIT);
+#endif
 					}
 					else
 					{
-						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
+#ifdef GL_ARB_map_buffer_range
+						src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, 
+							GL_MAP_WRITE_BIT | 
+							GL_MAP_FLUSH_EXPLICIT_BIT |
+							GL_MAP_UNSYNCHRONIZED_BIT);
+#endif
+					}
+				}
+				else if (gGLManager.mHasFlushBufferRange)
+				{
+					if (map_range)
+					{
+						glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+						glBufferParameteriAPPLE(GL_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+						src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+					}
+					else
+					{
+						src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 					}
 				}
 				else
-#else
-				llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
 				{
 					map_range = false;
 					src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 				}
 
+				llassert(src != NULL);
+
 				mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
 				mAlignedOffset = mMappedData - src;
 			
@@ -1082,7 +1189,6 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 					llerrs << "memory allocation for vertex data failed." << llendl ;
 				}
 			}
-			sMappedCount++;
 		}
 	}
 	else
@@ -1090,7 +1196,7 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran
 		map_range = false;
 	}
 	
-	if (map_range && !sDisableVBOMapping)
+	if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping)
 	{
 		return mMappedData;
 	}
@@ -1114,7 +1220,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 
 	if (useVBOs())
 	{
-		if (sDisableVBOMapping || gGLManager.mHasMapBufferRange)
+		if (sDisableVBOMapping || gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 		{
 			if (count == -1)
 			{
@@ -1152,6 +1258,7 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 
 			setBuffer(0, TYPE_INDEX);
 			mIndexLocked = TRUE;
+			sMappedCount++;
 			stop_glerror();	
 
 			if(sDisableVBOMapping)
@@ -1162,29 +1269,53 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 			else
 			{
 				U8* src = NULL;
-#ifdef GL_ARB_map_buffer_range
+				waitFence();
 				if (gGLManager.mHasMapBufferRange)
 				{
 					if (map_range)
 					{
+#ifdef GL_ARB_map_buffer_range
 						S32 offset = sizeof(U16)*index;
 						S32 length = sizeof(U16)*count;
-						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_INVALIDATE_RANGE_BIT);
+						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, 
+							GL_MAP_WRITE_BIT | 
+							GL_MAP_FLUSH_EXPLICIT_BIT | 
+							GL_MAP_INVALIDATE_RANGE_BIT |
+							GL_MAP_UNSYNCHRONIZED_BIT);
+#endif
 					}
 					else
 					{
-						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
+#ifdef GL_ARB_map_buffer_range
+						src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, 
+							GL_MAP_WRITE_BIT | 
+							GL_MAP_FLUSH_EXPLICIT_BIT |
+							GL_MAP_UNSYNCHRONIZED_BIT);
+#endif
+					}
+				}
+				else if (gGLManager.mHasFlushBufferRange)
+				{
+					if (map_range)
+					{
+						glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_SERIALIZED_MODIFY_APPLE, GL_FALSE);
+						glBufferParameteriAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
+						src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+					}
+					else
+					{
+						src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 					}
 				}
 				else
-#else
-				llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
 				{
 					map_range = false;
 					src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
 				}
 
+				llassert(src != NULL);
+
+
 				mMappedIndexData = src; //LL_NEXT_ALIGNED_ADDRESS<U8>(src);
 				mAlignedIndexOffset = mMappedIndexData - src;
 				stop_glerror();
@@ -1211,15 +1342,13 @@ U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
 				llerrs << "memory allocation for Index data failed. " << llendl ;
 			}
 		}
-
-		sMappedCount++;
 	}
 	else
 	{
 		map_range = false;
 	}
 
-	if (map_range && !sDisableVBOMapping)
+	if (map_range && gGLManager.mHasMapBufferRange && !sDisableVBOMapping)
 	{
 		return mMappedIndexData;
 	}
@@ -1268,8 +1397,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
 		}
 		else
 		{
-#ifdef GL_ARB_map_buffer_range
-			if (gGLManager.mHasMapBufferRange)
+			if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 			{
 				if (!mMappedVertexRegions.empty())
 				{
@@ -1279,16 +1407,22 @@ void LLVertexBuffer::unmapBuffer(S32 type)
 						const MappedRegion& region = mMappedVertexRegions[i];
 						S32 offset = region.mIndex >= 0 ? mOffsets[region.mType]+sTypeSize[region.mType]*region.mIndex : 0;
 						S32 length = sTypeSize[region.mType]*region.mCount;
-						glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
+						if (gGLManager.mHasMapBufferRange)
+						{
+#ifdef GL_ARB_map_buffer_range
+							glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length);
+#endif
+						}
+						else if (gGLManager.mHasFlushBufferRange)
+						{
+							glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length);
+						}
 						stop_glerror();
 					}
 
 					mMappedVertexRegions.clear();
 				}
 			}
-#else
-			llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
 			stop_glerror();
 			glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
 			stop_glerror();
@@ -1326,8 +1460,7 @@ void LLVertexBuffer::unmapBuffer(S32 type)
 		}
 		else
 		{
-#ifdef GL_ARB_map_buffer_range
-			if (gGLManager.mHasMapBufferRange)
+			if (gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange)
 			{
 				if (!mMappedIndexRegions.empty())
 				{
@@ -1336,16 +1469,24 @@ void LLVertexBuffer::unmapBuffer(S32 type)
 						const MappedRegion& region = mMappedIndexRegions[i];
 						S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0;
 						S32 length = sizeof(U16)*region.mCount;
-						glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+						if (gGLManager.mHasMapBufferRange)
+						{
+#ifdef GL_ARB_map_buffer_range
+							glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+						}
+						else if (gGLManager.mHasFlushBufferRange)
+						{
+#ifdef GL_APPLE_flush_buffer_range
+							glFlushMappedBufferRangeAPPLE(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length);
+#endif
+						}
 						stop_glerror();
 					}
 
 					mMappedIndexRegions.clear();
 				}
 			}
-#else
-			llassert_always(!gGLManager.mHasMapBufferRange);
-#endif
 			stop_glerror();
 			glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
 			stop_glerror();
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index aa5df305a66f0eda5bf8b31caa304311f454e4d1..cc5d11e1c29018ff1ec085da20c4e7045d33600d 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -70,6 +70,12 @@ class LLVBOPool : public LLGLNamePool
 	}
 };
 
+class LLGLFence
+{
+public:
+	virtual void placeFence() = 0;
+	virtual void wait() = 0;
+};
 
 //============================================================================
 // base class 
@@ -270,6 +276,12 @@ class LLVertexBuffer : public LLRefCount
 	std::vector<MappedRegion> mMappedVertexRegions;
 	std::vector<MappedRegion> mMappedIndexRegions;
 
+	mutable LLGLFence* mFence;
+
+	void placeFence() const;
+	void waitFence() const;
+
+
 public:
 	static S32 sCount;
 	static S32 sGLCount;
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 22c79a4cbd2c18ed3b74842c5539f91a9a27ac7a..d2d0227f628a741b462fdd1ad7b12a90823642d5 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 30
+version 31
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -244,9 +244,9 @@ RenderDeferredSSAO			0	0
 RenderShadowDetail			0	0
 
 //
-// No GL_ARB_map_buffer_range
+// GL_ARB_map_buffer_range exists
 //
-list NoMapBufferRange
+list MapBufferRange
 RenderVBOMappingDisable		1	0
 
 
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index 649f5ebd186838cdf8c1d43a4c2b45e123a5a2ca..d9b408301654d8bb9765592bc89e96f67ca02421 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -1,4 +1,4 @@
-version 25
+version 26
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -242,9 +242,9 @@ RenderDeferredSSAO			0	0
 RenderShadowDetail			0	0
 
 //
-// No GL_ARB_map_buffer_range
+// GL_ARB_map_buffer_range exists
 //
-list NoMapBufferRange
+list MapBufferRange
 RenderVBOMappingDisable		1	0
 
 
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index ee08e78af5a2b475e3d71705ed8a5086810687d2..f0b1f532a951c268f224823c089f3b316a86c4d5 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 26
+version 28
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -48,7 +48,7 @@ RenderTransparentWater			1	1
 RenderTreeLODFactor				1	1.0
 RenderUseImpostors				1	1
 RenderVBOEnable					1	1
-RenderVBOMappingDisable		1	1
+RenderVBOMappingDisable		1	0
 RenderVolumeLODFactor			1	2.0
 UseStartScreen				1	1
 UseOcclusion					1	1
@@ -63,7 +63,7 @@ RenderDeferred				1	1
 RenderDeferredSSAO			1	1
 RenderShadowDetail			1	2
 WatchdogDisabled				1	1
-RenderUseStreamVBO			1	1
+RenderUseStreamVBO			1	0
 RenderFSAASamples			1	16
 
 //
@@ -243,13 +243,6 @@ RenderDeferred				0	0
 RenderDeferredSSAO			0	0
 RenderShadowDetail			0	0
 
-//
-// No GL_ARB_map_buffer_range
-//
-list NoMapBufferRange
-RenderVBOMappingDisable		1	0
-
-
 //
 // "Default" setups for safe, low, medium, high
 //
diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt
index ba74f9a6c24b9ec6f5b72faf254f64137557906b..6477dab35a9933be91be3fc8604bc35c8d501ff0 100644
--- a/indra/newview/featuretable_xp.txt
+++ b/indra/newview/featuretable_xp.txt
@@ -1,4 +1,4 @@
-version 30
+version 31
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -244,9 +244,9 @@ RenderDeferredSSAO			0	0
 RenderShadowDetail			0	0
 
 //
-// No GL_ARB_map_buffer_range
+// GL_ARB_map_buffer_range exists
 //
-list NoMapBufferRange
+list MapBufferRange
 RenderVBOMappingDisable		1	0
 
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index debac9dcbfd9dd4ebf10bb30f3deda6c1f2e0ad5..a5168fd897bccae01cf8336b9aa914afc6b58dd0 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -1524,6 +1524,11 @@ BOOL LLDrawable::isAnimating() const
 		return TRUE;
 	}
 
+	if (!LLVertexBuffer::sUseStreamDraw && mVObjp->isFlexible())
+	{
+		return TRUE;
+	}
+
 	return FALSE;
 }
 
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index b6566fcbd094da1b4c887f89ac667fafd942b1ba..59c6e904a13fc139e5137e5325294ea69b59333a 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1064,6 +1064,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	S32 num_vertices = (S32)vf.mNumVertices;
 	S32 num_indices = (S32) vf.mNumIndices;
 	
+	bool map_range = gGLManager.mHasMapBufferRange || gGLManager.mHasFlushBufferRange;
+
 	if (mVertexBuffer.notNull())
 	{
 		if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices())
@@ -1182,7 +1184,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	// INDICES
 	if (full_rebuild)
 	{
-		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, true);
+		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range);
 
 		__m128i* dst = (__m128i*) indicesp.get();
 		__m128i* src = (__m128i*) vf.mIndices;
@@ -1201,7 +1203,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			indicesp[i] = vf.mIndices[i]+index_offset;
 		}
 
-		mVertexBuffer->setBuffer(0);
+		if (map_range)
+		{
+			mVertexBuffer->setBuffer(0);
+		}
 	}
 	
 	LLMatrix4a mat_normal;
@@ -1422,11 +1427,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 			}
 
-			mVertexBuffer->setBuffer(0);
+			if (map_range)
+			{
+				mVertexBuffer->setBuffer(0);
+			}
 		}
 		else
 		{ //either bump mapped or in atlas, just do the whole expensive loop
-			mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, true);
+			mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range);
 
 			std::vector<LLVector2> bump_tc;
 		
@@ -1566,12 +1574,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 			}
 
-			mVertexBuffer->setBuffer(0);
-
+			if (map_range)
+			{
+				mVertexBuffer->setBuffer(0);
+			}
 
 			if (do_bump)
 			{
-				mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, true);
+				mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range);
 		
 				for (S32 i = 0; i < num_vertices; i++)
 				{
@@ -1601,14 +1611,17 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					*tex_coords2++ = tc;
 				}
 
-				mVertexBuffer->setBuffer(0);
+				if (map_range)
+				{
+					mVertexBuffer->setBuffer(0);
+				}
 			}
 		}
 	}
 
 	if (rebuild_pos)
 	{
-		mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, true);
+		mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
 		vertices = (LLVector4a*) vert.get();
 	
 		LLMatrix4a mat_vert;
@@ -1637,12 +1650,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 		while (index_dst < index_end);
 
-		mVertexBuffer->setBuffer(0);
+		if (map_range)
+		{
+			mVertexBuffer->setBuffer(0);
+		}
 	}
 		
 	if (rebuild_normal)
 	{
-		mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, true);
+		mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
 		normals = (LLVector4a*) norm.get();
 	
 		for (S32 i = 0; i < num_vertices; i++)
@@ -1653,12 +1669,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			normals[i] = normal;
 		}
 
-		mVertexBuffer->setBuffer(0);
+		if (map_range)
+		{
+			mVertexBuffer->setBuffer(0);
+		}
 	}
 		
 	if (rebuild_binormal)
 	{
-		mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, true);
+		mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range);
 		binormals = (LLVector4a*) binorm.get();
 		
 		for (S32 i = 0; i < num_vertices; i++)
@@ -1669,20 +1688,26 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			binormals[i] = binormal;
 		}
 
-		mVertexBuffer->setBuffer(0);
+		if (map_range)
+		{
+			mVertexBuffer->setBuffer(0);
+		}
 	}
 	
 	if (rebuild_weights && vf.mWeights)
 	{
-		mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, true);
+		mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
 		weights = (LLVector4a*) wght.get();
 		LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
-		mVertexBuffer->setBuffer(0);
+		if (map_range)
+		{
+			mVertexBuffer->setBuffer(0);
+		}
 	}
 
 	if (rebuild_color)
 	{
-		mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, true);
+		mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
 
 		LLVector4a src;
 
@@ -1703,7 +1728,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			dst[i] = src;
 		}
 
-		mVertexBuffer->setBuffer(0);
+		if (map_range)
+		{
+			mVertexBuffer->setBuffer(0);
+		}
 	}
 
 	if (rebuild_tcoord)
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 83844048d1d2c14f3877b4131a6354bcc6ddc4ab..0ea0e41dfae9fbff54752eb5ee30f9802fec1f67 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -769,6 +769,10 @@ void LLFeatureManager::applyBaseMasks()
 	{
 		maskFeatures("TexUnit8orLess");
 	}
+	if (gGLManager.mHasMapBufferRange)
+	{
+		maskFeatures("MapBufferRange");
+	}
 
 	// now mask by gpu string
 	// Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e6da8eb89d8ec90617d1f70d354adff65008b19e..40afabdb650d02e49eb595c4a8529f29f7123fc4 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4361,6 +4361,8 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 
 		group->mBuilt = 1.f;
 		
+		std::set<LLVertexBuffer*> mapped_buffers;
+
 		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 		{
 			LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
@@ -4375,35 +4377,31 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 				{
 					LLFace* face = drawablep->getFace(i);
-					if (face && face->getVertexBuffer())
+					if (face)
 					{
-						face->getGeometryVolume(*volume, face->getTEOffset(), 
-							vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+						LLVertexBuffer* buff = face->getVertexBuffer();
+						if (buff)
+						{
+							face->getGeometryVolume(*volume, face->getTEOffset(), 
+								vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+
+							if (buff->isLocked())
+							{
+								mapped_buffers.insert(buff);
+							}
+						}
 					}
 				}
-
+				
 				drawablep->clearState(LLDrawable::REBUILD_ALL);
 			}
 		}
 		
-		//unmap all the buffers
-		for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
+		for (std::set<LLVertexBuffer*>::iterator iter = mapped_buffers.begin(); iter != mapped_buffers.end(); ++iter)
 		{
-			LLSpatialGroup::buffer_texture_map_t& map = i->second;
-			for (LLSpatialGroup::buffer_texture_map_t::iterator j = map.begin(); j != map.end(); ++j)
-			{
-				LLSpatialGroup::buffer_list_t& list = j->second;
-				for (LLSpatialGroup::buffer_list_t::iterator k = list.begin(); k != list.end(); ++k)
-				{
-					LLVertexBuffer* buffer = *k;
-					if (buffer->isLocked())
-					{
-						buffer->setBuffer(0);
-					}
-				}
-			}
+			(*iter)->setBuffer(0);
 		}
-		
+
 		// don't forget alpha
 		if(group != NULL && 
 		   !group->mVertexBuffer.isNull() &&