diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index dab7dc9ebf7e169154eb9ecdaa3f74eafe7c2ce3..31199980fcaeeb1824f4a0089a6a511f12df2b01 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -117,6 +117,7 @@ bool LLVertexBuffer::sMapped = false;
 bool LLVertexBuffer::sUseStreamDraw = true;
 bool LLVertexBuffer::sUseVAO = false;
 bool LLVertexBuffer::sPreferStreamDraw = false;
+LLVertexBuffer* LLVertexBuffer::sUtilityBuffer = nullptr;
 
 
 U32 LLVBOPool::genBuffer()
@@ -590,71 +591,80 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con
 		return;
 	}
 
-	unbind();
-	
-	setupClientArrays(MAP_VERTEX | MAP_NORMAL);
-
-	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-
-	if (shader)
+	if (!sUtilityBuffer)
 	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		if (loc > -1)
-		{
-			glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
-		}
-		loc = LLVertexBuffer::TYPE_NORMAL;
-		if (loc > -1)
-		{
-			glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
-		}
+		sUtilityBuffer = new LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0, GL_STREAM_DRAW);
+		sUtilityBuffer->allocateBuffer(count, count, true);
 	}
-	else
+	if (sUtilityBuffer->getNumVerts() < (S32) count)
 	{
-		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
-		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+		sUtilityBuffer->resizeBuffer(count, count);
 	}
+
+	LLStrider<LLVector3> vertex_strider;
+	LLStrider<LLVector3> normal_strider;
+	sUtilityBuffer->getVertexStrider(vertex_strider);
+	sUtilityBuffer->getNormalStrider(normal_strider);
+	vertex_strider.copyArray(0, pos.data(), count);
+	normal_strider.copyArray(0, norm.data(), count);
+
+	sUtilityBuffer->setBuffer(MAP_VERTEX | MAP_NORMAL);
 	LLGLSLShader::startProfile();
-	glDrawArrays(sGLMode[mode], 0, count);
+	sUtilityBuffer->drawArrays(mode, 0, pos.size());
 	LLGLSLShader::stopProfile(count, mode);
 }
 
 //static
-void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
+void LLVertexBuffer::drawElements(U32 mode, const S32 num_vertices, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 {
 	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 
-	gGL.syncMatrices();
+	if (num_vertices <= 0)
+	{
+		LL_WARNS() << "Called drawElements with 0 vertices" << LL_ENDL;
+		return;
+	}
 
-	U32 mask = LLVertexBuffer::MAP_VERTEX;
-	if (tc)
+	if (num_indices <= 0)
 	{
-		mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
+		LL_WARNS() << "Called drawElements with 0 indices" << LL_ENDL;
+		return;
 	}
 
-	unbind();
-	
-	setupClientArrays(mask);
+	gGL.syncMatrices();
 
-	if (LLGLSLShader::sNoFixedFunction)
+	if (!sUtilityBuffer)
 	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
-
-		if (tc)
-		{
-			loc = LLVertexBuffer::TYPE_TEXCOORD0;
-			glVertexAttribPointer(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
-		}
+		sUtilityBuffer = new LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0, GL_STREAM_DRAW);
+		sUtilityBuffer->allocateBuffer(num_vertices, num_indices, true);
 	}
-	else
+	if (sUtilityBuffer->getNumVerts() < num_vertices || sUtilityBuffer->getNumIndices() < num_indices)
+	{
+		sUtilityBuffer->resizeBuffer(llmax(sUtilityBuffer->getNumVerts(), num_vertices), llmax(sUtilityBuffer->getNumIndices(), num_indices));
+	}
+
+	U32 mask = LLVertexBuffer::MAP_VERTEX;
+
+	LLStrider<U16> index_strider;
+	LLStrider<LLVector4a> vertex_strider;
+	sUtilityBuffer->getIndexStrider(index_strider);
+	sUtilityBuffer->getVertexStrider(vertex_strider);
+	const S32 index_size = ((num_indices * sizeof(U16)) + 0xF) & ~0xF;
+	const S32 vertex_size = ((num_vertices * 4 * sizeof(F32)) + 0xF) & ~0xF;
+	LLVector4a::memcpyNonAliased16((F32*)index_strider.get(), (F32*)indicesp, index_size);
+	LLVector4a::memcpyNonAliased16((F32*)vertex_strider.get(), (F32*)pos, vertex_size);
+	if (tc)
 	{
-		glTexCoordPointer(2, GL_FLOAT, 0, tc);
-		glVertexPointer(3, GL_FLOAT, 16, pos);
+		mask = mask | LLVertexBuffer::MAP_TEXCOORD0;
+		LLStrider<LLVector2> tc_strider;
+		sUtilityBuffer->getTexCoord0Strider(tc_strider);
+		const S32 tc_size = ((num_vertices * 2 * sizeof(F32)) + 0xF) & ~0xF;
+		LLVector4a::memcpyNonAliased16((F32*)tc_strider.get(), (F32*)tc, tc_size);
 	}
 
+	sUtilityBuffer->setBuffer(mask);
 	LLGLSLShader::startProfile();
-	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+	sUtilityBuffer->draw(mode, num_indices, 0);
 	LLGLSLShader::stopProfile(num_indices, mode);
 }
 
@@ -917,6 +927,8 @@ void LLVertexBuffer::cleanupClass()
 	sStreamVBOPool.cleanup();
 	sDynamicVBOPool.cleanup();
 	sDynamicCopyVBOPool.cleanup();
+	delete sUtilityBuffer;
+	sUtilityBuffer = nullptr;
 }
 
 //----------------------------------------------------------------------------
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index bd99ef7feff9c71ce0da17db084618267aac63f9..89e83688fcf1a9c1ebab1354968dd7ceddf07072 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -135,7 +135,7 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	static void setupClientArrays(U32 data_mask);
 	static void pushPositions(U32 mode, const LLVector4a* pos, U32 count);
 	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
-	static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
+	static void drawElements(U32 mode, const S32 num_vertices, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
 
  	static void unbind(); //unbind any bound vertex buffer
 
@@ -345,6 +345,9 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	static U32 sIndexCount;
 	static U32 sBindCount;
 	static U32 sSetCount;
+
+private:
+	static LLVertexBuffer* sUtilityBuffer;
 };
 
 
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 90088975bd07a8952451d972529c886e9f91196b..9c91bdf3b63e9cea00eab86867882528de9b8335 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -638,7 +638,7 @@ void renderFace(LLDrawable* drawable, LLFace *face)
         if (volume)
         {
             const LLVolumeFace& vol_face = volume->getVolumeFace(face->getTEOffset());
-            LLVertexBuffer::drawElements(LLRender::TRIANGLES, vol_face.mPositions, NULL, vol_face.mNumIndices, vol_face.mIndices);
+            LLVertexBuffer::drawElements(LLRender::TRIANGLES, vol_face.mNumVertices, vol_face.mPositions, NULL, vol_face.mNumIndices, vol_face.mIndices);
         }
     }
 }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 8c04cf80cfbf1d25b8271a5cb8fcc6f84ff9f99c..2f7d6590dd1d15d34c341db9efe249df9bde25f7 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1614,7 +1614,7 @@ void pushVerts(LLVolume* volume)
 	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 	{
 		const LLVolumeFace& face = volume->getVolumeFace(i);
-		LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices);
+		LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mNumVertices, face.mPositions, NULL, face.mNumIndices, face.mIndices);
 	}
 }
 
@@ -2575,11 +2575,11 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 
 				llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0);
 							
-				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 				
 				gGL.diffuseColor4fv(color.mV);
 				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
+				LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mNumHullPoints, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 				
 			}
 			else