From 57620a9da903f3c6fe482627d18c44b6411e6910 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Fri, 23 Sep 2011 17:59:05 -0500
Subject: [PATCH] SH-2244 Vertex buffer cleanup, fix for bad vertices in rigged
 attachments, added "RenderUseVAO" debug setting to control whether or not to
 use VAO's in non-core GL profiles.

---
 indra/llrender/llgl.cpp                 |   1 +
 indra/llrender/llimagegl.cpp            |   5 +-
 indra/llrender/llvertexbuffer.cpp       | 276 ++++++++++--------------
 indra/llrender/llvertexbuffer.h         |  13 +-
 indra/newview/app_settings/settings.xml |  11 +
 indra/newview/lldrawpoolavatar.cpp      |  73 ++++++-
 indra/newview/lldrawpoolavatar.h        |   1 +
 indra/newview/llviewercontrol.cpp       |   1 +
 indra/newview/pipeline.cpp              |   2 +
 9 files changed, 201 insertions(+), 182 deletions(-)

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 6875674e792..f546e073205 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -656,6 +656,7 @@ bool LLGLManager::initGL()
 
 	if (mHasDebugOutput && gDebugGL)
 	{ //setup debug output callback
+		glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
 		glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
 		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
 	}
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 4da796dd1e7..12089e5ad3d 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1153,9 +1153,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 			U32 pixel_count = (U32) (width*height);
 			for (U32 i = 0; i < pixel_count; i++)
 			{
-				U8 lum = ((U8*) pixels)[i*2+0];
-				U8 alpha = ((U8*) pixels)[i*2+1];
-
+				U8 lum = ((U8*) pixels)[i];
+				
 				U8* pix = (U8*) &scratch[i];
 				pix[0] = pix[1] = pix[2] = lum;
 				pix[3] = 255;
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index a48669a3007..b2a0f6822d2 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -63,6 +63,7 @@ BOOL LLVertexBuffer::sIBOActive = FALSE;
 U32 LLVertexBuffer::sAllocatedBytes = 0;
 BOOL LLVertexBuffer::sMapped = FALSE;
 BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
+BOOL LLVertexBuffer::sUseVAO = FALSE;
 BOOL LLVertexBuffer::sPreferStreamDraw = FALSE;
 std::vector<U32> LLVertexBuffer::sDeleteList;
 
@@ -134,6 +135,7 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
 	sizeof(F32),	   // TYPE_WEIGHT,
 	sizeof(LLVector4), // TYPE_WEIGHT4,
 	sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
+	sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
 };
 
 U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = 
@@ -150,188 +152,135 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
 
 
 //static
-void LLVertexBuffer::setupClientArrays(U32 data_mask, U32& sLastMask)
+void LLVertexBuffer::setupClientArrays(U32 data_mask)
 {
-	/*if (LLGLImmediate::sStarted)
-	{
-		llerrs << "Cannot use LLGLImmediate and LLVertexBuffer simultaneously!" << llendl;
-	}*/
-
 	if (sLastMask != data_mask)
 	{
-
-		LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
-
-		U32 mask[] =
-		{
-			MAP_VERTEX,
-			MAP_NORMAL,
-			MAP_TEXCOORD0,
-			MAP_COLOR,
-			MAP_EMISSIVE,
-			MAP_WEIGHT,
-			MAP_WEIGHT4,
-			MAP_BINORMAL,
-			MAP_CLOTHWEIGHT,
-			MAP_TEXTURE_INDEX,
-		};
-		
-		U32 type[] =
-		{
-			TYPE_VERTEX,
-			TYPE_NORMAL,
-			TYPE_TEXCOORD0,
-			TYPE_COLOR,
-			TYPE_EMISSIVE,
-			TYPE_WEIGHT,
-			TYPE_WEIGHT4,
-			TYPE_BINORMAL,
-			TYPE_CLOTHWEIGHT,
-			TYPE_TEXTURE_INDEX-1,
-		};
-
-		GLenum array[] =
-		{
-			GL_VERTEX_ARRAY,
-			GL_NORMAL_ARRAY,
-			GL_TEXTURE_COORD_ARRAY,
-			GL_COLOR_ARRAY,
-			0,
-			0,
-			0,
-			0,
-			0,
-			0,
-		};
-
 		BOOL error = FALSE;
-		for (U32 i = 0; i < 10; ++i)
-		{
-			S32 loc = -1;
 
-			if (LLGLSLShader::sNoFixedFunction)
+		if (LLGLSLShader::sNoFixedFunction)
+		{
+			for (U32 i = 0; i < TYPE_MAX; ++i)
 			{
-				loc = type[i];
-			}
-									
-			if (sLastMask & mask[i])
-			{ //was enabled
-				if (!(data_mask & mask[i]))
-				{ //needs to be disabled
-					if (loc >= 0)
-					{
+				S32 loc = i;
+										
+				U32 mask = 1 << i;
+
+				if (sLastMask & (1 << i))
+				{ //was enabled
+					if (!(data_mask & mask))
+					{ //needs to be disabled
 						glDisableVertexAttribArrayARB(loc);
 					}
-					else
-					{
+				}
+				else 
+				{	//was disabled
+					if (data_mask & mask)
+					{ //needs to be enabled
+						glEnableVertexAttribArrayARB(loc);
+					}
+				}
+			}
+		}
+		else
+		{
+
+			GLenum array[] =
+			{
+				GL_VERTEX_ARRAY,
+				GL_NORMAL_ARRAY,
+				GL_TEXTURE_COORD_ARRAY,
+				GL_COLOR_ARRAY,
+			};
+
+			GLenum mask[] = 
+			{
+				MAP_VERTEX,
+				MAP_NORMAL,
+				MAP_TEXCOORD0,
+				MAP_COLOR
+			};
+
+
+
+			for (U32 i = 0; i < 4; ++i)
+			{
+				if (sLastMask & mask[i])
+				{ //was enabled
+					if (!(data_mask & mask[i]))
+					{ //needs to be disabled
 						glDisableClientState(array[i]);
 					}
+					else if (gDebugGL)
+					{ //needs to be enabled, make sure it was (DEBUG)
+						if (!glIsEnabled(array[i]))
+						{
+							if (gDebugSession)
+							{
+								error = TRUE;
+								gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+							}
+							else
+							{
+								llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+							}
+						}
+					}
 				}
-				else if (gDebugGL && !LLGLSLShader::sNoFixedFunction && array[i])
-				{ //needs to be enabled, make sure it was (DEBUG)
-					if (loc < 0 && !glIsEnabled(array[i]))
-					{
+				else 
+				{	//was disabled
+					if (data_mask & mask[i])
+					{ //needs to be enabled
+						glEnableClientState(array[i]);
+					}
+					else if (gDebugGL && glIsEnabled(array[i]))
+					{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
 						if (gDebugSession)
 						{
 							error = TRUE;
-							gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl;
+							gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
 						}
 						else
 						{
-							llerrs << "Bad client state! " << array[i] << " disabled." << llendl;
+							llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
 						}
 					}
 				}
 			}
-			else 
-			{	//was disabled
-				if (data_mask & mask[i])
-				{ //needs to be enabled
-					if (loc >= 0)
-					{
-						glEnableVertexAttribArrayARB(loc);
-					}
-					else
-					{
-						glEnableClientState(array[i]);
-					}
-				}
-				else if (!LLGLSLShader::sNoFixedFunction && array[i] && gDebugGL && glIsEnabled(array[i]))
-				{ //needs to be disabled, make sure it was (DEBUG TEMPORARY)
-					if (gDebugSession)
-					{
-						error = TRUE;
-						gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl;
-					}
-					else
-					{
-						llerrs << "Bad client state! " << array[i] << " enabled." << llendl;
-					}
-				}
-			}
-		}
-
-		if (error)
-		{
-			ll_fail("LLVertexBuffer::setupClientArrays failed");
-		}
-
-		U32 map_tc[] = 
-		{
-			MAP_TEXCOORD1,
-			MAP_TEXCOORD2,
-			MAP_TEXCOORD3
-		};
-
-		U32 type_tc[] = 
-		{
-			TYPE_TEXCOORD1,
-			TYPE_TEXCOORD2,
-			TYPE_TEXCOORD3
-		};
-
-		for (U32 i = 0; i < 3; i++)
-		{
-			S32 loc = -1;
+		
+			U32 map_tc[] = 
+			{
+				MAP_TEXCOORD1,
+				MAP_TEXCOORD2,
+				MAP_TEXCOORD3
+			};
 
-			if (LLGLSLShader::sNoFixedFunction)
+			U32 type_tc[] = 
 			{
-				loc = type_tc[i];
-			}
+				TYPE_TEXCOORD1,
+				TYPE_TEXCOORD2,
+				TYPE_TEXCOORD3
+			};
 
-			if (sLastMask & map_tc[i])
+			for (U32 i = 0; i < 3; i++)
 			{
-				if (!(data_mask & map_tc[i]))
-				{ //disable
-					if (loc >= 0)
-					{
-						glDisableVertexAttribArrayARB(loc);
-					}
-					else
-					{
+				if (sLastMask & map_tc[i])
+				{
+					if (!(data_mask & map_tc[i]))
+					{ //disable
 						glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
 						glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 						glClientActiveTextureARB(GL_TEXTURE0_ARB);
 					}
 				}
-			}
-			else if (data_mask & map_tc[i])
-			{
-				if (loc >= 0)
-				{
-					glEnableVertexAttribArrayARB(loc);
-				}
-				else
+				else if (data_mask & map_tc[i])
 				{
 					glClientActiveTextureARB(GL_TEXTURE1_ARB+i);
 					glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 					glClientActiveTextureARB(GL_TEXTURE0_ARB);
 				}
 			}
-		}
 
-		if (!LLGLSLShader::sNoFixedFunction)
-		{
 			if (sLastMask & MAP_BINORMAL)
 			{
 				if (!(data_mask & MAP_BINORMAL))
@@ -348,7 +297,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask, U32& sLastMask)
 				glClientActiveTextureARB(GL_TEXTURE0_ARB);
 			}
 		}
-		
+				
 		sLastMask = data_mask;
 	}
 }
@@ -734,12 +683,12 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_vertices)
 {
 	S32 offset = 0;
-	for (S32 i=0; i<TYPE_MAX; i++)
+	for (S32 i=0; i<TYPE_TEXTURE_INDEX; i++)
 	{
 		U32 mask = 1<<i;
 		if (typemask & mask)
 		{
-			if (offsets)
+			if (offsets && LLVertexBuffer::sTypeSize[i])
 			{
 				offsets[i] = offset;
 				offset += LLVertexBuffer::sTypeSize[i]*num_vertices;
@@ -748,6 +697,8 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti
 		}
 	}
 
+	offsets[TYPE_TEXTURE_INDEX] = offsets[TYPE_VERTEX] + 12;
+	
 	return offset+16;
 }
 
@@ -755,7 +706,7 @@ S32 LLVertexBuffer::calcOffsets(const U32& typemask, S32* offsets, S32 num_verti
 S32 LLVertexBuffer::calcVertexSize(const U32& typemask)
 {
 	S32 size = 0;
-	for (S32 i = 0; i < TYPE_MAX; i++)
+	for (S32 i = 0; i < TYPE_TEXTURE_INDEX; i++)
 	{
 		U32 mask = 1<<i;
 		if (typemask & mask)
@@ -1096,7 +1047,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 		createGLIndices();
 
 
-		if (gGLManager.mHasVertexArrayObject && useVBOs() && LLRender::sGLCoreProfile)
+		if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
 		{
 			glGenVertexArrays(1, &mGLArray);
 			setupVertexArray();
@@ -1124,6 +1075,7 @@ void LLVertexBuffer::setupVertexArray()
 		1, //TYPE_WEIGHT,
 		4, //TYPE_WEIGHT4,
 		4, //TYPE_CLOTHWEIGHT,
+		1, //TYPE_TEXTURE_INDEX
 	};
 
 	U32 attrib_type[] =
@@ -1140,6 +1092,7 @@ void LLVertexBuffer::setupVertexArray()
 		GL_FLOAT, //TYPE_WEIGHT,
 		GL_FLOAT, //TYPE_WEIGHT4,
 		GL_FLOAT, //TYPE_CLOTHWEIGHT,
+		GL_FLOAT, //TYPE_TEXTURE_INDEX
 	};
 
 	U32 attrib_normalized[] =
@@ -1156,6 +1109,7 @@ void LLVertexBuffer::setupVertexArray()
 		GL_FALSE, //TYPE_WEIGHT,
 		GL_FALSE, //TYPE_WEIGHT4,
 		GL_FALSE, //TYPE_CLOTHWEIGHT,
+		GL_FALSE, //TYPE_TEXTURE_INDEX
 	};
 
 	bindGLBuffer(true);
@@ -1174,16 +1128,6 @@ void LLVertexBuffer::setupVertexArray()
 		}
 	}
 
-	if (mTypeMask & MAP_VERTEX)
-	{ //special handling for texture index
-		S32 loc = TYPE_TEXTURE_INDEX-1;
-		glEnableVertexAttribArrayARB(loc);
-		glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, sTypeSize[TYPE_VERTEX], (void*) (mOffsets[TYPE_VERTEX]+12));
-	}
-	else
-	{
-		glDisableVertexAttribArrayARB(TYPE_TEXTURE_INDEX-1);
-	}
 	glBindVertexArray(0);
 }
 
@@ -2162,7 +2106,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 
 	if (!mGLArray)
 	{
-		setupClientArrays(data_mask, sLastMask);
+		setupClientArrays(data_mask);
 	}
 			
 	if (mGLBuffer)
@@ -2257,7 +2201,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 		}
 		if (data_mask & MAP_TEXTURE_INDEX)
 		{
-			S32 loc = TYPE_TEXTURE_INDEX-1; //hack, texture index attrib location is off by one
+			S32 loc = TYPE_TEXTURE_INDEX;
 			void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
 			glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
 		}
@@ -2315,3 +2259,11 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 	llglassertok();
 }
 
+LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count)
+: mType(type), mIndex(index), mCount(count)
+{ 
+	llassert(mType == LLVertexBuffer::TYPE_INDEX || 
+			mType < LLVertexBuffer::TYPE_TEXTURE_INDEX);
+}	
+
+
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index eba10dbaa5f..d116a552faf 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -91,9 +91,7 @@ class LLVertexBuffer : public LLRefCount
 		S32 mIndex;
 		S32 mCount;
 		
-		MappedRegion(S32 type, S32 index, S32 count)
-			: mType(type), mIndex(index), mCount(count)
-		{ }	
+		MappedRegion(S32 type, S32 index, S32 count);
 	};
 
 	LLVertexBuffer(const LLVertexBuffer& rhs)
@@ -113,11 +111,12 @@ class LLVertexBuffer : public LLRefCount
 	static LLVBOPool sDynamicIBOPool;
 
 	static BOOL	sUseStreamDraw;
+	static BOOL sUseVAO;
 	static BOOL	sPreferStreamDraw;
 
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
-	static void setupClientArrays(U32 data_mask, U32& ref_mask = LLVertexBuffer::sLastMask);
+	static void setupClientArrays(U32 data_mask);
 	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);
 
@@ -141,7 +140,7 @@ class LLVertexBuffer : public LLRefCount
 	// 5 - modify LLViewerShaderMgr::mReservedAttribs
 	// 6 - update LLVertexBuffer::setupVertexArray
 	enum {
-		TYPE_VERTEX,
+		TYPE_VERTEX = 0,
 		TYPE_NORMAL,
 		TYPE_TEXCOORD0,
 		TYPE_TEXCOORD1,
@@ -149,14 +148,12 @@ class LLVertexBuffer : public LLRefCount
 		TYPE_TEXCOORD3,
 		TYPE_COLOR,
 		TYPE_EMISSIVE,
-		// These use VertexAttribPointer and should possibly be made generic
 		TYPE_BINORMAL,
 		TYPE_WEIGHT,
 		TYPE_WEIGHT4,
 		TYPE_CLOTHWEIGHT,
-		TYPE_MAX,
-		//no actual additional data, but indicates position.w is texture index
 		TYPE_TEXTURE_INDEX,
+		TYPE_MAX,
 		TYPE_INDEX,		
 	};
 	enum {
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 32d4097ff36..5201349b174 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9205,6 +9205,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>RenderUseVAO</key>
+    <map>
+      <key>Comment</key>
+      <string>Use GL Vertex Array Objects</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RenderVBOMappingDisable</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index f161790b99d..f4e6bb9b1dc 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1274,9 +1274,11 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
 
 	U32 data_mask = face->getRiggedVertexBufferDataMask();
 	
+	S32 num_verts = (vol_face.mNumVertices + 0xF) & ~0xF;
+
 	if (!buffer || 
 		buffer->getTypeMask() != data_mask ||
-		buffer->getRequestedVerts() != vol_face.mNumVertices)
+		buffer->getRequestedVerts() != num_verts)
 	{
 		face->setGeomIndex(0);
 		face->setIndicesIndex(0);
@@ -1310,6 +1312,8 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
 		LLMatrix3 mat_normal(mat3);				
 
 		face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
+
+		buffer->flush();
 	}
 
 	if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime())
@@ -1441,12 +1445,12 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 			continue;
 		}
 
-		stop_glerror();
+		//stop_glerror();
 
-		const LLVolumeFace& vol_face = volume->getVolumeFace(te);
-		updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
+		//const LLVolumeFace& vol_face = volume->getVolumeFace(te);
+		//updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
 		
-		stop_glerror();
+		//stop_glerror();
 
 		U32 data_mask = LLFace::getRiggedDataMask(type);
 
@@ -1482,17 +1486,15 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 				data_mask &= ~LLVertexBuffer::MAP_WEIGHT4;
 			}
 
-			buff->setBuffer(data_mask);
-
 			U16 start = face->getGeomStart();
 			U16 end = start + face->getGeomCount()-1;
 			S32 offset = face->getIndicesStart();
 			U32 count = face->getIndicesCount();
 
-			if (glow)
+			/*if (glow)
 			{
 				gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow());
-			}
+			}*/
 
 			gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
 			if (normal_channel > -1)
@@ -1504,12 +1506,14 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 			{
 				gGL.matrixMode(LLRender::MM_TEXTURE);
 				gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix);
+				buff->setBuffer(data_mask);
 				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
 				gGL.loadIdentity();
 				gGL.matrixMode(LLRender::MM_MODELVIEW);
 			}
 			else
 			{
+				buff->setBuffer(data_mask);
 				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
 			}
 		}
@@ -1518,6 +1522,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 
 void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar)
 {
+	updateRiggedVertexBuffers(avatar);
 	renderRigged(avatar, RIGGED_DEFERRED_SIMPLE);
 }
 
@@ -1526,8 +1531,58 @@ void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
 	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
 }
 
+void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
+{
+	//update rigged vertex buffers
+	for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type)
+	{
+		for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
+		{
+			LLFace* face = mRiggedFace[type][i];
+			LLDrawable* drawable = face->getDrawable();
+			if (!drawable)
+			{
+				continue;
+			}
+
+			LLVOVolume* vobj = drawable->getVOVolume();
+
+			if (!vobj)
+			{
+				continue;
+			}
+
+			LLVolume* volume = vobj->getVolume();
+			S32 te = face->getTEOffset();
+
+			if (!volume || volume->getNumVolumeFaces() <= te)
+			{
+				continue;
+			}
+
+			LLUUID mesh_id = volume->getParams().getSculptID();
+			if (mesh_id.isNull())
+			{
+				continue;
+			}
+
+			const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj);
+			if (!skin)
+			{
+				continue;
+			}
+
+			stop_glerror();
+
+			const LLVolumeFace& vol_face = volume->getVolumeFace(te);
+			updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face);
+		}
+	}
+}
+
 void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
 {
+	updateRiggedVertexBuffers(avatar);
 	renderRigged(avatar, RIGGED_SIMPLE);
 }
 
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index e0326bcfaff..69e30688589 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -134,6 +134,7 @@ class LLDrawPoolAvatar : public LLFacePool
 									  const LLMeshSkinInfo* skin, 
 									  LLVolume* volume,
 									  const LLVolumeFace& vol_face);
+	void updateRiggedVertexBuffers(LLVOAvatar* avatar);
 
 	void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);
 	void renderRiggedSimple(LLVOAvatar* avatar);
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index b87ca1eaecd..e2674a8e193 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -660,6 +660,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
 	gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
 	gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+	gSavedSettings.getControl("RenderUseVAO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderVBOMappingDisable")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderPreferStreamDraw")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 28391bf423f..8c1bb0f6280 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -379,6 +379,7 @@ void LLPipeline::init()
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
 	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseVAO");
 	LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
 	sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
 	sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
@@ -6061,6 +6062,7 @@ void LLPipeline::resetVertexBuffers()
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
 	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseVAO");
 	LLVertexBuffer::sPreferStreamDraw = gSavedSettings.getBOOL("RenderPreferStreamDraw");
 	LLVertexBuffer::sEnableVBOs = gSavedSettings.getBOOL("RenderVBOEnable");
 	LLVertexBuffer::sDisableVBOMapping = LLVertexBuffer::sEnableVBOs && gSavedSettings.getBOOL("RenderVBOMappingDisable") ;
-- 
GitLab