diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index abc6af2cfcadf5bd5e87c86b0d87d2e823ee6b02..04872564bfc94e81ede194ee54cdfdba3dfbb8c8 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -44,6 +44,7 @@ void *operator new(size_t size)
     {
         LL_PROFILE_ZONE_SCOPED;
         ptr = (malloc)(size);
+        TracyAlloc(ptr, size);
     }
     else
     {
@@ -53,17 +54,15 @@ void *operator new(size_t size)
     {
         throw std::bad_alloc();
     }
-    TracyAlloc(ptr, size);
     return ptr;
 }
 
 void operator delete(void *ptr) noexcept
 {
-    TracyFree(ptr);
-
     if (gProfilerEnabled)
     {
         LL_PROFILE_ZONE_SCOPED;
+        TracyFree(ptr);
         (free)(ptr);
     }
     else
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index a269549c4910e467e2079768ec452d9cfdf4c8f8..b66521132c0817483b950a03771a416b31e4fbc7 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2117,6 +2117,7 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask)
 LLGLState::LLGLState(LLGLenum state, S32 enabled) :
 	mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	if (LLGLSLShader::sNoFixedFunction)
 	{ //always ignore state that's deprecated post GL 3.0
 		switch (state)
@@ -2175,6 +2176,7 @@ void LLGLState::setEnabled(S32 enabled)
 
 LLGLState::~LLGLState() 
 {
+    LL_PROFILE_ZONE_SCOPED;
 	stop_glerror();
 	if (mState)
 	{
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 103d5388d32e44a63df27d3a759c320167e86ddc..7e726df90774fac14276826d5ddc295e26ab28fc 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -577,63 +577,22 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 }
 
 //static
-static LLTrace::BlockTimerStatHandle FTM_VB_DRAW_ARRAYS("drawArrays");
-void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos)
 {
-	LL_RECORD_BLOCK_TIME(FTM_VB_DRAW_ARRAYS);
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	gGL.syncMatrices();
-
-	U32 count = pos.size();
-	
-	llassert(norm.size() >= pos.size());
-	llassert(count > 0);
-
-	if( count == 0 )
-	{
-		LL_WARNS() << "Called drawArrays with 0 vertices" << LL_ENDL;
-		return;
-	}
-
-	if( norm.size() < pos.size() )
-	{
-		LL_WARNS() << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << LL_ENDL;
-		return;
-	}
-
-	unbind();
-	
-	setupClientArrays(MAP_VERTEX | MAP_NORMAL);
-
-	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-
-	if (shader)
-	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		if (loc > -1)
-		{
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV);
-		}
-		loc = LLVertexBuffer::TYPE_NORMAL;
-		if (loc > -1)
-		{
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV);
-		}
-	}
-	else
-	{
-		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
-		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
-	}
-	LLGLSLShader::startProfile();
-	LL_PROFILER_GPU_ZONEC( "gl.DrawArrays", 0xFF0000 )
-	glDrawArrays(sGLMode[mode], 0, count);
-	LLGLSLShader::stopProfile(count, mode);
+    LL_PROFILE_ZONE_SCOPED;
+    gGL.begin(mode);
+    for (auto& v : pos)
+    {
+        gGL.vertex3fv(v.mV);
+    }
+    gGL.end();
+    gGL.flush();
 }
 
 //static
 void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp)
 {
+    LL_PROFILE_ZONE_SCOPED;
 	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
 
 	gGL.syncMatrices();
@@ -646,29 +605,27 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
 
 	unbind();
 	
-	setupClientArrays(mask);
+    gGL.begin(mode);
 
-	if (LLGLSLShader::sNoFixedFunction)
-	{
-		S32 loc = LLVertexBuffer::TYPE_VERTEX;
-		glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos);
-
-		if (tc)
-		{
-			loc = LLVertexBuffer::TYPE_TEXCOORD0;
-			glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc);
-		}
-	}
-	else
-	{
-		glTexCoordPointer(2, GL_FLOAT, 0, tc);
-		glVertexPointer(3, GL_FLOAT, 16, pos);
-	}
-
-	LLGLSLShader::startProfile();
-    LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x80FF80 )
-	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
-	LLGLSLShader::stopProfile(num_indices, mode);
+    if (tc != nullptr)
+    {
+        for (int i = 0; i < num_indices; ++i)
+        {
+            U16 idx = indicesp[i];
+            gGL.texCoord2fv(tc[idx].mV);
+            gGL.vertex3fv(pos[idx].getF32ptr());
+        }
+    }
+    else
+    {
+        for (int i = 0; i < num_indices; ++i)
+        {
+            U16 idx = indicesp[i];
+            gGL.vertex3fv(pos[idx].getF32ptr());
+        }
+    }
+    gGL.end();
+    gGL.flush();
 }
 
 void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
@@ -851,51 +808,51 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 static LLTrace::BlockTimerStatHandle FTM_GL_DRAW_ARRAYS("GL draw arrays");
 void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 {
-	llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
-	mMappable = false;
-	gGL.syncMatrices();
-	
-	llassert(mNumVerts >= 0);
-	if (first >= (U32) mNumVerts ||
-	    first + count > (U32) mNumVerts)
-	{
-		LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << LL_ENDL;
-	}
+    llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL);
+    mMappable = false;
+    gGL.syncMatrices();
 
-	if (mGLArray)
-	{
-		if (mGLArray != sGLRenderArray)
-		{
-			LL_ERRS() << "Wrong vertex array bound." << LL_ENDL;
-		}
-	}
-	else
-	{
-		if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
-		{
-			LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
-		}
-	}
+    llassert(mNumVerts >= 0);
+    if (first >= (U32)mNumVerts ||
+        first + count > (U32)mNumVerts)
+    {
+        LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first + count << "]" << LL_ENDL;
+    }
 
-	if (mode >= LLRender::NUM_MODES)
-	{
-		LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
-		return;
-	}
+    if (mGLArray)
+    {
+        if (mGLArray != sGLRenderArray)
+        {
+            LL_ERRS() << "Wrong vertex array bound." << LL_ENDL;
+        }
+    }
+    else
+    {
+        if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive)
+        {
+            LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL;
+        }
+    }
 
-	{
-		LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS);
-		stop_glerror();
-		LLGLSLShader::startProfile();
-		stop_glerror();
-        LL_PROFILER_GPU_ZONEC( "gl.DrawArrays", 0xFF4040 )
-		glDrawArrays(sGLMode[mode], first, count);
-		stop_glerror();
-		LLGLSLShader::stopProfile(count, mode);
-	}
+    if (mode >= LLRender::NUM_MODES)
+    {
+        LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL;
+        return;
+    }
 
-	stop_glerror();
-	placeFence();
+    {
+        LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS);
+        stop_glerror();
+        LLGLSLShader::startProfile();
+        stop_glerror();
+        LL_PROFILER_GPU_ZONEC("gl.DrawArrays", 0xFF4040)
+            glDrawArrays(sGLMode[mode], first, count);
+        stop_glerror();
+        LLGLSLShader::stopProfile(count, mode);
+    }
+
+    stop_glerror();
+    placeFence();
 }
 
 //static
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 51ed85510e1b1cc4ce7b31d82c7b0642f9705b1f..fad474a143ff4df1da02f710ba56b9eb46ac87b2 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -146,8 +146,7 @@ class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexB
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
 	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 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 unbind(); //unbind any bound vertex buffer
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 3611539ff84a548d05e7949345387631a9754bef..9dd365e3dc31d2ad3ad1351828ad0d47298db379 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -271,10 +271,10 @@ class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16>
 	LLColor4	mFaceColor;			// overrides material color if state |= USE_FACE_COLOR
 	
 	U16			mGeomCount;			// vertex count for this face
-	U16			mGeomIndex;			// index into draw pool
+	U16			mGeomIndex;			// starting index into mVertexBuffer's vertex array
 	U8			mTextureIndex;		// index of texture channel to use for pseudo-atlasing
 	U32			mIndicesCount;
-	U32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
+	U32			mIndicesIndex;		// index into mVertexBuffer's index array
 	S32         mIndexInTex[LLRender::NUM_TEXTURE_CHANNELS];
 
 	LLXformMatrix* mXform;
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 01bddd781d2798cfd6740c925b30ec4bfffadbb0..4fce6735e0dec37aedcd2d1f5f2547ea93b077ea 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -3126,7 +3126,7 @@ BOOL LLModelPreview::render()
                                         }
 
                                         gGL.diffuseColor4ubv(hull_colors[i].mV);
-                                        LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
+                                        LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions);
 
                                         if (explode > 0.f)
                                         {
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 253b6b995399ede5c5b3772b47ac26bb384e27fc..5cac9cd7aeb3833d1bae265422a10e0e8fe1dced 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2386,7 +2386,12 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 		if (!decomp->mBaseHullMesh.empty())
 		{
 			gGL.diffuseColor4fv(color.mV);
-			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
+			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions);
+
+            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+            gGL.diffuseColor4fv(line_color.mV);
+            LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions);
+            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 		}
 		else
 		{
@@ -2406,13 +2411,11 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
 {
 	gGL.diffuseColor4fv(color.mV);
-	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
-	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-	glPolygonOffset(3.f, 3.f);
 	glLineWidth(3.f);
 	gGL.diffuseColor4fv(line_color.mV);
-	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions);
 	glLineWidth(1.f);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
@@ -2467,6 +2470,9 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 	gGL.pushMatrix();
 	gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix);
 		
+    LLGLEnable(GL_POLYGON_OFFSET_LINE);
+    glPolygonOffset(3.f, 3.f);
+
 	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
 	{
 		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
@@ -2494,12 +2500,12 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 			{ 
 				//decomp has physics mesh, render that mesh
 				gGL.diffuseColor4fv(color.mV);
-				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions);
 								
 				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 				gGL.diffuseColor4fv(line_color.mV);
-				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
-				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+                LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions);
+                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 			}
 			else
 			{ //no mesh or decomposition, render base hull
@@ -2626,8 +2632,8 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 				LLVertexBuffer::unbind();
 
 				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->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices);
 				
 				gGL.diffuseColor4fv(color.mV);
 				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);