diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp
index f546ac164533f1f4c5a55837483da7befb4d485e..0ab97a0df3ba6be44a7397c2d1af2cd3cceb2905 100644
--- a/indra/llprimitive/llmaterial.cpp
+++ b/indra/llprimitive/llmaterial.cpp
@@ -27,6 +27,7 @@
 #include "linden_common.h"
 
 #include "llmaterial.h"
+#include "llmd5.h"
 
 /**
  * Materials cap parameters
@@ -475,4 +476,16 @@ U32 LLMaterial::getShaderMask(U32 alpha_mode)
     return ret;
 }
 
+LLUUID LLMaterial::getHash() const
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+    LLMD5 md5;
+    // HACK - hash the bytes of this LLMaterial, but trim off the S32 in LLRefCount
+    md5.update((unsigned char*)this + sizeof(S32), sizeof(this) - sizeof(S32));
+    md5.finalize();
+    LLUUID id;
+    md5.raw_digest(id.mData);
+    // *TODO: Hash the overrides
+    return id;
+}
 
diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h
index 2f8aafc2cfb9aff9188ed2874a4ec05f664b787c..d715671ae17a089dd4ae2974f680c23361447aea 100644
--- a/indra/llprimitive/llmaterial.h
+++ b/indra/llprimitive/llmaterial.h
@@ -125,6 +125,7 @@ class LLMaterial : public LLRefCount
     bool        operator != (const LLMaterial& rhs) const;
 
     U32         getShaderMask(U32 alpha_mode = DIFFUSE_ALPHA_MODE_DEFAULT);
+    LLUUID      getHash() const;
 
 protected:
     LLUUID      mNormalID;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 67bd9e277e6608d7f831c2e4bc0a19f69958dbce..9dfe5ef9ffa04ef843e830bc2ad33668129620b9 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2395,234 +2395,39 @@ void LLGLState::dumpStates()
 	}
 }
 
-void LLGLState::checkStates(const std::string& msg)  
+void LLGLState::checkStates(GLboolean writeAlpha)
 {
 	if (!gDebugGL)
 	{
 		return;
 	}
 
-	stop_glerror();
-
 	GLint src;
 	GLint dst;
 	glGetIntegerv(GL_BLEND_SRC, &src);
 	glGetIntegerv(GL_BLEND_DST, &dst);
-	
-	stop_glerror();
-
-	BOOL error = FALSE;
-
-	/*if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA)
-	{
-		if (gDebugSession)
-		{
-			gFailLog << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << "  " << msg << std::dec << std::endl;
-			error = TRUE;
-		}
-		else
-		{
-			LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << "  " << msg << std::dec << LL_ENDL;
-		}
-	}*/
+    llassert_always(src == GL_SRC_ALPHA);
+    llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA);
+  
+    GLboolean colorMask[4];
+    glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
+    llassert_always(colorMask[0]);
+    llassert_always(colorMask[1]);
+    llassert_always(colorMask[2]);
+    llassert_always(colorMask[3] == writeAlpha);
 	
 	for (boost::unordered_map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin();
 		 iter != sStateMap.end(); ++iter)
 	{
 		LLGLenum state = iter->first;
 		LLGLboolean cur_state = iter->second;
-		stop_glerror();
 		LLGLboolean gl_state = glIsEnabled(state);
-		stop_glerror();
 		if(cur_state != gl_state)
 		{
 			dumpStates();
-			if (gDebugSession)
-			{
-				gFailLog << llformat("LLGLState error. State: 0x%04x",state) << std::endl;
-				error = TRUE;
-			}
-			else
-			{
-				LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL;
-			}
-		}
-	}
-	
-	if (error)
-	{
-		ll_fail("LLGLState::checkStates failed.");
-	}
-	stop_glerror();
-}
-
-void LLGLState::checkTextureChannels(const std::string& msg)
-{
-#if 0
-	if (!gDebugGL)
-	{
-		return;
-	}
-	stop_glerror();
-
-	GLint activeTexture;
-	glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
-	stop_glerror();
-
-	BOOL error = FALSE;
-
-	if (activeTexture == GL_TEXTURE0)
-	{
-		GLint tex_env_mode = 0;
-
-		glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_env_mode);
-		stop_glerror();
-
-		if (tex_env_mode != GL_MODULATE)
-		{
-			error = TRUE;
-			LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << LL_ENDL;
-			if (gDebugSession)
-			{
-				gFailLog << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << std::endl;
-			}
+			LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL;
 		}
 	}
-
-	static const char* label[] =
-	{
-		"GL_TEXTURE_2D",
-		"GL_TEXTURE_COORD_ARRAY",
-		"GL_TEXTURE_1D",
-		"GL_TEXTURE_CUBE_MAP",
-		"GL_TEXTURE_GEN_S",
-		"GL_TEXTURE_GEN_T",
-		"GL_TEXTURE_GEN_Q",
-		"GL_TEXTURE_GEN_R",
-		"GL_TEXTURE_RECTANGLE",
-		"GL_TEXTURE_2D_MULTISAMPLE"
-	};
-
-	static GLint value[] =
-	{
-		GL_TEXTURE_2D,
-		GL_TEXTURE_COORD_ARRAY,
-		GL_TEXTURE_1D,
-		GL_TEXTURE_CUBE_MAP,
-		GL_TEXTURE_GEN_S,
-		GL_TEXTURE_GEN_T,
-		GL_TEXTURE_GEN_Q,
-		GL_TEXTURE_GEN_R,
-		GL_TEXTURE_RECTANGLE,
-		GL_TEXTURE_2D_MULTISAMPLE
-	};
-
-	GLint stackDepth = 0;
-
-	glh::matrix4f mat;
-	glh::matrix4f identity;
-	identity.identity();
-
-	for (GLint i = 1; i < gGLManager.mNumTextureImageUnits; i++)
-	{
-		gGL.getTexUnit(i)->activate();
-
-		if (i < gGLManager.mNumTextureUnits)
-		{
-			glClientActiveTexture(GL_TEXTURE0+i);
-			stop_glerror();
-			glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &stackDepth);
-			stop_glerror();
-
-			if (stackDepth != 1)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "Texture matrix stack corrupted." << LL_ENDL;
-
-				if (gDebugSession)
-				{
-					gFailLog << "Texture matrix stack corrupted." << std::endl;
-				}
-			}
-
-			glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) mat.m);
-			stop_glerror();
-
-			if (mat != identity)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog << "Texture matrix in channel " << i << " corrupt." << std::endl;
-				}
-			}
-				
-			for (S32 j = (i == 0 ? 1 : 0); 
-				j < 9; j++)
-			{
-				if (glIsEnabled(value[j]))
-				{
-					error = TRUE;
-					LL_WARNS("RenderState") << "Texture channel " << i << " still has " << label[j] << " enabled." << LL_ENDL;
-					if (gDebugSession)
-					{
-						gFailLog << "Texture channel " << i << " still has " << label[j] << " enabled." << std::endl;
-					}
-				}
-				stop_glerror();
-			}
-
-			glGetFloatv(GL_TEXTURE_MATRIX, mat.m);
-			stop_glerror();
-
-			if (mat != identity)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "Texture matrix " << i << " is not identity." << LL_ENDL;
-				if (gDebugSession)
-				{
-					gFailLog << "Texture matrix " << i << " is not identity." << std::endl;
-				}
-			}
-		}
-
-		{
-			GLint tex = 0;
-			stop_glerror();
-			glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex);
-			stop_glerror();
-
-			if (tex != 0)
-			{
-				error = TRUE;
-				LL_WARNS("RenderState") << "Texture channel " << i << " still has texture " << tex << " bound." << LL_ENDL;
-
-				if (gDebugSession)
-				{
-					gFailLog << "Texture channel " << i << " still has texture " << tex << " bound." << std::endl;
-				}
-			}
-		}
-	}
-
-	stop_glerror();
-	gGL.getTexUnit(0)->activate();
-	glClientActiveTexture(GL_TEXTURE0);
-	stop_glerror();
-
-	if (error)
-	{
-		if (gDebugSession)
-		{
-			ll_fail("LLGLState::checkTextureChannels failed.");
-		}
-		else
-		{
-			LL_GL_ERRS << "GL texture state corruption detected.  " << msg << LL_ENDL;
-		}
-	}
-#endif
 }
 
 ///////////////////////////////////////////////////////////////////////
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index e3c07604aa75a46c32778bc85b5f6f86ebb6b65a..eb0650d99899d8bb597616964f6b9e42f70dc222 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -231,9 +231,12 @@ class LLGLState
 
 	static void resetTextureStates();
 	static void dumpStates();
-	static void checkStates(const std::string& msg = "");
-	static void checkTextureChannels(const std::string& msg = "");
-	
+
+    // make sure GL blend function, GL states, and GL color mask match
+    // what we expect 
+    //  writeAlpha - whether or not writing to alpha channel is expected
+	static void checkStates(GLboolean writeAlpha = GL_TRUE);
+
 protected:
 	static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap;
 	
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index c5f4efd2c0f3ce8c22f3c91e2cd662e5c7b0cbd8..982b2a847aaf69cdfb9d2f9b158ddf1ecede66d2 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -154,15 +154,33 @@ void LLGLSLShader::finishProfile(bool emit_report)
 
         std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed());
 
+        bool unbound = false;
         for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
         {
             (*iter)->dumpStats();
+            if ((*iter)->mBinds == 0)
+            {
+                unbound = true;
+            }
         }
 
         LL_INFOS() << "-----------------------------------" << LL_ENDL;
         LL_INFOS() << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed / 1000000.f) << LL_ENDL;
         LL_INFOS() << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn / 1000000.f) << LL_ENDL;
         LL_INFOS() << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn / 1000000.f) << LL_ENDL;
+        LL_INFOS() << "-----------------------------------" << LL_ENDL;
+
+        if (unbound)
+        {
+            LL_INFOS() << "The following shaders were unused: " << LL_ENDL;
+            for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
+            {
+                if ((*iter)->mBinds == 0)
+                {
+                    LL_INFOS() << (*iter)->mName << LL_ENDL;
+                }
+            }
+        }
     }
 }
 
@@ -985,6 +1003,8 @@ void LLGLSLShader::bind()
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
 
+    llassert(mProgramObject != 0);
+
     gGL.flush();
 
     if (sCurBoundShader != mProgramObject)  // Don't re-bind current shader
@@ -998,6 +1018,7 @@ void LLGLSLShader::bind()
         sCurBoundShader = mProgramObject;
         sCurBoundShaderPtr = this;
         placeProfileQuery();
+        LLVertexBuffer::setupClientArrays(mAttributeMask);
     }
 
     if (mUniformsDirty)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index bba6a46e4363a44608591d1271062f9cd25ab72d..a8db69a9a44c83a45eb211a4219de29c33195107 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -164,13 +164,10 @@ void LLTexUnit::enable(eTextureType type)
 
 	if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) )
 	{
-		stop_glerror();
 		activate();
-		stop_glerror();
 		if (mCurrTexType != TT_NONE && !gGL.mDirty)
 		{
 			disable(); // Force a disable of a previous texture type if it's enabled.
-			stop_glerror();
 		}
 		mCurrTexType = type;
 
@@ -184,11 +181,7 @@ void LLTexUnit::disable(void)
 
 	if (mCurrTexType != TT_NONE)
 	{
-		activate();
 		unbind(mCurrTexType);
-		gGL.flush();
-        setTextureColorSpace(TCS_LINEAR);
-		
 		mCurrTexType = TT_NONE;
 	}
 }
@@ -196,7 +189,7 @@ void LLTexUnit::disable(void)
 void LLTexUnit::bindFast(LLTexture* texture)
 {
     LLImageGL* gl_tex = texture->getGLTexture();
-
+    texture->setActive();
     glActiveTexture(GL_TEXTURE0 + mIndex);
     gGL.mCurrTextureUnitIndex = mIndex;
     mCurrTexture = gl_tex->getTexName();
@@ -889,12 +882,11 @@ void LLRender::init(bool needs_vertex_buffer)
     // necessary for reflection maps
     glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
 
-	if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
-	{ //bind a dummy vertex array object so we're core profile compliant
-		U32 ret;
-		glGenVertexArrays(1, &ret);
-		glBindVertexArray(ret);
-	}
+    { //bind a dummy vertex array object so we're core profile compliant
+        U32 ret;
+        glGenVertexArrays(1, &ret);
+        glBindVertexArray(ret);
+    }
 
     if (needs_vertex_buffer)
     {
@@ -906,8 +898,8 @@ void LLRender::initVertexBuffer()
 {
     llassert_always(mBuffer.isNull());
     stop_glerror();
-    mBuffer = new LLVertexBuffer(immediate_mask, 0);
-    mBuffer->allocateBuffer(4096, 0, TRUE);
+    mBuffer = new LLVertexBuffer(immediate_mask);
+    mBuffer->allocateBuffer(4096, 0);
     mBuffer->getVertexStrider(mVerticesp);
     mBuffer->getTexCoord0Strider(mTexcoordsp);
     mBuffer->getColorStrider(mColorsp);
@@ -1604,6 +1596,7 @@ void LLRender::flush()
 	if (mCount > 0)
 	{
         LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+        llassert(LLGLSLShader::sCurBoundShaderPtr != nullptr);
 		if (!mUIOffset.empty())
 		{
 			sUICalls++;
@@ -1691,8 +1684,11 @@ void LLRender::flush()
             else
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache miss");
-                vb = new LLVertexBuffer(attribute_mask, GL_STATIC_DRAW);
-                vb->allocateBuffer(count, 0, true);
+                vb = new LLVertexBuffer(attribute_mask);
+                vb->allocateBuffer(count, 0);
+
+                vb->setBuffer();
+
                 vb->setPositionData((LLVector4a*) mVerticesp.get());
 
                 if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
@@ -1733,7 +1729,7 @@ void LLRender::flush()
                 }
             }
 
-            vb->setBuffer(attribute_mask);
+            vb->setBuffer();
 
             if (mMode == LLRender::QUADS && sGLCoreProfile)
             {
@@ -2034,8 +2030,7 @@ void LLRender::texCoord2fv(const GLfloat* tc)
 
 void LLRender::color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a)
 {
-	if (!LLGLSLShader::sCurBoundShaderPtr ||
-		LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR)
+	if (!LLGLSLShader::sCurBoundShaderPtr || LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR)
 	{
 		mColorsp[mCount] = LLColor4U(r,g,b,a);
 	}
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 9fabeb1d7a4f41c13e3b138c1ae7646b0ca44c77..cbd3de5736a66907bf7c6aa8cf9093fa59ea6647 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -277,7 +277,7 @@ class LLRender
 	friend class LLTexUnit;
 public:
 
-	enum eTexIndex
+	enum eTexIndex : U8
 	{
 		DIFFUSE_MAP           = 0,
         ALTERNATE_DIFFUSE_MAP = 1,
@@ -286,14 +286,15 @@ class LLRender
 		NUM_TEXTURE_CHANNELS  = 3,
 	};
 
-	enum eVolumeTexIndex
+	enum eVolumeTexIndex : U8
 	{
 		LIGHT_TEX = 0,
 		SCULPT_TEX,
 		NUM_VOLUME_TEXTURE_CHANNELS,
 	};
 	
-	typedef enum {
+	enum eGeomModes : U8
+    {
 		TRIANGLES = 0,
 		TRIANGLE_STRIP,
 		TRIANGLE_FAN,
@@ -303,9 +304,9 @@ class LLRender
 		QUADS,
 		LINE_LOOP,
 		NUM_MODES
-	} eGeomModes;
+	};
 
-	typedef enum 
+	enum eCompareFunc : U8
 	{
 		CF_NEVER = 0,
 		CF_ALWAYS,
@@ -316,9 +317,9 @@ class LLRender
 		CF_GREATER_EQUAL,
 		CF_GREATER,
 		CF_DEFAULT
-	}  eCompareFunc;
+	};
 
-	typedef enum 
+	enum eBlendType : U8
 	{
 		BT_ALPHA = 0,
 		BT_ADD,
@@ -327,25 +328,26 @@ class LLRender
 		BT_MULT_ALPHA,
 		BT_MULT_X2,
 		BT_REPLACE
-	} eBlendType;
+	};
 
-	typedef enum 
+    // WARNING:  this MUST match the LL_PART_BF enum in LLPartData, so set values explicitly in case someone 
+    // decides to add more or reorder them
+	enum eBlendFactor : U8
 	{
 		BF_ONE = 0,
-		BF_ZERO,
-		BF_DEST_COLOR,
-		BF_SOURCE_COLOR,
-		BF_ONE_MINUS_DEST_COLOR,
-		BF_ONE_MINUS_SOURCE_COLOR,
-		BF_DEST_ALPHA,
-		BF_SOURCE_ALPHA,
-		BF_ONE_MINUS_DEST_ALPHA, 
-		BF_ONE_MINUS_SOURCE_ALPHA,
-
+		BF_ZERO = 1,
+		BF_DEST_COLOR = 2,
+		BF_SOURCE_COLOR = 3,
+		BF_ONE_MINUS_DEST_COLOR = 4,
+		BF_ONE_MINUS_SOURCE_COLOR = 5,
+		BF_DEST_ALPHA = 6,
+		BF_SOURCE_ALPHA = 7,
+		BF_ONE_MINUS_DEST_ALPHA = 8, 
+		BF_ONE_MINUS_SOURCE_ALPHA = 9,
 		BF_UNDEF
-	} eBlendFactor;
+	};
 
-	typedef enum
+	enum eMatrixMode : U8
 	{
 		MM_MODELVIEW = 0,
 		MM_PROJECTION,
@@ -355,7 +357,7 @@ class LLRender
 		MM_TEXTURE3,
 		NUM_MATRIX_MODES,
 		MM_TEXTURE
-	} eMatrixMode;
+	};
 
 	LLRender();
 	~LLRender();
diff --git a/indra/llrender/llrendernavprim.cpp b/indra/llrender/llrendernavprim.cpp
index ca729648327df6523bec73b41c438a510f8e8131..d610a44bc680c4462179af1d723cad84385f708a 100644
--- a/indra/llrender/llrendernavprim.cpp
+++ b/indra/llrender/llrendernavprim.cpp
@@ -53,7 +53,7 @@ void LLRenderNavPrim::renderLLTri( const LLVector3& a, const LLVector3& b, const
 //=============================================================================
 void LLRenderNavPrim::renderNavMeshVB( U32 mode, LLVertexBuffer* pVBO, int vertCnt )
 {	
-	pVBO->setBuffer( LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_NORMAL );
+	pVBO->setBuffer();
 	pVBO->drawArrays( mode, 0, vertCnt );	
 }
 //=============================================================================
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index b189e5452c834c203243bf31df1043a1e113bec5..ee8ac359c7e9988f9f153a72f76ab0c96b12acef 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -590,6 +590,7 @@ static std::string get_shader_log(GLuint ret)
 
 static std::string get_program_log(GLuint ret)
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
     std::string res;
 
     //get log length 
@@ -1113,16 +1114,24 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
 BOOL LLShaderMgr::linkProgramObject(GLuint obj, BOOL suppress_errors)
 {
 	//check for errors
-	glLinkProgram(obj);
-	GLint success = GL_TRUE;
-    glGetProgramiv(obj, GL_LINK_STATUS, &success);
-	if (!suppress_errors && success == GL_FALSE) 
-	{
-		//an error occured, print log
-		LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL;
-        dumpObjectLog(obj, TRUE, "linker");
-        return success;
-	}
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER("glLinkProgram");
+        glLinkProgram(obj);
+    }
+
+    GLint success = GL_TRUE;
+
+    {
+        LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER("glsl check link status");
+        glGetProgramiv(obj, GL_LINK_STATUS, &success);
+        if (!suppress_errors && success == GL_FALSE)
+        {
+            //an error occured, print log
+            LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL;
+            dumpObjectLog(obj, TRUE, "linker");
+            return success;
+        }
+    }
 
 	std::string log = get_program_log(obj);
 	LLStringUtil::toLower(log);
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index bc33591ed77c5b647c5ed12137c13c6e22cc4029..f1d71ec94d62fbbe7ec2cbd5ada1283919171ee1 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -70,25 +70,6 @@ struct CompareMappedRegion
     }
 };
 
-
-const U32 LL_VBO_BLOCK_SIZE = 2048;
-const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
-
-U32 vbo_block_size(U32 size)
-{ //what block size will fit size?
-	U32 mod = size % LL_VBO_BLOCK_SIZE;
-	return mod == 0 ? size : size + (LL_VBO_BLOCK_SIZE-mod);
-}
-
-U32 vbo_block_index(U32 size)
-{
-    U32 blocks = vbo_block_size(size)/LL_VBO_BLOCK_SIZE;   // block count reqd
-    llassert(blocks > 0);
-    return blocks - 1;  // Adj index, i.e. single-block allocations are at index 0, etc
-}
-
-const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE) + 1;
-
 #define ENABLE_GL_WORK_QUEUE 0
 
 #if ENABLE_GL_WORK_QUEUE
@@ -294,6 +275,8 @@ static GLuint gen_buffer()
     return sNamePool[--sIndex];
 }
 
+#define ANALYZE_VBO_POOL 0
+
 class LLVBOPool
 {
 public:
@@ -316,13 +299,42 @@ class LLVBOPool
     Pool mVBOPool;
     Pool mIBOPool;
 
-    U32 mMissCount = 0;
+    U32 mTouchCount = 0;
+
+#if ANALYZE_VBO_POOL
+    U64 mDistributed = 0;
+    U64 mAllocated = 0;
+    U64 mReserved = 0;
+    U32 mMisses = 0;
+    U32 mHits = 0;
+#endif
+
+    // increase the size to some common value (e.g. a power of two) to increase hit rate
+    void adjustSize(U32& size)
+    {
+        // size = nhpo2(size);  // (193/303)/580 MB (distributed/allocated)/reserved in VBO Pool. Overhead: 66 percent. Hit rate: 77 percent
+
+        //(245/276)/385 MB (distributed/allocated)/reserved in VBO Pool. Overhead: 57 percent. Hit rate: 69 percent
+        //(187/209)/397 MB (distributed/allocated)/reserved in VBO Pool. Overhead: 112 percent. Hit rate: 76 percent
+        U32 block_size = llmax(nhpo2(size) / 8, (U32) 16);
+        size += block_size - (size % block_size);
+    }
 
     void allocate(GLenum type, U32 size, GLuint& name, U8*& data)
     {
         LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
-        size = nhpo2(size);
+        llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
+        llassert(name == 0); // non zero name indicates a gl name that wasn't freed
+        llassert(data == nullptr);  // non null data indicates a buffer that wasn't freed
+        llassert(size >= 2);  // any buffer size smaller than a single index is nonsensical
+
+#if ANALYZE_VBO_POOL
+        mDistributed += size;
+        adjustSize(size);
+        mAllocated += size;
+#else
+        adjustSize(size);
+#endif
 
         auto& pool = type == GL_ELEMENT_ARRAY_BUFFER ? mIBOPool : mVBOPool;
 
@@ -332,13 +344,9 @@ class LLVBOPool
             LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vbo pool miss");
             LL_PROFILE_GPU_ZONE("vbo alloc");
 
-            ++mMissCount;
-            if (mMissCount > 1024)
-            { //clean cache on every 1024 misses
-                mMissCount = 0;
-                clean();
-            }
-
+#if ANALYZE_VBO_POOL
+            mMisses++;
+#endif
             name = gen_buffer();
             glBindBuffer(type, name);
             glBufferData(type, size, nullptr, GL_DYNAMIC_DRAW);
@@ -355,22 +363,47 @@ class LLVBOPool
         }
         else
         {
+#if ANALYZE_VBO_POOL
+            mHits++;
+            llassert(mReserved >= size); // assert if accounting gets messed up
+            mReserved -= size;
+#endif
+
             std::list<Entry>& entries = iter->second;
             Entry& entry = entries.back();
             name = entry.mGLName;
             data = entry.mData;
-
+            
             entries.pop_back();
             if (entries.empty())
             {
                 pool.erase(iter);
             }
         }
+
+        clean();
     }
 
     void free(GLenum type, U32 size, GLuint name, U8* data)
     {
-        size = nhpo2(size);
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+        llassert(type == GL_ARRAY_BUFFER || type == GL_ELEMENT_ARRAY_BUFFER);
+        llassert(size >= 2);
+        llassert(name != 0);
+        llassert(data != nullptr);
+
+        clean();
+
+#if ANALYZE_VBO_POOL
+        llassert(mDistributed >= size);
+        mDistributed -= size;
+        adjustSize(size);
+        llassert(mAllocated >= size);
+        mAllocated -= size;
+        mReserved += size;
+#else
+        adjustSize(size);
+#endif
 
         auto& pool = type == GL_ELEMENT_ARRAY_BUFFER ? mIBOPool : mVBOPool;
 
@@ -386,10 +419,19 @@ class LLVBOPool
         {
             iter->second.push_front({ data, name, std::chrono::steady_clock::now() });
         }
+
     }
 
+    // clean periodically (clean gets called for every alloc/free)
     void clean()
     {
+        mTouchCount++;
+        if (mTouchCount < 1024) // clean every 1k touches
+        {
+            return;
+        }
+        mTouchCount = 0;
+
         LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 
         std::unordered_map<U32, std::list<Entry>>* pools[] = { &mVBOPool, &mIBOPool };
@@ -410,7 +452,12 @@ class LLVBOPool
                     auto& entry = entries.back();
                     ll_aligned_free_16(entry.mData);
                     glDeleteBuffers(1, &entry.mGLName);
+#if ANALYZE_VBO_POOL
+                    llassert(mReserved >= iter->first);
+                    mReserved -= iter->first;
+#endif
                     entries.pop_back();
+
                 }
 
                 if (entries.empty())
@@ -423,6 +470,16 @@ class LLVBOPool
                 }
             }
         }
+
+#if ANALYZE_VBO_POOL
+        LL_INFOS() << llformat("(%d/%d)/%d MB (distributed/allocated)/total in VBO Pool. Overhead: %d percent. Hit rate: %d percent", 
+            mDistributed / 1000000, 
+            mAllocated / 1000000, 
+            (mAllocated + mReserved) / 1000000, // total bytes
+            ((mAllocated+mReserved-mDistributed)*100)/llmax(mDistributed, (U64) 1), // overhead percent
+            (mHits*100)/llmax(mMisses+mHits, (U32)1)) // hit rate percent
+            << LL_ENDL;
+#endif
     }
 
     void clear()
@@ -445,6 +502,10 @@ class LLVBOPool
             }
         }
 
+#if ANALYZE_VBO_POOL
+        mReserved = 0;
+#endif
+
         mIBOPool.clear();
         mVBOPool.clear();
     }
@@ -457,35 +518,14 @@ static LLVBOPool* sVBOPool = nullptr;
 //============================================================================
 // 
 //static
-std::list<U32> LLVertexBuffer::sAvailableVAOName;
-U32 LLVertexBuffer::sCurVAOName = 1;
-
-U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
-U32 LLVertexBuffer::sIndexCount = 0;
-
-U32 LLVertexBuffer::sBindCount = 0;
-U32 LLVertexBuffer::sSetCount = 0;
-S32 LLVertexBuffer::sCount = 0;
-S32 LLVertexBuffer::sGLCount = 0;
-S32 LLVertexBuffer::sMappedCount = 0;
-bool LLVertexBuffer::sDisableVBOMapping = false;
-bool LLVertexBuffer::sEnableVBOs = true;
 U32 LLVertexBuffer::sGLRenderBuffer = 0;
-U32 LLVertexBuffer::sGLRenderArray = 0;
 U32 LLVertexBuffer::sGLRenderIndices = 0;
 U32 LLVertexBuffer::sLastMask = 0;
-bool LLVertexBuffer::sVBOActive = false;
-bool LLVertexBuffer::sIBOActive = false;
-U32 LLVertexBuffer::sAllocatedBytes = 0;
 U32 LLVertexBuffer::sVertexCount = 0;
-bool LLVertexBuffer::sMapped = false;
-bool LLVertexBuffer::sUseStreamDraw = true;
-bool LLVertexBuffer::sUseVAO = false;
-bool LLVertexBuffer::sPreferStreamDraw = false;
 
 
 //NOTE: each component must be AT LEAST 4 bytes in size to avoid a performance penalty on AMD hardware
-const S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
+const U32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
 {
 	sizeof(LLVector4), // TYPE_VERTEX,
 	sizeof(LLVector4), // TYPE_NORMAL,
@@ -534,62 +574,34 @@ const U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
 };
 
 //static
-U32 LLVertexBuffer::getVAOName()
-{
-	U32 ret = 0;
-
-	if (!sAvailableVAOName.empty())
-	{
-		ret = sAvailableVAOName.front();
-		sAvailableVAOName.pop_front();
-	}
-	else
-	{
-#ifdef GL_ARB_vertex_array_object
-		glGenVertexArrays(1, &ret);
-#endif
-	}
-
-	return ret;		
-}
-
-//static
-void LLVertexBuffer::releaseVAOName(U32 name)
+void LLVertexBuffer::setupClientArrays(U32 data_mask)
 {
-	sAvailableVAOName.push_back(name);
-}
+    if (sLastMask != data_mask)
+    {
+        for (U32 i = 0; i < TYPE_MAX; ++i)
+        {
+            S32 loc = i;
 
+            U32 mask = 1 << i;
 
-//static
-void LLVertexBuffer::setupClientArrays(U32 data_mask)
-{
-	if (sLastMask != data_mask)
-	{
+            if (sLastMask & (1 << i))
+            { //was enabled
+                if (!(data_mask & mask))
+                { //needs to be disabled
+                    glDisableVertexAttribArray(loc);
+                }
+            }
+            else
+            {	//was disabled
+                if (data_mask & mask)
+                { //needs to be enabled
+                    glEnableVertexAttribArray(loc);
+                }
+            }
+        }
+    }
 
-		for (U32 i = 0; i < TYPE_MAX; ++i)
-		{
-			S32 loc = i;
-										
-			U32 mask = 1 << i;
-
-			if (sLastMask & (1 << i))
-			{ //was enabled
-				if (!(data_mask & mask))
-				{ //needs to be disabled
-					glDisableVertexAttribArray(loc);
-				}
-			}
-			else 
-			{	//was disabled
-				if (data_mask & mask)
-				{ //needs to be enabled
-					glEnableVertexAttribArray(loc);
-				}
-			}
-		}
-				
-		sLastMask = data_mask;
-	}
+    sLastMask = data_mask;
 }
 
 //static
@@ -606,7 +618,7 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 }
 
 //static
-void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
+void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, U32 num_indices, const U16* indicesp)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
 	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
@@ -644,8 +656,13 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
     gGL.flush();
 }
 
-void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
+bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
 {
+    if (!gDebugGL)
+    {
+        return true;
+    }
+
     llassert(start < (U32)mNumVerts);
     llassert(end < (U32)mNumVerts);
 
@@ -663,9 +680,8 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
 		LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << LL_ENDL;
 	}
 
-	if (gDebugGL && !useVBOs())
 	{
-		U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+		U16* idx = (U16*) mMappedIndexData+indices_offset;
 		for (U32 i = 0; i < count; ++i)
 		{
             llassert(idx[i] >= start);
@@ -681,22 +697,20 @@ void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
 
 		if (shader && shader->mFeatures.mIndexedTextureChannels > 1)
 		{
-			LLStrider<LLVector4a> v;
-			//hack to get non-const reference
-			LLVertexBuffer* vb = (LLVertexBuffer*) this;
-			vb->getVertexStrider(v);
-
+			LLVector4a* v = (LLVector4a*) mMappedData;
+			
 			for (U32 i = start; i < end; i++)
 			{
-				S32 idx = (S32) (v[i][3]+0.25f);
-                llassert(idx >= 0);
-				if (idx < 0 || idx >= shader->mFeatures.mIndexedTextureChannels)
+                U32 idx = (U32) (v[i][3]+0.25f);
+				if (idx >= shader->mFeatures.mIndexedTextureChannels)
 				{
 					LL_ERRS() << "Bad texture index found in vertex data stream." << LL_ENDL;
 				}
 			}
 		}
 	}
+
+    return true;
 }
 
 #ifdef LL_PROFILER_ENABLE_RENDER_DOC
@@ -707,124 +721,35 @@ void LLVertexBuffer::setLabel(const char* label) {
 
 void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
 {
-	validateRange(start, end, count, indices_offset);
-	gGL.syncMatrices();
-
-	llassert(mNumVerts >= 0);
-	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
-
-	if (mGLIndices != sGLRenderIndices)
-	{
-		LL_ERRS() << "Wrong index buffer bound." << LL_ENDL;
-	}
-
-	if (mGLBuffer != sGLRenderBuffer)
-	{
-		LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
-	}
-
-	if (gDebugGL && useVBOs())
-	{
-		GLint elem = 0;
-		glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &elem);
-
-		if (elem != mGLIndices)
-		{
-			LL_ERRS() << "Wrong index buffer bound!" << LL_ENDL;
-		}
-	}
-
-	if (mode >= LLRender::NUM_MODES)
-	{
-		LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
-		return;
-	}
-
-	U16* idx = ((U16*) getIndicesPointer())+indices_offset;
-
-	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
-		idx);
-}
-
-void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
-{
+    llassert(validateRange(start, end, count, indices_offset));
+    llassert(mGLBuffer == sGLRenderBuffer);
+    llassert(mGLIndices == sGLRenderIndices);
     gGL.syncMatrices();
 
-    U16* idx = ((U16*)getIndicesPointer()) + indices_offset;
-
-        glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
-            idx);
+    glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT,
+        (GLvoid*) (indices_offset * sizeof(U16)));
 }
 
 void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 {
-	llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
-	gGL.syncMatrices();
-
-	llassert(mNumIndices >= 0);
-	if (indices_offset >= (U32) mNumIndices ||
-	    indices_offset + count > (U32) mNumIndices)
-	{
-		LL_ERRS() << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << LL_ENDL;
-	}
-
-	
-	if (mGLIndices != sGLRenderIndices)
-	{
-		LL_ERRS() << "Wrong index buffer bound." << LL_ENDL;
-	}
-
-	if (mGLBuffer != sGLRenderBuffer)
-	{
-		LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
-	}
-
-	if (mode >= LLRender::NUM_MODES)
-	{
-		LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
-		return;
-	}
-
-    glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
-		((U16*) getIndicesPointer()) + indices_offset);
+    drawRange(mode, 0, mNumVerts, count, indices_offset);
 }
 
 
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-    llassert(LLGLSLShader::sCurBoundShaderPtr != NULL);
+    llassert(first + count <= mNumVerts);
+    llassert(mGLBuffer == sGLRenderBuffer);
+    llassert(mGLIndices == sGLRenderIndices);
+    
     gGL.syncMatrices();
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
-    llassert(mNumVerts >= 0);
-	if (first >= (U32) mNumVerts ||
-	    first + count > (U32) mNumVerts)
-    {
-		LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << LL_ENDL;
-    }
-
-    if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
-    {
-        LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
-    }
-
-    if (mode >= LLRender::NUM_MODES)
-    {
-        LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
-        return;
-    }
-#endif
-
     glDrawArrays(sGLMode[mode], first, count);
 }
 
 //static
 void LLVertexBuffer::initClass(LLWindow* window)
 {
-    sEnableVBOs = true;
-    sDisableVBOMapping = true;
-
+    llassert(sVBOPool == nullptr);
     sVBOPool = new LLVBOPool();
 
 #if ENABLE_GL_WORK_QUEUE
@@ -841,29 +766,11 @@ void LLVertexBuffer::initClass(LLWindow* window)
 //static 
 void LLVertexBuffer::unbind()
 {
-	if (sGLRenderArray)
-	{
-		glBindVertexArray(0);
-		sGLRenderArray = 0;
-		sGLRenderIndices = 0;
-		sIBOActive = false;
-	}
-
-	if (sVBOActive)
-	{
-		glBindBuffer(GL_ARRAY_BUFFER, 0);
-		sVBOActive = false;
-	}
-	if (sIBOActive)
-	{
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-		sIBOActive = false;
-	}
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
 	sGLRenderBuffer = 0;
 	sGLRenderIndices = 0;
-
-	setupClientArrays(0);
 }
 
 //static
@@ -886,67 +793,26 @@ void LLVertexBuffer::cleanupClass()
     delete sQueue;
     sQueue = nullptr;
 #endif
-
-    //llassert(0 == sAllocatedBytes);
-    //llassert(0 == sAllocatedIndexBytes);
 }
 
 //----------------------------------------------------------------------------
 
-S32 LLVertexBuffer::determineUsage(S32 usage)
-{
-	S32 ret_usage = usage;
-
-	if (!sEnableVBOs)
-	{
-		ret_usage = 0;
-	}
-	
-	if (ret_usage == GL_STREAM_DRAW && !sUseStreamDraw)
-	{
-		ret_usage = 0;
-	}
-	
-    // dynamic draw or nothing
-    ret_usage = GL_DYNAMIC_DRAW;
-	
-	return ret_usage;
-}
-
-LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) 
+LLVertexBuffer::LLVertexBuffer(U32 typemask) 
 :	LLRefCount(),
-
-	mNumVerts(0),
-	mNumIndices(0),
-	mSize(0),
-	mIndicesSize(0),
-	mTypeMask(typemask),
-	mUsage(LLVertexBuffer::determineUsage(usage)),
-	mGLBuffer(0),
-	mGLIndices(0),
-	mMappedData(NULL),
-	mMappedIndexData(NULL),
-	mMappedDataUsingVBOs(false),
-	mMappedIndexDataUsingVBOs(false),
-	mVertexLocked(false),
-	mIndexLocked(false),
-	mFinal(false),
-	mEmpty(true)
+	mTypeMask(typemask)
 {
 	//zero out offsets
 	for (U32 i = 0; i < TYPE_MAX; i++)
 	{
 		mOffsets[i] = 0;
 	}
-
-	sCount++;
 }
 
 //static
-S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
+U32 LLVertexBuffer::calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices)
 {
-	S32 offset = 0;
-	for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++)
+    U32 offset = 0;
+	for (U32 i=0; i<TYPE_TEXTURE_INDEX; i++)
 	{
 		U32 mask = 1<<i;
 		if (typemask & mask)
@@ -966,10 +832,10 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti
 }
 
 //static 
-S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
+U32 LLVertexBuffer::calcVertexSize(const U32& typemask)
 {
-	S32 size = 0;
-	for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
+    U32 size = 0;
+	for (U32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
 	{
 		U32 mask = 1<<i;
 		if (typemask & mask)
@@ -981,11 +847,6 @@ S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
 	return size;
 }
 
-S32 LLVertexBuffer::getSize() const
-{
-	return mSize;
-}
-
 // protected, use unref()
 //virtual
 LLVertexBuffer::~LLVertexBuffer()
@@ -993,11 +854,6 @@ LLVertexBuffer::~LLVertexBuffer()
 	destroyGLBuffer();
 	destroyGLIndices();
 
-	sCount--;
-
-	sVertexCount -= mNumVerts;
-	sIndexCount -= mNumIndices;
-
 	if (mMappedData)
 	{
 		LL_ERRS() << "Failed to clear vertex buffer's vertices" << LL_ENDL;
@@ -1013,57 +869,32 @@ LLVertexBuffer::~LLVertexBuffer()
 void LLVertexBuffer::genBuffer(U32 size)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
-    mSize = size;
+    llassert(sVBOPool);
 
     if (sVBOPool)
     {
-        sVBOPool->allocate(GL_ARRAY_BUFFER, size, mGLBuffer, mMappedData);
-    }
-    
-    sGLCount++;
-}
-
-void LLVertexBuffer::genIndices(U32 size)
-{
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
-    mIndicesSize = size;
+        llassert(mSize == 0);
+        llassert(mGLBuffer == 0);
+        llassert(mMappedData == nullptr);
 
-    if (sVBOPool)
-    {
-        sVBOPool->allocate(GL_ELEMENT_ARRAY_BUFFER, size, mGLIndices, mMappedIndexData);
+        mSize = size;
+        sVBOPool->allocate(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData);
     }
-	sGLCount++;
 }
 
-void LLVertexBuffer::releaseBuffer()
+void LLVertexBuffer::genIndices(U32 size)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+    llassert(sVBOPool);
 
     if (sVBOPool)
     {
-        sVBOPool->free(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData);
-    }
-
-    mGLBuffer = 0;
-    mMappedData = nullptr;
-	
-	sGLCount--;
-}
-
-void LLVertexBuffer::releaseIndices()
-{
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-    
-    if (sVBOPool)
-    {
-        sVBOPool->free(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData);
+        llassert(mIndicesSize == 0);
+        llassert(mGLIndices == 0);
+        llassert(mMappedIndexData == nullptr);
+        mIndicesSize = size;
+        sVBOPool->allocate(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData);
     }
-
-    mMappedIndexData = nullptr;
-
-	sGLCount--;
 }
 
 bool LLVertexBuffer::createGLBuffer(U32 size)
@@ -1080,23 +911,8 @@ bool LLVertexBuffer::createGLBuffer(U32 size)
 
 	bool success = true;
 
-	mEmpty = true;
-
-	mMappedDataUsingVBOs = useVBOs();
+	genBuffer(size);
 	
-	if (mMappedDataUsingVBOs)
-	{
-		genBuffer(size);
-	}
-	else
-	{
-		static int gl_buffer_idx = 0;
-		mGLBuffer = ++gl_buffer_idx;
-
-		mMappedData = (U8*)ll_aligned_malloc_16(size);
-		mSize = size;
-	}
-
 	if (!mMappedData)
 	{
 		success = false;
@@ -1118,27 +934,8 @@ bool LLVertexBuffer::createGLIndices(U32 size)
 
 	bool success = true;
 
-	mEmpty = true;
-
-	//pad by 16 bytes for aligned copies
-	size += 16;
-
-	mMappedIndexDataUsingVBOs = useVBOs();
-
-	if (mMappedIndexDataUsingVBOs)
-	{
-		//pad by another 16 bytes for VBO pointer adjustment
-		size += 16;
-		genIndices(size);
-	}
-	else
-	{
-		mMappedIndexData = (U8*)ll_aligned_malloc_16(size);
-		static int gl_buffer_idx = 0;
-		mGLIndices = ++gl_buffer_idx;
-		mIndicesSize = size;
-	}
-
+	genIndices(size);
+	
 	if (!mMappedIndexData)
 	{
 		success = false;
@@ -1150,43 +947,37 @@ void LLVertexBuffer::destroyGLBuffer()
 {
 	if (mGLBuffer || mMappedData)
 	{
-		if (mMappedDataUsingVBOs)
-		{
-			releaseBuffer();
-		}
-		else
-		{
-			ll_aligned_free_16((void*)mMappedData);
-			mMappedData = NULL;
-			mEmpty = true;
-		}
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+        //llassert(sVBOPool);
+        if (sVBOPool)
+        {
+            sVBOPool->free(GL_ARRAY_BUFFER, mSize, mGLBuffer, mMappedData);
+        }
+
+        mSize = 0;
+        mGLBuffer = 0;
+        mMappedData = nullptr;
 	}
-	
-	mGLBuffer = 0;
-	//unbind();
 }
 
 void LLVertexBuffer::destroyGLIndices()
 {
 	if (mGLIndices || mMappedIndexData)
 	{
-		if (mMappedIndexDataUsingVBOs)
-		{
-			releaseIndices();
-		}
-		else
-		{
-			ll_aligned_free_16((void*)mMappedIndexData);
-			mMappedIndexData = NULL;
-			mEmpty = true;
-		}
-	}
+        LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
+        //llassert(sVBOPool);
+        if (sVBOPool)
+        {
+            sVBOPool->free(GL_ELEMENT_ARRAY_BUFFER, mIndicesSize, mGLIndices, mMappedIndexData);
+        }
 
-	mGLIndices = 0;
-	//unbind();
+        mIndicesSize = 0;
+        mGLIndices = 0;
+        mMappedIndexData = nullptr;
+	}
 }
 
-bool LLVertexBuffer::updateNumVerts(S32 nverts)
+bool LLVertexBuffer::updateNumVerts(U32 nverts)
 {
 	llassert(nverts >= 0);
 
@@ -1200,19 +991,17 @@ bool LLVertexBuffer::updateNumVerts(S32 nverts)
 
 	U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
 
-	if (needed_size > mSize || needed_size <= mSize/2)
-	{
-		success &= createGLBuffer(needed_size);
-	}
+    if (needed_size != mSize)
+    {
+        success &= createGLBuffer(needed_size);
+    }
 
-	sVertexCount -= mNumVerts;
+    llassert(mSize == needed_size);
 	mNumVerts = nverts;
-	sVertexCount += mNumVerts;
-
 	return success;
 }
 
-bool LLVertexBuffer::updateNumIndices(S32 nindices)
+bool LLVertexBuffer::updateNumIndices(U32 nindices)
 {
 	llassert(nindices >= 0);
 
@@ -1220,22 +1009,18 @@ bool LLVertexBuffer::updateNumIndices(S32 nindices)
 
 	U32 needed_size = sizeof(U16) * nindices;
 
-	if (needed_size > mIndicesSize || needed_size <= mIndicesSize/2)
+	if (needed_size != mIndicesSize)
 	{
 		success &= createGLIndices(needed_size);
 	}
 
-	sIndexCount -= mNumIndices;
+    llassert(mIndicesSize == needed_size);
 	mNumIndices = nindices;
-	sIndexCount += mNumIndices;
-
 	return success;
 }
 
-bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
+bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices)
 {
-	stop_glerror();
-
 	if (nverts < 0 || nindices < 0 ||
 		nverts > 65536)
 	{
@@ -1247,44 +1032,14 @@ bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 	success &= updateNumVerts(nverts);
 	success &= updateNumIndices(nindices);
 	
-	if (create && (nverts || nindices))
-	{
-		//actually allocate space for the vertex buffer if using VBO mapping
-		flush(); //unmap
-	}
-
 	return success;
 }
 
-bool LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
-{
-	llassert(newnverts >= 0);
-	llassert(newnindices >= 0);
-
-	bool success = true;
-
-	success &= updateNumVerts(newnverts);		
-	success &= updateNumIndices(newnindices);
-	
-	if (useVBOs())
-	{
-		flush(); //unmap
-	}
-
-	return success;
-}
-
-bool LLVertexBuffer::useVBOs() const
-{
-	//it's generally ineffective to use VBO for things that are streaming on apple
-	return (mUsage != 0);
-}
-
 //----------------------------------------------------------------------------
 
 // if no gap between region and given range exists, expand region to cover given range and return true
 // otherwise return false
-bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end)
+bool expand_region(LLVertexBuffer::MappedRegion& region, U32 start, U32 end)
 {
 	
 	if (end < region.mStart ||
@@ -1301,152 +1056,79 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end)
 
 
 // Map for data access
-U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapVertexBuffer(LLVertexBuffer::AttributeType type, U32 index, S32 count)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-	if (mFinal)
-	{
-		LL_ERRS() << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << LL_ENDL;
-	}
-	if (!useVBOs() && !mMappedData && !mMappedIndexData)
-	{
-		LL_ERRS() << "LLVertexBuffer::mapVertexBuffer() called on unallocated buffer." << LL_ENDL;
-	}
+	
+    if (count == -1)
+    {
+        count = mNumVerts - index;
+    }
 
+    U32 start = mOffsets[type] + sTypeSize[type] * index;
+    U32 end = start + sTypeSize[type] * count-1;
 
-    if (useVBOs())
-    {
-        if (count == -1)
+	bool flagged = false;
+	// flag region as mapped
+	for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
+	{
+		MappedRegion& region = mMappedVertexRegions[i];
+        if (expand_region(region, start, end))
         {
-            count = mNumVerts - index;
+            flagged = true;
+            break;
         }
-
-        S32 start = mOffsets[type] + sTypeSize[type] * index;
-        S32 end = start + sTypeSize[type] * count;
-
-		bool flagged = false;
-		// flag region as mapped
-		for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
-		{
-			MappedRegion& region = mMappedVertexRegions[i];
-            if (expand_region(region, start, end))
-            {
-                flagged = true;
-                break;
-            }
-		}
-
-		if (!flagged)
-		{
-			//didn't expand an existing region, make a new one
-            mMappedVertexRegions.push_back({ start, end });
-		}
-
-		if (mVertexLocked && map_range)
-		{
-			LL_ERRS() << "Attempted to map a specific range of a buffer that was already mapped." << LL_ENDL;
-		}
-
-		if (!mVertexLocked)
-		{
-			mVertexLocked = true;
-			sMappedCount++;
-			stop_glerror();	
-
-			map_range = false;
-				
-			if (!mMappedData)
-			{
-				log_glerror();
-
-				//check the availability of memory
-				LLMemory::logMemoryInfo(true);
-				
-				LL_ERRS() << "memory allocation for vertex data failed." << LL_ENDL;
-
-			}
-		}
 	}
-	else
+
+	if (!flagged)
 	{
-		map_range = false;
+		//didn't expand an existing region, make a new one
+        mMappedVertexRegions.push_back({ start, end });
 	}
 	
     return mMappedData+mOffsets[type]+sTypeSize[type]*index;
 }
 
 
-U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)
+U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-	if (mFinal)
-	{
-		LL_ERRS() << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << LL_ENDL;
-	}
-	if (!useVBOs() && !mMappedData && !mMappedIndexData)
+	
+	if (count == -1)
 	{
-		LL_ERRS() << "LLVertexBuffer::mapIndexBuffer() called on unallocated buffer." << LL_ENDL;
+		count = mNumIndices-index;
 	}
 
-	if (useVBOs())
-	{
-		if (count == -1)
-		{
-			count = mNumIndices-index;
-		}
-
-        S32 start = sizeof(U16) * index;
-        S32 end = start + sizeof(U16) * count;
-
-        bool flagged = false;
-        // flag region as mapped
-        for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
-        {
-            MappedRegion& region = mMappedIndexRegions[i];
-            if (expand_region(region, start, end))
-            {
-                flagged = true;
-                break;
-            }
-        }
+    U32 start = sizeof(U16) * index;
+    U32 end = start + sizeof(U16) * count-1;
 
-        if (!flagged)
+    bool flagged = false;
+    // flag region as mapped
+    for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+    {
+        MappedRegion& region = mMappedIndexRegions[i];
+        if (expand_region(region, start, end))
         {
-            //didn't expand an existing region, make a new one
-            mMappedIndexRegions.push_back({ start, end });
+            flagged = true;
+            break;
         }
+    }
 
-		if (mIndexLocked && map_range)
-		{
-			LL_ERRS() << "Attempted to map a specific range of a buffer that was already mapped." << LL_ENDL;
-		}
-
-		if (!mIndexLocked)
-		{
-			mIndexLocked = true;
-			sMappedCount++;
-			stop_glerror();	
-
-			map_range = false;
-		}
-
-		if (!mMappedIndexData)
-		{
-			log_glerror();
-			LLMemory::logMemoryInfo(true);
-
-			LL_ERRS() << "memory allocation for Index data failed. " << LL_ENDL;
-		}
-	}
-	else
-	{
-		map_range = false;
-	}
+    if (!flagged)
+    {
+        //didn't expand an existing region, make a new one
+        mMappedIndexRegions.push_back({ start, end });
+    }
 
     return mMappedIndexData + sizeof(U16)*index;
 }
 
-static void flush_vbo(GLenum target, S32 start, S32 end, void* data)
+// flush the given byte range
+//  target -- "targret" parameter for glBufferSubData
+//  start -- first byte to copy
+//  end -- last byte to copy (NOT last byte + 1)
+//  data -- mMappedData or mMappedIndexData
+static void flush_vbo(GLenum target, U32 start, U32 end, void* data)
 {
     if (end != 0)
     {
@@ -1455,122 +1137,109 @@ static void flush_vbo(GLenum target, S32 start, S32 end, void* data)
         LL_PROFILE_ZONE_NUM(end);
         LL_PROFILE_ZONE_NUM(end-start);
 
-        constexpr S32 block_size = 65536;
+        constexpr U32 block_size = 8192;
 
-        for (S32 i = start; i < end; i += block_size)
+        for (U32 i = start; i <= end; i += block_size)
         {
             LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("glBufferSubData block");
-            LL_PROFILE_GPU_ZONE("glBufferSubData");
-            S32 tend = llmin(i + block_size, end);
-            glBufferSubData(target, i, tend - i, (U8*) data + (i-start));
+            //LL_PROFILE_GPU_ZONE("glBufferSubData");
+            U32 tend = llmin(i + block_size, end);
+            glBufferSubData(target, i, tend - i+1, (U8*) data + (i-start));
         }
     }
 }
 
 void LLVertexBuffer::unmapBuffer()
 {
-	if (!useVBOs())
-	{
-		return; //nothing to unmap
-	}
+    struct SortMappedRegion
+    {
+        bool operator()(const MappedRegion& lhs, const MappedRegion& rhs)
+        {
+            return lhs.mStart < rhs.mStart;
+        }
+    };
 
-	bool updated_all = false;
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-	if (mMappedData && mVertexLocked)
+	if (!mMappedVertexRegions.empty())
 	{
         LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex");
-		bindGLBuffer(true);
-		updated_all = mIndexLocked; //both vertex and index buffers done updating
-
-		if (!mMappedVertexRegions.empty())
-		{
-            S32 start = 0;
-            S32 end = 0;
-
-			for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
-			{
-				const MappedRegion& region = mMappedVertexRegions[i];
-                if (region.mStart == end + 1)
-                {
-                    end = region.mEnd;
-                }
-                else
-                {
-                    flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
-                    start = region.mStart;
-                    end = region.mEnd;
-                }
-			}
+        if (sGLRenderBuffer != mGLBuffer)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
+            sGLRenderBuffer = mGLBuffer;
+        }
+            
+        U32 start = 0;
+        U32 end = 0;
 
-            flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
+        std::sort(mMappedVertexRegions.begin(), mMappedVertexRegions.end(), SortMappedRegion());
 
-			mMappedVertexRegions.clear();
-		}
-		else
+		for (U32 i = 0; i < mMappedVertexRegions.size(); ++i)
 		{
-            llassert(false); // this shouldn't happen -- a buffer must always be explicitly mapped
+			const MappedRegion& region = mMappedVertexRegions[i];
+            if (region.mStart == end + 1)
+            {
+                end = region.mEnd;
+            }
+            else
+            {
+                flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
+                start = region.mStart;
+                end = region.mEnd;
+            }
 		}
-		
-		mVertexLocked = false;
-		sMappedCount--;
+
+        flush_vbo(GL_ARRAY_BUFFER, start, end, (U8*)mMappedData + start);
+
+		mMappedVertexRegions.clear();
 	}
 	
-	if (mMappedIndexData && mIndexLocked)
+	if (!mMappedIndexRegions.empty())
 	{
         LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index");
-		bindGLIndices();
-		
-		if (!mMappedIndexRegions.empty())
-		{
-            S32 start = 0;
-            S32 end = 0;
 
-            for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+        if (mGLIndices != sGLRenderIndices)
+        {
+            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
+            sGLRenderIndices = mGLIndices;
+        }
+        U32 start = 0;
+        U32 end = 0;
+
+        std::sort(mMappedIndexRegions.begin(), mMappedIndexRegions.end(), SortMappedRegion());
+
+        for (U32 i = 0; i < mMappedIndexRegions.size(); ++i)
+        {
+            const MappedRegion& region = mMappedIndexRegions[i];
+            if (region.mStart == end + 1)
             {
-                const MappedRegion& region = mMappedIndexRegions[i];
-                if (region.mStart == end + 1)
-                {
-                    end = region.mEnd;
-                }
-                else
-                {
-                    flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
-                    start = region.mStart;
-                    end = region.mEnd;
-                }
+                end = region.mEnd;
             }
+            else
+            {
+                flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
+                start = region.mStart;
+                end = region.mEnd;
+            }
+        }
 
-            flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
-
-			mMappedIndexRegions.clear();
-		}
-		else
-		{
-            llassert(false); // this shouldn't happen -- a buffer must always be explicitly mapped
-		}
-		
-		mIndexLocked = false;
-		sMappedCount--;
-	}
+        flush_vbo(GL_ELEMENT_ARRAY_BUFFER, start, end, (U8*)mMappedIndexData + start);
 
-	if(updated_all)
-	{
-		mEmpty = false;
+		mMappedIndexRegions.clear();
 	}
 }
 
 //----------------------------------------------------------------------------
 
-template <class T,S32 type> struct VertexBufferStrider
+template <class T,LLVertexBuffer::AttributeType type> struct VertexBufferStrider
 {
 	typedef LLStrider<T> strider_t;
 	static bool get(LLVertexBuffer& vbo, 
 					strider_t& strider, 
-					S32 index, S32 count, bool map_range)
+					S32 index, S32 count)
 	{
 		if (type == LLVertexBuffer::TYPE_INDEX)
 		{
-			U8* ptr = vbo.mapIndexBuffer(index, count, map_range);
+			U8* ptr = vbo.mapIndexBuffer(index, count);
 
 			if (ptr == NULL)
 			{
@@ -1584,9 +1253,9 @@ template <class T,S32 type> struct VertexBufferStrider
 		}
 		else if (vbo.hasDataType(type))
 		{
-			S32 stride = LLVertexBuffer::sTypeSize[type];
+            U32 stride = LLVertexBuffer::sTypeSize[type];
 
-			U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range);
+			U8* ptr = vbo.mapVertexBuffer(type, index, count);
 
 			if (ptr == NULL)
 			{
@@ -1606,500 +1275,157 @@ template <class T,S32 type> struct VertexBufferStrider
 	}
 };
 
-bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector3,TYPE_VERTEX>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector4a,TYPE_VERTEX>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getIndexStrider(LLStrider<U16>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<U16,TYPE_INDEX>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD0>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLColor4U,TYPE_COLOR>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getEmissiveStrider(LLStrider<LLColor4U>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLColor4U,TYPE_EMISSIVE>::get(*this, strider, index, count);
 }
-bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index, count);
 }
 
-bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index, count);
 }
 
-bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index, S32 count)
 {
-	return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index, count);
 }
 
 //----------------------------------------------------------------------------
 
-bool LLVertexBuffer::bindGLBuffer(bool force_bind)
+
+// Set for rendering
+void LLVertexBuffer::setBuffer()
 {
-	bool ret = false;
+    // no data may be pending
+    llassert(mMappedVertexRegions.empty());
+    llassert(mMappedIndexRegions.empty());
 
-	if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))))
-	{
-        LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-		glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
-		sGLRenderBuffer = mGLBuffer;
-		sBindCount++;
-		sVBOActive = true;
-		ret = true;
-	}
+    // a shader must be bound
+    llassert(LLGLSLShader::sCurBoundShaderPtr);
 
-	return ret;
-}
+    U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
 
-bool LLVertexBuffer::bindGLBufferFast()
-{
-    if (mGLBuffer != sGLRenderBuffer || !sVBOActive)
+    // this Vertex Buffer must provide all necessary attributes for currently bound shader
+    llassert(((~data_mask & mTypeMask) > 0) || (mTypeMask == data_mask));
+
+    if (sGLRenderBuffer != mGLBuffer)
     {
         glBindBuffer(GL_ARRAY_BUFFER, mGLBuffer);
         sGLRenderBuffer = mGLBuffer;
-        sBindCount++;
-        sVBOActive = true;
 
-        return true;
-    }
-
-    return false;
-}
-
-bool LLVertexBuffer::bindGLIndices(bool force_bind)
-{
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX;
-
-    bool ret = false;
-	if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive))))
-	{
-		/*if (sMapped)
-		{
-			LL_ERRS() << "VBO bound while another VBO mapped!" << LL_ENDL;
-		}*/
-		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
-		sGLRenderIndices = mGLIndices;
-		stop_glerror();
-		sBindCount++;
-		sIBOActive = true;
-		ret = true;
-	}
-
-	return ret;
-}
-
-bool LLVertexBuffer::bindGLIndicesFast()
-{
-    if (mGLIndices != sGLRenderIndices || !sIBOActive)
-    {
-        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
-        sGLRenderIndices = mGLIndices;
-        sBindCount++;
-        sIBOActive = true;
-        
-        return true;
+        setupVertexBuffer();
     }
-
-    return false;
-}
-
-void LLVertexBuffer::flush(bool discard)
-{
-	if (useVBOs())
-	{
-        unmapBuffer();
-	}
-}
-
-// bind for transform feedback (quick 'n dirty)
-void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count)
-{
-#ifdef GL_TRANSFORM_FEEDBACK_BUFFER
-	U32 offset = mOffsets[type] + sTypeSize[type]*index;
-	U32 size= (sTypeSize[type]*count);
-	glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size);
-#endif
-}
-
-// Set for rendering
-void LLVertexBuffer::setBuffer(U32 data_mask)
-{
-	flush();
-
-	//set up pointers if the data mask is different ...
-	bool setup = (sLastMask != data_mask);
-
-	if (gDebugGL && data_mask != 0)
-	{ //make sure data requirements are fulfilled
-		LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-		if (shader)
-		{
-			U32 required_mask = 0;
-			for (U32 i = 0; i < LLVertexBuffer::TYPE_TEXTURE_INDEX; ++i)
-			{
-				if (shader->getAttribLocation(i) > -1)
-				{
-					U32 required = 1 << i;
-					if ((data_mask & required) == 0)
-					{
-						LL_WARNS() << "Missing attribute: " << LLShaderMgr::instance()->mReservedAttribs[i] << LL_ENDL;
-					}
-
-					required_mask |= required;
-				}
-			}
-
-			if ((data_mask & required_mask) != required_mask)
-			{
-				
-				U32 unsatisfied_mask = (required_mask & ~data_mask);
-
-                for (U32 i = 0; i < TYPE_MAX; i++)
-                {
-                    U32 unsatisfied_flag = unsatisfied_mask & (1 << i);
-                    switch (unsatisfied_flag)
-                    {
-                        case 0: break;
-                        case MAP_VERTEX: LL_INFOS() << "Missing vert pos" << LL_ENDL; break;
-                        case MAP_NORMAL: LL_INFOS() << "Missing normals" << LL_ENDL; break;
-                        case MAP_TEXCOORD0: LL_INFOS() << "Missing TC 0" << LL_ENDL; break;
-                        case MAP_TEXCOORD1: LL_INFOS() << "Missing TC 1" << LL_ENDL; break;
-                        case MAP_TEXCOORD2: LL_INFOS() << "Missing TC 2" << LL_ENDL; break;
-                        case MAP_TEXCOORD3: LL_INFOS() << "Missing TC 3" << LL_ENDL; break;
-                        case MAP_COLOR: LL_INFOS() << "Missing vert color" << LL_ENDL; break;
-                        case MAP_EMISSIVE: LL_INFOS() << "Missing emissive" << LL_ENDL; break;
-                        case MAP_TANGENT: LL_INFOS() << "Missing tangent" << LL_ENDL; break;
-                        case MAP_WEIGHT: LL_INFOS() << "Missing weight" << LL_ENDL; break;
-                        case MAP_WEIGHT4: LL_INFOS() << "Missing weightx4" << LL_ENDL; break;
-                        case MAP_CLOTHWEIGHT: LL_INFOS() << "Missing clothweight" << LL_ENDL; break;
-                        case MAP_TEXTURE_INDEX: LL_INFOS() << "Missing tex index" << LL_ENDL; break;
-                        default: LL_INFOS() << "Missing who effin knows: " << unsatisfied_flag << LL_ENDL;
-                    }
-                }
-
-                // TYPE_INDEX is beyond TYPE_MAX, so check for it individually
-                if (unsatisfied_mask & (1 << TYPE_INDEX))
-                {
-                   LL_INFOS() << "Missing indices" << LL_ENDL;
-                }
-
-				LL_ERRS() << "Shader consumption mismatches data provision." << LL_ENDL;
-			}
-		}
-	}
-
-	if (useVBOs())
-	{
-		const bool bindBuffer = bindGLBuffer();
-		const bool bindIndices = bindGLIndices();
-			
-		setup = setup || bindBuffer || bindIndices;
-
-		if (gDebugGL)
-		{
-			GLint buff;
-			glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buff);
-			if ((GLuint)buff != mGLBuffer)
-			{
-				if (gDebugSession)
-				{
-					gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl;
-				}
-				else
-				{
-					LL_ERRS() << "Invalid GL vertex buffer bound: " << buff << LL_ENDL;
-				}
-			}
-
-			if (mGLIndices)
-			{
-				glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buff);
-				if ((GLuint)buff != mGLIndices)
-				{
-					if (gDebugSession)
-					{
-						gFailLog << "Invalid GL index buffer bound: " << buff <<  std::endl;
-					}
-					else
-					{
-						LL_ERRS() << "Invalid GL index buffer bound: " << buff << LL_ENDL;
-					}
-				}
-			}
-		}
-
-		
-	}
-	else
-	{	
-		if (sGLRenderArray)
-		{
-			glBindVertexArray(0);
-			sGLRenderArray = 0;
-			sGLRenderIndices = 0;
-			sIBOActive = false;
-		}
-
-		if (mGLBuffer)
-		{
-			if (sVBOActive)
-			{
-				glBindBuffer(GL_ARRAY_BUFFER, 0);
-				sBindCount++;
-				sVBOActive = false;
-				setup = true; // ... or a VBO is deactivated
-			}
-			if (sGLRenderBuffer != mGLBuffer)
-			{
-				sGLRenderBuffer = mGLBuffer;
-				setup = true; // ... or a client memory pointer changed
-			}
-		}
-		if (mGLIndices)
-		{
-			if (sIBOActive)
-			{
-				glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-				sBindCount++;
-				sIBOActive = false;
-			}
-			
-			sGLRenderIndices = mGLIndices;
-		}
-	}
-
-	setupClientArrays(data_mask);
-
-	if (mGLBuffer)
-	{
-		if (data_mask && setup)
-		{
-			setupVertexBuffer(data_mask); // subclass specific setup (virtual function)
-			sSetCount++;
-		}
-	}
-}
-
-void LLVertexBuffer::setBufferFast(U32 data_mask)
-{
-    if (useVBOs())
+    else if (sLastMask != data_mask)
     {
-        //set up pointers if the data mask is different ...
-        bool setup = (sLastMask != data_mask);
-
-        const bool bindBuffer = bindGLBufferFast();
-        const bool bindIndices = bindGLIndicesFast();
-
-        setup = setup || bindBuffer || bindIndices;
-        
-        setupClientArrays(data_mask);
-
-        if (data_mask && setup)
-        {
-            setupVertexBufferFast(data_mask);
-            sSetCount++;
-        }
+        setupVertexBuffer();
+        sLastMask = data_mask;
     }
-    else
+    
+    if (mGLIndices != sGLRenderIndices)
     {
-        //fallback to slow path when not using VBOs
-        setBuffer(data_mask);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mGLIndices);
+        sGLRenderIndices = mGLIndices;
     }
 }
 
 
 // virtual (default)
-void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
-{
-	stop_glerror();
-	U8* base = useVBOs() ? nullptr: mMappedData;
-
-	if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
-	{
-		for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i)
-		{
-			U32 mask = 1 << i;
-			if (mask & data_mask && !(mask & mTypeMask))
-			{ //bit set in data_mask, but not set in mTypeMask
-				LL_WARNS() << "Missing required component " << vb_type_name[i] << LL_ENDL;
-			}
-		}
-		LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL;
-	}
-
-	if (data_mask & MAP_NORMAL)
-	{
-		S32 loc = TYPE_NORMAL;
-		void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
-		glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
-	}
-	if (data_mask & MAP_TEXCOORD3)
-	{
-		S32 loc = TYPE_TEXCOORD3;
-		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
-		glVertexAttribPointer(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
-	}
-	if (data_mask & MAP_TEXCOORD2)
-	{
-		S32 loc = TYPE_TEXCOORD2;
-		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
-		glVertexAttribPointer(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
-	}
-	if (data_mask & MAP_TEXCOORD1)
-	{
-		S32 loc = TYPE_TEXCOORD1;
-		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
-		glVertexAttribPointer(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
-	}
-	if (data_mask & MAP_TANGENT)
-	{
-		S32 loc = TYPE_TANGENT;
-		void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
-		glVertexAttribPointer(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
-	}
-	if (data_mask & MAP_TEXCOORD0)
-	{
-		S32 loc = TYPE_TEXCOORD0;
-		void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
-		glVertexAttribPointer(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
-	}
-	if (data_mask & MAP_COLOR)
-	{
-		S32 loc = TYPE_COLOR;
-		//bind emissive instead of color pointer if emissive is present
-		void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
-		glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
-	}
-	if (data_mask & MAP_EMISSIVE)
-	{
-		S32 loc = TYPE_EMISSIVE;
-		void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
-		glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
-
-		if (!(data_mask & MAP_COLOR))
-		{ //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps
-			loc = TYPE_COLOR;
-			glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
-		}
-	}
-	if (data_mask & MAP_WEIGHT)
-	{
-		S32 loc = TYPE_WEIGHT;
-		void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
-		glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
-	}
-	if (data_mask & MAP_WEIGHT4)
-	{
-		S32 loc = TYPE_WEIGHT4;
-		void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
-		glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
-	}
-	if (data_mask & MAP_CLOTHWEIGHT)
-	{
-		S32 loc = TYPE_CLOTHWEIGHT;
-		void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
-		glVertexAttribPointer(loc, 4, GL_FLOAT, GL_TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
-	}
-	if (data_mask & MAP_TEXTURE_INDEX && 
-			(gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later
-	{
-		S32 loc = TYPE_TEXTURE_INDEX;
-		void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
-		glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
-	}
-	if (data_mask & MAP_VERTEX)
-	{
-		S32 loc = TYPE_VERTEX;
-		void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
-		glVertexAttribPointer(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
-	}	
-
-	llglassertok();
-	}	
-
-void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)
+void LLVertexBuffer::setupVertexBuffer()
 {
     U8* base = nullptr;
 
+    U32 data_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
+
     if (data_mask & MAP_NORMAL)
     {
-        S32 loc = TYPE_NORMAL;
+        AttributeType loc = TYPE_NORMAL;
         void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
         glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
     }
     if (data_mask & MAP_TEXCOORD3)
     {
-        S32 loc = TYPE_TEXCOORD3;
+        AttributeType loc = TYPE_TEXCOORD3;
         void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
         glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
     }
     if (data_mask & MAP_TEXCOORD2)
     {
-        S32 loc = TYPE_TEXCOORD2;
+        AttributeType loc = TYPE_TEXCOORD2;
         void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
         glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
     }
     if (data_mask & MAP_TEXCOORD1)
     {
-        S32 loc = TYPE_TEXCOORD1;
+        AttributeType loc = TYPE_TEXCOORD1;
         void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
         glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
     }
     if (data_mask & MAP_TANGENT)
     {
-        S32 loc = TYPE_TANGENT;
+        AttributeType loc = TYPE_TANGENT;
         void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
         glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
     }
     if (data_mask & MAP_TEXCOORD0)
     {
-        S32 loc = TYPE_TEXCOORD0;
+        AttributeType loc = TYPE_TEXCOORD0;
         void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
         glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
     }
     if (data_mask & MAP_COLOR)
     {
-        S32 loc = TYPE_COLOR;
+        AttributeType loc = TYPE_COLOR;
         //bind emissive instead of color pointer if emissive is present
         void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]);
         glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
     }
     if (data_mask & MAP_EMISSIVE)
     {
-        S32 loc = TYPE_EMISSIVE;
+        AttributeType loc = TYPE_EMISSIVE;
         void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
         glVertexAttribPointer(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
 
@@ -2111,31 +1437,31 @@ void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)
     }
     if (data_mask & MAP_WEIGHT)
     {
-        S32 loc = TYPE_WEIGHT;
+        AttributeType loc = TYPE_WEIGHT;
         void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
         glVertexAttribPointer(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
     }
     if (data_mask & MAP_WEIGHT4)
     {
-        S32 loc = TYPE_WEIGHT4;
+        AttributeType loc = TYPE_WEIGHT4;
         void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]);
         glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
     }
     if (data_mask & MAP_CLOTHWEIGHT)
     {
-        S32 loc = TYPE_CLOTHWEIGHT;
+        AttributeType loc = TYPE_CLOTHWEIGHT;
         void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
         glVertexAttribPointer(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
     }
     if (data_mask & MAP_TEXTURE_INDEX)
     {
-        S32 loc = TYPE_TEXTURE_INDEX;
+        AttributeType loc = TYPE_TEXTURE_INDEX;
         void* ptr = (void*)(base + mOffsets[TYPE_VERTEX] + 12);
         glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
     }
     if (data_mask & MAP_VERTEX)
     {
-        S32 loc = TYPE_VERTEX;
+        AttributeType loc = TYPE_VERTEX;
         void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);
         glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
     }
@@ -2143,20 +1469,20 @@ void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)
 
 void LLVertexBuffer::setPositionData(const LLVector4a* data)
 {
-    bindGLBuffer();
-    flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts(), (U8*) data);
+    llassert(sGLRenderBuffer == mGLBuffer);
+    flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data);
 }
 
 void LLVertexBuffer::setTexCoordData(const LLVector2* data)
 {
-    bindGLBuffer();
-    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts(), (U8*)data);
+    llassert(sGLRenderBuffer == mGLBuffer);
+    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data);
 }
 
 void LLVertexBuffer::setColorData(const LLColor4U* data)
 {
-    bindGLBuffer();
-    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts(), (U8*) data);
+    llassert(sGLRenderBuffer == mGLBuffer);
+    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data);
 }
 
 
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 926d37b0523278eff7b2d38b5f8f379c6952ddd2..571856f0138cc0fac0589a0e262a03fa087a4d7a 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -53,17 +53,16 @@
 //============================================================================
 // base class 
 class LLPrivateMemoryPool;
-class LLVertexBuffer : public LLRefCount
+class LLVertexBuffer final : public LLRefCount
 {
 public:
 	struct MappedRegion
 	{
-        S32 mStart;
-        S32 mEnd;
+        U32 mStart;
+        U32 mEnd;
 	};
 
 	LLVertexBuffer(const LLVertexBuffer& rhs)
-	:	mUsage(rhs.mUsage)
 	{
 		*this = rhs;
 	}
@@ -74,42 +73,31 @@ class LLVertexBuffer : public LLRefCount
 		return *this;
 	}
 
-	static std::list<U32> sAvailableVAOName;
-	static U32 sCurVAOName;
-
-	static bool	sUseStreamDraw;
-	static bool sUseVAO;
-	static bool	sPreferStreamDraw;
-
-	static U32 getVAOName();
-	static void releaseVAOName(U32 name);
-
 	static void initClass(LLWindow* window);
 	static void cleanupClass();
 	static void setupClientArrays(U32 data_mask);
 	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos);
-	static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
+	static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, U32 num_indices, const U16* indicesp);
 
  	static void unbind(); //unbind any bound vertex buffer
 
 	//get the size of a vertex with the given typemask
-	static S32 calcVertexSize(const U32& typemask);
+	static U32 calcVertexSize(const U32& typemask);
 
 	//get the size of a buffer with the given typemask and vertex count
 	//fill offsets with the offset of each vertex component array into the buffer
 	// indexed by the following enum
-	static S32 calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices);
+	static U32 calcOffsets(const U32& typemask, U32* offsets, U32 num_vertices);
 
 	//WARNING -- when updating these enums you MUST 
 	// 1 - update LLVertexBuffer::sTypeSize
     // 2 - update LLVertexBuffer::vb_type_name
 	// 3 - add a strider accessor
 	// 4 - modify LLVertexBuffer::setupVertexBuffer
-    // 5 - modify LLVertexBuffer::setupVertexBufferFast
 	// 6 - modify LLViewerShaderMgr::mReservedAttribs
 	
     // clang-format off
-    enum {                      // Shader attribute name, set in LLShaderMgr::initAttribsAndUniforms()
+    enum AttributeType {                      // Shader attribute name, set in LLShaderMgr::initAttribsAndUniforms()
         TYPE_VERTEX = 0,        //  "position"
         TYPE_NORMAL,            //  "normal"
         TYPE_TEXCOORD0,         //  "texcoord0"
@@ -147,45 +135,37 @@ class LLVertexBuffer : public LLRefCount
 protected:
 	friend class LLRender;
 
-	virtual ~LLVertexBuffer(); // use unref()
+	~LLVertexBuffer(); // use unref()
 
-	virtual void setupVertexBuffer(U32 data_mask);
-    void setupVertexBufferFast(U32 data_mask);
+	void setupVertexBuffer();
 
 	void	genBuffer(U32 size);
 	void	genIndices(U32 size);
-	bool	bindGLBuffer(bool force_bind = false);
-    bool	bindGLBufferFast();
-	bool	bindGLIndices(bool force_bind = false);
-    bool    bindGLIndicesFast();
-	void	releaseBuffer();
-	void	releaseIndices();
 	bool	createGLBuffer(U32 size);
 	bool	createGLIndices(U32 size);
 	void 	destroyGLBuffer();
 	void 	destroyGLIndices();
-	bool	updateNumVerts(S32 nverts);
-	bool	updateNumIndices(S32 nindices); 
-	void	unmapBuffer();
-		
+	bool	updateNumVerts(U32 nverts);
+	bool	updateNumIndices(U32 nindices); 
+
 public:
-	LLVertexBuffer(U32 typemask, S32 usage);
+	LLVertexBuffer(U32 typemask);
 	
-	// map for data access
-	U8*		mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
-	U8*		mapIndexBuffer(S32 index, S32 count, bool map_range);
+    // allocate buffer
+    bool	allocateBuffer(U32 nverts, U32 nindices);
 
-	void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
+	// map for data access (see also getFooStrider below)
+	U8*		mapVertexBuffer(AttributeType type, U32 index, S32 count = -1);
+	U8*		mapIndexBuffer(U32 index, S32 count = -1);
+    void	unmapBuffer();
 
 	// set for rendering
-	virtual void	setBuffer(U32 data_mask); 	// calls  setupVertexBuffer() if data_mask is not 0
-    void	setBufferFast(U32 data_mask); 	// calls setupVertexBufferFast(), assumes data_mask is not 0 among other assumptions
-
-    void flush(bool discard = false); //flush pending data to GL memory, if discard is true, discard previous VBO
-	// allocate buffer
-	bool	allocateBuffer(S32 nverts, S32 nindices, bool create);
-	virtual bool resizeBuffer(S32 newnverts, S32 newnindices);
-			
+    // assumes (and will assert on) the following:
+    //      - this buffer has no pending unampBuffer call
+    //      - a shader is currently bound
+    //      - This buffer has sufficient attributes within it to satisfy the needs of the currently bound shader
+	void	setBuffer();
+    		
 	// Only call each getVertexPointer, etc, once before calling unmapBuffer()
 	// call unmapBuffer() after calls to getXXXStrider() before any cals to setBuffer()
 	// example:
@@ -193,57 +173,49 @@ class LLVertexBuffer : public LLRefCount
 	//   vb->getNormalStrider(norms);
 	//   setVertsNorms(verts, norms);
 	//   vb->unmapBuffer();
-	bool getVertexStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getVertexStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getIndexStrider(LLStrider<U16>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getTangentStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getTangentStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-    bool getBasecolorTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-    bool getNormalTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-    bool getMetallicRoughnessTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-    bool getEmissiveTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+	bool getVertexStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
+	bool getVertexStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1);
+	bool getIndexStrider(LLStrider<U16>& strider, U32 index=0, S32 count = -1);
+	bool getTexCoord0Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+	bool getTexCoord1Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+	bool getTexCoord2Strider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+	bool getNormalStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
+	bool getTangentStrider(LLStrider<LLVector3>& strider, U32 index=0, S32 count = -1);
+	bool getTangentStrider(LLStrider<LLVector4a>& strider, U32 index=0, S32 count = -1);
+	bool getColorStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1);
+	bool getEmissiveStrider(LLStrider<LLColor4U>& strider, U32 index=0, S32 count = -1);
+	bool getWeightStrider(LLStrider<F32>& strider, U32 index=0, S32 count = -1);
+	bool getWeight4Strider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1);
+	bool getClothWeightStrider(LLStrider<LLVector4>& strider, U32 index=0, S32 count = -1);
+    bool getBasecolorTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+    bool getNormalTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+    bool getMetallicRoughnessTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
+    bool getEmissiveTexcoordStrider(LLStrider<LLVector2>& strider, U32 index=0, S32 count = -1);
 	
     void setPositionData(const LLVector4a* data);
     void setTexCoordData(const LLVector2* data);
     void setColorData(const LLColor4U* data);
 
 
-	bool useVBOs() const;
-	bool isEmpty() const					{ return mEmpty; }
-	bool isLocked() const					{ return mVertexLocked || mIndexLocked; }
-	S32 getNumVerts() const					{ return mNumVerts; }
-	S32 getNumIndices() const				{ return mNumIndices; }
+	U32 getNumVerts() const					{ return mNumVerts; }
+	U32 getNumIndices() const				{ return mNumIndices; }
 	
-	U8* getIndicesPointer() const			{ return useVBOs() ? nullptr : mMappedIndexData; }
-	U8* getVerticesPointer() const			{ return useVBOs() ? nullptr : mMappedData; }
 	U32 getTypeMask() const					{ return mTypeMask; }
-	bool hasDataType(S32 type) const		{ return ((1 << type) & getTypeMask()); }
-	S32 getSize() const;
-	S32 getIndicesSize() const				{ return mIndicesSize; }
+	bool hasDataType(AttributeType type) const		{ return ((1 << type) & getTypeMask()); }
+    U32 getSize() const                     { return mSize; }
+	U32 getIndicesSize() const				{ return mIndicesSize; }
 	U8* getMappedData() const				{ return mMappedData; }
 	U8* getMappedIndices() const			{ return mMappedIndexData; }
-	S32 getOffset(S32 type) const			{ return mOffsets[type]; }
-	S32 getUsage() const					{ return mUsage; }
-	bool isWriteable() const				{ return (mUsage == GL_STREAM_DRAW) ? true : false; }
-
+	U32 getOffset(AttributeType type) const			{ return mOffsets[type]; }
+	
+    // these functions assume (and assert on) the current VBO being bound
+    // Detailed error checking can be enabled by setting gDebugGL to true
 	void draw(U32 mode, U32 count, U32 indices_offset) const;
 	void drawArrays(U32 mode, U32 offset, U32 count) const;
-	void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
-
-    //implementation for inner loops that does no safety checking
-    void drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
+    void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
 
 	//for debugging, validate data in given range is valid
-	void validateRange(U32 start, U32 end, U32 count, U32 offset) const;
+	bool validateRange(U32 start, U32 end, U32 count, U32 offset) const;
 
 	#ifdef LL_PROFILER_ENABLE_RENDER_DOC
 	void setLabel(const char* label);
@@ -251,62 +223,45 @@ class LLVertexBuffer : public LLRefCount
 	
 
 protected:	
-    U32		mGLBuffer;		// GL VBO handle
-    U32		mGLIndices;		// GL IBO handle
+    U32		mGLBuffer = 0;		// GL VBO handle
+    U32		mGLIndices = 0;		// GL IBO handle
+    U32		mNumVerts = 0;		// Number of vertices allocated
+    U32		mNumIndices = 0;	// Number of indices allocated
+    U32		mOffsets[TYPE_MAX]; // byte offsets into mMappedData of each attribute
 
-    U32		mTypeMask;
+    U8* mMappedData = nullptr;	// pointer to currently mapped data (NULL if unmapped)
+    U8* mMappedIndexData = nullptr;	// pointer to currently mapped indices (NULL if unmapped)
 
-	S32		mNumVerts;		// Number of vertices allocated
-	S32		mNumIndices;	// Number of indices allocated
-    
-	S32		mSize;
-	S32		mIndicesSize;
-
-	const S32		mUsage;			// GL usage
-
-	U8* mMappedData;	// pointer to currently mapped data (NULL if unmapped)
-	U8* mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped)
-
-	U32		mMappedDataUsingVBOs : 1;
-	U32		mMappedIndexDataUsingVBOs : 1;
-	U32		mVertexLocked : 1;			// if true, vertex buffer is being or has been written to in client memory
-	U32		mIndexLocked : 1;			// if true, index buffer is being or has been written to in client memory
-	U32		mFinal : 1;			// if true, buffer can not be mapped again
-	U32		mEmpty : 1;			// if true, client buffer is empty (or NULL). Old values have been discarded.	
+    U32		mTypeMask = 0;      // bitmask of present vertex attributes
 	
-	S32		mOffsets[TYPE_MAX];
-
-	std::vector<MappedRegion> mMappedVertexRegions;
-	std::vector<MappedRegion> mMappedIndexRegions;
+	U32		mSize = 0;          // size in bytes of mMappedData
+	U32		mIndicesSize = 0;   // size in bytes of mMappedIndexData
 
-	static S32 determineUsage(S32 usage);
+	std::vector<MappedRegion> mMappedVertexRegions;  // list of mMappedData byte ranges that must be sent to GL
+	std::vector<MappedRegion> mMappedIndexRegions;   // list of mMappedIndexData byte ranges that must be sent to GL
 
 private:
-	static LLPrivateMemoryPool* sPrivatePoolp;
+    // DEPRECATED
+    // These function signatures are deprecated, but for some reason 
+    // there are classes in an external package that depend on LLVertexBuffer
+    
+    // TODO: move these classes into viewer repository
+    friend class LLNavShapeVBOManager;
+    friend class LLNavMeshVBOManager;
+    
+    LLVertexBuffer(U32 typemask, U32 usage)
+        : LLVertexBuffer(typemask)
+    {}
+
+    bool	allocateBuffer(S32 nverts, S32 nindices, BOOL create) { return allocateBuffer(nverts, nindices); }
 
 public:
-	static S32 sCount;
-	static S32 sGLCount;
-	static S32 sMappedCount;
-	static bool sMapped;
-	typedef std::list<LLVertexBuffer*> buffer_list_t;
-		
-	static bool sDisableVBOMapping; //disable glMapBufferARB
-	static bool sEnableVBOs;
-	static const S32 sTypeSize[TYPE_MAX];
+	static const U32 sTypeSize[TYPE_MAX];
 	static const U32 sGLMode[LLRender::NUM_MODES];
 	static U32 sGLRenderBuffer;
-	static U32 sGLRenderArray;
 	static U32 sGLRenderIndices;
-	static bool sVBOActive;
-	static bool sIBOActive;
 	static U32 sLastMask;
-	static U32 sAllocatedBytes;
-	static U32 sAllocatedIndexBytes;
 	static U32 sVertexCount;
-	static U32 sIndexCount;
-	static U32 sBindCount;
-	static U32 sSetCount;
 };
 
 #ifdef LL_PROFILER_ENABLE_RENDER_DOC
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 7787e2eb26a4b9539a97c0064505dd4af5145319..a195964bb1a2881b4c943443854cd3bbf6e5be87 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -1051,16 +1051,19 @@ BOOL LLWindowWin32::maximize()
 	BOOL success = FALSE;
 	if (!mWindowHandle) return success;
 
-	WINDOWPLACEMENT placement;
-	placement.length = sizeof(WINDOWPLACEMENT);
-
-	success = GetWindowPlacement(mWindowHandle, &placement);
-	if (!success) return success;
+    mWindowThread->post([=]
+        {
+            WINDOWPLACEMENT placement;
+            placement.length = sizeof(WINDOWPLACEMENT);
 
-	placement.showCmd = SW_MAXIMIZE;
+            if (GetWindowPlacement(mWindowHandle, &placement))
+            {
+                placement.showCmd = SW_MAXIMIZE;
+                SetWindowPlacement(mWindowHandle, &placement);
+            }
+        });
 
-	success = SetWindowPlacement(mWindowHandle, &placement);
-	return success;
+    return TRUE;
 }
 
 BOOL LLWindowWin32::getFullscreen()
@@ -1408,14 +1411,6 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO
 		return FALSE;
 	}
 
-	if (pfd.cAlphaBits < 8)
-	{
-		OSMessageBox(mCallbacks->translateString("MBAlpha"),
-			mCallbacks->translateString("MBError"), OSMB_OK);
-        close();
-		return FALSE;
-	}
-
 	if (!SetPixelFormat(mhDC, pixel_format, &pfd))
 	{
 		OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
@@ -1474,7 +1469,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO
 		attrib_list[cur_attrib++] = 24;
 
 		attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB;
-		attrib_list[cur_attrib++] = 8;
+		attrib_list[cur_attrib++] = 0;
 
 		U32 end_attrib = 0;
 		if (mFSAASamples > 0)
@@ -1705,13 +1700,6 @@ const	S32   max_format  = (S32)num_formats - 1;
 		return FALSE;
 	}
 
-	if (pfd.cAlphaBits < 8)
-	{
-		OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK);
-		close();
-		return FALSE;
-	}
-
 	mhRC = 0;
 	if (wglCreateContextAttribsARB)
 	{ //attempt to create a specific versioned context
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index ac449e45efcccb4ebf1d066a6b733053491a6d5b..ec4125c2bfeeb9383c8d417870ac10da08060a03 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8745,7 +8745,7 @@
     <string>Vector3</string>
     <key>Value</key>
     <array>
-      <real>0.01</real>
+      <real>0.25</real>
       <real>0.0</real>
       <real>0.0</real>
     </array>
diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
index ea41ac5f2d40fecbca60a0167f33d5976df9fe4b..0cb966296addde14a74923dcfdb302f7aa22bb92 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
@@ -505,7 +505,7 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i)
     v -= c;
     v = env_mat * v;
     {
-        return texture(irradianceProbes, vec4(v.xyz, refIndex[i].x)).rgb * refParams[i].x;
+        return textureLod(irradianceProbes, vec4(v.xyz, refIndex[i].x), 0).rgb * refParams[i].x;
     }
 }
 
@@ -676,14 +676,15 @@ void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout
 
     vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
 
+    
     ambenv = sampleProbeAmbient(pos, norm);
-
+    
     if (glossiness > 0.0)
     {
         float lod = (1.0-glossiness)*reflection_lods;
         glossenv = sampleProbes(pos, normalize(refnormpersp), lod, false);
     }
-
+    
     if (envIntensity > 0.0)
     {
         legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0, false);
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index f8a5086130e7c7b958c283f0a86f9c6c21f6c068..90de3694243a6c058e887a9ccf20a31ec1ec2143 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 43
+version 44
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -55,7 +55,7 @@ RenderVBOEnable				1	1
 RenderVBOMappingDisable		1	1
 RenderVolumeLODFactor		1	2.0
 UseStartScreen				1	1
-UseOcclusion				1	0
+UseOcclusion				1	1
 WindLightUseAtmosShaders	1	1
 WLSkyDetail					1	128
 Disregard128DefaultDrawDistance	1	1
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 0f84ade82aa7a8d723036919517af98b79715aa1..45e3827f605e3a1611170dc5d412cbd3e1aa2c09 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 42
+version 43
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -53,7 +53,7 @@ RenderVBOEnable				1	1
 RenderVBOMappingDisable		1	1
 RenderVolumeLODFactor		1	2.0
 UseStartScreen				1	1
-UseOcclusion				1	0
+UseOcclusion				1	1
 WindLightUseAtmosShaders	1	1
 WLSkyDetail					1	128
 Disregard128DefaultDrawDistance	1	1
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index d4d8b985ceec9e16e73c82dd817cb5d897683929..dd4363d2a43709912d5fb262ae13ac9abb18fd8f 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -535,7 +535,6 @@ static void settings_to_globals()
     LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile");
 #endif
 	LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport");
-	LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
 	LLImageGL::sGlobalUseAnisotropic	= gSavedSettings.getBOOL("RenderAnisotropic");
 	LLImageGL::sCompressTextures		= gSavedSettings.getBOOL("RenderCompressTextures");
 	LLVOVolume::sLODFactor				= llclamp(gSavedSettings.getF32("RenderVolumeLODFactor"), 0.01f, MAX_LOD_FACTOR);
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 74625423fe6eb5127e54d2aea5aaf45b82a6a612..7d869562cafa63a5c6adfdeea519a3e9c036fde2 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -702,7 +702,8 @@ F32 LLDrawable::updateXform(BOOL undamped)
 			((dist_vec_squared(old_pos, target_pos) > 0.f)
 			|| (1.f - dot(old_rot, target_rot)) > 0.f))
 	{ //fix for BUG-840, MAINT-2275, MAINT-1742, MAINT-2247
-			gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
+        mVObjp->shrinkWrap();
+		gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
 	}
 	else if (!getVOVolume() && !isAvatar())
 	{
@@ -1252,10 +1253,10 @@ LLSpatialPartition* LLDrawable::getSpatialPartition()
 
 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, regionp)
+	LLSpatialPartition(data_mask, render_by_group, regionp)
 {
-	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE;
+    mOcclusionEnabled = false;
 	mBridge = this;
 	mDrawable = root;
 	root->setSpatialBridge(this);
@@ -1758,7 +1759,7 @@ LLDrawable* LLDrawable::getRoot()
 }
 
 LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp)
-: LLSpatialPartition(0, FALSE, 0, regionp) 
+: LLSpatialPartition(0, false, regionp) 
 { 
 	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME; 
 	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 2abbe2f2f81bb8de7388f9b59ba60fa41451fc04..a5990492b16cadeefd9a3a85372972ef19759d1d 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -385,7 +385,7 @@ LLRenderPass::~LLRenderPass()
 
 }
 
-void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
+void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, bool texture)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
@@ -395,19 +395,18 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t
 		LLDrawInfo *pparams = *k;
 		if (pparams) 
         {
-			pushBatch(*pparams, mask, texture);
+			pushBatch(*pparams, texture);
 		}
 	}
 }
 
-void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture)
+void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, bool texture)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
-    mask |= LLVertexBuffer::MAP_WEIGHT4;
-
+    
     for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
     {
         LLDrawInfo* pparams = *k;
@@ -420,7 +419,7 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask,
                 lastMeshId = pparams->mSkinInfo->mHash;
             }
 
-            pushBatch(*pparams, mask, texture);
+            pushBatch(*pparams, texture);
         }
     }
 }
@@ -446,7 +445,7 @@ void teardown_texture_matrix(LLDrawInfo& params)
     }
 }
 
-void LLRenderPass::pushGLTFBatches(U32 type, U32 mask)
+void LLRenderPass::pushGLTFBatches(U32 type)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     auto* begin = gPipeline.beginRenderMap(type);
@@ -467,19 +466,19 @@ void LLRenderPass::pushGLTFBatches(U32 type, U32 mask)
         
         applyModelMatrix(params);
 
-        params.mVertexBuffer->setBufferFast(mask);
-        params.mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+        params.mVertexBuffer->setBuffer();
+        params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 
         teardown_texture_matrix(params);
     }
 }
 
-void LLRenderPass::pushRiggedGLTFBatches(U32 type, U32 mask)
+void LLRenderPass::pushRiggedGLTFBatches(U32 type)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
-    mask |= LLVertexBuffer::MAP_WEIGHT4;
+
     auto* begin = gPipeline.beginRenderMap(type);
     auto* end = gPipeline.endRenderMap(type);
     for (LLCullResult::drawinfo_iterator i = begin; i != end; )
@@ -505,14 +504,14 @@ void LLRenderPass::pushRiggedGLTFBatches(U32 type, U32 mask)
             lastMeshId = params.mSkinInfo->mHash;
         }
 
-        params.mVertexBuffer->setBufferFast(mask);
-        params.mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+        params.mVertexBuffer->setBuffer();
+        params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 
         teardown_texture_matrix(params);
     }
 }
 
-void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+void LLRenderPass::pushBatches(U32 type, bool texture, bool batch_textures)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     auto* begin = gPipeline.beginRenderMap(type);
@@ -522,16 +521,15 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text
         LLDrawInfo* pparams = *i;
         LLCullResult::increment_iterator(i, end);
 
-		pushBatch(*pparams, mask, texture, batch_textures);
+		pushBatch(*pparams, texture, batch_textures);
 	}
 }
 
-void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+void LLRenderPass::pushRiggedBatches(U32 type, bool texture, bool batch_textures)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOAvatar* lastAvatar = nullptr;
     U64 lastMeshId = 0;
-    mask |= LLVertexBuffer::MAP_WEIGHT4;
     auto* begin = gPipeline.beginRenderMap(type);
     auto* end = gPipeline.endRenderMap(type);
     for (LLCullResult::drawinfo_iterator i = begin; i != end; )
@@ -546,11 +544,11 @@ void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batc
             lastMeshId = pparams->mSkinInfo->mHash;
         }
 
-        pushBatch(*pparams, mask, texture, batch_textures);
+        pushBatch(*pparams, texture, batch_textures);
     }
 }
 
-void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+void LLRenderPass::pushMaskBatches(U32 type, bool texture, bool batch_textures)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     auto* begin = gPipeline.beginRenderMap(type);
@@ -560,11 +558,11 @@ void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_
         LLDrawInfo* pparams = *i;
         LLCullResult::increment_iterator(i, end);
 		LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
-		pushBatch(*pparams, mask, texture, batch_textures);
+		pushBatch(*pparams, texture, batch_textures);
 	}
 }
 
-void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+void LLRenderPass::pushRiggedMaskBatches(U32 type, bool texture, bool batch_textures)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     LLVOAvatar* lastAvatar = nullptr;
@@ -593,7 +591,7 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL
             lastMeshId = pparams->mSkinInfo->mHash;
         }
 
-        pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_textures);
+        pushBatch(*pparams, texture, batch_textures);
     }
 }
 
@@ -612,7 +610,7 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params)
 	}
 }
 
-void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
+void LLRenderPass::pushBatch(LLDrawInfo& params, bool texture, bool batch_textures)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     if (!params.mCount)
@@ -662,8 +660,8 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba
     //    params.mGroup->rebuildMesh();
     //}
 
-    params.mVertexBuffer->setBufferFast(mask);
-    params.mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+    params.mVertexBuffer->setBuffer();
+    params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 
 	if (tex_setup)
 	{
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 9a4b09b973362fde428c85bc93b523fae5f949a5..7050723116cad350a49af8c716e8358c6f6dcce2 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -333,7 +333,6 @@ class LLRenderPass : public LLDrawPool
                 return "PASS_GLTF_PBR";
             case PASS_GLTF_PBR_RIGGED:
                 return "PASS_GLTF_PBR_RIGGED";
-
             default:
                 return "Unknown pass";
         }
@@ -350,17 +349,17 @@ class LLRenderPass : public LLDrawPool
 	void resetDrawOrders() { }
 
 	static void applyModelMatrix(const LLDrawInfo& params);
-	virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
-    virtual void pushRiggedBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
-    void pushGLTFBatches(U32 type, U32 mask);
-    void pushRiggedGLTFBatches(U32 type, U32 mask);
-	virtual void pushMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
-    virtual void pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
-	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+	virtual void pushBatches(U32 type, bool texture = true, bool batch_textures = false);
+    virtual void pushRiggedBatches(U32 type, bool texture = true, bool batch_textures = false);
+    void pushGLTFBatches(U32 type);
+    void pushRiggedGLTFBatches(U32 type);
+	virtual void pushMaskBatches(U32 type, bool texture = true, bool batch_textures = false);
+    virtual void pushRiggedMaskBatches(U32 type, bool texture = true, bool batch_textures = false);
+	virtual void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false);
     static bool uploadMatrixPalette(LLDrawInfo& params);
     static bool uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo);
-	virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-    virtual void renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
+	virtual void renderGroup(LLSpatialGroup* group, U32 type, bool texture = true);
+    virtual void renderRiggedGroup(LLSpatialGroup* group, U32 type, bool texture = true);
 };
 
 class LLFacePool : public LLDrawPool
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 07381acd257834b4afdf9817ac2562fecd6a9192..ed952689fa873784461f5a9cfba839af78ff317f 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -379,11 +379,6 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
                 {
                     LLDrawInfo& params = **k;
 
-                    if (params.mParticle)
-                    {
-                        continue;
-                    }
-
                     bool rigged = (params.mAvatar != nullptr);
                     gHighlightProgram.bind(rigged);
                     gGL.diffuseColor4f(1, 0, 0, 1);
@@ -403,12 +398,8 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
                     }
 
                     LLRenderPass::applyModelMatrix(params);
-                    if (params.mGroup)
-                    {
-                        params.mGroup->rebuildMesh();
-                    }
-                    params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask);
-                    params.mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+                    params.mVertexBuffer->setBuffer();
+                    params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
                 }
             }
         }
@@ -435,9 +426,9 @@ inline bool IsEmissive(LLDrawInfo& params)
 
 inline void Draw(LLDrawInfo* draw, U32 mask)
 {
-    draw->mVertexBuffer->setBufferFast(mask);
+    draw->mVertexBuffer->setBuffer();
     LLRenderPass::applyModelMatrix(*draw);
-	draw->mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);                    
+	draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);                    
 }
 
 bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material)
@@ -530,8 +521,8 @@ void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup)
 void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw)
 {
     LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f);
-    draw->mVertexBuffer->setBufferFast((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE);
-	draw->mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
+    draw->mVertexBuffer->setBuffer();
+	draw->mVertexBuffer->drawRange(LLRender::TRIANGLES, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset);
 }
 
 
@@ -665,30 +656,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
 
                 LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch");
 
-                U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;
-				if (have_mask != mask)
-				{ //FIXME!
-					LL_WARNS_ONCE() << "Missing required components, expected mask: " << mask
-									<< " present: " << have_mask
-									<< ". Skipping render batch." << LL_ENDL;
-					continue;
-				}
-
-				if(depth_only)
-				{
-                    // when updating depth buffer, discard faces that are more than 90% transparent
-					LLFace*	face = params.mFace;
-					if(face)
-					{
-						const LLTextureEntry* tep = face->getTextureEntry();
-						if(tep)
-						{ // don't render faces that are more than 90% transparent
-							if(tep->getColor().mV[3] < MINIMUM_IMPOSTOR_ALPHA)
-								continue;
-						}
-					}
-				}
-
                 LLRenderPass::applyModelMatrix(params);
 
                 LLMaterial* mat = NULL;
@@ -835,18 +802,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                         reset_minimum_alpha = true;
                     }
                     
-                    U32 drawMask = mask;
-                    if (params.mFullbright)
-                    {
-                        drawMask &= ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
-                    }
-                    if (params.mAvatar != nullptr)
-                    {
-                        drawMask |= LLVertexBuffer::MAP_WEIGHT4;
-                    }
-
-                    params.mVertexBuffer->setBufferFast(drawMask);
-                    params.mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+                    params.mVertexBuffer->setBuffer();
+                    params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 
                     if (reset_minimum_alpha)
                     {
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 67c30004106e05a7574559191365bd8d658b1fe4..8a3ab20ab4106254e1c73f99194296a3c68bb9ac 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -53,8 +53,6 @@
 #include "llviewercontrol.h" // for gSavedSettings
 #include "llviewertexturelist.h"
 
-static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
-static U32 sBufferUsage = GL_STREAM_DRAW;
 static U32 sShaderLevel = 0;
 
 LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = NULL;
@@ -143,15 +141,6 @@ void LLDrawPoolAvatar::prerender()
 	mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR);
 	
 	sShaderLevel = mShaderLevel;
-	
-	if (sShaderLevel > 0)
-	{
-		sBufferUsage = GL_DYNAMIC_DRAW;
-	}
-	else
-	{
-		sBufferUsage = GL_STREAM_DRAW;
-	}
 }
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
@@ -932,11 +921,3 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
 }
 
 
-LLVertexBufferAvatar::LLVertexBufferAvatar()
-: LLVertexBuffer(sDataMask, 
-	GL_STREAM_DRAW) //avatars are always stream draw due to morph targets
-{
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
-}
-
-
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 21add39b21be9ca48a7ef3fc86cde9632e1442ff..ff78c6c60a6b8284448a23b014bd6ace11819618 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -129,12 +129,6 @@ typedef enum
 	static LLGLSLShader* sVertexProgram;
 };
 
-class LLVertexBufferAvatar : public LLVertexBuffer
-{
-public:
-	LLVertexBufferAvatar();
-};
-
 extern S32 AVATAR_OFFSET_POS;
 extern S32 AVATAR_OFFSET_NORMAL;
 extern S32 AVATAR_OFFSET_TEX0;
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 4379fdc603b39a08e8b78fe19b658389b3826dc3..9c871514f7a36c76f6164e6deac5e9046cd5a83b 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -353,22 +353,22 @@ void LLDrawPoolBump::renderShiny()
 		{
             if (mRigged)
             {
-                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_SHINY_RIGGED, true, true);
             }
             else
             {
-                LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+                LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, true, true);
             }
 		}
 		else
 		{
             if (mRigged)
             {
-                gPipeline.renderRiggedGroups(this, LLRenderPass::PASS_SHINY_RIGGED, sVertexMask, TRUE);
+                gPipeline.renderRiggedGroups(this, LLRenderPass::PASS_SHINY_RIGGED, true);
             }
             else
             {
-                gPipeline.renderGroups(this, LLRenderPass::PASS_SHINY, sVertexMask, TRUE);
+                gPipeline.renderGroups(this, LLRenderPass::PASS_SHINY, true);
             }
 		}
 	}
@@ -508,22 +508,22 @@ void LLDrawPoolBump::renderFullbrightShiny()
 		{
             if (mRigged)
             {
-                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, true, true);
             }
             else
             {
-                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, true, true);
             }
 		}
 		else
 		{
             if (mRigged)
             {
-                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask);
+                LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED);
             }
             else
             {
-                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask);
+                LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY);
             }
 		}
 	}
@@ -549,7 +549,7 @@ void LLDrawPoolBump::endFullbrightShiny()
 	mShiny = FALSE;
 }
 
-void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE)
+void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, bool texture = true)
 {					
 	LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type];	
 	
@@ -559,11 +559,7 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 		
 		applyModelMatrix(params);
 
-		if (params.mGroup)
-		{
-			params.mGroup->rebuildMesh();
-		}
-		params.mVertexBuffer->setBuffer(mask);
+		params.mVertexBuffer->setBuffer();
 		params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 	}
 }
@@ -574,7 +570,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 {
 	U8 bump_code = params.mBump;
 
-	return bindBumpMap(bump_code, params.mTexture, params.mVSize, channel);
+	return bindBumpMap(bump_code, params.mTexture, channel);
 }
 
 //static
@@ -584,14 +580,14 @@ BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel)
 	if (te)
 	{
 		U8 bump_code = te->getBumpmap();
-		return bindBumpMap(bump_code, face->getTexture(), face->getVirtualSize(), channel);
+		return bindBumpMap(bump_code, face->getTexture(), channel);
 	}
 
 	return FALSE;
 }
 
 //static
-BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel)
+BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, S32 channel)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	//Note: texture atlas does not support bump texture now.
@@ -617,7 +613,7 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 		if( bump_code < LLStandardBumpmap::sStandardBumpmapCount )
 		{
 			bump = gStandardBumpmapList[bump_code].mImage;
-			gBumpImageList.addTextureStats(bump_code, tex->getID(), vsize);
+			gBumpImageList.addTextureStats(bump_code, tex->getID(), tex->getMaxVirtualSize());
 		}
 		break;
 	}
@@ -674,7 +670,7 @@ void LLDrawPoolBump::renderBump(U32 pass)
 	/// Get rid of z-fighting with non-bump pass.
 	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
 	glPolygonOffset(-1.0f, -1.0f);
-	renderBump(pass, sVertexMask);
+	pushBumpBatches(pass);
 }
 
 //static
@@ -719,8 +715,6 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
         LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
         LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
-        U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
-
         LLVOAvatar* avatar = nullptr;
         U64 skin = 0;
 
@@ -741,11 +735,11 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
                     avatar = params.mAvatar;
                     skin = params.mSkinInfo->mHash;
                 }
-                pushBatch(params, mask | LLVertexBuffer::MAP_WEIGHT4, TRUE, FALSE);
+                pushBatch(params, true, false);
             }
             else
             {
-                pushBatch(params, mask, TRUE, FALSE);
+                pushBatch(params, true, false);
             }
         }
 
@@ -1342,7 +1336,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 	}
 }
 
-void LLDrawPoolBump::renderBump(U32 type, U32 mask)
+void LLDrawPoolBump::pushBumpBatches(U32 type)
 {	
     LLVOAvatar* avatar = nullptr;
     U64 skin = 0;
@@ -1350,7 +1344,6 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
     if (mRigged)
     { // nudge type enum and include skinweights for rigged pass
         type += 1;
-        mask |= LLVertexBuffer::MAP_WEIGHT4;
     }
 
     LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
@@ -1377,12 +1370,12 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask)
                     }
                 }
             }
-			pushBatch(params, mask, FALSE);
+			pushBatch(params, false);
 		}
 	}
 }
 
-void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
+void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_textures)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
 	applyModelMatrix(params);
@@ -1435,12 +1428,8 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL
 		}
 	}
 
-	if (params.mGroup)
-	{
-		params.mGroup->rebuildMesh();
-	}
-	params.mVertexBuffer->setBufferFast(mask);
-	params.mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+	params.mVertexBuffer->setBuffer();
+	params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 
     if (tex_setup)
 	{
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index cf463f4458ecc48981628764271a63204d90cbbe..4400308451825e3367e482bed68367af3bc77df1 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -55,10 +55,10 @@ protected :
 	virtual void render(S32 pass = 0) override;
 	virtual S32	 getNumPasses() override;
 	/*virtual*/ void prerender() override;
-	void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE) override;
+	void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false) override;
 
-	void renderBump(U32 type, U32 mask);
-	void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) override;
+	void pushBumpBatches(U32 type);
+	void renderGroup(LLSpatialGroup* group, U32 type, bool texture) override;
 		
 	S32 numBumpPasses();
 	
@@ -87,7 +87,7 @@ protected :
 	static BOOL bindBumpMap(LLFace* face, S32 channel = -2);
 
 private:
-	static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, F32 vsize, S32 channel);
+	static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, S32 channel);
     bool mRigged = false; // if true, doing a rigged pass
 
 };
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 858fb871d3ce0aec9265f596daea15916851a81a..735f32ddbbf18f9235c5c99a0013405af32b6985 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -156,8 +156,6 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
         type += 1;
     }
 
-	U32 mask = mShader->mAttributeMask;
-
 	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
 	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 	
@@ -304,8 +302,8 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
             params.mGroup->rebuildMesh();
         }*/
 
-        params.mVertexBuffer->setBufferFast(mask);
-        params.mVertexBuffer->drawRangeFast(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
+        params.mVertexBuffer->setBuffer();
+        params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset);
 
         if (tex_setup)
         {
diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp
index 0e44a9be28e70400c3bee1db1d18a3bf0eb42e22..9dd1bc0ba224ddec152543d2e3ca90c92855278b 100644
--- a/indra/newview/lldrawpoolpbropaque.cpp
+++ b/indra/newview/lldrawpoolpbropaque.cpp
@@ -43,13 +43,11 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
     for (U32 type : types)
     {
         gDeferredPBROpaqueProgram.bind();
-        pushGLTFBatches(type, getVertexDataMask());
+        pushGLTFBatches(type);
         
         gDeferredPBROpaqueProgram.bind(true);
-        pushRiggedGLTFBatches(type+1, getVertexDataMask());
+        pushRiggedGLTFBatches(type+1);
     }
-
-    LLGLSLShader::sCurBoundShaderPtr->unbind();
 }
 
 
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 57aa1c73f0389526cd5d66c8d2d0eb3ae488f0a4..3a659e0efca47925c78537c0af4a567422bc8205 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -99,12 +99,12 @@ void LLDrawPoolGlow::render(LLGLSLShader* shader)
 
     //first pass -- static objects
     setup_glow_shader(shader);
-    pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_GLOW, true, true);
         
     // second pass -- rigged objects
     shader = shader->mRiggedVariant;
     setup_glow_shader(shader);
-    pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, true, true);
  
     gGL.setColorMask(true, false);
     gGL.setSceneBlendType(LLRender::BT_ALPHA);	
@@ -161,21 +161,19 @@ void LLDrawPoolSimple::render(S32 pass)
 	
 		gPipeline.enableLightsDynamic();
 
-		U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
-
         // first pass -- static objects
         {
             setup_simple_shader(shader);
-            pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE);
+            pushBatches(LLRenderPass::PASS_SIMPLE, true, true);
 
             if (LLPipeline::sRenderDeferred)
             { //if deferred rendering is enabled, bump faces aren't registered as simple
                 //render bump faces here as simple so bump faces will appear under water
-                pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);
-                pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE);
-                pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE);
-                pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE);
-                pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE);
+                pushBatches(LLRenderPass::PASS_BUMP, true, true);
+                pushBatches(LLRenderPass::PASS_MATERIAL, true, true);
+                pushBatches(LLRenderPass::PASS_SPECMAP, true, true);
+                pushBatches(LLRenderPass::PASS_NORMMAP, true, true);
+                pushBatches(LLRenderPass::PASS_NORMSPEC, true, true);
             }
         }
         
@@ -183,16 +181,16 @@ void LLDrawPoolSimple::render(S32 pass)
         {
             shader = shader->mRiggedVariant;
             setup_simple_shader(shader);
-            pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, mask, TRUE, TRUE);
+            pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, true, true);
 
             if (LLPipeline::sRenderDeferred)
             { //if deferred rendering is enabled, bump faces aren't registered as simple
                 //render bump faces here as simple so bump faces will appear under water
-                pushRiggedBatches(LLRenderPass::PASS_BUMP_RIGGED, mask, TRUE, TRUE);
-                pushRiggedBatches(LLRenderPass::PASS_MATERIAL_RIGGED, mask, TRUE, TRUE);
-                pushRiggedBatches(LLRenderPass::PASS_SPECMAP_RIGGED, mask, TRUE, TRUE);
-                pushRiggedBatches(LLRenderPass::PASS_NORMMAP_RIGGED, mask, TRUE, TRUE);
-                pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_RIGGED, mask, TRUE, TRUE);
+                pushRiggedBatches(LLRenderPass::PASS_BUMP_RIGGED, true, true);
+                pushRiggedBatches(LLRenderPass::PASS_MATERIAL_RIGGED, true, true);
+                pushRiggedBatches(LLRenderPass::PASS_SPECMAP_RIGGED, true, true);
+                pushRiggedBatches(LLRenderPass::PASS_NORMMAP_RIGGED, true, true);
+                pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_RIGGED, true, true);
             }
         }
 	}
@@ -228,19 +226,19 @@ void LLDrawPoolAlphaMask::render(S32 pass)
 
     // render static
     setup_simple_shader(shader);
-    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, true, true);
+	pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, true, true);
+	pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, true, true);
+	pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, true, true);
+	pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, true, true);
 
     // render rigged
     setup_simple_shader(shader->mRiggedVariant);
-    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    pushRiggedMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    pushRiggedMaskBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    pushRiggedMaskBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-    pushRiggedMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, true, true);
+    pushRiggedMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, true, true);
+    pushRiggedMaskBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, true, true);
+    pushRiggedMaskBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, true, true);
+    pushRiggedMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, true, true);
 }
 
 LLDrawPoolFullbrightAlphaMask::LLDrawPoolFullbrightAlphaMask() :
@@ -269,11 +267,11 @@ void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
 
     // render static
     setup_fullbright_shader(shader);
-    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true);
 
     // render rigged
     setup_fullbright_shader(shader->mRiggedVariant);
-    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, true, true);
 }
 
 //===============================
@@ -293,11 +291,11 @@ void LLDrawPoolSimple::renderDeferred(S32 pass)
 
 	//render static
     setup_simple_shader(&gDeferredDiffuseProgram);
-	pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	pushBatches(LLRenderPass::PASS_SIMPLE, true, true);
 	
     //render rigged
     setup_simple_shader(gDeferredDiffuseProgram.mRiggedVariant);
-    pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, true, true);
 }
 
 static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask");
@@ -310,11 +308,11 @@ void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
 
     //render static
     setup_simple_shader(shader);
-    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, true, true);
 
     //render rigged
     setup_simple_shader(shader->mRiggedVariant);
-    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, true, true);
 }
 
 // grass drawpool
@@ -453,15 +451,14 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
     }
 
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
-	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
     
     // render static
     setup_fullbright_shader(shader);
-    pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_FULLBRIGHT, true, true);
     
     // render rigged
     setup_fullbright_shader(shader->mRiggedVariant);
-    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, true, true);
 }
 
 void LLDrawPoolFullbright::render(S32 pass)
@@ -480,24 +477,21 @@ void LLDrawPoolFullbright::render(S32 pass)
         shader = &gObjectFullbrightProgram;
     }
 
-
-	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-
     // render static
     setup_fullbright_shader(shader);
-    pushBatches(LLRenderPass::PASS_FULLBRIGHT, mask, TRUE, TRUE);
-    pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, mask, TRUE, TRUE);
-    pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, mask, TRUE, TRUE);
-    pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, mask, TRUE, TRUE);
-    pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, mask, TRUE, TRUE);
+    pushBatches(LLRenderPass::PASS_FULLBRIGHT, true, true);
+    pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, true, true);
+    pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, true, true);
+    pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, true, true);
+    pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, true, true);
  
     // render rigged
     setup_fullbright_shader(shader->mRiggedVariant);
-    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, mask, TRUE, TRUE);
-    pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, mask, TRUE, TRUE);
-    pushRiggedBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE);
-    pushRiggedBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE);
-    pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, mask, TRUE, TRUE);
+    pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, true, true);
+    pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, true, true);
+    pushRiggedBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, true, true);
+    pushRiggedBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, true, true);
+    pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, true, true);
 }
 
 S32 LLDrawPoolFullbright::getNumPasses()
@@ -531,14 +525,13 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
     }
 
 	LLGLDisable blend(GL_BLEND);
-	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
-    
+	
     // render static
     setup_fullbright_shader(shader);
-    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
+    pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true);
     
     // render rigged
     setup_fullbright_shader(shader->mRiggedVariant);
-    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, fullbright_mask, TRUE, TRUE);
+    pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, true, true);
 }
 
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 55c8d848388dd261c14c1aff064bf08aa0fd61d6..64178f0a594f88fde33b746a657a9625be1a3651 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -148,7 +148,7 @@ void LLDrawPoolTerrain::boostTerrainDetailTextures()
 	for (S32 i = 0; i < 4; i++)
 	{
 		compp->mDetailTextures[i]->setBoostLevel(LLGLTexture::BOOST_TERRAIN);
-        gPipeline.touchTexture(compp->mDetailTextures[i], 1024.f * 1024.f);
+        compp->mDetailTextures[i]->addTextureStats(1024.f * 1024.f);
 	}
 }
 
@@ -821,8 +821,7 @@ void LLDrawPoolTerrain::renderOwnership()
 		 iter != mDrawFace.end(); iter++)
 	{
 		LLFace *facep = *iter;
-		facep->renderIndexed(LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_TEXCOORD0);
+		facep->renderIndexed();
 	}
 
 	gGL.matrixMode(LLRender::MM_TEXTURE);
diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h
index 5b4558020d6b9d63be94b9da99e9a8560dcb7c08..e00e0c4720d89efc8212becb9bba9407da74165a 100644
--- a/indra/newview/lldrawpoolterrain.h
+++ b/indra/newview/lldrawpoolterrain.h
@@ -33,14 +33,12 @@ class LLDrawPoolTerrain : public LLFacePool
 {
 	LLPointer<LLViewerTexture> mTexturep;
 public:
-	enum
-	{
-		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
-							LLVertexBuffer::MAP_NORMAL |
-							LLVertexBuffer::MAP_TEXCOORD0 |
-							LLVertexBuffer::MAP_TEXCOORD1 |
-							LLVertexBuffer::MAP_TEXCOORD2 |
-							LLVertexBuffer::MAP_TEXCOORD3
+    enum
+    {
+        VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX |
+                    LLVertexBuffer::MAP_NORMAL |
+                    LLVertexBuffer::MAP_TEXCOORD0 |
+                    LLVertexBuffer::MAP_TEXCOORD1
 	};
 
 	virtual U32 getVertexDataMask();
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index facfb235c914e09caf964c56ceb6a4ca0ee37fda..61a8e20b54d4bdc1fc131e269befc651ae8ca7bf 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -93,7 +93,7 @@ void LLDrawPoolTree::render(S32 pass)
 	LLGLState test(GL_ALPHA_TEST, 0);
 
 	gGL.getTexUnit(sDiffTex)->bindFast(mTexturep);
-    gPipeline.touchTexture(mTexturep, 1024.f * 1024.f); // <=== keep Linden tree textures at full res
+    mTexturep->addTextureStats(1024.f * 1024.f); // <=== keep Linden tree textures at full res
 
 	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
 		 iter != mDrawFace.end(); iter++)
@@ -117,8 +117,8 @@ void LLDrawPoolTree::render(S32 pass)
 				gPipeline.mMatrixOpCount++;
 			}
 
-			buff->setBufferFast(LLDrawPoolTree::VERTEX_DATA_MASK);
-			buff->drawRangeFast(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
+			buff->setBuffer();
+			buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
 		}
 	}
 }
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index c2fe52683b558f961337bdbc0259f1a6617530c2..1808fb59873c73d9d6ef686b17ce2e22ab0b06b2 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -92,36 +92,19 @@ void LLDrawPoolWater::setNormalMaps(const LLUUID& normalMapId, const LLUUID& nex
     mWaterNormp[1]->addTextureStats(1024.f*1024.f);
 }
 
-//static
-void LLDrawPoolWater::restoreGL()
-{
-	/*LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater();
-    if (pwater)
-    {
-        setTransparentTextures(pwater->getTransparentTextureID(), pwater->getNextTransparentTextureID());
-        setOpaqueTexture(pwater->GetDefaultOpaqueTextureAssetId());
-        setNormalMaps(pwater->getNormalMapID(), pwater->getNextNormalMapID());
-    }*/
-}
-
 void LLDrawPoolWater::prerender()
 {
 	mShaderLevel = LLCubeMap::sUseCubeMaps ? LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WATER) : 0;
 }
 
-S32 LLDrawPoolWater::getNumPasses()
-{
-	if (LLViewerCamera::getInstance()->getOrigin().mV[2] < 1024.f)
-	{
-		return 1;
-	}
-
-	return 0;
-}
-
 S32 LLDrawPoolWater::getNumPostDeferredPasses()
 {
-    return 1;
+    if (LLViewerCamera::getInstance()->getOrigin().mV[2] < 1024.f)
+    {
+        return 1;
+    }
+
+    return 0;
 }
 
 void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
@@ -134,13 +117,6 @@ void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
         LLRenderTarget& src = gPipeline.mRT->screen;
         LLRenderTarget& dst = gPipeline.mWaterDis;
 
-#if 0
-        dst.copyContents(src,
-            0, 0, src.getWidth(), src.getHeight(),
-            0, 0, dst.getWidth(), dst.getHeight(),
-            GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT,
-            GL_NEAREST);
-#else
         dst.bindTarget();
         gCopyDepthProgram.bind();
 
@@ -150,369 +126,14 @@ void LLDrawPoolWater::beginPostDeferredPass(S32 pass)
         gGL.getTexUnit(diff_map)->bind(&src);
         gGL.getTexUnit(depth_map)->bind(&src, true);
 
-        gPipeline.mScreenTriangleVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+        gPipeline.mScreenTriangleVB->setBuffer();
         gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
 
         dst.flush();
-#endif
     }
 }
 
 void LLDrawPoolWater::renderPostDeferred(S32 pass) 
-{
-    renderWater();
-}
-
-
-S32 LLDrawPoolWater::getNumDeferredPasses() 
-{ 
-    return 0;
-}
-
-//===============================
-//DEFERRED IMPLEMENTATION
-//===============================
-void LLDrawPoolWater::renderDeferred(S32 pass)
-{
-#if 0
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
-
-    if (!LLPipeline::sRenderTransparentWater)
-    {
-        // Will render opaque water without use of ALM
-        render(pass);
-        return;
-    }
-
-	deferred_render = TRUE;
-	renderWater();
-	deferred_render = FALSE;
-#endif
-}
-
-//=========================================
-
-void LLDrawPoolWater::render(S32 pass)
-{
-#if 0
-	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER);
-	if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1)
-	{
-		return;
-	}
-
-	//do a quick 'n dirty depth sort
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-			 iter != mDrawFace.end(); iter++)
-	{
-		LLFace* facep = *iter;
-		facep->mDistance = -facep->mCenterLocal.mV[2];
-	}
-
-	std::sort(mDrawFace.begin(), mDrawFace.end(), LLFace::CompareDistanceGreater());
-
-	// See if we are rendering water as opaque or not
-	if (!LLPipeline::sRenderTransparentWater)
-	{
-		// render water for low end hardware
-		renderOpaqueLegacyWater();
-		return;
-	}
-
-	LLGLEnable blend(GL_BLEND);
-
-	if ((mShaderLevel > 0) && !sSkipScreenCopy)
-	{
-		renderWater();
-		return;
-	}
-
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-	stop_glerror();
-
-	LLFace* refl_face = voskyp->getReflFace();
-
-	gPipeline.disableLights();
-	
-	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
-
-	LLGLDisable cullFace(GL_CULL_FACE);
-	
-	// Set up second pass first
-	gGL.getTexUnit(1)->activate();
-	gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(1)->bind(mWaterImagep[0]) ;
-
-    gGL.getTexUnit(2)->activate();
-	gGL.getTexUnit(2)->enable(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(2)->bind(mWaterImagep[1]) ;
-
-	LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis();
-	F32 up_dot = camera_up * LLVector3::z_axis;
-
-	LLColor4 water_color;
-	if (LLViewerCamera::getInstance()->cameraUnderWater())
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.4f);
-	}
-	else
-	{
-		water_color.setVec(1.f, 1.f, 1.f, 0.5f*(1.f + up_dot));
-	}
-
-	gGL.diffuseColor4fv(water_color.mV);
-
-	// Automatically generate texture coords for detail map
-	glEnable(GL_TEXTURE_GEN_S); //texture unit 1
-	glEnable(GL_TEXTURE_GEN_T); //texture unit 1
-	glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-
-	// Slowly move over time.
-	F32 offset = fmod(gFrameTimeSeconds*2.f, 100.f);
-	F32 tp0[4] = {16.f/256.f, 0.0f, 0.0f, offset*0.01f};
-	F32 tp1[4] = {0.0f, 16.f/256.f, 0.0f, offset*0.01f};
-	glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
-	glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
-
-	gGL.getTexUnit(0)->activate();
-	
-	glClearStencil(1);
-	glClear(GL_STENCIL_BUFFER_BIT);
-	//LLGLEnable gls_stencil(GL_STENCIL_TEST);
-	glStencilOp(GL_KEEP, GL_REPLACE, GL_KEEP);
-	glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
-
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-		 iter != mDrawFace.end(); iter++)
-	{
-		LLFace *face = *iter;
-		if (voskyp->isReflFace(face))
-		{
-			continue;
-		}
-		gGL.getTexUnit(0)->bind(face->getTexture());
-		face->renderIndexed();
-	}
-
-	// Now, disable texture coord generation on texture state 1
-	gGL.getTexUnit(1)->activate();
-	gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(1)->disable();
-
-    glDisable(GL_TEXTURE_GEN_S); //texture unit 1
-	glDisable(GL_TEXTURE_GEN_T); //texture unit 1
-
-    gGL.getTexUnit(2)->activate();
-	gGL.getTexUnit(2)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(2)->disable();
-
-	glDisable(GL_TEXTURE_GEN_S); //texture unit 1
-	glDisable(GL_TEXTURE_GEN_T); //texture unit 1
-
-	// Disable texture coordinate and color arrays
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
-	stop_glerror();
-	
-	if (gSky.mVOSkyp->getCubeMap() && !LLPipeline::sReflectionProbesEnabled)
-	{
-		gSky.mVOSkyp->getCubeMap()->enable(0);
-		gSky.mVOSkyp->getCubeMap()->bind();
-
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.loadIdentity();
-		LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
-		LLMatrix4 camera_rot(camera_mat.getMat3());
-		camera_rot.invert();
-
-		gGL.loadMatrix((F32 *)camera_rot.mMatrix);
-
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-		LLOverrideFaceColor overrid(this, 1.f, 1.f, 1.f,  0.5f*up_dot);
-
-		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-			 iter != mDrawFace.end(); iter++)
-		{
-			LLFace *face = *iter;
-			if (voskyp->isReflFace(face))
-			{
-				//refl_face = face;
-				continue;
-			}
-
-			if (face->getGeomCount() > 0)
-			{					
-				face->renderIndexed();
-			}
-		}
-
-		gSky.mVOSkyp->getCubeMap()->disable();
-		
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.loadIdentity();
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-		
-	}
-
-	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
-    if (refl_face)
-	{
-		glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
-		renderReflection(refl_face);
-	}
-#endif
-}
-
-// for low end hardware
-void LLDrawPoolWater::renderOpaqueLegacyWater()
-{
-#if 0
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-    if (voskyp == NULL)
-    {
-        return;
-    }
-
-	LLGLSLShader* shader = NULL;
-		if (LLPipeline::sUnderWaterRender)
-		{
-			shader = &gObjectSimpleNonIndexedTexGenWaterProgram;
-		}
-		else
-		{
-			shader = &gObjectSimpleNonIndexedTexGenProgram;
-		}
-
-		shader->bind();
-
-	stop_glerror();
-
-	// Depth sorting and write to depth buffer
-	// since this is opaque, we should see nothing
-	// behind the water.  No blending because
-	// of no transparency.  And no face culling so
-	// that the underside of the water is also opaque.
-	LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
-	LLGLDisable no_cull(GL_CULL_FACE);
-	LLGLDisable no_blend(GL_BLEND);
-
-	gPipeline.disableLights();
-
-	// Activate the texture binding and bind one
-	// texture since all images will have the same texture
-	gGL.getTexUnit(0)->activate();
-	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-	gGL.getTexUnit(0)->bind(mOpaqueWaterImagep);
-
-	// Automatically generate texture coords for water texture
-	if (!shader)
-	{
-		glEnable(GL_TEXTURE_GEN_S); //texture unit 0
-		glEnable(GL_TEXTURE_GEN_T); //texture unit 0
-		glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-		glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-	}
-
-	// Use the fact that we know all water faces are the same size
-	// to save some computation
-
-	// Slowly move texture coordinates over time so the watter appears
-	// to be moving.
-	F32 movement_period_secs = 50.f;
-
-	F32 offset = fmod(gFrameTimeSeconds, movement_period_secs);
-
-	if (movement_period_secs != 0)
-	{
-	 	offset /= movement_period_secs;
-	}
-	else
-	{
-		offset = 0;
-	}
-
-	F32 tp0[4] = { 16.f / 256.f, 0.0f, 0.0f, offset };
-	F32 tp1[4] = { 0.0f, 16.f / 256.f, 0.0f, offset };
-
-	if (!shader)
-	{
-		glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0);
-		glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1);
-	}
-	else
-	{
-		shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0);
-		shader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1);
-	}
-
-	gGL.diffuseColor3f(1.f, 1.f, 1.f);
-
-	for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
-		 iter != mDrawFace.end(); iter++)
-	{
-		LLFace *face = *iter;
-		if (voskyp->isReflFace(face))
-		{
-			continue;
-		}
-
-		face->renderIndexed();
-	}
-
-	stop_glerror();
-
-	if (!shader)
-	{
-		// Reset the settings back to expected values
-		glDisable(GL_TEXTURE_GEN_S); //texture unit 0
-		glDisable(GL_TEXTURE_GEN_T); //texture unit 0
-	}
-
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-#endif
-}
-
-
-void LLDrawPoolWater::renderReflection(LLFace* face)
-{
-#if 0
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
-	LLVOSky *voskyp = gSky.mVOSkyp;
-
-	if (!voskyp)
-	{
-		return;
-	}
-
-	if (!face->getGeomCount())
-	{
-		return;
-	}
-	
-	S8 dr = voskyp->getDrawRefl();
-	if (dr < 0)
-	{
-		return;
-	}
-
-	LLGLSNoFog noFog;
-
-	gGL.getTexUnit(0)->bind((dr == 0) ? voskyp->getSunTex() : voskyp->getMoonTex());
-
-	LLOverrideFaceColor override(this, LLColor4(face->getFaceColor().mV));
-	face->renderIndexed();
-#endif
-}
-
-void LLDrawPoolWater::renderWater()
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     if (!deferred_render)
diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h
index 418430d68a03fa9dc9389e3d6fc2929a65d3dc6b..3158b0a59bf813753743e70d33b984012b6627bc 100644
--- a/indra/newview/lldrawpoolwater.h
+++ b/indra/newview/lldrawpoolwater.h
@@ -61,25 +61,15 @@ class LLDrawPoolWater final: public LLFacePool
 	LLDrawPoolWater();
 	/*virtual*/ ~LLDrawPoolWater();
 
-	static void restoreGL();
-	
-    
     S32 getNumPostDeferredPasses() override;
     void beginPostDeferredPass(S32 pass) override;
     void renderPostDeferred(S32 pass) override;
-    S32 getNumDeferredPasses() override;
-	void renderDeferred(S32 pass = 0) override;
 
-	S32 getNumPasses() override;
-	void render(S32 pass = 0) override;
 	void prerender() override;
 
 	LLViewerTexture *getDebugTexture() override;
 	LLColor3 getDebugColor() const; // For AGP debug display
 
-	void renderReflection(LLFace* face);
-	void renderWater();
-
     void setTransparentTextures(const LLUUID& transparentTextureId, const LLUUID& nextTransparentTextureId);
     void setOpaqueTexture(const LLUUID& opaqueTextureId);
     void setNormalMaps(const LLUUID& normalMapId, const LLUUID& nextNormalMapId);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 878022a2c8e87791e97d0549d1cc05dc1462fb6f..345fb81ada5a342a4dfb9ac557789e99b1df795b 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -192,7 +192,6 @@ void LLFace::destroy()
 	
 	if (isState(LLFace::PARTICLE))
 	{
-		LLVOPartGroup::freeVBSlot(getGeomIndex()/4);
 		clearState(LLFace::PARTICLE);
 	}
 
@@ -539,6 +538,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 	
 		if (mDrawablep->isState(LLDrawable::RIGGED))
 		{
+#if 0 // TODO --  there is no way this won't destroy our GL machine as implemented, rewrite it to not rely on software skinning
 			LLVOVolume* volume = mDrawablep->getVOVolume();
 			if (volume)
 			{
@@ -562,12 +562,13 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 				}
 			}
+#endif
 		}
 		else
 		{
 			// cheaters sometimes prosper...
 			//
-			mVertexBuffer->setBuffer(mVertexBuffer->getTypeMask());
+			mVertexBuffer->setBuffer();
 			mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
 		}
 
@@ -654,54 +655,8 @@ void LLFace::renderOneWireframe(const LLColor4 &color, F32 fogCfx, bool wirefram
     }
 }
 
-/* removed in lieu of raycast uv detection
-void LLFace::renderSelectedUV()
-{
-	LLViewerTexture* red_blue_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test1.j2c", TRUE, LLGLTexture::BOOST_UI);
-	LLViewerTexture* green_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test2.tga", TRUE, LLGLTexture::BOOST_UI);
-
-	LLGLSUVSelect object_select;
-
-	// use red/blue gradient to get coarse UV coordinates
-	renderSelected(red_blue_imagep, LLColor4::white);
-	
-	static F32 bias = 0.f;
-	static F32 factor = -10.f;
-	glPolygonOffset(factor, bias);
-
-	// add green dither pattern on top of red/blue gradient
-	gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_ONE);
-	gGL.matrixMode(LLRender::MM_TEXTURE);
-	gGL.pushMatrix();
-	// make green pattern repeat once per texel in red/blue texture
-	gGL.scalef(256.f, 256.f, 1.f);
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-
-	renderSelected(green_imagep, LLColor4::white);
-
-	gGL.matrixMode(LLRender::MM_TEXTURE);
-	gGL.popMatrix();
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-}
-*/
-
 void LLFace::setDrawInfo(LLDrawInfo* draw_info)
 {
-	if (draw_info)
-	{
-		if (draw_info->mFace)
-		{
-			draw_info->mFace->setDrawInfo(NULL);
-		}
-		draw_info->mFace = this;
-	}
-	
-	if (mDrawInfo)
-	{
-		mDrawInfo->mFace = NULL;
-	}
-
 	mDrawInfo = draw_info;
 }
 
@@ -1225,10 +1180,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		updateRebuildFlags();
 	}
 
-
-	//don't use map range (generates many redundant unmap calls)
-	bool map_range = false;
-
 	if (mVertexBuffer.notNull())
 	{
 		if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices())
@@ -1355,7 +1306,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	if (full_rebuild)
 	{
         LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices");
-		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range);
+		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount);
 
 		volatile __m128i* dst = (__m128i*) indicesp.get();
 		__m128i* src = (__m128i*) vf.mIndices;
@@ -1378,11 +1329,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				*idx++ = vf.mIndices[i]+index_offset;
 			}
 		}
-
-		if (map_range)
-		{
-			mVertexBuffer->flush();
-		}
 	}
 	
 	F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
@@ -1694,11 +1640,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						}
 					}
 				}
-
-				if (map_range)
-				{
-					mVertexBuffer->flush();
-				}
 			}
 			else
 			{ //bump mapped or has material, just do the whole expensive loop
@@ -1718,12 +1659,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					switch (ch)
 					{
 						case 0: 
-							mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount, map_range); 
+							mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount); 
 							break;
 						case 1:
 							if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
 							{
-								mVertexBuffer->getTexCoord1Strider(dst, mGeomIndex, mGeomCount, map_range);
+								mVertexBuffer->getTexCoord1Strider(dst, mGeomIndex, mGeomCount);
 								if (mat && !tex_anim)
 								{
 									r  = mat->getNormalRotation();
@@ -1743,7 +1684,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						case 2:
 							if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2))
 							{
-								mVertexBuffer->getTexCoord2Strider(dst, mGeomIndex, mGeomCount, map_range);
+								mVertexBuffer->getTexCoord2Strider(dst, mGeomIndex, mGeomCount);
 								if (mat && !tex_anim)
 								{
 									r  = mat->getSpecularRotation();
@@ -1802,14 +1743,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 				}
 
-				if (map_range)
-				{
-					mVertexBuffer->flush();
-				}
-
 				if ((!mat && !gltf_mat) && do_bump)
 				{
-					mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount, map_range);
+					mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount);
 		
                     mVObjp->getVolume()->genTangents(f);
 
@@ -1844,11 +1780,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					
 						*tex_coords1++ = tc;
 					}
-
-					if (map_range)
-					{
-						mVertexBuffer->flush();
-					}
 				}
 			}
 		}
@@ -1864,7 +1795,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 			llassert(num_vertices > 0);
 		
-			mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
+			mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount);
 			
 			
 			F32* dst = (F32*) vert.get();
@@ -1910,18 +1841,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				res0.store4a((F32*) dst);
 				dst += 4;
 			}
-
-			if (map_range)
-			{
-				mVertexBuffer->flush();
-			}
 		}
 
 		if (rebuild_normal)
 		{
             LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - normal");
 
-			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
+			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount);
 			F32* normals = (F32*) norm.get();
 			LLVector4a* src = vf.mNormals;
 			LLVector4a* end = src+num_vertices;
@@ -1933,17 +1859,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				normal.store4a(normals);
 				normals += 4;
 			}
-
-			if (map_range)
-			{
-				mVertexBuffer->flush();
-			}
 		}
 		
 		if (rebuild_tangent)
 		{
             LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent");
-			mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range);
+			mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount);
 			F32* tangents = (F32*) tangent.get();
 			
             mVObjp->getVolume()->genTangents(f);
@@ -1965,29 +1886,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				src++;
 				tangents += 4;
 			}
-
-			if (map_range)
-			{
-				mVertexBuffer->flush();
-			}
 		}
 	
 		if (rebuild_weights && vf.mWeights)
 		{
             LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight");
-			mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
+			mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount);
 			F32* weights = (F32*) wght.get();
 			LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
-			if (map_range)
-			{
-				mVertexBuffer->flush();
-			}
 		}
 
 		if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) )
 		{
             LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - color");
-			mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
+			mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount);
 
 			LLVector4a src;
 
@@ -2008,18 +1920,13 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				src.store4a(dst);
 				dst += 4;
 			}
-
-			if (map_range)
-			{
-				mVertexBuffer->flush();
-			}
 		}
 
 		if (rebuild_emissive)
 		{
             LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - emissive");
 			LLStrider<LLColor4U> emissive;
-			mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range);
+			mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount);
 
 			U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255);
 
@@ -2047,11 +1954,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				src.store4a(dst);
 				dst += 4;
 			}
-
-			if (map_range)
-			{
-				mVertexBuffer->flush();
-			}
 		}
 	}
 
@@ -2074,6 +1976,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	return TRUE;
 }
 
+void LLFace::renderIndexed()
+{
+    if (mVertexBuffer.notNull())
+    {
+        mVertexBuffer->setBuffer();
+        mVertexBuffer->drawRange(LLRender::TRIANGLES, getGeomIndex(), getGeomIndex() + getGeomCount()-1, getIndicesCount(), getIndicesStart());
+    }
+}
+
 //check if the face has a media
 BOOL LLFace::hasMedia() const 
 {
@@ -2405,92 +2316,12 @@ void LLFace::setViewerObject(LLViewerObject* objp)
 	mVObjp = objp;
 }
 
-const LLColor4& LLFace::getRenderColor() const
-{
-	if (isState(USE_FACE_COLOR))
-	{
-		  return mFaceColor; // Face Color
-	}
-	else
-	{
-		const LLTextureEntry* tep = getTextureEntry();
-		return (tep ? tep->getColor() : LLColor4::white);
-	}
-}
-	
-void LLFace::renderSetColor() const
-{
-	if (!LLFacePool::LLOverrideFaceColor::sOverrideFaceColor)
-	{
-		const LLColor4* color = &(getRenderColor());
-		
-		gGL.diffuseColor4fv(color->mV);
-	}
-}
-
-S32 LLFace::pushVertices(const U16* index_array) const
-{
-	if (mIndicesCount)
-	{
-		mVertexBuffer->drawRange(LLRender::TRIANGLES, mGeomIndex, mGeomIndex+mGeomCount-1, mIndicesCount, mIndicesIndex);
-		gPipeline.addTrianglesDrawn(mIndicesCount);
-	}
-
-	return mIndicesCount;
-}
 
 const LLMatrix4& LLFace::getRenderMatrix() const
 {
 	return mDrawablep->getRenderMatrix();
 }
 
-S32 LLFace::renderElements(const U16 *index_array) const
-{
-	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
-
-	S32 ret = 0;
-	
-	if (isState(GLOBAL))
-	{	
-		ret = pushVertices(index_array);
-	}
-	else
-	{
-		gGL.pushMatrix();
-		gGL.multMatrix((float*)getRenderMatrix().mMatrix);
-		ret = pushVertices(index_array);
-		gGL.popMatrix();
-	}
-	
-	return ret;
-}
-
-S32 LLFace::renderIndexed()
-{
-	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
-
-	if(mDrawablep == NULL || mDrawPoolp == NULL)
-	{
-		return 0;
-	}
-	
-	return renderIndexed(mDrawPoolp->getVertexDataMask());
-}
-
-S32 LLFace::renderIndexed(U32 mask)
-{
-	LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE
-
-	if (mVertexBuffer.isNull())
-	{
-		return 0;
-	}
-
-	mVertexBuffer->setBuffer(mask);
-	U16* index_array = (U16*) mVertexBuffer->getIndicesPointer();
-	return renderElements(index_array);
-}
-
 //============================================================================
 // From llface.inl
 
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 0cb986b8edbdd661313a97a51d89388ac1668e0c..ee8316018b6e95fc4b870ef9aaa4f942533cf5aa 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -125,12 +125,6 @@ class alignas(16) LLFace
 
 	S32             getIndexInTex(U32 ch) const {llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); return mIndexInTex[ch];}
 	void            setIndexInTex(U32 ch, S32 index) { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);  mIndexInTex[ch] = index ;}
-
-	void			renderSetColor() const;
-	S32				renderElements(const U16 *index_array) const;
-	S32				renderIndexed ();
-	S32				renderIndexed (U32 mask);
-	S32				pushVertices(const U16* index_array) const;
 	
 	void			setWorldMatrix(const LLMatrix4& mat);
 	const LLTextureEntry* getTextureEntry()	const { return mVObjp->getTE(mTEOffset); }
@@ -151,11 +145,12 @@ class alignas(16) LLFace
 	void			setDrawable(LLDrawable *drawable);
 	void			setTEOffset(const S32 te_offset);
 	
+    void            renderIndexed();
 
 	void			setFaceColor(const LLColor4& color); // override material color
 	void			unsetFaceColor(); // switch back to material color
 	const LLColor4&	getFaceColor() const { return mFaceColor; } 
-	const LLColor4& getRenderColor() const;
+	
 
 	//for volumes
 	void updateRebuildFlags();
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index d5115df35f6711967e3c2141905d22482d2e407e..500e3cc41b0f8da0af577d136e44d8924a5b63b4 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -399,6 +399,7 @@ void LLVolumeImplFlexible::doIdleUpdate()
 
 							updateRenderRes();
 
+                            mVO->shrinkWrap();
 							gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION, FALSE);
 						}
 					}
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 89ba687d2546d2173a7b8ea619c6e1d2c6396395..b2be6a925ec8be045416cf964dcf81996395d4fc 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -797,8 +797,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
 	U32 num_indices = vf.mNumIndices;
 	U32 num_vertices = vf.mNumVertices;
 
-	mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0, 0);
-	if (!mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE))
+	mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+	if (!mVertexBuffer->allocateBuffer(num_vertices, num_indices))
 	{
 		LL_WARNS() << "Failed to allocate Vertex Buffer for image preview to"
 			<< num_vertices << " vertices and "
@@ -906,7 +906,7 @@ BOOL LLImagePreviewSculpted::render()
 	const F32 BRIGHTNESS = 0.9f;
 	gGL.diffuseColor3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS);
 
-	mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0);
+	mVertexBuffer->setBuffer();
 	mVertexBuffer->draw(LLRender::TRIANGLES, num_indices, 0);
 
 	gGL.popMatrix();
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 78dba81d9a3f74bb2a033da2db9a9e02ae21d8d4..fe7c1c8f2c4134db7ee9c118537327ca8a85efb4 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -1083,9 +1083,9 @@ F32 gpu_benchmark()
     delete [] pixels;
 
 	//make a dummy triangle to draw with
-	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_STREAM_DRAW);
+	LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX);
 
-	if (!buff->allocateBuffer(3, 0, true))
+	if (!buff->allocateBuffer(3, 0))
 	{
 		LL_WARNS("Benchmark") << "Failed to allocate buffer during benchmark." << LL_ENDL;
 		// abandon the benchmark test
@@ -1109,12 +1109,12 @@ F32 gpu_benchmark()
 	v[1].set(-1, -3, 0);
 	v[2].set(3, 1, 0);
 
-	buff->flush();
+	buff->unmapBuffer();
 
 	// ensure matched pair of bind() and unbind() calls
 	ShaderBinder binder(gBenchmarkProgram);
 
-	buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+	buff->setBuffer();
 	glFinish();
 
 	F32 time_passed = 0; // seconds
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index fe6793ce7302ceb5fb5cfec1c13e3a8e48aab795..292045f25d9ee35ae23a20f0f9603b1b105de17c 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -269,9 +269,9 @@ void LLHUDObject::renderAll()
 {
     LLGLSUIDefault gls_ui;
 
+    gUIProgram.bind();
     gGL.color4f(1, 1, 1, 1);
 
-    gUIProgram.bind();
     LLGLDepthTest depth(GL_FALSE, GL_FALSE);
 
 	LLHUDObject *hud_objp;
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 5544f33aeafd6ff996a8ff85f6cc2296bb80c30b..22dca07096fd5d3e330f6f511d14d06f69a70320 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -573,7 +573,6 @@ void LLHUDText::markDead()
 void LLHUDText::renderAllHUD()
 {
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 
 	{
 		LLGLEnable color_mat(GL_COLOR_MATERIAL);
@@ -590,7 +589,6 @@ void LLHUDText::renderAllHUD()
 	LLVertexBuffer::unbind();
 
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 }
 
 void LLHUDText::shiftAll(const LLVector3& offset)
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 914528c7cef69e4ae2cc6dfc0a9a96ea67a02711..df1a29d039d18034eeff6bfb5bfd88d708ec3649 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -2788,9 +2788,9 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
                 mask |= LLVertexBuffer::MAP_WEIGHT4;
             }
 
-            vb = new LLVertexBuffer(mask, 0);
+            vb = new LLVertexBuffer(mask);
 
-            if (!vb->allocateBuffer(num_vertices, num_indices, TRUE))
+            if (!vb->allocateBuffer(num_vertices, num_indices))
             {
                 // We are likely to crash due this failure, if this happens, find a way to gracefully stop preview
                 std::ostringstream out;
@@ -2861,7 +2861,7 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)
                 *(index_strider++) = vf.mIndices[i];
             }
 
-            vb->flush();
+            vb->unmapBuffer();
 
             mVertexBuffer[lod][mdl].push_back(vb);
 
@@ -3055,11 +3055,11 @@ void LLModelPreview::addEmptyFace(LLModel* pTarget)
 {
     U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
 
-    LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0);
+    LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask);
 
-    buff->allocateBuffer(1, 3, true);
+    buff->allocateBuffer(1, 3);
     memset((U8*)buff->getMappedData(), 0, buff->getSize());
-    memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize());
+    memset((U8*)buff->getMappedIndices(), 0, buff->getIndicesSize());
 
     buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0);
 
@@ -3316,8 +3316,6 @@ BOOL LLModelPreview::render()
     gGL.pushMatrix();
     gGL.color4fv(PREVIEW_EDGE_COL.mV);
 
-    const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0;
-
     LLGLEnable normalize(GL_NORMALIZE);
 
     if (!mBaseModel.empty() && mVertexBuffer[5].empty())
@@ -3380,7 +3378,7 @@ BOOL LLModelPreview::render()
                 {
                     LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i];
 
-                    buffer->setBuffer(type_mask & buffer->getTypeMask());
+                    buffer->setBuffer();
 
                     if (textures)
                     {
@@ -3417,7 +3415,7 @@ BOOL LLModelPreview::render()
                         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                         glLineWidth(1.f);
                     }
-                    buffer->flush();
+                    buffer->unmapBuffer();
                 }
                 gGL.popMatrix();
             }
@@ -3531,7 +3529,7 @@ BOOL LLModelPreview::render()
                                     gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
                                     gGL.diffuseColor4fv(PREVIEW_PSYH_FILL_COL.mV);
 
-                                    buffer->setBuffer(type_mask & buffer->getTypeMask());
+                                    buffer->setBuffer();
                                     buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts() - 1, buffer->getNumIndices(), 0);
 
                                     gGL.diffuseColor4fv(PREVIEW_PSYH_EDGE_COL.mV);
@@ -3542,7 +3540,7 @@ BOOL LLModelPreview::render()
                                     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                                     glLineWidth(1.f);
 
-                                    buffer->flush();
+                                    buffer->unmapBuffer();
                                 }
                             }
                         }
@@ -3592,7 +3590,7 @@ BOOL LLModelPreview::render()
                                     {
                                         LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][v];
 
-                                        buffer->setBuffer(type_mask & buffer->getTypeMask());
+                                        buffer->setBuffer();
 
                                         LLStrider<LLVector3> pos_strider;
                                         buffer->getVertexStrider(pos_strider, 0);
@@ -3614,7 +3612,7 @@ BOOL LLModelPreview::render()
                                             }
                                         }
 
-                                        buffer->flush();
+                                        buffer->unmapBuffer();
                                     }
                                 }
                             }
@@ -3745,7 +3743,7 @@ BOOL LLModelPreview::render()
                             const std::string& binding = instance.mModel->mMaterialList[i];
                             const LLImportMaterial& material = instance.mMaterial[binding];
 
-                            buffer->setBuffer(type_mask & buffer->getTypeMask());
+                            buffer->setBuffer();
                             gGL.diffuseColor4fv(material.mDiffuseColor.mV);
                             gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index d9d63416178c39040aea1990c04ad8da02fb9648..b87406cb6e7306d6f7aab90aa1c1c6b27d77e308 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -513,7 +513,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
     {
         //generate radiance map
         gRadianceGenProgram.bind();
-        mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX);
+        mVertexBuffer->setBuffer();
 
         S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
         mTexture->bind(channel);
@@ -563,7 +563,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
         mTexture->bind(channel);
 
         gIrradianceGenProgram.uniform1i(sSourceIdx, targetIdx);
-        mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX);
+        mVertexBuffer->setBuffer();
         int start_mip = 0;
         // find the mip target to start with based on irradiance map resolution
         for (start_mip = 0; start_mip < mMipChain.size(); ++start_mip)
@@ -900,8 +900,8 @@ void LLReflectionMapManager::initReflectionMaps()
     if (mVertexBuffer.isNull())
     {
         U32 mask = LLVertexBuffer::MAP_VERTEX;
-        LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, GL_STATIC_DRAW);
-        buff->allocateBuffer(4, 0, TRUE);
+        LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask);
+        buff->allocateBuffer(4, 0);
 
         LLStrider<LLVector3> v;
         
@@ -912,7 +912,7 @@ void LLReflectionMapManager::initReflectionMaps()
         v[2] = LLVector3(-1, 1, -1);
         v[3] = LLVector3(1, 1, -1);
 
-        buff->flush();
+        buff->unmapBuffer();
 
         mVertexBuffer = buff;
     }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 7653913c2b3c36ab6775489bf30a794c60a51b45..2f199cc8e79864accef5fd6e4268f93d99af9bbc 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -59,12 +59,12 @@ extern bool gShiftFrame;
 static U32 sZombieGroups = 0;
 U32 LLSpatialGroup::sNodeCount = 0;
 
-BOOL LLSpatialGroup::sNoDelete = FALSE;
+bool LLSpatialGroup::sNoDelete = false;
 
 static F32 sLastMaxTexPriority = 1.f;
 static F32 sCurMaxTexPriority = 1.f;
 
-BOOL LLSpatialPartition::sTeleportRequested = FALSE;
+bool LLSpatialPartition::sTeleportRequested = false;
 
 //static counter for frame to switch LOD on
 
@@ -309,14 +309,13 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	if (vertex_count > 0 && index_count > 0)
 	{ //create vertex buffer containing volume geometry for this node
 		{
-
 			group->mBuilt = 1.f;
-			if (group->mVertexBuffer.isNull() ||
-				!group->mVertexBuffer->isWriteable() ||
-				(group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
+			if (group->mVertexBuffer.isNull() || 
+                group->mVertexBuffer->getNumVerts() != vertex_count ||
+                group->mVertexBuffer->getNumVerts() != index_count)
 			{
-				group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
-				if (!group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true))
+				group->mVertexBuffer = new LLVertexBuffer(mVertexDataMask);
+				if (!group->mVertexBuffer->allocateBuffer(vertex_count, index_count))
 				{
 					LL_WARNS() << "Failed to allocate Vertex Buffer on rebuild to "
 						<< vertex_count << " vertices and "
@@ -325,18 +324,6 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 					group->mBufferMap.clear();
 				}
 			}
-			else
-			{
-				if (!group->mVertexBuffer->resizeBuffer(vertex_count, index_count))
-				{
-					// Is likely to cause a crash. If this gets triggered find a way to avoid it (don't forget to reset face)
-					LL_WARNS() << "Failed to resize Vertex Buffer on rebuild to "
-						<< vertex_count << " vertices and "
-						<< index_count << " indices" << LL_ENDL;
-					group->mVertexBuffer = NULL;
-					group->mBufferMap.clear();
-				}
-			}
 		}
 
 		if (group->mVertexBuffer)
@@ -538,7 +525,6 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO
 	mSurfaceArea(0.f),
 	mBuilt(0.f),
 	mVertexBuffer(NULL), 
-	mBufferUsage(part->mBufferUsage),
 	mDistance(0.f),
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
@@ -567,6 +553,7 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 	if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD)
 	{
 		LL_WARNS() << "Attempted to update distance for camera other than world camera!" << LL_ENDL;
+        llassert(false);
 		return;
 	}
 
@@ -838,13 +825,12 @@ void LLSpatialGroup::destroyGL(bool keep_occlusion)
 
 //==============================================
 
-LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32 buffer_usage, LLViewerRegion* regionp)
+LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, LLViewerRegion* regionp)
 : mRenderByGroup(render_by_group), mBridge(NULL)
 {
 	mRegionp = regionp;		
 	mPartitionType = LLViewerRegion::PARTITION_NONE;
 	mVertexDataMask = data_mask;
-	mBufferUsage = buffer_usage;
 	mDepthMask = FALSE;
 	mSlopRatio = 0.25f;
 	mInfiniteFarClip = FALSE;
@@ -1437,15 +1423,15 @@ S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
 	return 0;
 }
 
-void pushVerts(LLDrawInfo* params, U32 mask)
+void pushVerts(LLDrawInfo* params)
 {
 	LLRenderPass::applyModelMatrix(*params);
-	params->mVertexBuffer->setBuffer(mask);
-	params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+	params->mVertexBuffer->setBuffer();
+	params->mVertexBuffer->drawRange(LLRender::TRIANGLES,
 								params->mStart, params->mEnd, params->mCount, params->mOffset);
 }
 
-void pushVerts(LLSpatialGroup* group, U32 mask)
+void pushVerts(LLSpatialGroup* group)
 {
 	LLDrawInfo* params = NULL;
 
@@ -1454,36 +1440,25 @@ void pushVerts(LLSpatialGroup* group, U32 mask)
 		for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) 
 		{
 			params = *j;
-			pushVerts(params, mask);
+			pushVerts(params);
 		}
 	}
 }
 
-void pushVerts(LLFace* face, U32 mask)
+void pushVerts(LLFace* face)
 {
 	if (face)
 	{
 		llassert(face->verify());
-
-		LLVertexBuffer* buffer = face->getVertexBuffer();
-
-		if (buffer && (face->getGeomCount() >= 3))
-		{
-			buffer->setBuffer(mask);
-			U16 start = face->getGeomStart();
-			U16 end = start + face->getGeomCount()-1;
-			U32 count = face->getIndicesCount();
-			U16 offset = face->getIndicesStart();
-			buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
-		}
+        face->renderIndexed();
 	}
 }
 
-void pushVerts(LLDrawable* drawable, U32 mask)
+void pushVerts(LLDrawable* drawable)
 {
 	for (S32 i = 0; i < drawable->getNumFaces(); ++i)
 	{
-		pushVerts(drawable->getFace(i), mask);
+		pushVerts(drawable->getFace(i));
 	}
 }
 
@@ -1497,16 +1472,16 @@ void pushVerts(LLVolume* volume)
 	}
 }
 
-void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
+void pushBufferVerts(LLVertexBuffer* buffer)
 {
 	if (buffer)
 	{
-		buffer->setBuffer(mask);
+		buffer->setBuffer();
 		buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
 	}
 }
 
-void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true)
+void pushBufferVerts(LLSpatialGroup* group, bool push_alpha = true)
 {
 	if (group->getSpatialPartition()->mRenderByGroup)
 	{
@@ -1517,7 +1492,7 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true)
 		
 			if (push_alpha)
 			{
-				pushBufferVerts(group->mVertexBuffer, mask);
+				pushBufferVerts(group->mVertexBuffer);
 			}
 
 			for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
@@ -1526,7 +1501,7 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true)
 				{
 					for (LLSpatialGroup::buffer_list_t::iterator k = j->second.begin(); k != j->second.end(); ++k)
 					{
-						pushBufferVerts(*k, mask);
+						pushBufferVerts(*k);
 					}
 				}
 			}
@@ -1539,7 +1514,7 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true)
 	}*/
 }
 
-void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
+void pushVertsColorCoded(LLSpatialGroup* group)
 {
 	LLDrawInfo* params = NULL;
 
@@ -1564,8 +1539,8 @@ void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
 			params = *j;
 			LLRenderPass::applyModelMatrix(*params);
 			gGL.diffuseColor4f(colors[col].mV[0], colors[col].mV[1], colors[col].mV[2], 0.5f);
-			params->mVertexBuffer->setBuffer(mask);
-			params->mVertexBuffer->drawRange(params->mParticle ? LLRender::POINTS : LLRender::TRIANGLES,
+			params->mVertexBuffer->setBuffer();
+			params->mVertexBuffer->drawRange(LLRender::TRIANGLES,
 				params->mStart, params->mEnd, params->mCount, params->mOffset);
 			col = (col+1)%col_count;
 		}
@@ -1637,17 +1612,8 @@ void renderOctree(LLSpatialGroup* group)
 	if (group->mBuilt > 0.f)
 	{
 		group->mBuilt -= 2.f * gFrameIntervalSeconds.value();
-		if (group->mBufferUsage == GL_STATIC_DRAW)
-		{
-			col.setVec(1.0f, 0, 0, group->mBuilt*0.5f);
-		}
-		else 
-		{
-			col.setVec(0.1f,0.1f,1,0.1f);
-			//col.setVec(1.0f, 1.0f, 0, sinf(group->mBuilt*3.14159f)*0.5f);
-		}
-
-		if (group->mBufferUsage != GL_STATIC_DRAW)
+		col.setVec(0.1f,0.1f,1,0.1f);
+		
 		{
 			LLGLDepthTest gl_depth(FALSE, FALSE);
 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
@@ -1708,20 +1674,36 @@ void renderOctree(LLSpatialGroup* group)
 					LLFace* face = drawable->getFace(j);
 					if (face && face->getVertexBuffer())
 					{
-						if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
-						{
-							gGL.diffuseColor4f(0, 1, 0, group->mBuilt);
-						}
-						else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
-						{
-							gGL.diffuseColor4f(1, 0, 0, group->mBuilt);
-						}
-						else
-						{
-							continue;
-						}
+                        LLVOVolume* vol = drawable->getVOVolume();
 
-						face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX | (rigged ? LLVertexBuffer::MAP_WEIGHT4 : 0));
+                        if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
+                        {
+                            if (vol && vol->isShrinkWrapped())
+                            {
+                                gGL.diffuseColor4f(0, 1, 1, group->mBuilt);
+                            }
+                            else
+                            {
+                                gGL.diffuseColor4f(0, 1, 0, group->mBuilt);
+                            }
+                        }
+                        else if (gFrameTimeSeconds - face->mLastMoveTime < 0.5f)
+                        {
+                            if (vol && vol->isShrinkWrapped())
+                            {
+                                gGL.diffuseColor4f(1, 1, 0, group->mBuilt);
+                            }
+                            else
+                            {
+                                gGL.diffuseColor4f(1, 0, 0, group->mBuilt);
+                            }
+                        }
+                        else
+                        {
+                            continue;
+                        }
+
+						face->getVertexBuffer()->setBuffer();
 						//drawBox((face->mExtents[0] + face->mExtents[1])*0.5f,
 						//		(face->mExtents[1]-face->mExtents[0])*0.5f);
 						face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart());
@@ -1743,18 +1725,6 @@ void renderOctree(LLSpatialGroup* group)
 			gGL.diffuseColor4f(1,1,1,1);
 		}
 	}
-	else
-	{
-		if (group->mBufferUsage == GL_STATIC_DRAW && !group->isEmpty() 
-			&& group->getSpatialPartition()->mRenderByGroup)
-		{
-			col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
-		}
-		else
-		{
-			col.setVec(0.1f, 0.1f, 1.f, 0.1f);
-		}
-	}
 
 	gGL.diffuseColor4fv(col.mV);
 	LLVector4a fudge;
@@ -1907,7 +1877,7 @@ void renderXRay(LLSpatialGroup* group, LLCamera* camera)
 	
 	if (render_objects)
 	{
-		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
+		pushBufferVerts(group, false);
 
 		bool selected = false;
 
@@ -1989,7 +1959,7 @@ void renderUpdateType(LLDrawable* drawablep)
 	{
 		for (S32 i = 0; i < num_faces; ++i)
 		{
-			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+			pushVerts(drawablep->getFace(i));
 		}
 	}
 }
@@ -2080,7 +2050,7 @@ void renderComplexityDisplay(LLDrawable* drawablep)
 		{
 			for (S32 i = 0; i < num_faces; ++i)
 			{
-				pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+				pushVerts(drawablep->getFace(i));
 			}
 		}
 		LLViewerObject::const_child_list_t children = voVol->getChildren();
@@ -2094,7 +2064,7 @@ void renderComplexityDisplay(LLDrawable* drawablep)
 				{
 					for (S32 i = 0; i < num_faces; ++i)
 					{
-						pushVerts(child->mDrawable->getFace(i), LLVertexBuffer::MAP_VERTEX);
+						pushVerts(child->mDrawable->getFace(i));
 					}
 				}
 			}
@@ -2736,7 +2706,7 @@ void renderPhysicsShapes(LLSpatialGroup* group, bool wireframe)
 							{
 								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
-								buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+								buff->setBuffer();
 								gGL.diffuseColor4f(0.2f, 0.5f, 0.3f, 0.5f);
 								buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
 									
@@ -2842,7 +2812,7 @@ void renderTextureAnim(LLDrawInfo* params)
 	
 	LLGLEnable blend(GL_BLEND);
 	gGL.diffuseColor4f(1,1,0,0.5f);
-	pushVerts(params, LLVertexBuffer::MAP_VERTEX);
+	pushVerts(params);
 }
 
 void renderBatchSize(LLDrawInfo* params)
@@ -2850,7 +2820,6 @@ void renderBatchSize(LLDrawInfo* params)
 	LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
 	glPolygonOffset(-1.f, 1.f);
     LLGLSLShader* old_shader = LLGLSLShader::sCurBoundShaderPtr;
-    U32 mask = LLVertexBuffer::MAP_VERTEX;
     bool bind = false;
     if (params->mAvatar)
     { 
@@ -2859,11 +2828,11 @@ void renderBatchSize(LLDrawInfo* params)
         bind = true;
         old_shader->mRiggedVariant->bind();
         LLRenderPass::uploadMatrixPalette(*params);
-        mask |= LLVertexBuffer::MAP_WEIGHT4;
     }
 	
-    gGL.diffuseColor4ubv((GLubyte*)&(params->mDebugColor));
-	pushVerts(params, mask);
+    
+    gGL.diffuseColor4ubv(params->getDebugColor().mV);
+	pushVerts(params);
 
     if (bind)
     {
@@ -2919,7 +2888,7 @@ void renderTexelDensity(LLDrawable* drawable)
 
 		if (buffer && (facep->getGeomCount() >= 3))
 		{
-			buffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+			buffer->setBuffer();
 			U16 start = facep->getGeomStart();
 			U16 end = start + facep->getGeomCount()-1;
 			U32 count = facep->getIndicesCount();
@@ -2994,7 +2963,7 @@ void renderLights(LLDrawable* drawablep)
 			LLFace * face = drawablep->getFace(i);
 			if (face)
 			{
-				pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+				pushVerts(face);
 			}
 		}
 
@@ -3967,58 +3936,46 @@ LLDrawable* LLSpatialGroup::lineSegmentIntersect(const LLVector4a& start, const
 
 LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
 					   LLViewerTexture* texture, LLVertexBuffer* buffer,
-					   bool selected,
-					   BOOL fullbright, U8 bump, BOOL particle, F32 part_size)
+					   bool fullbright, U8 bump)
 :	mVertexBuffer(buffer),
 	mTexture(texture),
-	mTextureMatrix(NULL),
-	mModelMatrix(NULL),
 	mStart(start),
 	mEnd(end),
 	mCount(count),
 	mOffset(offset), 
 	mFullbright(fullbright),
 	mBump(bump),
-	mParticle(particle),
-	mPartSize(part_size),
-	mVSize(0.f),
-	mGroup(NULL),
-	mFace(NULL),
-	mDistance(0.f),
-	mMaterial(NULL),
-	mShaderMask(0),
-	mSpecColor(1.0f, 1.0f, 1.0f, 0.5f),
 	mBlendFuncSrc(LLRender::BF_SOURCE_ALPHA),
 	mBlendFuncDst(LLRender::BF_ONE_MINUS_SOURCE_ALPHA),
-	mHasGlow(FALSE),
+	mHasGlow(false),
 	mEnvIntensity(0.0f),
-	mAlphaMaskCutoff(0.5f),
-	mDiffuseAlphaMode(0)
+	mAlphaMaskCutoff(0.5f)
 {
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
-	
-    mDebugColor = (rand() << 16) + rand();
-    ((U8*)&mDebugColor)[3] = 200;
 }
 
 LLDrawInfo::~LLDrawInfo()	
 {
-	/*if (LLSpatialGroup::sNoDelete)
-	{
-		LL_ERRS() << "LLDrawInfo deleted illegally!" << LL_ENDL;
-	}*/
-
-	if (mFace)
-	{
-		mFace->setDrawInfo(NULL);
-	}
-
 	if (gDebugGL)
 	{
 		gPipeline.checkReferences(this);
 	}
 }
 
+LLColor4U LLDrawInfo::getDebugColor() const
+{
+    LLColor4U color;
+
+    LLCRC hash;
+    hash.update((U8*)this + sizeof(S32), sizeof(LLDrawInfo) - sizeof(S32));
+
+    *((U32*) color.mV) = hash.getCRC();
+
+    color.mV[3] = 200;
+    
+    return color;
+}
+
 void LLDrawInfo::validate()
 {
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
@@ -4029,11 +3986,6 @@ U64 LLDrawInfo::getSkinHash()
     return mSkinInfo ? mSkinInfo->mHash : 0;
 }
 
-LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
-{
-	return new LLVertexBuffer(type_mask, usage);
-}
-
 LLCullResult::LLCullResult() 
 {
 	mVisibleGroupsAllocated = 0;
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index b765bd163269069c66daf03e3f7947421fd3c942..bc0eabfa0e51d0b1dafc31bdbdfb1d16e7f7dc0b 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -56,9 +56,15 @@ class LLSpatialGroup;
 class LLViewerRegion;
 class LLReflectionMap;
 
-void pushVerts(LLFace* face, U32 mask);
+void pushVerts(LLFace* face);
 
-class LLDrawInfo : public LLRefCount
+/*
+    Class that represents a single Draw Call
+
+    Make every effort to keep size minimal.
+    Member ordering is important for cache coherency
+*/
+class LLDrawInfo final : public LLRefCount
 {
     LL_ALIGN_NEW;
 protected:
@@ -75,11 +81,13 @@ class LLDrawInfo : public LLRefCount
 		LL_ERRS() << "Illegal operation!" << LL_ENDL;
 		return *this;
 	}
+    
+    // return a hash of this LLDrawInfo as a debug color
+    LLColor4U getDebugColor() const;
 
 	LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
-				LLViewerTexture* image, LLVertexBuffer* buffer, 
-				bool selected,
-				BOOL fullbright = FALSE, U8 bump = 0, BOOL particle = FALSE, F32 part_size = 0);
+				LLViewerTexture* image, LLVertexBuffer* buffer,
+				bool fullbright = false, U8 bump = 0);
 	
 
 	void validate();
@@ -88,54 +96,46 @@ class LLDrawInfo : public LLRefCount
     U64 getSkinHash();
 
 	LLPointer<LLVertexBuffer> mVertexBuffer;
+    U16 mStart = 0;
+    U16 mEnd = 0;
+    U32 mCount = 0;
+    U32 mOffset = 0;
+
 	LLPointer<LLViewerTexture>     mTexture;
-	std::vector<LLPointer<LLViewerTexture> > mTextureList;
+    LLPointer<LLViewerTexture> mSpecularMap;
+    LLPointer<LLViewerTexture> mNormalMap;
 
-    // virtual size of mTexture and mTextureList textures
-    // used to update the decode priority of textures in this DrawInfo
-    std::vector<F32> mTextureListVSize;
-
-	const LLMatrix4* mTextureMatrix;
-	const LLMatrix4* mModelMatrix;
-	U16 mStart;
-	U16 mEnd;
-	U32 mCount;
-	U32 mOffset;
-	BOOL mFullbright;
-	U8 mBump;
-	U8 mShiny;
-    U8 mTextureTimer = 1;
-	BOOL mParticle;
-	F32 mPartSize;
-	F32 mVSize;
-	LLSpatialGroup* mGroup;
-	LL_ALIGN_16(LLFace* mFace); //associated face
-	F32 mDistance;
-    S32 mDebugColor;
+    const LLMatrix4* mSpecularMapMatrix = nullptr;
+    const LLMatrix4* mNormalMapMatrix = nullptr;
+    const LLMatrix4* mTextureMatrix = nullptr;
+    const LLMatrix4* mModelMatrix = nullptr;
+
+    LLPointer<LLVOAvatar> mAvatar = nullptr;
+    LLMeshSkinInfo* mSkinInfo = nullptr;
 
     // Material pointer here is likely for debugging only and are immaterial (zing!)
-    LLMaterialPtr mMaterial; 
-    
+    LLPointer<LLMaterial> mMaterial;
+
     // PBR material parameters
     LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial;
-	
+
+    LLVector4 mSpecColor = LLVector4(1.f, 1.f, 1.f, 0.5f); // XYZ = Specular RGB, W = Specular Exponent
+
+	std::vector<LLPointer<LLViewerTexture> > mTextureList;
+
     LLUUID mMaterialID; // id of LLGLTFMaterial or LLMaterial applied to this draw info
 
-    U32 mShaderMask;
-	U32 mBlendFuncSrc;
-	U32 mBlendFuncDst;
-	BOOL mHasGlow;
-	LLPointer<LLViewerTexture> mSpecularMap;
-	const LLMatrix4* mSpecularMapMatrix;
-	LLPointer<LLViewerTexture> mNormalMap;
-	const LLMatrix4* mNormalMapMatrix;
-
-	LLVector4 mSpecColor; // XYZ = Specular RGB, W = Specular Exponent
-	F32  mEnvIntensity;
-	F32  mAlphaMaskCutoff;
-	U8   mDiffuseAlphaMode;
-    LLPointer<LLVOAvatar> mAvatar = nullptr;
-    LLMeshSkinInfo* mSkinInfo = nullptr;
+    U32 mShaderMask = 0;
+    F32  mEnvIntensity = 0.f;
+	F32  mAlphaMaskCutoff = 0.5f;
+
+    LLRender::eBlendFactor mBlendFuncSrc = LLRender::BF_SOURCE_ALPHA;
+    LLRender::eBlendFactor  mBlendFuncDst = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;
+	U8   mDiffuseAlphaMode = 0;
+    U8   mBump = 0;
+    U8   mShiny = 0;
+    bool mFullbright = false;
+    bool mHasGlow = false;
 
 	struct CompareTexture
 	{
@@ -196,19 +196,9 @@ class LLDrawInfo : public LLRefCount
 						&& (lhs.isNull() || (rhs.notNull() && lhs->mBump > rhs->mBump));
 		}
 	};
-
-	struct CompareDistanceGreater
-	{
-		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs) 
-		{
-			// sort by mBump value, sort NULL down to the end
-			return lhs.get() != rhs.get() 
-						&& (lhs.isNull() || (rhs.notNull() && lhs->mDistance > rhs->mDistance));
-		}
-	};
 };
 
-LL_ALIGN_PREFIX(64)
+LL_ALIGN_PREFIX(16)
 class LLSpatialGroup : public LLOcclusionCullingGroup
 {
 	friend class LLSpatialPartition;
@@ -227,7 +217,7 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
 	}
 
 	static U32 sNodeCount;
-	static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE
+	static bool sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE
 
 	typedef std::vector<LLPointer<LLSpatialGroup> > sg_vector_t;
 	typedef std::vector<LLPointer<LLSpatialBridge> > bridge_list_t;
@@ -343,25 +333,21 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
 	LL_ALIGN_16(LLVector4a mViewAngle);
 	LL_ALIGN_16(LLVector4a mLastUpdateViewAngle);
 
-	F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3()
-
 protected:
 	virtual ~LLSpatialGroup();
 
 public:
+    LLPointer<LLVertexBuffer> mVertexBuffer;
+    draw_map_t mDrawMap;
+
 	bridge_list_t mBridgeList;
 	buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers
 
+    F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3()
 	U32 mGeometryBytes; //used by volumes to track how many bytes of geometry data are in this node
 	F32 mSurfaceArea; //used by volumes to track estimated surface area of geometry in this node
-
 	F32 mBuilt;
 	
-	LLPointer<LLVertexBuffer> mVertexBuffer;
-
-	U32 mBufferUsage;
-	draw_map_t mDrawMap;
-	
 	F32 mDistance;
 	F32 mDepth;
 	F32 mLastUpdateDistance;
@@ -375,8 +361,7 @@ class LLSpatialGroup : public LLOcclusionCullingGroup
     U32 mRenderOrder = 0; 
     // Reflection Probe associated with this node (if any)
     LLPointer<LLReflectionMap> mReflectionProbe = nullptr;
-
-} LL_ALIGN_POSTFIX(64);
+} LL_ALIGN_POSTFIX(16);
 
 class LLGeometryManager
 {
@@ -387,14 +372,12 @@ class LLGeometryManager
 	virtual void rebuildMesh(LLSpatialGroup* group) = 0;
 	virtual void getGeometry(LLSpatialGroup* group) = 0;
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count);
-	
-	virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage);
 };
 
 class LLSpatialPartition: public LLViewerOctreePartition, public LLGeometryManager
 {
 public:
-	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, U32 mBufferUsage, LLViewerRegion* regionp);
+	LLSpatialPartition(U32 data_mask,  BOOL render_by_group, LLViewerRegion* regionp);
 	virtual ~LLSpatialPartition();
 
 	LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE);
@@ -445,14 +428,13 @@ class LLSpatialPartition: public LLViewerOctreePartition, public LLGeometryManag
 							// use a pointer instead of making "isBridge" and "asBridge" virtual so it's safe
 							// to call asBridge() from the destructor
 	
-	BOOL mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
-	U32 mBufferUsage;
-	const BOOL mRenderByGroup;
+	bool mInfiniteFarClip; // if TRUE, frustum culling ignores far clip plane
+	const bool mRenderByGroup;
 	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
+    bool mDepthMask; //if TRUE, objects in this partition will be written to depth during alpha rendering
 
-	static BOOL sTeleportRequested; //started to issue a teleport request
+	static bool sTeleportRequested; //started to issue a teleport request
 };
 
 // class for creating bridges between spatial partitions
@@ -631,7 +613,6 @@ class LLTerrainPartition : public LLSpatialPartition
 public:
 	LLTerrainPartition(LLViewerRegion* regionp);
 	virtual void getGeometry(LLSpatialGroup* group);
-	virtual LLVertexBuffer* createVertexBuffer(U32 type_mask, U32 usage);
 };
 
 //spatial partition for trees
diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp
index 0cdad86a76db7b06daf6b5aeccf91aa31287366a..b641afc1ef7dc77d99eb84adb0349c521dd74afb 100644
--- a/indra/newview/llsprite.cpp
+++ b/indra/newview/llsprite.cpp
@@ -189,9 +189,8 @@ void LLSprite::updateFace(LLFace &face)
 	if (!face.getVertexBuffer())
 	{	
 		LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | 
-												LLVertexBuffer::MAP_TEXCOORD0,
-												GL_STREAM_DRAW);
-		buff->allocateBuffer(4, 12, TRUE);
+												LLVertexBuffer::MAP_TEXCOORD0 );
+		buff->allocateBuffer(4, 12);
 		face.setGeomIndex(0);
 		face.setIndicesIndex(0);
 		face.setVertexBuffer(buff);
@@ -243,7 +242,7 @@ void LLSprite::updateFace(LLFace &face)
 		*indicesp++ = 3 + index_offset;
 	}
 
-	face.getVertexBuffer()->flush();
+	face.getVertexBuffer()->unmapBuffer();
 	face.mCenterAgent = mPosition;
 }
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 76b7347b217924819096ca3b6c19f756c00d5e90..0019038c763359b614223693b9176cd9661aea0f 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1559,12 +1559,10 @@ bool idle_startup()
 		LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
 		// Initialize all of the viewer object classes for the first time (doing things like texture fetches.
 		LLGLState::checkStates();
-		LLGLState::checkTextureChannels();
 
 		gSky.init();
 
 		LLGLState::checkStates();
-		LLGLState::checkTextureChannels();
 
 		display_startup();
 
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index d1a89a5846094c2a45c51d20192d1a4383c40849..5af03477d6a86cc542528205760b7568ecc6faca 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -148,7 +148,6 @@ void display_startup()
 	static S32 frame_count = 0;
 
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 
 	if (frame_count++ > 1) // make sure we have rendered a frame first
 	{
@@ -160,7 +159,6 @@ void display_startup()
     }
 
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // | GL_STENCIL_BUFFER_BIT);
 	LLGLSUIDefault gls_ui;
@@ -168,7 +166,6 @@ void display_startup()
 
 	if (gViewerWindow)
 	gViewerWindow->setup2DRender();
-	gGL.color4f(1,1,1,1);
 	if (gViewerWindow)
 	gViewerWindow->draw();
 	gGL.flush();
@@ -176,7 +173,6 @@ void display_startup()
 	LLVertexBuffer::unbind();
 
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 
 	if (gViewerWindow && gViewerWindow->getWindow())
 	gViewerWindow->getWindow()->swapBuffers();
@@ -282,7 +278,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	LLVertexBuffer::unbind();
 
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 	
 	stop_glerror();
 
@@ -324,7 +319,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	
 	LLAppViewer::instance()->pingMainloopTimeout("Display:CheckStates");
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 	
 	//////////////////////////////////////////////////////////
 	//
@@ -681,7 +675,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		gDepthDirty = FALSE;
 
 		LLGLState::checkStates();
-		LLGLState::checkTextureChannels();
 
 		static LLCullResult result;
 		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
@@ -690,7 +683,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		stop_glerror();
 
 		LLGLState::checkStates();
-		LLGLState::checkTextureChannels();
 		
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Swap");
 		
@@ -706,7 +698,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			glClearColor(0,0,0,0);
 
 			LLGLState::checkStates();
-			LLGLState::checkTextureChannels();
 
 			if (!for_snapshot)
 			{
@@ -719,7 +710,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				LLVertexBuffer::unbind();
 
 				LLGLState::checkStates();
-				LLGLState::checkTextureChannels();
 
 				glh::matrix4f proj = get_current_projection();
 				glh::matrix4f mod = get_current_modelview();
@@ -736,10 +726,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				gViewerWindow->setup3DViewport();
 
 				LLGLState::checkStates();
-				LLGLState::checkTextureChannels();
-
 			}
-            glClear(GL_DEPTH_BUFFER_BIT); // | GL_STENCIL_BUFFER_BIT);
+            glClear(GL_DEPTH_BUFFER_BIT);
 		}
 
 		//////////////////////////////////////
@@ -925,19 +913,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				}
 
 				gOcclusionProgram.unbind();
-			}
-
 
-			gGL.setColorMask(true, false);
-			if (LLPipeline::sRenderDeferred)
-			{
-				gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance(), true);
 			}
-			else
-			{
-				gPipeline.renderGeom(*LLViewerCamera::getInstance(), TRUE);
-			}			
+
 			gGL.setColorMask(true, true);
+			gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance(), true);
 
 			//store this frame's modelview matrix for use
 			//when rendering next frame's occlusion queries
@@ -1099,14 +1079,10 @@ void display_cube_face()
     }
     gPipeline.mRT->deferredScreen.clear();
         
-    gGL.setColorMask(true, false);
-
     LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 
     gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
 
-    gGL.setColorMask(true, true);
-
     gPipeline.mRT->deferredScreen.flush();
        
     gPipeline.renderDeferredLighting();
@@ -1340,9 +1316,12 @@ void render_ui(F32 zoom_factor, int subfield)
 	}
 
 	{
+        LLGLState::checkStates();
+
 		// Render our post process prior to the HUD, UI, etc.
 		gPipeline.renderPostProcess();
 
+        LLGLState::checkStates();
         // draw hud and 3D ui elements into screen render target so they'll be able to use 
         // the depth buffer (avoids extra copy of depth buffer per frame)
         gPipeline.screenTarget()->bindTarget();
@@ -1354,6 +1333,7 @@ void render_ui(F32 zoom_factor, int subfield)
 		// 3. Use transient zones
 		LL_PROFILE_ZONE_NAMED_CATEGORY_UI("HUD"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD);
 		render_hud_elements();
+        LLGLState::checkStates();
 		render_hud_attachments();
 
         LLGLState::checkStates();
@@ -1364,8 +1344,6 @@ void render_ui(F32 zoom_factor, int subfield)
 			gPipeline.disableLights();
 		}
 
-        gGL.color4f(1,1,1,1);
-
         bool render_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
         if (render_ui)
         {
@@ -1507,6 +1485,7 @@ void render_ui_3d()
 	stop_glerror();
 	
 	gUIProgram.bind();
+    gGL.color4f(1, 1, 1, 1);
 
 	// Coordinate axes
 	if (gSavedSettings.getBOOL("ShowAxes"))
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index f3b0e82b3af2f383ccd2692f1a9f6564343c3d14..be2a1da9685c18a113e7974687e3bc81193f37fe 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -1,4 +1,4 @@
-/** 
+ /** 
  * @file llviewerjointmesh.cpp
  * @brief Implementation of LLViewerJointMesh class
  *
@@ -62,10 +62,6 @@ extern PFNGLWEIGHTFVARBPROC glWeightfvARB;
 extern PFNGLVERTEXBLENDARBPROC glVertexBlendARB;
 #endif
 
-static const U32 sRenderMask = LLVertexBuffer::MAP_VERTEX |
-							   LLVertexBuffer::MAP_NORMAL |
-							   LLVertexBuffer::MAP_TEXCOORD0;
-
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // LLViewerJointMesh
@@ -287,8 +283,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
 	}
 	
-	U32 mask = sRenderMask;
-
 	U32 start = mMesh->mFaceVertexOffset;
 	U32 end = start + mMesh->mFaceVertexCount - 1;
 	U32 count = mMesh->mFaceIndexCount;
@@ -304,14 +298,9 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 			{
 				uploadJointMatrices();
 			}
-			mask = mask | LLVertexBuffer::MAP_WEIGHT;
-			if (mFace->getPool()->getShaderLevel() > 1)
-			{
-				mask = mask | LLVertexBuffer::MAP_CLOTHWEIGHT;
-			}
 		}
 		
-		buff->setBuffer(mask);
+		buff->setBuffer();
 		buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
 	}
 	else
@@ -319,7 +308,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		gGL.pushMatrix();
 		LLMatrix4 jointToWorld = getWorldMatrix();
 		gGL.multMatrix((GLfloat*)jointToWorld.mMatrix);
-		buff->setBuffer(mask);
+		buff->setBuffer();
 		buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
 		gGL.popMatrix();
 	}
@@ -506,7 +495,7 @@ void LLViewerJointMesh::updateGeometry(LLFace *mFace, LLPolyMesh *mMesh)
 		}
 	}
 
-	buffer->flush();
+	buffer->unmapBuffer();
 }
 
 void LLViewerJointMesh::updateJointGeometry()
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 2bd0de4d6c52fa75846b0c26bc16700078f0b6df..f416080f9eb650c49c929719df6b48f05a3292ab 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5477,6 +5477,7 @@ S32 LLViewerObject::setTERotation(const U8 te, const F32 r)
 	if (mDrawable.notNull() && retval)
 	{
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_TCOORD);
+        shrinkWrap();
 	}
 	return retval;
 }
@@ -6865,7 +6866,7 @@ F32 LLAlphaObject::getPartSize(S32 idx)
 	return 0.f;
 }
 
-void LLAlphaObject::getBlendFunc(S32 face, U32& src, U32& dst)
+void LLAlphaObject::getBlendFunc(S32 face, LLRender::eBlendFactor& src, LLRender::eBlendFactor& dst)
 {
 
 }
@@ -7278,6 +7279,18 @@ void LLViewerObject::setRenderMaterialIDs(const LLRenderMaterialParams* material
     }
 }
 
+void LLViewerObject::shrinkWrap()
+{
+    if (!mShouldShrinkWrap)
+    {
+        mShouldShrinkWrap = true;
+        if (mDrawable)
+        { // we weren't shrink wrapped before but we are now, update the spatial partition
+            gPipeline.markPartitionMove(mDrawable);
+        }
+    }
+}
+
 class ObjectPhysicsProperties : public LLHTTPNode
 {
 public:
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 71d7a7ebbba8f6338be07dc8aaaf154693be535f..fae29c3bc2fc918ba0fa9abe01311022df90bcc1 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -602,6 +602,14 @@ class LLViewerObject
 	virtual void parameterChanged(U16 param_type, bool local_origin);
 	virtual void parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin);
 	
+    bool isShrinkWrapped() const { return mShouldShrinkWrap; }
+
+    // Used to improve performance.  If an object is likely to rebuild its vertex buffer often
+    // as a side effect of some update (color update, scale, etc), setting this to true
+    // will cause it to be pushed deeper into the octree and isolate it from other nodes
+    // so that nearby objects won't attempt to share a vertex buffer with this object.
+    void shrinkWrap();
+
 	friend class LLViewerObjectList;
 	friend class LLViewerMediaList;
 
@@ -866,6 +874,9 @@ class LLViewerObject
 	F32 mPhysicsCost;
 	F32 mLinksetPhysicsCost;
     
+    // If true, "shrink wrap" this volume in its spatial partition.  See "shrinkWrap"
+    bool mShouldShrinkWrap = false;
+
 	bool mCostStale;
 	mutable bool mPhysicsShapeUnknown;
 
@@ -978,7 +989,7 @@ class LLAlphaObject : public LLViewerObject
 								LLStrider<LLColor4U>& emissivep,
 								LLStrider<U16>& indicesp) = 0;
 
-	virtual void getBlendFunc(S32 face, U32& src, U32& dst);
+	virtual void getBlendFunc(S32 face, LLRender::eBlendFactor& src, LLRender::eBlendFactor& dst);
 
 	F32 mDepth;
 };
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 1f1616178018e7804a5fa8c71b74c007104ae9a5..7d6c18ae67e7485508ec09252abec1d21a9d1f5e 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -103,11 +103,11 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
 }
 
 //create a vertex buffer for efficiently rendering cubes
-LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage)
+LLVertexBuffer* ll_create_cube_vb(U32 type_mask)
 {
-	LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage);
+	LLVertexBuffer* ret = new LLVertexBuffer(type_mask);
 
-	ret->allocateBuffer(8, 64, true);
+	ret->allocateBuffer(8, 64);
 
 	LLStrider<LLVector3> pos;
 	LLStrider<U16> idx;
@@ -129,7 +129,7 @@ LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage)
 		idx[i] = sOcclusionIndices[i];
 	}
 
-	ret->flush();
+	ret->unmapBuffer();
 
 	return ret;
 }
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 5d79c8e6b2cb3e14583c495bfbc246e47ea60826..ebc6df22acca289d5045f788d25236d691251d10 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -192,7 +192,6 @@ LLGLSLShader			gDeferredUnderWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
 LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 LLGLSLShader            gDeferredSkinnedDiffuseAlphaMaskProgram;
-LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram;
 LLGLSLShader			gDeferredSkinnedDiffuseProgram;
@@ -435,6 +434,7 @@ S32 LLViewerShaderMgr::getShaderLevel(S32 type)
 
 void LLViewerShaderMgr::setShaders()
 {
+    LL_PROFILE_ZONE_SCOPED;
     //setShaders might be called redundantly by gSavedSettings, so return on reentrance
     static bool reentrance = false;
     
@@ -792,7 +792,6 @@ void LLViewerShaderMgr::unloadShaders()
     gDeferredSkinnedDiffuseAlphaMaskProgram.unload();
 	gDeferredNonIndexedDiffuseAlphaMaskProgram.unload();
 	gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload();
-	gDeferredNonIndexedDiffuseProgram.unload();
 	gDeferredSkinnedDiffuseProgram.unload();
 	gDeferredSkinnedBumpProgram.unload();
 	
@@ -969,6 +968,7 @@ std::string LLViewerShaderMgr::loadBasicShaders()
 
 BOOL LLViewerShaderMgr::loadShadersEnvironment()
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if 1 // DEPRECATED -- forward rendering is deprecated
 	BOOL success = TRUE;
 
@@ -1039,6 +1039,7 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment()
 
 BOOL LLViewerShaderMgr::loadShadersWater()
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if 1 // DEPRECATED -- forward rendering is deprecated
 	BOOL success = TRUE;
 	BOOL terrainWaterSuccess = TRUE;
@@ -1179,6 +1180,7 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 
 BOOL LLViewerShaderMgr::loadShadersEffects()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 
 	if (mShaderLevel[SHADER_EFFECT] == 0)
@@ -1224,6 +1226,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 
 BOOL LLViewerShaderMgr::loadShadersDeferred()
 {
+    LL_PROFILE_ZONE_SCOPED;
     bool use_sun_shadow = mShaderLevel[SHADER_DEFERRED] > 1 && 
         gSavedSettings.getS32("RenderShadowDetail") > 0;
 
@@ -1237,14 +1240,13 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredTreeShadowProgram.unload();
         gDeferredSkinnedTreeShadowProgram.unload();
 		gDeferredDiffuseProgram.unload();
+        gDeferredSkinnedDiffuseProgram.unload();
 		gDeferredDiffuseAlphaMaskProgram.unload();
         gDeferredSkinnedDiffuseAlphaMaskProgram.unload();
 		gDeferredNonIndexedDiffuseAlphaMaskProgram.unload();
 		gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload();
-		gDeferredNonIndexedDiffuseProgram.unload();
-		gDeferredSkinnedDiffuseProgram.unload();
-		gDeferredSkinnedBumpProgram.unload();
 		gDeferredBumpProgram.unload();
+        gDeferredSkinnedBumpProgram.unload();
 		gDeferredImpostorProgram.unload();
 		gDeferredTerrainProgram.unload();
 		gDeferredTerrainWaterProgram.unload();
@@ -1410,19 +1412,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		llassert(success);
 	}
 
-	if (success)
-	{
-		gDeferredNonIndexedDiffuseProgram.mName = "Non Indexed Deferred Diffuse Shader";
-		gDeferredNonIndexedDiffuseProgram.mShaderFiles.clear();
-        gDeferredNonIndexedDiffuseProgram.mFeatures.encodesNormal = true;
-        gDeferredNonIndexedDiffuseProgram.mFeatures.hasSrgb = true;
-		gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER));
-		gDeferredNonIndexedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER));
-		gDeferredNonIndexedDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
-		success = gDeferredNonIndexedDiffuseProgram.createShader(NULL, NULL);
-        llassert(success);
-	}
-
 	if (success)
 	{
 		gDeferredBumpProgram.mName = "Deferred Bump Shader";
@@ -2961,6 +2950,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 BOOL LLViewerShaderMgr::loadShadersObject()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 
     if (success)
@@ -3487,6 +3477,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 
 BOOL LLViewerShaderMgr::loadShadersAvatar()
 {
+    LL_PROFILE_ZONE_SCOPED;
 #if 1 // DEPRECATED -- forward rendering is deprecated
 	BOOL success = TRUE;
 
@@ -3585,6 +3576,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar()
 
 BOOL LLViewerShaderMgr::loadShadersInterface()
 {
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 
 	if (success)
@@ -3964,6 +3956,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 
 BOOL LLViewerShaderMgr::loadShadersWindLight()
 {	
+    LL_PROFILE_ZONE_SCOPED;
 	BOOL success = TRUE;
 #if 1 // DEPRECATED -- forward rendering is deprecated
 	if (mShaderLevel[SHADER_WINDLIGHT] < 2)
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index c295bc76c0ae8c9b0d0a78b0beff1e004c93dbc6..721498572f52f06679fcc7ad8beb6165f47e024f 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1018,7 +1018,7 @@ LLViewerFetchedTexture* LLViewerFetchedTexture::getSmokeImage()
         sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE);
     }
 
-    gPipeline.touchTexture(sSmokeImagep, 1024.f * 1024.f);
+    sSmokeImagep->addTextureStats(1024.f * 1024.f);
 
     return sSmokeImagep;
 }
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 1b9154a15880748168637fbdcd1f92a2cf73d19c..312bc31faa566ab9d7237a7da888179c5def4df8 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -861,6 +861,14 @@ void LLViewerTextureList::clearFetchingRequests()
 	}
 }
 
+static void touch_texture(LLViewerFetchedTexture* tex, F32 vsize)
+{
+    if (tex)
+    {
+        tex->addTextureStats(vsize);
+    }
+}
+
 void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imagep)
 {
     if (imagep->isInDebug() || imagep->isUnremovable())
@@ -869,6 +877,39 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
         return; //is in debug, ignore.
     }
 
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE
+    {
+        for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+        {
+            for (U32 fi = 0; fi < imagep->getNumFaces(i); ++fi)
+            {
+                const LLFace* face = (*(imagep->getFaceList(i)))[fi];
+
+                if (face && face->getViewerObject() && face->getTextureEntry())
+                {
+                    F32 vsize = face->getVirtualSize();
+
+                    // if a GLTF material is present, ignore that face
+                    // as far as this texture stats go, but update the GLTF material 
+                    // stats
+                    const LLTextureEntry* te = face->getTextureEntry();
+                    LLFetchedGLTFMaterial* mat = te ? (LLFetchedGLTFMaterial*)te->getGLTFRenderMaterial() : nullptr;
+                    if (mat)
+                    {
+                        touch_texture(mat->mBaseColorTexture, vsize);
+                        touch_texture(mat->mNormalTexture, vsize);
+                        touch_texture(mat->mMetallicRoughnessTexture, vsize);
+                        touch_texture(mat->mEmissiveTexture, vsize);
+                    }
+                    else
+                    {
+                        imagep->addTextureStats(vsize);
+                    }
+                }
+            }
+        }
+    }
+    
     F32 lazy_flush_timeout = 30.f; // stop decoding
     F32 max_inactive_time = 20.f; // actually delete
     S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5848cbfd9dbc45f5ea38913d71230b87e2c4b8a8..bccb2a5e77a18229c7f2021a8e408461facda772 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -658,18 +658,6 @@ class LLDebugText
 			
 			}
 
-			addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
-			ypos += y_inc;
-
-			addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount));
-			ypos += y_inc;
-
-			addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount));
-			ypos += y_inc;
-
-			addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount));
-			ypos += y_inc;
-
 			addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
 			ypos += y_inc;
 
@@ -744,9 +732,7 @@ class LLDebugText
 				ypos += y_inc;
 			}
 
-			LLVertexBuffer::sBindCount = LLImageGL::sBindCount = 
-				LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount = 
-				gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
+            gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
 		}
 		if (gSavedSettings.getBOOL("DebugShowAvatarRenderInfo"))
 		{
@@ -2641,10 +2627,10 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
 
 void LLViewerWindow::drawDebugText()
 {
+    gUIProgram.bind();
 	gGL.color4f(1,1,1,1);
 	gGL.pushMatrix();
 	gGL.pushUIMatrix();
-	gUIProgram.bind();
 	{
 		// scale view by UI global scale factor and aspect ratio correction factor
 		gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
@@ -2701,6 +2687,7 @@ void LLViewerWindow::draw()
 	// No translation needed, this view is glued to 0,0
 
 	gUIProgram.bind();
+    gGL.color4f(1, 1, 1, 1);
 
 	gGL.pushMatrix();
 	LLUI::pushMatrix();
@@ -5688,7 +5675,6 @@ void LLViewerWindow::restoreGL(const std::string& progress_message)
 				
 		gSky.restoreGL();
 		gPipeline.restoreGL();
-		LLDrawPoolWater::restoreGL();
 		LLManipTranslate::restoreGL();
 		
 		gBumpImageList.restoreGL();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index ee12019da2c5262441b4bbe3a1b0b483c5a03cde..05fac036fb50fabbd2b6b46838c653f76660a22d 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -2348,15 +2348,15 @@ void LLVOAvatar::updateMeshData()
 			LLVertexBuffer* buff = facep->getVertexBuffer();
 			if(!facep->getVertexBuffer())
 			{
-				buff = new LLVertexBufferAvatar();
-				if (!buff->allocateBuffer(num_vertices, num_indices, TRUE))
+                buff = new LLVertexBuffer(LLDrawPoolAvatar::VERTEX_DATA_MASK);
+				if (!buff->allocateBuffer(num_vertices, num_indices))
 				{
 					LL_WARNS() << "Failed to allocate Vertex Buffer for Mesh to "
 						<< num_vertices << " vertices and "
 						<< num_indices << " indices" << LL_ENDL;
 					// Attempt to create a dummy triangle (one vertex, 3 indices, all 0)
 					facep->setSize(1, 3);
-					buff->allocateBuffer(1, 3, true);
+					buff->allocateBuffer(1, 3);
 					memset((U8*) buff->getMappedData(), 0, buff->getSize());
 					memset((U8*) buff->getMappedIndices(), 0, buff->getIndicesSize());
 				}
@@ -2371,12 +2371,13 @@ void LLVOAvatar::updateMeshData()
 				}
 				else
 				{
-					if (!buff->resizeBuffer(num_vertices, num_indices))
-					{
+                    buff = new LLVertexBuffer(buff->getTypeMask());
+                    if (!buff->allocateBuffer(num_vertices, num_indices))
+                    {
 						LL_WARNS() << "Failed to allocate vertex buffer for Mesh, Substituting" << LL_ENDL;
 						// Attempt to create a dummy triangle (one vertex, 3 indices, all 0)
 						facep->setSize(1, 3);
-						buff->resizeBuffer(1, 3);
+						buff->allocateBuffer(1, 3);
 						memset((U8*) buff->getMappedData(), 0, buff->getSize());
 						memset((U8*) buff->getMappedIndices(), 0, buff->getIndicesSize());
 					}
@@ -2413,7 +2414,7 @@ void LLVOAvatar::updateMeshData()
 			}
 
 			stop_glerror();
-			buff->flush();
+			buff->unmapBuffer();
 
 			if(!f_num)
 			{
@@ -5039,7 +5040,7 @@ U32 LLVOAvatar::renderSkinned()
 				LLVertexBuffer* vb = face->getVertexBuffer();
 				if (vb)
 				{
-					vb->flush();
+					vb->unmapBuffer();
 				}
 			}
 		}
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index b4b2db5d511ca119e5257a47b9acea4d9305e66b..56faab92c5690f775ce967d75288bb3eec0f6067 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -594,7 +594,7 @@ U32 LLVOGrass::getPartitionType() const
 }
 
 LLGrassPartition::LLGrassPartition(LLViewerRegion* regionp)
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW, regionp)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, regionp)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_GRASS;
 	mPartitionType = LLViewerRegion::PARTITION_GRASS;
@@ -602,13 +602,10 @@ LLGrassPartition::LLGrassPartition(LLViewerRegion* regionp)
 	mDepthMask = TRUE;
 	mSlopRatio = 0.1f;
 	mRenderPass = LLRenderPass::PASS_GRASS;
-	mBufferUsage = GL_DYNAMIC_DRAW;
 }
 
 void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
 {
-	group->mBufferUsage = mBufferUsage;
-
 	mFaceList.clear();
 
 	LLViewerCamera* camera = LLViewerCamera::getInstance();
@@ -624,11 +621,6 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count
 		LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get();
 		obj->mDepth = 0.f;
 		
-		if (drawablep->isAnimating())
-		{
-			group->mBufferUsage = GL_STREAM_DRAW;
-		}
-
 		U32 count = 0;
 		for (S32 j = 0; j < drawablep->getNumFaces(); ++j)
 		{
@@ -707,8 +699,7 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group)
 
 		S32 idx = draw_vec.size()-1;
 
-		BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
-		F32 vsize = facep->getVirtualSize();
+		bool fullbright = facep->isState(LLFace::FULLBRIGHT);
 
 		if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
 			draw_vec[idx]->mTexture == facep->getTexture() &&
@@ -719,7 +710,6 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group)
 		{
 			draw_vec[idx]->mCount += facep->getIndicesCount();
 			draw_vec[idx]->mEnd += facep->getGeomCount();
-			draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
 		}
 		else
 		{
@@ -731,14 +721,13 @@ void LLGrassPartition::getGeometry(LLSpatialGroup* group)
 				//facep->getTexture(),
 				buffer, object->isSelected(), fullbright);
 
-			info->mVSize = vsize;
 			draw_vec.push_back(info);
 			//for alpha sorting
 			facep->setDrawInfo(info);
 		}
 	}
 
-	buffer->flush();
+	buffer->unmapBuffer();
 	mFaceList.clear();
 }
 
diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp
index 28bd5a3c97bdf8fce199b34817038859c6e90a42..c2f7d4fef62e1797356af05eda4058a844c67e0c 100644
--- a/indra/newview/llvoground.cpp
+++ b/indra/newview/llvoground.cpp
@@ -93,8 +93,8 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
 	if (!face->getVertexBuffer())
 	{
 		face->setSize(5, 12);
-		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK, GL_STREAM_DRAW);
-		if (!buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE))
+		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolGround::VERTEX_DATA_MASK);
+		if (!buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount()))
 		{
 			LL_WARNS() << "Failed to allocate Vertex Buffer for VOGround to "
 				<< face->getGeomCount() << " vertices and "
@@ -160,7 +160,7 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
 	*(texCoordsp++) = LLVector2(0.f, 1.f);
 	*(texCoordsp++) = LLVector2(0.5f, 0.5f);
 	
-	face->getVertexBuffer()->flush();
+	face->getVertexBuffer()->unmapBuffer();
 	LLPipeline::sCompiles++;
 	return TRUE;
 }
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index a5c65d6ed478ffe27f3d89f00c7c9561106c4827..ac302ef421849e416fb3298adabb7a8eddd858bb 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -46,18 +46,8 @@
 
 extern U64MicrosecondsImplicit gFrameTime;
 
-LLPointer<LLVertexBuffer> LLVOPartGroup::sVB = NULL;
-S32 LLVOPartGroup::sVBSlotFree[];
-S32* LLVOPartGroup::sVBSlotCursor = NULL;
-
 void LLVOPartGroup::initClass()
 {
-	for (S32 i = 0; i < LL_MAX_PARTICLE_COUNT; ++i)
-	{
-		sVBSlotFree[i] = i;
-	}
-	
-	sVBSlotCursor = sVBSlotFree;
 }
 
 //static
@@ -65,9 +55,10 @@ void LLVOPartGroup::restoreGL()
 {
 
 	//TODO: optimize out binormal mask here.  Specular and normal coords as well.
-	sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, GL_STREAM_DRAW);
+#if 0
+	sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
 	U32 count = LL_MAX_PARTICLE_COUNT;
-	if (!sVB->allocateBuffer(count*4, count*6, true))
+	if (!sVB->allocateBuffer(count*4, count*6))
 	{
 		LL_WARNS() << "Failed to allocate Vertex Buffer to "
 			<< count*4 << " vertices and "
@@ -117,27 +108,14 @@ void LLVOPartGroup::restoreGL()
 		*texcoordsp++ = LLVector2(1.f, 0.f);
 	}
 
-	sVB->flush();
+	sVB->unmapBuffer();
+#endif
 
 }
 
 //static
 void LLVOPartGroup::destroyGL()
 {
-	sVB = NULL;
-}
-
-//static
-S32 LLVOPartGroup::findAvailableVBSlot()
-{
-	if (sVBSlotCursor >= sVBSlotFree + LL_MAX_PARTICLE_COUNT)
-	{ //no more available slots
-		return -1;
-	}
-
-	S32 ret = *sVBSlotCursor;
-	sVBSlotCursor++;
-	return ret;
 }
 
 bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end)
@@ -155,20 +133,6 @@ bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end)
 	return false;
 }
 
-//static
-void LLVOPartGroup::freeVBSlot(S32 idx)
-{
-	llassert(idx < LL_MAX_PARTICLE_COUNT && idx >= 0);
-	//llassert(sVBSlotCursor > sVBSlotFree);
-	//llassert(ll_is_part_idx_allocated(idx, sVBSlotCursor, sVBSlotFree+LL_MAX_PARTICLE_COUNT));
-
-	if (sVBSlotCursor > sVBSlotFree)
-	{
-		sVBSlotCursor--;
-		*sVBSlotCursor = idx;
-	}
-}
-
 LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	:	LLAlphaObject(id, pcode, regionp),
 		mViewerPartGroupp(NULL)
@@ -291,13 +255,13 @@ F32 LLVOPartGroup::getPartSize(S32 idx)
 	return 0.f;
 }
 
-void LLVOPartGroup::getBlendFunc(S32 idx, U32& src, U32& dst)
+void LLVOPartGroup::getBlendFunc(S32 idx, LLRender::eBlendFactor& src, LLRender::eBlendFactor& dst)
 {
 	if (idx < (S32) mViewerPartGroupp->mParticles.size())
 	{
 		LLViewerPart* part = mViewerPartGroupp->mParticles[idx];
-		src = part->mBlendFuncSource;
-		dst = part->mBlendFuncDest;
+		src = (LLRender::eBlendFactor) part->mBlendFuncSource;
+		dst = (LLRender::eBlendFactor) part->mBlendFuncDest;
 	}
 }
 
@@ -738,7 +702,7 @@ U32 LLVOPartGroup::getPartitionType() const
 }
 
 LLParticlePartition::LLParticlePartition(LLViewerRegion* regionp)
-: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW, regionp)
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, regionp)
 {
 	mRenderPass = LLRenderPass::PASS_ALPHA;
 	mDrawableType = LLPipeline::RENDER_TYPE_PARTICLES;
@@ -758,32 +722,68 @@ void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
 {
     LL_PROFILE_ZONE_SCOPED;
     LL_PROFILE_GPU_ZONE("particle vbo");
-	if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
-	{
-		return;
-	}
+    if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY))
+    {
+        return;
+    }
 
-	if (group->changeLOD())
-	{
-		group->mLastUpdateDistance = group->mDistance;
-		group->mLastUpdateViewAngle = group->mViewAngle;
-	}
-	
-	group->clearDrawMap();
-	
-	//get geometry count
-	U32 index_count = 0;
-	U32 vertex_count = 0;
+    if (group->changeLOD())
+    {
+        group->mLastUpdateDistance = group->mDistance;
+        group->mLastUpdateViewAngle = group->mViewAngle;
+    }
 
-	addGeometryCount(group, vertex_count, index_count);
-	
+    group->clearDrawMap();
+
+    //get geometry count
+    U32 index_count = 0;
+    U32 vertex_count = 0;
+
+    addGeometryCount(group, vertex_count, index_count);
 
-	if (vertex_count > 0 && index_count > 0 && LLVOPartGroup::sVB)
-	{ 
-		group->mBuilt = 1.f;
-		//use one vertex buffer for all groups
-		group->mVertexBuffer = LLVOPartGroup::sVB;
-		getGeometry(group);
+
+    if (vertex_count > 0 && index_count > 0)
+    {
+        group->mBuilt = 1.f;
+        if (group->mVertexBuffer.isNull() ||
+            group->mVertexBuffer->getNumVerts() < vertex_count || group->mVertexBuffer->getNumIndices() < index_count)
+        {
+            group->mVertexBuffer = new LLVertexBuffer(LLVOPartGroup::VERTEX_DATA_MASK);
+            group->mVertexBuffer->allocateBuffer(vertex_count, index_count);
+
+            // initialize index and texture coordinates only when buffer is reallocated
+            U16* indicesp = (U16*)group->mVertexBuffer->mapIndexBuffer(0, index_count);
+
+            U16 geom_idx = 0;
+            for (U32 i = 0; i < index_count; i += 6)
+            {
+                *indicesp++ = geom_idx + 0;
+                *indicesp++ = geom_idx + 1;
+                *indicesp++ = geom_idx + 2;
+
+                *indicesp++ = geom_idx + 1;
+                *indicesp++ = geom_idx + 3;
+                *indicesp++ = geom_idx + 2;
+
+                geom_idx += 4;
+            }
+
+            LLStrider<LLVector2> texcoordsp;
+
+            group->mVertexBuffer->getTexCoord0Strider(texcoordsp);
+
+            for (U32 i = 0; i < vertex_count; i += 4)
+            {
+                *texcoordsp++ = LLVector2(0.f, 1.f);
+                *texcoordsp++ = LLVector2(0.f, 0.f);
+                *texcoordsp++ = LLVector2(1.f, 1.f);
+                *texcoordsp++ = LLVector2(1.f, 0.f);
+            }
+
+        }
+
+        
+    	getGeometry(group);
 	}
 	else
 	{
@@ -797,8 +797,6 @@ void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
 
 void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
 {
-	group->mBufferUsage = mBufferUsage;
-
 	mFaceList.clear();
 
 	LLViewerCamera* camera = LLViewerCamera::getInstance();
@@ -851,10 +849,8 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 
 	LLVertexBuffer* buffer = group->mVertexBuffer;
 
-	LLStrider<U16> indicesp;
 	LLStrider<LLVector4a> verticesp;
 	LLStrider<LLVector3> normalsp;
-	LLStrider<LLVector2> texcoordsp;
 	LLStrider<LLColor4U> colorsp;
 	LLStrider<LLColor4U> emissivep;
 
@@ -863,7 +859,9 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 	buffer->getColorStrider(colorsp);
 	buffer->getEmissiveStrider(emissivep);
 
-	
+    S32 geom_idx = 0;
+    S32 indices_idx = 0;
+
 	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];	
 
 	for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
@@ -871,56 +869,44 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 		LLFace* facep = *i;
 		LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject();
 
-		if (!facep->isState(LLFace::PARTICLE))
-		{ //set the indices of this face
-			S32 idx = LLVOPartGroup::findAvailableVBSlot();
-			if (idx >= 0)
-			{
-				facep->setGeomIndex(idx*4);
-				facep->setIndicesIndex(idx*6);
-				facep->setVertexBuffer(LLVOPartGroup::sVB);
-				facep->setPoolType(LLDrawPool::POOL_ALPHA);
-				facep->setState(LLFace::PARTICLE);
-			}
-			else
-			{
-				continue; //out of space in particle buffer
-			}		
-		}
-
-		S32 geom_idx = (S32) facep->getGeomIndex();
+        facep->setGeomIndex(geom_idx);
+        facep->setIndicesIndex(indices_idx);
 
-		LLStrider<U16> cur_idx = indicesp + facep->getIndicesStart();
 		LLStrider<LLVector4a> cur_vert = verticesp + geom_idx;
 		LLStrider<LLVector3> cur_norm = normalsp + geom_idx;
-		LLStrider<LLVector2> cur_tc = texcoordsp + geom_idx;
 		LLStrider<LLColor4U> cur_col = colorsp + geom_idx;
 		LLStrider<LLColor4U> cur_glow = emissivep + geom_idx;
 
+        // not actually used
+        LLStrider<LLVector2> cur_tc;
+        LLStrider<U16> cur_idx;
+
+
+        geom_idx += 4;
+        indices_idx += 6;
+
 		LLColor4U* start_glow = cur_glow.get();
 
 		object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_glow, cur_idx);
 		
-		BOOL has_glow = FALSE;
+		bool has_glow = FALSE;
 
 		if (cur_glow.get() != start_glow)
 		{
-			has_glow = TRUE;
+			has_glow = true;
 		}
 
 		llassert(facep->getGeomCount() == 4);
 		llassert(facep->getIndicesCount() == 6);
-
-
+        
 		S32 idx = draw_vec.size()-1;
 
-		BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
-		F32 vsize = facep->getVirtualSize();
+		bool fullbright = facep->isState(LLFace::FULLBRIGHT);
         
 		bool batched = false;
 	
-		U32 bf_src = LLRender::BF_SOURCE_ALPHA;
-		U32 bf_dst = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;
+		LLRender::eBlendFactor bf_src = LLRender::BF_SOURCE_ALPHA;
+        LLRender::eBlendFactor bf_dst = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;
 
 		object->getBlendFunc(facep->getTEOffset(), bf_src, bf_dst);
 
@@ -940,7 +926,6 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 					batched = true;
 					info->mCount += facep->getIndicesCount();
 					info->mEnd += facep->getGeomCount();
-					info->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
 				}
 				else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1)
 				{
@@ -948,12 +933,10 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 					info->mCount += facep->getIndicesCount();
 					info->mStart -= facep->getGeomCount();
 					info->mOffset = facep->getIndicesStart();
-					info->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
 				}
 			}
 		}
 
-
 		if (!batched)
 		{
 			U32 start = facep->getGeomIndex();
@@ -961,19 +944,18 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 			U32 offset = facep->getIndicesStart();
 			U32 count = facep->getIndicesCount();
 			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), 
-				buffer, object->isSelected(), fullbright);
+				buffer, fullbright);
 
-			info->mVSize = vsize;
 			info->mBlendFuncDst = bf_dst;
 			info->mBlendFuncSrc = bf_src;
 			info->mHasGlow = has_glow;
-			info->mParticle = TRUE;
 			draw_vec.push_back(info);
 			//for alpha sorting
 			facep->setDrawInfo(info);
 		}
 	}
 
+    buffer->unmapBuffer();
 	mFaceList.clear();
 }
 
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index a45d381dfa14d33505587105f9b5a9ce6afe00fe..4d471134d4a9df6f09ddc5ff3fc8d5712b13676a 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -40,16 +40,9 @@ class LLVOPartGroup : public LLAlphaObject
 {
 public:
 
-	//vertex buffer for holding all particles
-	static LLPointer<LLVertexBuffer> sVB;
-	static S32 sVBSlotFree[LL_MAX_PARTICLE_COUNT];
-	static S32 *sVBSlotCursor;
-
 	static void initClass();
 	static void restoreGL();
 	static void destroyGL();
-	static S32 findAvailableVBSlot();
-	static void freeVBSlot(S32 idx);
 
 	enum
 	{
@@ -99,7 +92,7 @@ class LLVOPartGroup : public LLAlphaObject
 
 	void updateFaceSize(S32 idx) { }
 	F32 getPartSize(S32 idx);
-	void getBlendFunc(S32 idx, U32& src, U32& dst);
+	void getBlendFunc(S32 idx, LLRender::eBlendFactor& src, LLRender::eBlendFactor& dst);
 	LLUUID getPartOwner(S32 idx);
 	LLUUID getPartSource(S32 idx);
 
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index d5979b2280c0e90603ccb25f2baf4ef7288200b4..59fcacf91486c28ebcf9b7a400462ff37655df18 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -1010,8 +1010,8 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 			face->setSize(4, 6);
 			face->setGeomIndex(0);
 			face->setIndicesIndex(0);
-			LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW);
-			buff->allocateBuffer(4, 6, TRUE);
+			LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK);
+			buff->allocateBuffer(4, 6);
 			face->setVertexBuffer(buff);
 
 			index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
@@ -1046,7 +1046,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 			*indicesp++ = index_offset + 3;
 			*indicesp++ = index_offset + 2;
 
-			buff->flush();
+			buff->unmapBuffer();
 		}
 	}
 
@@ -1139,8 +1139,8 @@ bool LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const
 	if (!facep->getVertexBuffer())
 	{
 		facep->setSize(4, 6);
-		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW);
-		if (!buff->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE))
+		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK);
+		if (!buff->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount()))
 		{
 			LL_WARNS() << "Failed to allocate Vertex Buffer for vosky to "
 				<< facep->getGeomCount() << " vertices and "
@@ -1179,7 +1179,7 @@ bool LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const
 	*indicesp++ = index_offset + 2;
 	*indicesp++ = index_offset + 3;
 
-	facep->getVertexBuffer()->flush();
+	facep->getVertexBuffer()->unmapBuffer();
 
 	return TRUE;
 }
@@ -1379,8 +1379,8 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 	if (!face->getVertexBuffer() || quads*4 != face->getGeomCount())
 	{
 		face->setSize(quads * 4, quads * 6);
-		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_STREAM_DRAW);
-		if (!buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE))
+		LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK);
+		if (!buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount()))
 		{
 			LL_WARNS() << "Failed to allocate Vertex Buffer for vosky to "
 				<< face->getGeomCount() << " vertices and "
@@ -1523,7 +1523,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H,
 		}
 	}
 
-	face->getVertexBuffer()->flush();
+	face->getVertexBuffer()->unmapBuffer();
 }
 }
 
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 69ae3cf23b6ac247d09ab485469862fb5aea08b6..067272ec44d1e4c15843c12a8af25b1393729d4d 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -45,26 +45,6 @@
 
 F32 LLVOSurfacePatch::sLODFactor = 1.f;
 
-//============================================================================
-
-class LLVertexBufferTerrain : public LLVertexBuffer
-{
-public:
-	LLVertexBufferTerrain() :
-		LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0 | MAP_TEXCOORD1 | MAP_COLOR, GL_DYNAMIC_DRAW)
-	{
-		//texture coordinates 2 and 3 exist, but use the same data as texture coordinate 1
-	};
-
-	// virtual
-	void setupVertexBuffer(U32 data_mask)
-	{	
-		LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3));
-	}
-};
-
-//============================================================================
-
 LLVOSurfacePatch::LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	:	LLStaticViewerObject(id, pcode, regionp),
 		mDirtiedPatch(FALSE),
@@ -1001,7 +981,7 @@ U32 LLVOSurfacePatch::getPartitionType() const
 }
 
 LLTerrainPartition::LLTerrainPartition(LLViewerRegion* regionp)
-: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, GL_DYNAMIC_DRAW, regionp)
+: LLSpatialPartition(LLDrawPoolTerrain::VERTEX_DATA_MASK, FALSE, regionp)
 {
 	mOcclusionEnabled = FALSE;
 	mInfiniteFarClip = TRUE;
@@ -1009,11 +989,6 @@ LLTerrainPartition::LLTerrainPartition(LLViewerRegion* regionp)
 	mPartitionType = LLViewerRegion::PARTITION_TERRAIN;
 }
 
-LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage)
-{
-	return new LLVertexBufferTerrain();
-}
-
 void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 {
     LL_PROFILE_ZONE_SCOPED;
@@ -1051,7 +1026,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)
 		index_offset += facep->getGeomCount();
 	}
 
-	buffer->flush();
+	buffer->unmapBuffer();
 	mFaceList.clear();
 }
 
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index b6f8d162baceabf4a5b3fcaed69b6d7ad3daa8bd..0da77e4f8b5cd8f7801cc1dad537f90584388050 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -538,8 +538,8 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 			max_vertices += sLODVertexCount[lod];
 		}
 
-		mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, 0);
-		if (!mReferenceBuffer->allocateBuffer(max_vertices, max_indices, TRUE))
+		mReferenceBuffer = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+		if (!mReferenceBuffer->allocateBuffer(max_vertices, max_indices))
 		{
 			LL_WARNS() << "Failed to allocate Vertex Buffer on update to "
 				<< max_vertices << " vertices and "
@@ -862,7 +862,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 			slices /= 2; 
 		}
 
-		mReferenceBuffer->flush();
+		mReferenceBuffer->unmapBuffer();
 		llassert(vertex_count == max_vertices);
 		llassert(index_count == max_indices);
 	}
@@ -921,19 +921,19 @@ void LLVOTree::updateMesh()
 
 	LLFace* facep = mDrawable->getFace(0);
 	if (!facep) return;
-	LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW);
-	if (!buff->allocateBuffer(vert_count, index_count, TRUE))
+	LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
+	if (!buff->allocateBuffer(vert_count, index_count))
 	{
 		LL_WARNS() << "Failed to allocate Vertex Buffer on mesh update to "
 			<< vert_count << " vertices and "
 			<< index_count << " indices" << LL_ENDL;
-		buff->allocateBuffer(1, 3, true);
+		buff->allocateBuffer(1, 3);
 		memset((U8*)buff->getMappedData(), 0, buff->getSize());
 		memset((U8*)buff->getMappedIndices(), 0, buff->getIndicesSize());
 		facep->setSize(1, 3);
 		facep->setVertexBuffer(buff);
-		mReferenceBuffer->flush();
-		buff->flush();
+		mReferenceBuffer->unmapBuffer();
+		buff->unmapBuffer();
 		return;
 	}
 
@@ -954,8 +954,8 @@ void LLVOTree::updateMesh()
 
 	genBranchPipeline(vertices, normals, tex_coords, colors, indices, idx_offset, scale_mat, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, 1.0, mTwist, droop, mBranches, alpha);
 	
-	mReferenceBuffer->flush();
-	buff->flush();
+	mReferenceBuffer->unmapBuffer();
+	buff->unmapBuffer();
 }
 
 void LLVOTree::appendMesh(LLStrider<LLVector3>& vertices, 
@@ -1226,7 +1226,7 @@ U32 LLVOTree::getPartitionType() const
 }
 
 LLTreePartition::LLTreePartition(LLViewerRegion* regionp)
-: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW, regionp)
+: LLSpatialPartition(0, FALSE, regionp)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_TREE;
 	mPartitionType = LLViewerRegion::PARTITION_TREE;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 53158ee66fa33e4d1f36d39a516faf6f31f64b91..02d1654878a18932c29c57b8a95252955818a8c0 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -95,7 +95,6 @@ const F32 FORCE_CULL_AREA = 8.f;
 U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG = 1;
 
 BOOL gAnimateTextures = TRUE;
-//extern BOOL gHideSelectedObjects;
 
 F32 LLVOVolume::sLODFactor = 1.f;
 F32	LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop 
@@ -526,6 +525,10 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 				if (result & teDirtyBits)
 				{
 					updateTEData();
+                    if (mDrawable)
+                    { //on the fly TE updates break batches, isolate in octree
+                        shrinkWrap();
+                    }
 				}
 				if (result & TEM_CHANGE_MEDIA)
 				{
@@ -585,6 +588,7 @@ void LLVOVolume::animateTextures()
 {
 	if (!mDead)
 	{
+        shrinkWrap();
 		F32 off_s = 0.f, off_t = 0.f, scale_s = 1.f, scale_t = 1.f, rot = 0.f;
 		S32 result = mTextureAnimp->animateTextures(off_s, off_t, scale_s, scale_t, rot);
 	
@@ -976,6 +980,11 @@ void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped)
 		//since drawable transforms do not include scale, changing volume scale
 		//requires an immediate rebuild of volume verts.
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION, TRUE);
+
+        if (mDrawable)
+        {
+            shrinkWrap();
+        }
 	}
 }
 
@@ -2197,7 +2206,12 @@ S32 LLVOVolume::setTETexture(const U8 te, const LLUUID &uuid)
 	S32 res = LLViewerObject::setTETexture(te, uuid);
 	if (res)
 	{
-		gPipeline.markTextured(mDrawable);
+        if (mDrawable)
+        {
+            // dynamic texture changes break batches, isolate in octree
+            shrinkWrap();
+            gPipeline.markTextured(mDrawable);
+        }
 		mFaceMappingChanged = TRUE;
 	}
 	return res;
@@ -2232,6 +2246,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
 			// These should only happen on updates which are not the initial update.
             mColorChanged = TRUE;
 			mDrawable->setState(LLDrawable::REBUILD_COLOR);
+            shrinkWrap();
 			dirtyMesh();
 		}
 	}
@@ -2321,7 +2336,11 @@ S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow)
 	S32 res = LLViewerObject::setTEGlow(te, glow);
 	if (res)
 	{
-		gPipeline.markTextured(mDrawable);
+        if (mDrawable)
+        {
+            gPipeline.markTextured(mDrawable);
+            shrinkWrap();
+        }
 		mFaceMappingChanged = TRUE;
 	}
 	return  res;
@@ -4359,83 +4378,61 @@ void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 F32 LLVOVolume::getBinRadius()
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
-	F32 radius;
-	
-	F32 scale = 1.f;
-
-	static LLCachedControl<S32> octree_size_factor(gSavedSettings, "OctreeStaticObjectSizeFactor", 3);
-	static LLCachedControl<S32> octree_attachment_size_factor(gSavedSettings, "OctreeAttachmentSizeFactor", 4);
-	static LLCachedControl<LLVector3> octree_distance_factor(gSavedSettings, "OctreeDistanceFactor", LLVector3(0.01f, 0.f, 0.f));
-	static LLCachedControl<LLVector3> octree_alpha_distance_factor(gSavedSettings, "OctreeAlphaDistanceFactor", LLVector3(0.1f, 0.f, 0.f));
+    F32 radius;
 
-	S32 size_factor = llmax((S32)octree_size_factor, 1);
-	S32 attachment_size_factor = llmax((S32)octree_attachment_size_factor, 1);
-	LLVector3 distance_factor = octree_distance_factor;
-	LLVector3 alpha_distance_factor = octree_alpha_distance_factor;
+    static LLCachedControl<S32> octree_size_factor(gSavedSettings, "OctreeStaticObjectSizeFactor", 3);
+    static LLCachedControl<S32> octree_attachment_size_factor(gSavedSettings, "OctreeAttachmentSizeFactor", 4);
+    static LLCachedControl<LLVector3> octree_distance_factor(gSavedSettings, "OctreeDistanceFactor", LLVector3(0.01f, 0.f, 0.f));
+    static LLCachedControl<LLVector3> octree_alpha_distance_factor(gSavedSettings, "OctreeAlphaDistanceFactor", LLVector3(0.1f, 0.f, 0.f));
 
-	const LLVector4a* ext = mDrawable->getSpatialExtents();
-	
-	BOOL shrink_wrap = mDrawable->isAnimating();
-	BOOL alpha_wrap = FALSE;
+    S32 size_factor = llmax((S32)octree_size_factor, 1);
+    LLVector3 alpha_distance_factor = octree_alpha_distance_factor;
 
-	if (!isHUDAttachment())
-	{
-		for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
-		{
-			LLFace* face = mDrawable->getFace(i);
-			if (!face) continue;
-			if (face->isInAlphaPool() &&
-			    !face->canRenderAsMask())
-			{
-				alpha_wrap = TRUE;
-				break;
-			}
-		}
-	}
-	else
-	{
-		shrink_wrap = FALSE;
-	}
+    //const LLVector4a* ext = mDrawable->getSpatialExtents();
 
-	if (alpha_wrap)
-	{
-		LLVector3 bounds = getScale();
-		radius = llmin(bounds.mV[1], bounds.mV[2]);
-		radius = llmin(radius, bounds.mV[0]);
-		radius *= 0.5f;
-		radius *= 1.f+mDrawable->mDistanceWRTCamera*alpha_distance_factor[1];
-		radius += mDrawable->mDistanceWRTCamera*alpha_distance_factor[0];
-	}
-	else if (shrink_wrap)
-	{
-		LLVector4a rad;
-		rad.setSub(ext[1], ext[0]);
-		
-		radius = rad.getLength3().getF32()*0.5f;
-	}
-	else if (mDrawable->isStatic())
-	{
-		F32 szf = size_factor;
+    bool shrink_wrap = mShouldShrinkWrap || mDrawable->isAnimating();
+    bool alpha_wrap = FALSE;
 
-		radius = llmax(mDrawable->getRadius(), szf);
-		
-		radius = powf(radius, 1.f+szf/radius);
+    if (!isHUDAttachment() && mDrawable->mDistanceWRTCamera < alpha_distance_factor[2])
+    {
+        for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
+        {
+            LLFace* face = mDrawable->getFace(i);
+            if (!face) continue;
+            if (face->isInAlphaPool() &&
+                !face->canRenderAsMask())
+            {
+                alpha_wrap = TRUE;
+                break;
+            }
+        }
+    }
+    else
+    {
+        shrink_wrap = FALSE;
+    }
 
-		radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
-		radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
-	}
-	else if (mDrawable->getVObj()->isAttachment())
-	{
-		radius = llmax((S32) mDrawable->getRadius(),1)*attachment_size_factor;
-	}
-	else
-	{
-		radius = mDrawable->getRadius();
-		radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
-		radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
-	}
+    if (alpha_wrap)
+    {
+        LLVector3 bounds = getScale();
+        radius = llmin(bounds.mV[1], bounds.mV[2]);
+        radius = llmin(radius, bounds.mV[0]);
+        radius *= 0.5f;
+        //radius *= 1.f+mDrawable->mDistanceWRTCamera*alpha_distance_factor[1];
+        //radius += mDrawable->mDistanceWRTCamera*alpha_distance_factor[0];
+    }
+    else if (shrink_wrap)
+    {
+        radius = mDrawable->getRadius() * 0.25f;
+    }
+    else
+    {
+        F32 szf = size_factor;
+        radius = llmax(mDrawable->getRadius(), szf);
+        //radius = llmax(radius, mDrawable->mDistanceWRTCamera * distance_factor[0]);
+    }
 
-	return llclamp(radius*scale, 0.5f, 256.f);
+    return llclamp(radius, 0.5f, 256.f);
 }
 
 const LLVector3 LLVOVolume::getPivotPositionAgent() const
@@ -4478,6 +4475,11 @@ void LLVOVolume::markForUpdate(BOOL priority)
         }
     }
 
+    if (mDrawable)
+    {
+        shrinkWrap();
+    }
+
     LLViewerObject::markForUpdate(priority); 
     mVolumeChanged = TRUE; 
 }
@@ -4990,7 +4992,7 @@ U32 LLVOVolume::getPartitionType() const
 }
 
 LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp)
-: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW, regionp),
+: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, regionp),
 LLVolumeGeometryManager()
 {
 	mLODPeriod = 32;
@@ -4998,7 +5000,6 @@ LLVolumeGeometryManager()
 	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
 	mPartitionType = LLViewerRegion::PARTITION_VOLUME;
 	mSlopRatio = 0.25f;
-	mBufferUsage = GL_DYNAMIC_DRAW;
 }
 
 LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep, LLViewerRegion* regionp)
@@ -5010,8 +5011,6 @@ LLVolumeGeometryManager()
 	mDrawableType = LLPipeline::RENDER_TYPE_VOLUME;
 	mPartitionType = LLViewerRegion::PARTITION_BRIDGE;
 	
-	mBufferUsage = GL_DYNAMIC_DRAW;
-
 	mSlopRatio = 0.25f;
 }
 
@@ -5164,7 +5163,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 
 	S32 idx = draw_vec.size()-1;
 
-	BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
+	bool fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
 		(type == LLRenderPass::PASS_INVISIBLE) ||
 		(type == LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK) ||
 		(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)) ||
@@ -5227,7 +5226,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
         mat = facep->getTextureEntry()->getMaterialParams().get();
         if (mat)
         {
-            mat_id = facep->getTextureEntry()->getMaterialID().asUUID();
+            //mat_id = facep->getTextureEntry()->getMaterialID().asUUID();
+            mat_id = facep->getTextureEntry()->getMaterialParams()->getHash();
         }
     }
 
@@ -5247,8 +5247,6 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		}
 	}
 
-    F32 vsize = facep->getVirtualSize(); //TODO -- adjust by texture scale?
-
 	if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0)
 	{
 		if (mat || gltf_mat || draw_vec[idx]->mMaterial)
@@ -5261,12 +5259,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 			{
 				batchable = true;
 				draw_vec[idx]->mTextureList[index] = tex;
-                draw_vec[idx]->mTextureListVSize[index] = vsize;
 			}
 			else if (draw_vec[idx]->mTextureList[index] == tex)
 			{ //this face's texture index can be used with this batch
 				batchable = true;
-                draw_vec[idx]->mTextureListVSize[index] = llmax(vsize, draw_vec[idx]->mTextureListVSize[index]);
 			}
 		}
 		else
@@ -5295,14 +5291,11 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	{
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
-		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
 
 		if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= draw_vec[idx]->mTextureList.size())
 		{
 			draw_vec[idx]->mTextureList.resize(index+1);
 			draw_vec[idx]->mTextureList[index] = tex;
-            draw_vec[idx]->mTextureListVSize.resize(index + 1);
-            draw_vec[idx]->mTextureListVSize[index] = vsize;
 		}
 		draw_vec[idx]->validate();
 	}
@@ -5312,10 +5305,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		U32 end = start + facep->getGeomCount()-1;
 		U32 offset = facep->getIndicesStart();
 		U32 count = facep->getIndicesCount();
-		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, 
-			facep->getVertexBuffer(), selected, fullbright, bump);
-		draw_info->mGroup = group;
-		draw_info->mVSize = vsize;
+		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex,
+			facep->getVertexBuffer(), fullbright, bump);
 		draw_vec.push_back(draw_info);
 		draw_info->mTextureMatrix = tex_mat;
 		draw_info->mModelMatrix = model_mat;
@@ -5388,8 +5379,6 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		{ //initialize texture list for texture batching
 			draw_info->mTextureList.resize(index+1);
 			draw_info->mTextureList[index] = tex;
-            draw_info->mTextureListVSize.resize(index + 1);
-            draw_info->mTextureListVSize[index] = vsize;
 		}
 		draw_info->validate();
 	}
@@ -5551,8 +5540,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	U32 spec_count[2] = { 0 };
 	U32 normspec_count[2] = { 0 };
 
-	U32 useage = group->getSpatialPartition()->mBufferUsage;
-
 	static LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512);
 	static LLCachedControl<S32> max_node_size(gSavedSettings, "RenderMaxNodeSize", 65536);
 	U32 max_vertices = (max_vbo_size * 1024)/LLVertexBuffer::calcVertexSize(group->getSpatialPartition()->mVertexDataMask);
@@ -5584,11 +5571,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				continue;
 			}
 	
-			if (drawablep->isAnimating())
-			{ //fall back to stream draw for animating verts
-				useage = GL_STREAM_DRAW;
-			}
-
 			LLVOVolume* vobj = drawablep->getVOVolume();
             
 			if (!vobj)
@@ -5928,8 +5910,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 		}
 	}
 
-	group->mBufferUsage = useage;
-
 	//PROCESS NON-ALPHA FACES
 	U32 simple_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 	U32 alpha_mask = simple_mask | 0x80000000; //hack to give alpha verts their own VBO
@@ -6022,8 +6002,6 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 
             group->mBuilt = 1.f;
 		
-			S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ;
-
 			const U32 MAX_BUFFER_COUNT = 4096;
 			LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT];
 
@@ -6074,11 +6052,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 									gPipeline.markRebuild(group, TRUE);
 								}
 
-
-								if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT)
-								{
-									locked_buffer[buffer_count++] = buff;
-								}
+                                buff->unmapBuffer();
 							}
 						}
 					}
@@ -6096,44 +6070,17 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
                 LL_PROFILE_ZONE_NAMED("rebuildMesh - flush");
 				for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter)
 				{
-					(*iter)->flush();
+					(*iter)->unmapBuffer();
 				}
 
 				// don't forget alpha
 				if(group != NULL &&
-				   !group->mVertexBuffer.isNull() &&
-				   group->mVertexBuffer->isLocked())
+				   !group->mVertexBuffer.isNull())
 				{
-					group->mVertexBuffer->flush();
-				}
-			}
-
-			//if not all buffers are unmapped
-			if(num_mapped_vertex_buffer != LLVertexBuffer::sMappedCount)
-			{
-				LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ;
-				for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
-				{
-					LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable();
-					if(!drawablep)
-					{
-						continue;
-					}
-					for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
-					{
-						LLFace* face = drawablep->getFace(i);
-						if (face)
-						{
-							LLVertexBuffer* buff = face->getVertexBuffer();
-							if (buff && buff->isLocked())
-							{
-								buff->flush();
-							}
-						}
-					}
+					group->mVertexBuffer->unmapBuffer();
 				}
 			}
-
+			
 			group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 		}
 	} 
@@ -6200,18 +6147,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 
 	U32 geometryBytes = 0;
-	U32 buffer_usage = group->mBufferUsage;
-	
-#if LL_DARWIN
-	// HACK from Leslie:
-	// Disable VBO usage for alpha on Mac OS X because it kills the framerate
-	// due to implicit calls to glTexSubImage that are beyond our control.
-	// (this works because the only calls here that sort by distance are alpha)
-	if (distance_sort)
-	{
-		buffer_usage = 0x0;
-	}
-#endif
 	
 	//calculate maximum number of vertices to store in a single buffer
 	static LLCachedControl<S32> max_vbo_size(gSavedSettings, "RenderMaxVBOSize", 512);
@@ -6428,19 +6363,13 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 			}
 		}
 
-
-		if (flexi && buffer_usage && buffer_usage != GL_STREAM_DRAW)
-		{
-			buffer_usage = GL_STREAM_DRAW;
-		}
-
 		//create vertex buffer
 		LLPointer<LLVertexBuffer> buffer;
 
 		{
             LL_PROFILE_ZONE_NAMED("genDrawInfo - allocate");
-			buffer = createVertexBuffer(mask, buffer_usage);
-			if(!buffer->allocateBuffer(geom_count, index_count, TRUE))
+			buffer = new LLVertexBuffer(mask);
+			if(!buffer->allocateBuffer(geom_count, index_count))
 			{
 				LL_WARNS() << "Failed to allocate group Vertex Buffer to "
 					<< geom_count << " vertices and "
@@ -6830,7 +6759,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 		if (buffer)
 		{
-			buffer->flush();
+			buffer->unmapBuffer();
 		}
 	}
 
@@ -6845,9 +6774,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace
 
 void LLVolumeGeometryManager::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
 {
-    //initialize to default usage for this partition
-    U32 usage = group->getSpatialPartition()->mBufferUsage;
-
     //for each drawable
     for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
     {
@@ -6857,23 +6783,13 @@ void LLVolumeGeometryManager::addGeometryCount(LLSpatialGroup* group, U32& verte
         {
             continue;
         }
-
-        if (drawablep->isAnimating())
-        { //fall back to stream draw for animating verts
-            usage = GL_STREAM_DRAW;
-        }
     }
-
-    group->mBufferUsage = usage;
 }
 
 void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count)
 {	
     LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
 
-	//initialize to default usage for this partition
-	U32 usage = group->getSpatialPartition()->mBufferUsage;
-	
     //clear off any old faces
     mFaceList.clear();
 
@@ -6887,11 +6803,6 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 			continue;
 		}
 	
-		if (drawablep->isAnimating())
-		{ //fall back to stream draw for animating verts
-			usage = GL_STREAM_DRAW;
-		}
-
 		//for each face
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 		{
@@ -6916,8 +6827,6 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 			}
 		}
 	}
-	
-	group->mBufferUsage = usage;
 }
 
 LLHUDPartition::LLHUDPartition(LLViewerRegion* regionp) : LLBridgePartition(regionp)
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 6f30092326efe96f70cc0c197857758dc9e2e71d..2356e72aaba4d022dc85c7047a3ef822601e4ffe 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -150,10 +150,14 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 				  indices_per_quad * num_quads);
 	
 	LLVertexBuffer* buff = face->getVertexBuffer();
-	if (!buff || !buff->isWriteable())
+	if (!buff || 
+        buff->getNumIndices() != face->getIndicesCount() || 
+        buff->getNumVerts() != face->getGeomCount() ||
+        face->getIndicesStart() != 0 ||
+        face->getGeomIndex() != 0)
 	{
-		buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK, GL_DYNAMIC_DRAW);
-		if (!buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount(), TRUE))
+		buff = new LLVertexBuffer(LLDrawPoolWater::VERTEX_DATA_MASK);
+		if (!buff->allocateBuffer(face->getGeomCount(), face->getIndicesCount()))
 		{
 			LL_WARNS() << "Failed to allocate Vertex Buffer on water update to "
 				<< face->getGeomCount() << " vertices and "
@@ -163,13 +167,6 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 		face->setGeomIndex(0);
 		face->setVertexBuffer(buff);
 	}
-	else
-	{
-		if (!buff->resizeBuffer(face->getGeomCount(), face->getIndicesCount()))
-		{
-			LL_WARNS() << "Failed to resize Vertex Buffer" << LL_ENDL;
-		}
-	}
 		
 	index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp);
 		
@@ -230,7 +227,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 		}
 	}
 	
-	buff->flush();
+	buff->unmapBuffer();
 
 	mDrawable->movePartition();
 	LLPipeline::sCompiles++;
@@ -295,7 +292,7 @@ U32 LLVOVoidWater::getPartitionType() const
 }
 
 LLWaterPartition::LLWaterPartition(LLViewerRegion* regionp)
-: LLSpatialPartition(0, FALSE, GL_DYNAMIC_DRAW, regionp)
+: LLSpatialPartition(0, FALSE, regionp)
 {
 	mInfiniteFarClip = TRUE;
 	mDrawableType = LLPipeline::RENDER_TYPE_WATER;
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index 524fd4c49e5fd454d5adc60dbdf58a80d2eb007e..86e4853280939d0a409314e7dd7a8ce16c71f138 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -151,9 +151,9 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 
     if (mFsSkyVerts.isNull())
     {
-        mFsSkyVerts = new LLVertexBuffer(LLDrawPoolWLSky::ADV_ATMO_SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW);
+        mFsSkyVerts = new LLVertexBuffer(LLDrawPoolWLSky::ADV_ATMO_SKY_VERTEX_DATA_MASK);
 
-        if (!mFsSkyVerts->allocateBuffer(4, 6, TRUE))
+        if (!mFsSkyVerts->allocateBuffer(4, 6))
 		{
 			LL_WARNS() << "Failed to allocate Vertex Buffer on full screen sky update" << LL_ENDL;
 		}
@@ -184,7 +184,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 		*indices++ = 3;
 		*indices++ = 2;
 
-        mFsSkyVerts->flush();
+        mFsSkyVerts->unmapBuffer();
     }
 
 	{
@@ -216,7 +216,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 
 		for (U32 i = 0; i < strips_segments ;++i)
 		{
-			LLVertexBuffer * segment = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK, GL_STATIC_DRAW);
+			LLVertexBuffer * segment = new LLVertexBuffer(LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK);
 			mStripsVerts[i] = segment;
 
 			U32 num_stacks_this_seg = stacks_per_seg;
@@ -237,7 +237,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 			const U32 num_indices_this_seg = 1+num_stacks_this_seg*(2+2*verts_per_stack);
 			llassert(num_indices_this_seg * sizeof(U16) <= max_buffer_bytes);
 
-			bool allocated = segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE);
+			bool allocated = segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg);
 #if RELEASE_SHOW_WARNS
 			if( !allocated )
 			{
@@ -267,7 +267,7 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable)
 			buildStripsBuffer(begin_stack, end_stack, vertices, texCoords, indices, dome_radius, verts_per_stack, total_stacks);
 
 			// and unlock the buffer
-			segment->flush();
+			segment->unmapBuffer();
 		}
 	
 #if RELEASE_SHOW_DEBUG
@@ -288,7 +288,7 @@ void LLVOWLSky::drawStars(void)
 	//  render the stars as a sphere centered at viewer camera 
 	if (mStarsVerts.notNull())
 	{
-		mStarsVerts->setBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK);
+		mStarsVerts->setBuffer();
 		mStarsVerts->drawArrays(LLRender::TRIANGLES, 0, getStarsNumVerts()*4);
 	}
 }
@@ -302,7 +302,7 @@ void LLVOWLSky::drawFsSky(void)
 
     LLGLDisable disable_blend(GL_BLEND);
 
-	mFsSkyVerts->setBuffer(LLDrawPoolWLSky::ADV_ATMO_SKY_VERTEX_DATA_MASK);
+	mFsSkyVerts->setBuffer();
 	mFsSkyVerts->drawRange(LLRender::TRIANGLES, 0, mFsSkyVerts->getNumVerts() - 1, mFsSkyVerts->getNumIndices(), 0);
 	gPipeline.addTrianglesDrawn(mFsSkyVerts->getNumIndices());
 	LLVertexBuffer::unbind();
@@ -317,15 +317,13 @@ void LLVOWLSky::drawDome(void)
 
 	LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
 
-	const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK;
-	
 	std::vector< LLPointer<LLVertexBuffer> >::const_iterator strips_vbo_iter, end_strips;
 	end_strips = mStripsVerts.end();
 	for(strips_vbo_iter = mStripsVerts.begin(); strips_vbo_iter != end_strips; ++strips_vbo_iter)
 	{
 		LLVertexBuffer * strips_segment = strips_vbo_iter->get();
 
-		strips_segment->setBuffer(data_mask);
+		strips_segment->setBuffer();
 
 		strips_segment->drawRange(
 			LLRender::TRIANGLE_STRIP, 
@@ -518,10 +516,10 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable)
 	LLStrider<LLColor4U> colorsp;
 	LLStrider<LLVector2> texcoordsp;
 
-	if (mStarsVerts.isNull() || !mStarsVerts->isWriteable())
+	if (mStarsVerts.isNull())
 	{
-		mStarsVerts = new LLVertexBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK, GL_DYNAMIC_DRAW);
-		if (!mStarsVerts->allocateBuffer(getStarsNumVerts()*6, 0, TRUE))
+		mStarsVerts = new LLVertexBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK);
+		if (!mStarsVerts->allocateBuffer(getStarsNumVerts()*6, 0))
 		{
 			LL_WARNS() << "Failed to allocate Vertex Buffer for Sky to " << getStarsNumVerts() * 6 << " vertices" << LL_ENDL;
 		}
@@ -578,6 +576,6 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable)
 		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
 	}
 
-	mStarsVerts->flush();
+	mStarsVerts->unmapBuffer();
 	return TRUE;
 }
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index cedbe4d117e705a159ee6a482dac17b2e28d89a2..beaa3cdb699baef609ef41f8ebf8da33dcd0401b 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -285,7 +285,7 @@ static LLStaticHashedString sKernScale("kern_scale");
 void drawBox(const LLVector4a& c, const LLVector4a& r);
 void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
 U32 nhpo2(U32 v);
-LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage);
+LLVertexBuffer* ll_create_cube_vb(U32 type_mask);
 
 void display_update_camera();
 //----------------------------------------
@@ -416,9 +416,6 @@ void LLPipeline::init()
 	gOctreeMinSize = gSavedSettings.getF32("OctreeMinimumNodeSize");
 	sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
     sRenderBump = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("RenderObjectBump");
-	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
-	LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
-	LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
 	sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
 	sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
 
@@ -498,15 +495,15 @@ void LLPipeline::init()
 
 	if (mCubeVB.isNull())
 	{
-		mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW);
+		mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX);
 	}
 
-	mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0);
-	mDeferredVB->allocateBuffer(8, 0, true);
+	mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK);
+	mDeferredVB->allocateBuffer(8, 0);
 
     {
-        mScreenTriangleVB = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW);
-        mScreenTriangleVB->allocateBuffer(3, 0, true);
+        mScreenTriangleVB = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX);
+        mScreenTriangleVB->allocateBuffer(3, 0);
         LLStrider<LLVector3> vert;
         mScreenTriangleVB->getVertexStrider(vert);
 
@@ -514,7 +511,7 @@ void LLPipeline::init()
         vert[1].set(-1, -3, 0);
         vert[2].set(3, 1, 0);
 
-        mScreenTriangleVB->flush();
+        mScreenTriangleVB->unmapBuffer();
     }
 
     setLightingDetail(-1);
@@ -706,11 +703,6 @@ void LLPipeline::destroyGL()
 
 	releaseGLBuffers();
 
-	if (LLVertexBuffer::sEnableVBOs)
-	{
-		LLVertexBuffer::sEnableVBOs = FALSE;
-	}
-
 	if (mMeshDirtyQueryObject)
 	{
 		glDeleteQueries(1, &mMeshDirtyQueryObject);
@@ -2505,14 +2497,6 @@ void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& d
 	dest.bindTarget();
 	dest.clear(GL_DEPTH_BUFFER_BIT);
 
-	LLStrider<LLVector3> vert; 
-	mDeferredVB->getVertexStrider(vert);
-	LLStrider<LLVector2> tc0;
-		
-	vert[0].set(-1,1,0);
-	vert[1].set(-1,-3,0);
-	vert[2].set(3,1,0);
-	
 	if (source.getUsage() == LLTexUnit::TT_TEXTURE)
 	{
 		shader = &gDownsampleDepthRectProgram;
@@ -2532,8 +2516,8 @@ void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& d
 
 	{
 		LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
-		mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-		mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+        mScreenTriangleVB->setBuffer();
+        mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
 	}
 	
 	dest.flush();
@@ -2552,6 +2536,8 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     LL_PROFILE_GPU_ZONE("doOcclusion");
+    llassert(!gCubeSnapshot);
+
     if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested &&
 		(sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
 	{
@@ -2572,25 +2558,13 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 
 		LLGLDisable cull(GL_CULL_FACE);
 
-		
-		bool bind_shader = (LLGLSLShader::sCurBoundShader == 0);
-		if (bind_shader)
-		{
-			if (LLPipeline::sShadowRender)
-			{
-				gDeferredShadowCubeProgram.bind();
-			}
-			else
-			{
-				gOcclusionCubeProgram.bind();
-			}
-		}
+        gOcclusionCubeProgram.bind();
 
 		if (mCubeVB.isNull())
 		{ //cube VB will be used for issuing occlusion queries
-			mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW);
+			mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX);
 		}
-		mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+		mCubeVB->setBuffer();
 
 		for (LLCullResult::sg_iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
 		{
@@ -2610,19 +2584,7 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 			}
 		}
 
-		if (bind_shader)
-		{
-			if (LLPipeline::sShadowRender)
-			{
-				gDeferredShadowCubeProgram.unbind();
-			}
-			else
-			{
-				gOcclusionCubeProgram.unbind();
-			}
-		}
-
-		gGL.setColorMask(true, false);
+		gGL.setColorMask(true, true);
 	}
 }
 	
@@ -3661,50 +3623,6 @@ void renderSoundHighlights(LLDrawable *drawablep)
     }
 }
 
-void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize)
-{
-    if (tex)
-    {
-        tex->setActive();
-        tex->addTextureStats(vsize);
-    }
-}
-
-void LLPipeline::touchTextures(LLDrawInfo* info)
-{
-    if (--info->mTextureTimer == 0)
-    {
-        LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
-        // reset texture timer in a noisy fashion to avoid clumping of updates
-        const U32 MIN_WAIT_TIME = 8;
-        const U32 MAX_WAIT_TIME = 16;
-
-        info->mTextureTimer = ll_rand() % (MAX_WAIT_TIME - MIN_WAIT_TIME) + MIN_WAIT_TIME;
-
-        auto& mat = info->mGLTFMaterial;
-        if (mat.notNull())
-        {
-            touchTexture(mat->mBaseColorTexture, info->mVSize);
-            touchTexture(mat->mNormalTexture, info->mVSize);
-            touchTexture(mat->mMetallicRoughnessTexture, info->mVSize);
-            touchTexture(mat->mEmissiveTexture, info->mVSize);
-        }
-        else
-        {
-            info->mTextureTimer += (U8) info->mTextureList.size();
-
-            for (int i = 0; i < info->mTextureList.size(); ++i)
-            {
-                touchTexture(info->mTextureList[i], info->mTextureListVSize[i]);
-            }
-
-            touchTexture(info->mTexture, info->mVSize);
-            touchTexture(info->mSpecularMap, info->mVSize);
-            touchTexture(info->mNormalMap, info->mVSize);
-        }
-    }
-}
-
 void LLPipeline::postSort(LLCamera &camera)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
@@ -3757,28 +3675,6 @@ void LLPipeline::postSort(LLCamera &camera)
                 continue;
             }
 
-            // DEBUG -- force a texture virtual size update every frame
-            /*if (group->getSpatialPartition()->mDrawableType == LLPipeline::RENDER_TYPE_VOLUME)
-            {
-                LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("plps - update vsize");
-                auto& entries = group->getData();
-                for (auto& entry : entries)
-                {
-                    if (entry)
-                    {
-                        auto* data = entry->getDrawable();
-                        if (data)
-                        {
-                            LLVOVolume* volume = ((LLDrawable*)data)->getVOVolume();
-                            if (volume)
-                            {
-                                volume->updateTextureVirtualSize(true);
-                            }
-                        }
-                    }
-                }
-            }*/
-
             for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
             {
                 LLDrawInfo *info = *k;
@@ -3786,7 +3682,6 @@ void LLPipeline::postSort(LLCamera &camera)
                 sCull->pushDrawInfo(j->first, info);
                 if (!sShadowRender && !sReflectionRender && !gCubeSnapshot)
                 {
-                    touchTextures(info);
                     addTrianglesDrawn(info->mCount);
                 }
             }
@@ -3830,17 +3725,6 @@ void LLPipeline::postSort(LLCamera &camera)
         }
     }
 
-    // flush particle VB
-    if (LLVOPartGroup::sVB)
-    {
-        LL_PROFILE_GPU_ZONE("flush particle vb");
-        LLVOPartGroup::sVB->flush();
-    }
-    else
-    {
-        LL_WARNS_ONCE() << "Missing particle buffer" << LL_ENDL;
-    }
-
     /*bool use_transform_feedback = gTransformPositionProgram.mProgramObject && !mMeshDirtyGroup.empty();
 
     if (use_transform_feedback)
@@ -3989,9 +3873,8 @@ void render_hud_elements()
 	//glStencilMask(0xFFFFFFFF);
 	//glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
 	
-	gGL.color4f(1,1,1,1);
-	
 	gUIProgram.bind();
+    gGL.color4f(1, 1, 1, 1);
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 
 	if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
@@ -4151,261 +4034,6 @@ void LLPipeline::renderHighlights()
 //debug use
 U32 LLPipeline::sCurRenderPoolType = 0 ;
 
-void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
-{
-#if 0
-	LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY);
-    LL_PROFILE_GPU_ZONE("renderGeom");
-	assertInitialized();
-
-	F32 saved_modelview[16];
-	F32 saved_projection[16];
-
-	//HACK: preserve/restore matrices around HUD render
-	if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
-	{
-		for (U32 i = 0; i < 16; i++)
-		{
-			saved_modelview[i] = gGLModelView[i];
-			saved_projection[i] = gGLProjection[i];
-		}
-	}
-
-	///////////////////////////////////////////
-	//
-	// Sync and verify GL state
-	//
-	//
-
-	stop_glerror();
-
-	LLVertexBuffer::unbind();
-
-	// Do verification of GL state
-	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
-	if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
-	{
-		if (!verify())
-		{
-			LL_ERRS() << "Pipeline verification failed!" << LL_ENDL;
-		}
-	}
-
-	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
-	
-	// Initialize lots of GL state to "safe" values
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	gGL.matrixMode(LLRender::MM_TEXTURE);
-	gGL.loadIdentity();
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-
-	LLGLSPipeline gls_pipeline;
-	LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE : 0);
-
-	LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
-				
-	// Toggle backface culling for debugging
-	LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
-	// Set fog
-	bool use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
-	LLGLEnable fog_enable(use_fog &&
-						  !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
-	gSky.updateFog(camera.getFar());
-	if (!use_fog)
-	{
-		sUnderWaterRender = false;
-	}
-
-	gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep);
-	LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
-	
-
-	//////////////////////////////////////////////
-	//
-	// Actually render all of the geometry
-	//
-	//	
-	stop_glerror();
-	
-	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
-
-	for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
-	{
-		LLDrawPool *poolp = *iter;
-		if (hasRenderType(poolp->getType()))
-		{
-			poolp->prerender();
-		}
-	}
-
-	{
-        bool occlude = sUseOcclusion > 1;
-#if 1 // DEPRECATED -- requires forward rendering
-		LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pools"); //LL_RECORD_BLOCK_TIME(FTM_POOLS);
-		
-		// HACK: don't calculate local lights if we're rendering the HUD!
-		//    Removing this check will cause bad flickering when there are 
-		//    HUD elements being rendered AND the user is in flycam mode  -nyx
-		if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
-		{
-			calcNearbyLights(camera);
-			setupHWLights(NULL);
-		}
-
-		U32 cur_type = 0;
-
-		pool_set_t::iterator iter1 = mPools.begin();
-		while ( iter1 != mPools.end() )
-		{
-			LLDrawPool *poolp = *iter1;
-			
-			cur_type = poolp->getType();
-
-			//debug use
-			sCurRenderPoolType = cur_type ;
-
-			if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
-			{
-				occlude = false;
-				gGLLastMatrix = NULL;
-				gGL.loadMatrix(gGLModelView);
-				LLGLSLShader::bindNoShader();
-				doOcclusion(camera);
-			}
-
-
-			pool_set_t::iterator iter2 = iter1;
-			if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
-			{
-				LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pool render"); //LL_RECORD_BLOCK_TIME(FTM_POOLRENDER);
-
-				gGLLastMatrix = NULL;
-				gGL.loadMatrix(gGLModelView);
-			
-				for( S32 i = 0; i < poolp->getNumPasses(); i++ )
-				{
-					LLVertexBuffer::unbind();
-					poolp->beginRenderPass(i);
-					for (iter2 = iter1; iter2 != mPools.end(); iter2++)
-					{
-						LLDrawPool *p = *iter2;
-						if (p->getType() != cur_type)
-						{
-							break;
-						}
-						
-						if ( !p->getSkipRenderFlag() ) { p->render(i); }
-					}
-					poolp->endRenderPass(i);
-					LLVertexBuffer::unbind();
-					if (gDebugGL)
-					{
-						std::string msg = llformat("pass %d", i);
-						LLGLState::checkStates(msg);
-						//LLGLState::checkTextureChannels(msg);
-						//LLGLState::checkClientArrays(msg);
-					}
-				}
-			}
-			else
-			{
-				// Skip all pools of this type
-				for (iter2 = iter1; iter2 != mPools.end(); iter2++)
-				{
-					LLDrawPool *p = *iter2;
-					if (p->getType() != cur_type)
-					{
-						break;
-					}
-				}
-			}
-			iter1 = iter2;
-			stop_glerror();
-
-		}
-		
-		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
-
-		LLVertexBuffer::unbind();
-#endif			
-		gGLLastMatrix = NULL;
-		gGL.loadMatrix(gGLModelView);
-
-		if (occlude)
-		{ // catch uncommon condition where pools at drawpool grass and later are disabled
-			occlude = false;
-			gGLLastMatrix = NULL;
-			gGL.loadMatrix(gGLModelView);
-			LLGLSLShader::bindNoShader();
-			doOcclusion(camera);
-		}
-	}
-
-	LLVertexBuffer::unbind();
-	LLGLState::checkStates();
-
-	if (!LLPipeline::sImpostorRender)
-	{
-		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
-
-		if (!sReflectionRender)
-		{
-			renderHighlights();
-		}
-
-		// Contains a list of the faces of objects that are physical or
-		// have touch-handlers.
-		mHighlightFaces.clear();
-
-		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
-	
-		renderDebug();
-
-		LLVertexBuffer::unbind();
-	
-		if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
-		{
-			if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
-			{
-				// Render debugging beacons.
-				gObjectList.renderObjectBeacons();
-				gObjectList.resetObjectBeacons();
-                gSky.addSunMoonBeacons();
-			}
-			else
-			{
-				// Make sure particle effects disappear
-				LLHUDObject::renderAllForTimer();
-			}
-		}
-		else
-		{
-			// Make sure particle effects disappear
-			LLHUDObject::renderAllForTimer();
-		}
-
-		LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
-
-		//HACK: preserve/restore matrices around HUD render
-		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
-		{
-			for (U32 i = 0; i < 16; i++)
-			{
-				gGLModelView[i] = saved_modelview[i];
-				gGLProjection[i] = saved_projection[i];
-			}
-		}
-	}
-
-	LLVertexBuffer::unbind();
-
-	LLGLState::checkStates();
-//	LLGLState::checkTextureChannels();
-//	LLGLState::checkClientArrays();
-#endif
-}
-
 void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion)
 {
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
@@ -4438,7 +4066,6 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion)
 		LLVertexBuffer::unbind();
 
 		LLGLState::checkStates();
-		LLGLState::checkTextureChannels();
 
         if (LLViewerShaderMgr::instance()->mShaderLevel[LLViewerShaderMgr::SHADER_DEFERRED] > 1)
         {
@@ -4464,9 +4091,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion)
                 occlude = false;
                 gGLLastMatrix = NULL;
                 gGL.loadMatrix(gGLModelView);
-                LLGLSLShader::bindNoShader();
                 doOcclusion(camera);
-                gGL.setColorMask(true, false);
             }
 
 			pool_set_t::iterator iter2 = iter1;
@@ -4586,7 +4211,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 
 				if (gDebugGL || gDebugPipeline)
 				{
-					LLGLState::checkStates();
+					LLGLState::checkStates(GL_FALSE);
 				}
 			}
 		}
@@ -4667,8 +4292,6 @@ void LLPipeline::renderGeomShadow(LLCamera& camera)
 				}
 				poolp->endShadowPass(i);
 				LLVertexBuffer::unbind();
-
-				LLGLState::checkStates();
 			}
 		}
 		else
@@ -5049,8 +4672,6 @@ void LLPipeline::renderDebug()
 		}
 	}
 
-	gGL.color4f(1,1,1,1);
-
 	gGLLastMatrix = NULL;
 	gGL.loadMatrix(gGLModelView);
 	gGL.setColorMask(true, false);
@@ -5059,6 +4680,7 @@ void LLPipeline::renderDebug()
 	if (!hud_only && !mDebugBlips.empty())
 	{ //render debug blips
 		gUIProgram.bind();
+        gGL.color4f(1, 1, 1, 1);
 
 		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true);
 
@@ -5154,7 +4776,7 @@ void LLPipeline::renderDebug()
         LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("probe debug display");
 
         bindDeferredShader(gReflectionProbeDisplayProgram, NULL);
-        mScreenTriangleVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+        mScreenTriangleVB->setBuffer();
 
         // Provide our projection matrix.
         set_camera_projection_matrix(gReflectionProbeDisplayProgram);
@@ -7259,45 +6881,35 @@ void LLPipeline::doResetVertexBuffers(bool forced)
 	LLVOPartGroup::destroyGL();
     gGL.resetVertexBuffer();
 
-	if (LLVertexBuffer::sGLCount != 0)
-	{
-		LL_WARNS() << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << LL_ENDL;
-	}
-
 	LLVertexBuffer::unbind();	
 	
 	updateRenderBump();
 	updateRenderDeferred();
 
-	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
-	LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
-	LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
-	LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable");
-	LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ;
 	sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
 	sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
 	LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
 
     gGL.initVertexBuffer();
 
-    mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0);
-    mDeferredVB->allocateBuffer(8, 0, true);
+    mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK);
+    mDeferredVB->allocateBuffer(8, 0);
 
 	LLVOPartGroup::restoreGL();
 }
 
-void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
+void LLPipeline::renderObjects(U32 type, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
     if (rigged)
     {
-        mSimplePool->pushRiggedBatches(type + 1, mask, texture, batch_texture);
+        mSimplePool->pushRiggedBatches(type + 1, texture, batch_texture);
     }
     else
     {
-        mSimplePool->pushBatches(type, mask, texture, batch_texture);
+        mSimplePool->pushBatches(type, texture, batch_texture);
     }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
@@ -7326,8 +6938,8 @@ void LLPipeline::renderShadowSimple(U32 type)
         {
             LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("push shadow simple");
             mSimplePool->applyModelMatrix(params);
-            vb->setBufferFast(LLVertexBuffer::MAP_VERTEX);
-            vb->drawRangeFast(LLRender::TRIANGLES, 0, vb->getNumVerts()-1, vb->getNumIndices(), 0);
+            vb->setBuffer();
+            vb->drawRange(LLRender::TRIANGLES, 0, vb->getNumVerts()-1, vb->getNumIndices(), 0);
             last_vb = vb;
         }
     }
@@ -7335,7 +6947,7 @@ void LLPipeline::renderShadowSimple(U32 type)
     gGLLastMatrix = NULL;
 }
 
-void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture, bool rigged)
+void LLPipeline::renderAlphaObjects(bool texture, bool batch_texture, bool rigged)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     assertInitialized();
@@ -7363,12 +6975,12 @@ void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture,
                     lastMeshId = pparams->mSkinInfo->mHash;
                 }
 
-                mSimplePool->pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_texture);
+                mSimplePool->pushBatch(*pparams, texture, batch_texture);
             }
         }
         else if (pparams->mAvatar == nullptr)
         {
-            mSimplePool->pushBatch(*pparams, mask, texture, batch_texture);
+            mSimplePool->pushBatch(*pparams, texture, batch_texture);
         }
     }
 
@@ -7376,35 +6988,35 @@ void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture,
     gGLLastMatrix = NULL;
 }
 
-void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
+void LLPipeline::renderMaskedObjects(U32 type, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
     if (rigged)
     {
-        mAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture);
+        mAlphaMaskPool->pushRiggedMaskBatches(type+1, texture, batch_texture);
     }
     else
     {
-        mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+        mAlphaMaskPool->pushMaskBatches(type, texture, batch_texture);
     }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
 }
 
-void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged)
+void LLPipeline::renderFullbrightMaskedObjects(U32 type, bool texture, bool batch_texture, bool rigged)
 {
 	assertInitialized();
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;
     if (rigged)
     {
-        mFullbrightAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture);
+        mFullbrightAlphaMaskPool->pushRiggedMaskBatches(type+1, texture, batch_texture);
     }
     else
     {
-        mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+        mFullbrightAlphaMaskPool->pushMaskBatches(type, texture, batch_texture);
     }
 	gGL.loadMatrix(gGLModelView);
 	gGLLastMatrix = NULL;		
@@ -7476,7 +7088,6 @@ void LLPipeline::renderPostProcess()
 {
 	LLVertexBuffer::unbind();
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 
 	assertInitialized();
 
@@ -7486,7 +7097,6 @@ void LLPipeline::renderPostProcess()
 	LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM);
 	LL_PROFILE_GPU_ZONE("renderPostProcess");
 
-	gGL.color4f(1, 1, 1, 1);
 	LLGLDepthTest depth(GL_FALSE);
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable cull(GL_CULL_FACE);
@@ -7605,6 +7215,7 @@ void LLPipeline::renderPostProcess()
 		}
 
 		gGlowProgram.unbind();
+        gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	}
 	else // !sRenderGlow, skip the glow ping-pong and just clear the result target
 	{
@@ -7920,7 +7531,6 @@ void LLPipeline::renderFinalize()
 {
     LLVertexBuffer::unbind();
     LLGLState::checkStates();
-    LLGLState::checkTextureChannels();
 
     assertInitialized();
 
@@ -7952,7 +7562,7 @@ void LLPipeline::renderFinalize()
             LL_PROFILE_GPU_ZONE("screen space reflections");
 
             bindDeferredShader(gPostScreenSpaceReflectionProgram, NULL);
-            mScreenTriangleVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+            mScreenTriangleVB->setBuffer();
 
             set_camera_projection_matrix(gPostScreenSpaceReflectionProgram);
 
@@ -7993,7 +7603,7 @@ void LLPipeline::renderFinalize()
 
             // Apply gamma correction to the frame here.
             gDeferredPostGammaCorrectProgram.bind();
-            // mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+            
             S32 channel = 0;
             channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, screenTarget()->getUsage());
             if (channel > -1)
@@ -8134,7 +7744,7 @@ void LLPipeline::renderFinalize()
     {
         U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
         LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
-        buff->allocateBuffer(3, 0, TRUE);
+        buff->allocateBuffer(3, 0);
 
         LLStrider<LLVector3> v;
         LLStrider<LLVector2> uv1;
@@ -8167,7 +7777,7 @@ void LLPipeline::renderFinalize()
 
         LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE : 0);
 
-        buff->setBuffer(mask);
+        buff->setBuffer();
         buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
 
         gGlowCombineProgram.unbind();
@@ -8190,7 +7800,6 @@ void LLPipeline::renderFinalize()
     LLVertexBuffer::unbind();
 
     LLGLState::checkStates();
-    LLGLState::checkTextureChannels();
 
     // flush calls made to "addTrianglesDrawn" so far to stats machinery
     recordTrianglesDrawn();
@@ -8301,7 +7910,6 @@ void LLPipeline::bindDeferredShaderFast(LLGLSLShader& shader)
 void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
-    LL_PROFILE_GPU_ZONE("bindDeferredShader");
     LLRenderTarget* deferred_target       = &mRT->deferredScreen;
     //LLRenderTarget* deferred_depth_target = &mRT->deferredDepth;
     LLRenderTarget* deferred_light_target = &mRT->deferredLight;
@@ -8602,13 +8210,6 @@ void LLPipeline::renderDeferredLighting()
 
         glh::matrix4f mat = copy_matrix(gGLModelView);
 
-        LLStrider<LLVector3> vert;
-        mDeferredVB->getVertexStrider(vert);
-
-        vert[0].set(-1, 1, 0);
-        vert[1].set(-1, -3, 0);
-        vert[2].set(3, 1, 0);
-
         setupHWLights(NULL);  // to set mSun/MoonDir;
 
         glh::vec4f tc(mSunDir.mV);
@@ -8626,7 +8227,7 @@ void LLPipeline::renderDeferredLighting()
             {  // paint shadow/SSAO light map (direct lighting lightmap)
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - sun shadow");
                 bindDeferredShader(gDeferredSunProgram, deferred_light_target);
-                mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+                mScreenTriangleVB->setBuffer();
                 glClearColor(1, 1, 1, 1);
                 deferred_light_target->clear(GL_COLOR_BUFFER_BIT);
                 glClearColor(0, 0, 0, 0);
@@ -8658,9 +8259,7 @@ void LLPipeline::renderDeferredLighting()
                 {
                     LLGLDisable   blend(GL_BLEND);
                     LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
-                    stop_glerror();
-                    mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
-                    stop_glerror();
+                    mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
                 }
 
                 unbindDeferredShader(gDeferredSunProgram);
@@ -8690,7 +8289,7 @@ void LLPipeline::renderDeferredLighting()
                 glClearColor(0, 0, 0, 0);
 
                 bindDeferredShader(gDeferredBlurLightProgram);
-                mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+                mScreenTriangleVB->setBuffer();
                 LLVector3 go = RenderShadowGaussian;
                 const U32 kern_length = 4;
                 F32       blur_size = RenderShadowBlurSize;
@@ -8719,9 +8318,7 @@ void LLPipeline::renderDeferredLighting()
                 {
                     LLGLDisable   blend(GL_BLEND);
                     LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
-                    stop_glerror();
-                    mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
-                    stop_glerror();
+                    mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
                 }
 
                 screen_target->flush();
@@ -8729,7 +8326,7 @@ void LLPipeline::renderDeferredLighting()
 
                 bindDeferredShader(gDeferredBlurLightProgram, screen_target);
 
-                mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+                mScreenTriangleVB->setBuffer();
                 deferred_light_target->bindTarget();
 
                 gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f);
@@ -8737,9 +8334,7 @@ void LLPipeline::renderDeferredLighting()
                 {
                     LLGLDisable   blend(GL_BLEND);
                     LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
-                    stop_glerror();
-                    mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
-                    stop_glerror();
+                    mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
                 }
                 deferred_light_target->flush();
                 unbindDeferredShader(gDeferredBlurLightProgram);
@@ -8781,9 +8376,8 @@ void LLPipeline::renderDeferredLighting()
 
                 // full screen blit
 
-                mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-
-                mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+                mScreenTriangleVB->setBuffer();
+                mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
 
             }
 
@@ -8836,10 +8430,10 @@ void LLPipeline::renderDeferredLighting()
 
                 if (mCubeVB.isNull())
                 {
-                    mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW);
+                    mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX);
                 }
 
-                mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+                mCubeVB->setBuffer();
 
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
                 // mNearbyLights already includes distance calculation and excludes muted avatars.
@@ -8942,7 +8536,7 @@ void LLPipeline::renderDeferredLighting()
                 LLGLDepthTest depth(GL_TRUE, GL_FALSE);
                 bindDeferredShader(gDeferredSpotLightProgram);
 
-                mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+                mCubeVB->setBuffer();
 
                 gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
 
@@ -8976,12 +8570,6 @@ void LLPipeline::renderDeferredLighting()
                 unbindDeferredShader(gDeferredSpotLightProgram);
             }
 
-            // reset mDeferredVB to fullscreen triangle
-            mDeferredVB->getVertexStrider(vert);
-            vert[0].set(-1, 1, 0);
-            vert[1].set(-1, -3, 0);
-            vert[2].set(3, 1, 0);
-
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - fullscreen lights");
                 LLGLDepthTest depth(GL_FALSE);
@@ -9014,8 +8602,8 @@ void LLPipeline::renderDeferredLighting()
                         gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
                         far_z = 0.f;
                         count = 0;
-                        mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-                        mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+                        mScreenTriangleVB->setBuffer();
+                        mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
                         unbindDeferredShader(gDeferredMultiLightProgram[idx]);
                     }
                 }
@@ -9024,7 +8612,7 @@ void LLPipeline::renderDeferredLighting()
 
                 gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
 
-                mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+                mScreenTriangleVB->setBuffer();
 
                 for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
                 {
@@ -9049,7 +8637,7 @@ void LLPipeline::renderDeferredLighting()
                     gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, light_size_final);
                     gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
                     gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, light_falloff_final);
-                    mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+                    mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
                 }
 
                 gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
@@ -9098,6 +8686,8 @@ void LLPipeline::renderDeferredLighting()
     }
 
     screen_target->flush();
+
+    gGL.setColorMask(true, true);
 }
 
 void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
@@ -9534,7 +9124,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
         {
             if (rigged)
             {
-                renderObjects(type, LLVertexBuffer::MAP_VERTEX, FALSE, FALSE, rigged);
+                renderObjects(type, false, false, rigged);
             }
             else
             {
@@ -9571,11 +9161,6 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
         LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha");
         LL_PROFILE_GPU_ZONE("shadow alpha");
 
-        U32 mask = LLVertexBuffer::MAP_VERTEX |
-            LLVertexBuffer::MAP_TEXCOORD0 |
-            LLVertexBuffer::MAP_COLOR |
-            LLVertexBuffer::MAP_TEXTURE_INDEX;
-
         for (int i = 0; i < 2; ++i)
         {
             bool rigged = i == 1;
@@ -9586,37 +9171,44 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha masked");
-                renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE, rigged);
+                LL_PROFILE_GPU_ZONE("shadow alpha masked");
+                renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, true, true, rigged);
             }
 
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha blend");
+                LL_PROFILE_GPU_ZONE("shadow alpha blend");
                 LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
-                renderAlphaObjects(mask, TRUE, TRUE, rigged);
+                renderAlphaObjects(true, true, rigged);
             }
 
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow fullbright alpha masked");
+                LL_PROFILE_GPU_ZONE("shadow alpha masked");
                 gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged);
                 LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
                 LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
-                renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE, rigged);
+                renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true, rigged);
             }
 
             {
                 LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass");
+                LL_PROFILE_GPU_ZONE("shadow alpha grass");
                 gDeferredTreeShadowProgram.bind(rigged);
                 if (i == 0)
                 {
                     LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f);
-                    renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+                    renderObjects(LLRenderPass::PASS_GRASS, true);
                 }
 
-                U32 no_idx_mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX;
-                renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, no_idx_mask, true, false, rigged);
-                renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, no_idx_mask, true, false, rigged);
-                renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, no_idx_mask, true, false, rigged);
-                renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, no_idx_mask, true, false, rigged);
+                {
+                    LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha material");
+                    LL_PROFILE_GPU_ZONE("shadow alpha material");
+                    renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, true, false, rigged);
+                    renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, true, false, rigged);
+                    renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, true, false, rigged);
+                    renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, true, false, rigged);
+                }
             }
         }
 
@@ -9634,11 +9226,11 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
             if (rigged)
             {
-                mAlphaMaskPool->pushRiggedGLTFBatches(type + 1, mask);
+                mAlphaMaskPool->pushRiggedGLTFBatches(type + 1);
             }
             else
             {
-                mAlphaMaskPool->pushGLTFBatches(type, mask);
+                mAlphaMaskPool->pushGLTFBatches(type);
             }
 
             gGL.loadMatrix(gGLModelView);
@@ -9891,7 +9483,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	bool skip_avatar_update = false;
 	if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
 	{
-
 		skip_avatar_update = true;
 	}
 
@@ -10005,12 +9596,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	clip = RenderShadowOrthoClipPlanes;
 	mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
 
-    //if (gCubeSnapshot)
-    { //always do a single 64m shadow in reflection maps
-        mSunClipPlanes.set(64.f, 128.f, 256.f);
-        mSunOrthoClipPlanes.set(64.f, 128.f, 256.f);
-    }
-
 	//currently used for amount to extrude frusta corners for constructing shadow frusta
 	//LLVector3 n = RenderShadowNearDist;
 	//F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
@@ -10515,7 +10100,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
 			{
 				static LLCullResult result[4];
-				renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE, FALSE, target_width);
+				renderShadow(view[j], proj[j], shadow_cam, result[j], true, true, target_width);
 			}
 
 			mRT->shadow[j].flush();
@@ -10670,7 +10255,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
                 RenderSpotLight = drawable;
 
-                renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], FALSE, FALSE, target_width);
+                renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], false, true, target_width);
 
                 RenderSpotLight = nullptr;
 
@@ -10698,7 +10283,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		gGL.loadMatrix(proj[1].m);
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
 	}
-	gGL.setColorMask(true, false);
+	gGL.setColorMask(true, true);
 
 	for (U32 i = 0; i < 16; i++)
 	{
@@ -10714,7 +10299,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	}
 }
 
-void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture)
+void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, bool texture)
 {
 	for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
 	{
@@ -10724,12 +10309,12 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool textu
 			gPipeline.hasRenderType(group->getSpatialPartition()->mDrawableType) &&
 			group->mDrawMap.find(type) != group->mDrawMap.end())
 		{
-			pass->renderGroup(group,type,mask,texture);
+			pass->renderGroup(group,type,texture);
 		}
 	}
 }
 
-void LLPipeline::renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture)
+void LLPipeline::renderRiggedGroups(LLRenderPass* pass, U32 type, bool texture)
 {
     for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
     {
@@ -10739,7 +10324,7 @@ void LLPipeline::renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool
             gPipeline.hasRenderType(group->getSpatialPartition()->mDrawableType) &&
             group->mDrawMap.find(type) != group->mDrawMap.end())
         {
-            pass->renderRiggedGroup(group, type, mask, texture);
+            pass->renderRiggedGroup(group, type, texture);
         }
     }
 }
@@ -10751,7 +10336,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar)
     LL_RECORD_BLOCK_TIME(FTM_GENERATE_IMPOSTOR);
     LL_PROFILE_GPU_ZONE("generateImpostor");
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 
 	static LLCullResult result;
 	result.clear();
@@ -10977,17 +10561,10 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar)
     if (preview_avatar)
     {
         // previews don't care about imposters
-        if (LLPipeline::sRenderDeferred)
-        {
-            renderGeomDeferred(camera);
-            renderGeomPostDeferred(camera);
-        }
-        else
-        {
-            renderGeom(camera);
-        }
+        renderGeomDeferred(camera);
+        renderGeomPostDeferred(camera);
     }
-    else if (LLPipeline::sRenderDeferred)
+    else
 	{
 		avatar->mImpostor.clear();
 		renderGeomDeferred(camera);
@@ -11009,28 +10586,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar)
 		sImpostorRenderAlphaDepthPass = false;
 
 	}
-	else
-	{
-		LLGLEnable scissor(GL_SCISSOR_TEST);
-		glScissor(0, 0, resX, resY);
-		avatar->mImpostor.clear();
-		renderGeom(camera);
-
-		// Shameless hack time: render it all again,
-		// this time writing the depth
-		// values we need to generate the alpha mask below
-		// while preserving the alpha-sorted color rendering
-		// from the previous pass
-		//
-		sImpostorRenderAlphaDepthPass = true;
-
-		// depth-only here...
-		//
-		gGL.setColorMask(false,false);
-		renderGeom(camera);
-
-		sImpostorRenderAlphaDepthPass = false;
-	}
 
 	LLDrawPoolAvatar::sMinimumAlpha = old_alpha;
 
@@ -11121,7 +10676,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar)
 
 	LLVertexBuffer::unbind();
 	LLGLState::checkStates();
-	LLGLState::checkTextureChannels();
 }
 
 bool LLPipeline::hasRenderBatches(const U32 type) const
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index d3793da347746aae219c0e8affdeaa6bfa304d36..689dc385ae507d35c80847e6d425ec5667c41cc0 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -266,21 +266,17 @@ class LLPipeline
 	void stateSort(LLDrawable* drawablep, LLCamera& camera);
 	void postSort(LLCamera& camera);
     
-    //update stats for textures in given DrawInfo
-    void touchTextures(LLDrawInfo* info);
-    void touchTexture(LLViewerTexture* tex, F32 vsize);
-
 	void forAllVisibleDrawables(void (*func)(LLDrawable*));
 
-    void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+    void renderObjects(U32 type, bool texture = true, bool batch_texture = false, bool rigged = false);
     void renderShadowSimple(U32 type);
 
-    void renderAlphaObjects(U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
-	void renderMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
-    void renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false);
+    void renderAlphaObjects(bool texture = true, bool batch_texture = false, bool rigged = false);
+	void renderMaskedObjects(U32 type, bool texture = true, bool batch_texture = false, bool rigged = false);
+    void renderFullbrightMaskedObjects(U32 type, bool texture = true, bool batch_texture = false, bool rigged = false);
 
-	void renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture);
-    void renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture);
+	void renderGroups(LLRenderPass* pass, U32 type, bool texture);
+    void renderRiggedGroups(LLRenderPass* pass, U32 type, bool texture);
 
 	void grabReferences(LLCullResult& result);
 	void clearReferences();
@@ -290,9 +286,7 @@ class LLPipeline
 	void checkReferences(LLDrawable* drawable);
 	void checkReferences(LLDrawInfo* draw_info);
 	void checkReferences(LLSpatialGroup* group);
-
-
-	void renderGeom(LLCamera& camera, bool forceVBOUpdate = false);
+	
 	void renderGeomDeferred(LLCamera& camera, bool do_occlusion = false);
 	void renderGeomPostDeferred(LLCamera& camera);
 	void renderGeomShadow(LLCamera& camera);