diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 607473d4166292f2bf55a452120eab430eb90dd0..54f72d103ea9eaf1d6921f7ca98038b119d8d9d5 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -329,7 +329,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 		
 		if (glyph_count >= GLYPH_BATCH_SIZE)
 		{
-			gGL.begin(LLRender::QUADS);
+			gGL.begin(LLRender::TRIANGLES);
 			{
 				gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
 			}
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 718de346f6ec466094635207f76311709c044939..6875674e792b34c1e6deafe17fe8f7888bd3ef35 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -67,6 +67,22 @@ static const std::string HEADLESS_VERSION_STRING("1.0");
 
 std::ofstream gFailLog;
 
+void APIENTRY gl_debug_callback(GLenum source,
+                                GLenum type,
+                                GLuint id,
+                                GLenum severity,
+                                GLsizei length,
+                                const GLchar* message,
+                                GLvoid* userParam)
+{
+	llwarns << "----- GL ERROR --------" << llendl;
+	llwarns << "Type: " << std::hex << type << llendl;
+	llwarns << "ID: " << std::hex << id << llendl;
+	llwarns << "Severity: " << std::hex << severity << llendl;
+	llwarns << "Message: " << message << llendl;
+	llwarns << "-----------------------" << llendl;
+}
+
 void ll_init_fail_log(std::string filename)
 {
 	gFailLog.open(filename.c_str());
@@ -110,6 +126,9 @@ std::list<LLGLUpdate*> LLGLUpdate::sGLQ;
 
 #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS)  && !LL_MESA_HEADLESS
 // ATI prototypes
+
+PFNGLGETSTRINGIPROC glGetStringi = NULL;
+
 // vertex blending prototypes
 PFNGLWEIGHTPOINTERARBPROC			glWeightPointerARB = NULL;
 PFNGLVERTEXBLENDARBPROC				glVertexBlendARB = NULL;
@@ -128,6 +147,12 @@ PFNGLUNMAPBUFFERARBPROC				glUnmapBufferARB = NULL;
 PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB = NULL;
 PFNGLGETBUFFERPOINTERVARBPROC		glGetBufferPointervARB = NULL;
 
+//GL_ARB_vertex_array_object
+PFNGLBINDVERTEXARRAYPROC glBindVertexArray = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = NULL;
+PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = NULL;
+PFNGLISVERTEXARRAYPROC glIsVertexArray = NULL;
+
 // GL_ARB_map_buffer_range
 PFNGLMAPBUFFERRANGEPROC			glMapBufferRange = NULL;
 PFNGLFLUSHMAPPEDBUFFERRANGEPROC	glFlushMappedBufferRange = NULL;
@@ -197,10 +222,16 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = NULL;
 PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer = NULL;
 
 //GL_ARB_texture_multisample
-PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
-PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
-PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
-PFNGLSAMPLEMASKIPROC glSampleMaski;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL;
+PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL;
+PFNGLSAMPLEMASKIPROC glSampleMaski = NULL;
+
+//GL_ARB_debug_output
+PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
+PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL;
+PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB = NULL;
+PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB = NULL;
 
 // GL_EXT_blend_func_separate
 PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
@@ -353,6 +384,7 @@ LLGLManager::LLGLManager() :
 	mHasBlendFuncSeparate(FALSE),
 	mHasSync(FALSE),
 	mHasVertexBufferObject(FALSE),
+	mHasVertexArrayObject(FALSE),
 	mHasMapBufferRange(FALSE),
 	mHasFlushBufferRange(FALSE),
 	mHasPBuffer(FALSE),
@@ -374,6 +406,7 @@ LLGLManager::LLGLManager() :
 	mHasAnisotropic(FALSE),
 	mHasARBEnvCombine(FALSE),
 	mHasCubeMap(FALSE),
+	mHasDebugOutput(FALSE),
 
 	mIsATI(FALSE),
 	mIsNVIDIA(FALSE),
@@ -451,13 +484,39 @@ bool LLGLManager::initGL()
 		LL_ERRS("RenderInit") << "Calling init on LLGLManager after already initialized!" << LL_ENDL;
 	}
 
-	GLint alpha_bits;
-	glGetIntegerv( GL_ALPHA_BITS, &alpha_bits );
-	if( 8 != alpha_bits )
+	if (!glGetStringi)
 	{
-		LL_WARNS("RenderInit") << "Frame buffer has less than 8 bits of alpha.  Avatar texture compositing will fail." << LL_ENDL;
+		glGetStringi = (PFNGLGETSTRINGIPROC) GLH_EXT_GET_PROC_ADDRESS("glGetStringi");
 	}
 
+	//reload extensions string (may have changed after using wglCreateContextAttrib)
+	if (glGetStringi)
+	{
+		std::stringstream str;
+
+		GLint count = 0;
+		glGetIntegerv(GL_NUM_EXTENSIONS, &count);
+		for (GLint i = 0; i < count; ++i)
+		{
+			str << (const char*) glGetStringi(GL_EXTENSIONS, i) << " ";
+		}
+		
+#if LL_WINDOWS
+		{
+			PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0;
+			wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB");
+			if(wglGetExtensionsStringARB)
+			{
+				str << (const char*) wglGetExtensionsStringARB(wglGetCurrentDC());
+			}
+		}
+#endif
+		free(gGLHExts.mSysExts);
+		std::string extensions = str.str();
+		gGLHExts.mSysExts = strdup(extensions.c_str());
+		
+	}
+	
 	// Extract video card strings and convert to upper case to
 	// work around driver-to-driver variation in capitalization.
 	mGLVendor = std::string((const char *)glGetString(GL_VENDOR));
@@ -595,6 +654,12 @@ bool LLGLManager::initGL()
 		glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
 	}
 
+	if (mHasDebugOutput && gDebugGL)
+	{ //setup debug output callback
+		glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL);
+		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+	}
+
 	//HACK always disable texture multisample, use FXAA instead
 	mHasTextureMultisample = FALSE;
 #if LL_WINDOWS
@@ -789,7 +854,7 @@ void LLGLManager::initExtensions()
 	mHasVertexShader = FALSE;
 	mHasFragmentShader = FALSE;
 	mHasTextureRectangle = FALSE;
-#else // LL_MESA_HEADLESS
+#else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called
 	mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
 	mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
 	mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
@@ -803,6 +868,7 @@ void LLGLManager::initExtensions()
 	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
 	mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
 	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
+	mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts);
 	mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
 	mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
 	mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
@@ -821,6 +887,7 @@ void LLGLManager::initExtensions()
 	mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
 	mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
 	mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
+	mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
 #if !LL_DARWIN
 	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
 #endif
@@ -1000,6 +1067,13 @@ void LLGLManager::initExtensions()
 			mHasVertexBufferObject = FALSE;
 		}
 	}
+	if (mHasVertexArrayObject)
+	{
+		glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glBindVertexArray");
+		glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteVertexArrays");
+		glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) GLH_EXT_GET_PROC_ADDRESS("glGenVertexArrays");
+		glIsVertexArray = (PFNGLISVERTEXARRAYPROC) GLH_EXT_GET_PROC_ADDRESS("glIsVertexArray");
+	}
 	if (mHasSync)
 	{
 		glFenceSync = (PFNGLFENCESYNCPROC) GLH_EXT_GET_PROC_ADDRESS("glFenceSync");
@@ -1054,6 +1128,13 @@ void LLGLManager::initExtensions()
 		glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
 		glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
 	}	
+	if (mHasDebugOutput)
+	{
+		glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB");
+		glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageInsertARB");
+		glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageCallbackARB");
+		glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetDebugMessageLogARB");
+	}
 #if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
 	// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
 	glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
@@ -1341,9 +1422,6 @@ void LLGLState::initClass()
 	//make sure multisample defaults to disabled
 	sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
 	glDisable(GL_MULTISAMPLE_ARB);
-
-	sStateMap[GL_MULTISAMPLE_ARB] = GL_FALSE;
-	glDisable(GL_MULTISAMPLE_ARB);
 }
 
 //static
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 495e523c311f27eb1800a7dfcc72aace1efd737d..dee7ec07395c2646e704ccbb9ae87d3c6612c5c1 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -88,6 +88,7 @@ class LLGLManager
 		
 	// ARB Extensions
 	BOOL mHasVertexBufferObject;
+	BOOL mHasVertexArrayObject;
 	BOOL mHasSync;
 	BOOL mHasMapBufferRange;
 	BOOL mHasFlushBufferRange;
@@ -112,6 +113,7 @@ class LLGLManager
 	BOOL mHasAnisotropic;
 	BOOL mHasARBEnvCombine;
 	BOOL mHasCubeMap;
+	BOOL mHasDebugOutput;
 
 	// Vendor-specific extensions
 	BOOL mIsATI;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index f319009bc8e0f2b94c40d0aa48fa5994dd07059d..ede198365188020d0db9b2c44a036431c58d8542 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -533,6 +533,7 @@ extern PFNGLSAMPLEMASKIPROC glSampleMaski;
 
 // WGL_ARB_create_context
 extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
+extern PFNGLGETSTRINGIPROC glGetStringi;
 
 // GL_ARB_vertex_buffer_object
 extern PFNGLBINDBUFFERARBPROC		glBindBufferARB;
@@ -547,6 +548,12 @@ extern PFNGLUNMAPBUFFERARBPROC		glUnmapBufferARB;
 extern PFNGLGETBUFFERPARAMETERIVARBPROC	glGetBufferParameterivARB;
 extern PFNGLGETBUFFERPOINTERVARBPROC	glGetBufferPointervARB;
 
+// GL_ARB_vertex_array_object
+extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
+extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+extern PFNGLISVERTEXARRAYPROC glIsVertexArray;
+
 // GL_ARB_sync
 extern PFNGLFENCESYNCPROC				glFenceSync;
 extern PFNGLISSYNCPROC					glIsSync;
@@ -737,6 +744,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
 extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
 extern PFNGLSAMPLEMASKIPROC glSampleMaski;
 
+//GL_ARB_debug_output
+extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
+extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
+extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
+extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
+
 #elif LL_DARWIN
 //----------------------------------------------------------------------------
 // LL_DARWIN
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 0dcf5634914f7557d2af9ce78a7f71ef23fcf82f..da4658dc037b440f266f122835b89c286034d1ed 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -243,6 +243,13 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count)
 
 BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
 {
+	//before linking, make sure reserved attributes always have consistent locations
+	for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
+	{
+		const char* name = LLShaderMgr::instance()->mReservedAttribs[i].c_str();
+		glBindAttribLocationARB(mProgramObject, i, (const GLcharARB *) name);
+	}
+	
 	//link the program
 	BOOL res = link();
 
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 0fb4a7784ab85f28fa92e14cf648215a3cad29e5..4da796dd1e76743777f3055ed56a15396bdfb9a3 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -725,7 +725,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		}
 		else if (!is_compressed)
 		{
-			if (mAutoGenMips) //auto-generating mipmaps is deprecated in GL 3.0
+			if (mAutoGenMips && !LLRender::sGLCoreProfile) //auto-generating mipmaps is deprecated in GL 3.0
 			{
 				glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
 				stop_glerror();
@@ -877,6 +877,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 
 BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
 {
+	//not compatible with core GL profile
+	llassert(!LLRender::sGLCoreProfile);
+
 	if (gGLManager.mIsDisabled)
 	{
 		llwarns << "Trying to create a texture while GL is disabled!" << llendl;
@@ -903,29 +906,29 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
 	{
 		switch (mComponents)
 		{
-		  case 1:
+			case 1:
 			// Use luminance alpha (for fonts)
 			mFormatInternal = GL_LUMINANCE8;
 			mFormatPrimary = GL_LUMINANCE;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  case 2:
+			case 2:
 			// Use luminance alpha (for fonts)
 			mFormatInternal = GL_LUMINANCE8_ALPHA8;
 			mFormatPrimary = GL_LUMINANCE_ALPHA;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  case 3:
+			case 3:
 			mFormatInternal = GL_RGB8;
 			mFormatPrimary = GL_RGB;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  case 4:
+			case 4:
 			mFormatInternal = GL_RGBA8;
 			mFormatPrimary = GL_RGBA;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  default:
+			default:
 			llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
 		}
 	}
@@ -1101,8 +1104,76 @@ void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
 // static
 void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels)
 {
-	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
+	bool use_scratch = false;
+	U32* scratch = NULL;
+	if (LLRender::sGLCoreProfile)
+	{
+		if (intformat == GL_ALPHA8 && pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) 
+		{ //GL_ALPHA is deprecated, convert to RGBA
+			use_scratch = true;
+			scratch = new U32[width*height];
+
+			U32 pixel_count = (U32) (width*height);
+			for (U32 i = 0; i < pixel_count; i++)
+			{
+				U8* pix = (U8*) &scratch[i];
+				pix[0] = pix[1] = pix[2] = 0;
+				pix[3] = ((U8*) pixels)[i];
+			}				
+			
+			pixformat = GL_RGBA;
+			intformat = GL_RGBA8;
+		}
+
+		if (intformat == GL_LUMINANCE8_ALPHA8 && pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) 
+		{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+			use_scratch = true;
+			scratch = new U32[width*height];
+
+			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* pix = (U8*) &scratch[i];
+				pix[0] = pix[1] = pix[2] = lum;
+				pix[3] = alpha;
+			}				
+			
+			pixformat = GL_RGBA;
+			intformat = GL_RGBA8;
+		}
+
+		if (intformat == GL_LUMINANCE8 && pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) 
+		{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
+			use_scratch = true;
+			scratch = new U32[width*height];
+
+			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* pix = (U8*) &scratch[i];
+				pix[0] = pix[1] = pix[2] = lum;
+				pix[3] = 255;
+			}				
+			
+			pixformat = GL_RGBA;
+			intformat = GL_RGB8;
+		}
+	}
+
+	stop_glerror();
+	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
 	stop_glerror();
+
+	if (use_scratch)
+	{
+		delete [] scratch;
+	}
 }
 
 //create an empty GL texture: just create a texture name
@@ -1169,29 +1240,29 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 	{
 		switch (mComponents)
 		{
-		  case 1:
+			case 1:
 			// Use luminance alpha (for fonts)
 			mFormatInternal = GL_LUMINANCE8;
 			mFormatPrimary = GL_LUMINANCE;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  case 2:
+			case 2:
 			// Use luminance alpha (for fonts)
 			mFormatInternal = GL_LUMINANCE8_ALPHA8;
 			mFormatPrimary = GL_LUMINANCE_ALPHA;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  case 3:
+			case 3:
 			mFormatInternal = GL_RGB8;
 			mFormatPrimary = GL_RGB;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  case 4:
+			case 4:
 			mFormatInternal = GL_RGBA8;
 			mFormatPrimary = GL_RGBA;
 			mFormatType = GL_UNSIGNED_BYTE;
 			break;
-		  default:
+			default:
 			llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
 		}
 
@@ -1214,6 +1285,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
 	llassert(data_in);
+	stop_glerror();
 
 	if (discard_level < 0)
 	{
@@ -1242,8 +1314,11 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 		stop_glerror();
 		{
 			llverify(gGL.getTexUnit(0)->bind(this));
+			stop_glerror();
 			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
+			stop_glerror();
 			glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL,  mMaxDiscardLevel-discard_level);
+			stop_glerror();
 		}
 	}
 	if (!mTexName)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index efeb7709a4477751ee6d266eab88780b54e50018..daeb58b279bb542f963e860774224c3989f2e31c 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -179,10 +179,13 @@ 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;
 
@@ -191,7 +194,9 @@ void LLTexUnit::enable(eTextureType type)
 			type != LLTexUnit::TT_MULTISAMPLE_TEXTURE &&
 			mIndex < gGLManager.mNumTextureUnits)
 		{
+			stop_glerror();
 			glEnable(sGLTextureType[type]);
+			stop_glerror();
 		}
 	}
 }
@@ -287,26 +292,35 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
 		{
 			return bind(LLImageGL::sDefaultGLTexture) ;
 		}
+		stop_glerror();
 		return false ;
 	}
 
 	if ((mCurrTexture != texture->getTexName()) || forceBind)
 	{
 		gGL.flush();
+		stop_glerror();
 		activate();
+		stop_glerror();
 		enable(texture->getTarget());
+		stop_glerror();
 		mCurrTexture = texture->getTexName();
 		glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
+		stop_glerror();
 		texture->updateBindStats(texture->mTextureMemory);		
 		mHasMipMaps = texture->mHasMipMaps;
 		if (texture->mTexOptionsDirty)
 		{
+			stop_glerror();
 			texture->mTexOptionsDirty = false;
 			setTextureAddressMode(texture->mAddressMode);
 			setTextureFilteringOption(texture->mFilterOption);
+			stop_glerror();
 		}
 	}
 
+	stop_glerror();
+
 	return true;
 }
 
@@ -989,6 +1003,7 @@ void LLLightState::setSpotDirection(const LLVector3& direction)
 LLRender::LLRender()
   : mDirty(false),
     mCount(0),
+	mQuadCycle(0),
     mMode(LLRender::TRIANGLES),
     mCurrTextureUnitIndex(0),
     mMaxAnisotropy(0.f) 
@@ -1678,6 +1693,11 @@ void LLRender::begin(const GLuint& mode)
 {
 	if (mode != mMode)
 	{
+		if (mode == LLRender::QUADS)
+		{
+			mQuadCycle = 1;
+		}
+
 		if (mMode == LLRender::QUADS ||
 			mMode == LLRender::LINES ||
 			mMode == LLRender::TRIANGLES ||
@@ -1765,7 +1785,7 @@ void LLRender::flush()
 		
 		if (gDebugGL)
 		{
-			if (mMode == LLRender::QUADS)
+			if (mMode == LLRender::QUADS && !sGLCoreProfile)
 			{
 				if (mCount%4 != 0)
 				{
@@ -1794,12 +1814,30 @@ void LLRender::flush()
 		U32 count = mCount;
 		mCount = 0;
 
+		if (mBuffer->useVBOs() && !mBuffer->isLocked())
+		{ //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
+			mBuffer->getVertexStrider(mVerticesp, 0, count);
+			mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
+			mBuffer->getColorStrider(mColorsp, 0, count);
+		}
+		
+		//only flush the part of the 
 		mBuffer->setBuffer(immediate_mask);
-		mBuffer->drawArrays(mMode, 0, count);
+
+		if (mMode == LLRender::QUADS && sGLCoreProfile)
+		{
+			mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
+			mQuadCycle = 1;
+		}
+		else
+		{
+			mBuffer->drawArrays(mMode, 0, count);
+		}
 		
 		mVerticesp[0] = mVerticesp[count];
 		mTexcoordsp[0] = mTexcoordsp[count];
 		mColorsp[0] = mColorsp[count];
+		
 		mCount = 0;
 	}
 }
@@ -1823,10 +1861,29 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
 		mVerticesp[mCount] = vert;
 	}
 
+	if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile)
+	{
+		mQuadCycle++;
+		if (mQuadCycle == 4)
+		{ //copy two vertices so fourth quad element will add a triangle
+			mQuadCycle = 0;
+	
+			mCount++;
+			mVerticesp[mCount] = mVerticesp[mCount-3];
+			mColorsp[mCount] = mColorsp[mCount-3];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-3];
+
+			mCount++;
+			mVerticesp[mCount] = mVerticesp[mCount-2];
+			mColorsp[mCount] = mColorsp[mCount-2];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-2];
+		}
+	}
+
 	mCount++;
 	mVerticesp[mCount] = mVerticesp[mCount-1];
 	mColorsp[mCount] = mColorsp[mCount-1];
-	mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+	mTexcoordsp[mCount] = mTexcoordsp[mCount-1];	
 }
 
 void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
@@ -1837,13 +1894,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
 		return;
 	}
 
-	for (S32 i = 0; i < vert_count; i++)
+	if (sGLCoreProfile && mMode == LLRender::QUADS)
+	{ //quads are deprecated, convert to triangle list
+		S32 i = 0;
+		
+		while (i < vert_count)
+		{
+			//read first three
+			mVerticesp[mCount++] = verts[i++];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			mVerticesp[mCount++] = verts[i++];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			mVerticesp[mCount++] = verts[i++];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			//copy two
+			mVerticesp[mCount++] = verts[i-3];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			mVerticesp[mCount++] = verts[i-1];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+			
+			//copy last one
+			mVerticesp[mCount++] = verts[i++];
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+		}
+	}
+	else
 	{
-		mVerticesp[mCount] = verts[i];
+		for (S32 i = 0; i < vert_count; i++)
+		{
+			mVerticesp[mCount] = verts[i];
 
-		mCount++;
-		mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
-		mColorsp[mCount] = mColorsp[mCount-1];
+			mCount++;
+			mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+		}
 	}
 
 	mVerticesp[mCount] = mVerticesp[mCount-1];
@@ -1857,13 +1951,50 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 v
 		return;
 	}
 
-	for (S32 i = 0; i < vert_count; i++)
+	if (sGLCoreProfile && mMode == LLRender::QUADS)
+	{ //quads are deprecated, convert to triangle list
+		S32 i = 0;
+
+		while (i < vert_count)
+		{
+			//read first three
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount++] = uvs[i++];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount++] = uvs[i++];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount++] = uvs[i++];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			//copy last two
+			mVerticesp[mCount] = verts[i-3];
+			mTexcoordsp[mCount++] = uvs[i-3];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			mVerticesp[mCount] = verts[i-1];
+			mTexcoordsp[mCount++] = uvs[i-1];
+			mColorsp[mCount] = mColorsp[mCount-1];
+
+			//copy last one
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount++] = uvs[i++];
+			mColorsp[mCount] = mColorsp[mCount-1];
+		}
+	}
+	else
 	{
-		mVerticesp[mCount] = verts[i];
-		mTexcoordsp[mCount] = uvs[i];
+		for (S32 i = 0; i < vert_count; i++)
+		{
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount] = uvs[i];
 
-		mCount++;
-		mColorsp[mCount] = mColorsp[mCount-1];
+			mCount++;
+			mColorsp[mCount] = mColorsp[mCount-1];
+		}
 	}
 
 	mVerticesp[mCount] = mVerticesp[mCount-1];
@@ -1878,13 +2009,51 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLCol
 		return;
 	}
 
-	for (S32 i = 0; i < vert_count; i++)
+	
+	if (sGLCoreProfile && mMode == LLRender::QUADS)
+	{ //quads are deprecated, convert to triangle list
+		S32 i = 0;
+
+		while (i < vert_count)
+		{
+			//read first three
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount] = uvs[i];
+			mColorsp[mCount++] = colors[i++];
+
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount] = uvs[i];
+			mColorsp[mCount++] = colors[i++];
+
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount] = uvs[i];
+			mColorsp[mCount++] = colors[i++];
+
+			//copy last two
+			mVerticesp[mCount] = verts[i-3];
+			mTexcoordsp[mCount] = uvs[i-3];
+			mColorsp[mCount++] = colors[i-3];
+
+			mVerticesp[mCount] = verts[i-1];
+			mTexcoordsp[mCount] = uvs[i-1];
+			mColorsp[mCount++] = colors[i-1];
+
+			//copy last one
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount] = uvs[i];
+			mColorsp[mCount++] = colors[i++];
+		}
+	}
+	else
 	{
-		mVerticesp[mCount] = verts[i];
-		mTexcoordsp[mCount] = uvs[i];
-		mColorsp[mCount] = colors[i];
+		for (S32 i = 0; i < vert_count; i++)
+		{
+			mVerticesp[mCount] = verts[i];
+			mTexcoordsp[mCount] = uvs[i];
+			mColorsp[mCount] = colors[i];
 
-		mCount++;
+			mCount++;
+		}
 	}
 
 	mVerticesp[mCount] = mVerticesp[mCount-1];
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 44d9ec1f1566b40ea661027b371a3f8e9243ea8d..61e503d38418b034a2a743c96f129da0b450510d 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -442,6 +442,7 @@ class LLRender
 	LLColor4 mAmbientLightColor;
 	
 	bool			mDirty;
+	U32				mQuadCycle;
 	U32				mCount;
 	U32				mMode;
 	U32				mCurrTextureUnitIndex;
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 090da765ac6063567caa8312c48500a474fd978d..f822a7babd1ec125cbb35509dc41bcdd35f074bd 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -55,6 +55,7 @@ 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;
@@ -149,7 +150,7 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
 
 
 //static
-void LLVertexBuffer::setupClientArrays(U32 data_mask)
+void LLVertexBuffer::setupClientArrays(U32 data_mask, U32& ref_mask)
 {
 	/*if (LLGLImmediate::sStarted)
 	{
@@ -158,13 +159,10 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 
 	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
 
-	if (sLastMask != data_mask)
+	if (ref_mask != data_mask)
 	{
 		llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL);
-		static LLGLSLShader* last_shader = LLGLSLShader::sCurBoundShaderPtr;
-		llassert(sLastMask == 0 || last_shader == shader);
-		last_shader = shader;
-
+		
 		U32 mask[] =
 		{
 			MAP_VERTEX,
@@ -213,7 +211,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 				loc = shader->getAttribLocation(type[i]);
 			}
 
-			if (sLastMask & mask[i])
+			if (ref_mask & mask[i])
 			{ //was enabled
 				if (!(data_mask & mask[i]))
 				{ //needs to be disabled
@@ -297,7 +295,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 				loc = shader->getAttribLocation(type_tc[i]);
 			}
 
-			if (sLastMask & map_tc[i])
+			if (ref_mask & map_tc[i])
 			{
 				if (!(data_mask & map_tc[i]))
 				{ //disable
@@ -330,7 +328,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 
 		if (!shader)
 		{
-			if (sLastMask & MAP_BINORMAL)
+			if (ref_mask & MAP_BINORMAL)
 			{
 				if (!(data_mask & MAP_BINORMAL))
 				{
@@ -347,7 +345,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 			}
 		}
 		
-		sLastMask = data_mask;
+		ref_mask = data_mask;
 	}
 }
 
@@ -589,6 +587,12 @@ void LLVertexBuffer::initClass(bool use_vbo, bool no_vbo_mapping)
 //static 
 void LLVertexBuffer::unbind()
 {
+	if (sGLRenderArray)
+	{
+		glBindVertexArray(0);
+		sGLRenderArray = 0;
+	}
+
 	if (sVBOActive)
 	{
 		glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
@@ -640,6 +644,8 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 	mRequestedNumIndices(-1),
 	mUsage(usage),
 	mGLBuffer(0),
+	mGLArray(0),
+	mLastMask(0),
 	mGLIndices(0), 
 	mMappedData(NULL),
 	mMappedIndexData(NULL), 
@@ -669,12 +675,23 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 		mUsage = GL_STREAM_DRAW_ARB;
 	}
 
+	if (mUsage == 0 && LLRender::sGLCoreProfile)
+	{ //MUST use VBOs for all rendering
+		mUsage = GL_STREAM_DRAW_ARB;
+	}
+
 	//zero out offsets
 	for (U32 i = 0; i < TYPE_MAX; i++)
 	{
 		mOffsets[i] = 0;
 	}
 
+	//initialize cached attrib pointers
+	for (U32 i = 0; i < LL_MAX_VERTEX_ATTRIB_LOCATION; i++)
+	{
+		mLastPointer[i] = (void*) 0xFFFFFFFF;
+	}
+
 	mTypeMask = typemask;
 	mSize = 0;
 	mAlignedOffset = 0;
@@ -732,6 +749,12 @@ LLVertexBuffer::~LLVertexBuffer()
 	LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR);
 	destroyGLBuffer();
 	destroyGLIndices();
+
+	if (mGLArray)
+	{
+		glDeleteVertexArrays(1, &mGLArray);
+	}
+
 	sCount--;
 
 	if (mFence)
@@ -1041,6 +1064,11 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 	{
 		createGLBuffer();
 		createGLIndices();
+
+		if (gGLManager.mHasVertexArrayObject && useVBOs())
+		{
+			glGenVertexArrays(1, &mGLArray);
+		}
 	}
 	
 	sAllocatedBytes += getSize() + getIndicesSize();
@@ -1762,7 +1790,8 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
 {
 	LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER);
 	//set up pointers if the data mask is different ...
-	BOOL setup = (sLastMask != data_mask);
+	U32& ref_mask = mGLArray ? mLastMask : sLastMask;
+	BOOL setup = (ref_mask != data_mask);
 
 	if (gDebugGL && data_mask != 0)
 	{
@@ -1794,15 +1823,19 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
 
 	if (useVBOs())
 	{
+		if (mGLArray && mGLArray != sGLRenderArray)
+		{
+			glBindVertexArray(mGLArray);
+			sGLRenderArray = mGLArray;
+		}
+
 		if (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive))
 		{
 			/*if (sMapped)
 			{
 				llerrs << "VBO bound while another VBO mapped!" << llendl;
 			}*/
-			stop_glerror();
 			glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer);
-			stop_glerror();
 			sBindCount++;
 			sVBOActive = TRUE;
 			setup = TRUE; // ... or the bound buffer changed
@@ -1813,13 +1846,12 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
 			{
 				llerrs << "VBO bound while another VBO mapped!" << llendl;
 			}*/
-			stop_glerror();
 			glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices);
 			stop_glerror();
 			sBindCount++;
 			sIBOActive = TRUE;
 		}
-		
+
 		BOOL error = FALSE;
 		if (gDebugGL)
 		{
@@ -1957,7 +1989,10 @@ void LLVertexBuffer::setBuffer(U32 data_mask, S32 type)
 		}
 	}
 
-	setupClientArrays(data_mask);
+	if (data_mask)
+	{
+		setupClientArrays(data_mask, ref_mask);
+	}
 	
 	if (mGLIndices)
 	{
@@ -1998,10 +2033,18 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 		{
 			loc = shader->getAttribLocation(TYPE_NORMAL);
 		}
-
+		
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+			void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 		else if (!shader)
 		{
@@ -2018,7 +2061,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 		else if (!shader)
 		{
@@ -2037,7 +2088,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 		else if (!shader)
 		{
@@ -2056,7 +2115,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 		else if (!shader)
 		{
@@ -2075,7 +2142,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+			void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 		else if (!shader)
 		{
@@ -2094,7 +2169,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 		else if (!shader)
 		{
@@ -2111,7 +2194,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+			void* ptr = (void*)(base + mOffsets[TYPE_COLOR]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 		else if (!shader)
 		{
@@ -2128,7 +2219,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 
 		if (loc >= 0)
 		{
-			glVertexAttribPointerARB(loc, 1, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], (void*)(base + mOffsets[TYPE_EMISSIVE]));
+			void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc, 1, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
 	}
 	if (data_mask & MAP_WEIGHT)
@@ -2139,13 +2238,18 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 			loc = shader->getAttribLocation(TYPE_WEIGHT);
 		}
 
-		if (loc < 0)
-		{ //legacy behavior, some shaders have weight hardcoded to location 1
-			loc = 1;
+		if (loc > -1)
+		{
+			void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
-		
-		glVertexAttribPointerARB(loc, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
-		
 	}
 
 	if (data_mask & MAP_WEIGHT4)
@@ -2155,7 +2259,15 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 			S32 loc = shader->getAttribLocation(TYPE_WEIGHT4);
 			if (loc > -1)
 			{
-				glVertexAttribPointerARB(loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+				void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]);
+				if (mLastPointer[loc] != ptr)
+				{
+					glVertexAttribPointerARB(loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr);
+				}
+				if (mGLArray)
+				{
+					mLastPointer[loc] = ptr;
+				}
 			}
 		}
 	}
@@ -2168,11 +2280,18 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 			loc = shader->getAttribLocation(TYPE_CLOTHWEIGHT);
 		}
 
-		if (loc < 0)
-		{ //legacy behavior, some shaders have weight hardcoded to location 4
-			loc = 4;
+		if (loc > -1)
+		{
+			void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]);
+			if (mLastPointer[loc] != ptr)
+			{
+				glVertexAttribPointerARB(loc, 4, GL_FLOAT, TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr);
+			}
+			if (mGLArray)
+			{
+				mLastPointer[loc] = ptr;
+			}
 		}
-		glVertexAttribPointerARB(loc, 4, GL_FLOAT, TRUE,  LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
 	}
 	if (data_mask & MAP_VERTEX)
 	{
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 7aa592852418e6b3e69575e180b943816166540b..60cfde39f58df750e0814578a8647c17cf574879 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -38,6 +38,8 @@
 #include <vector>
 #include <list>
 
+#define LL_MAX_VERTEX_ATTRIB_LOCATION 64
+
 //============================================================================
 // NOTES
 // Threading:
@@ -49,7 +51,6 @@
 
 //============================================================================
 // gl name pools for dynamic and streaming buffers
-
 class LLVBOPool : public LLGLNamePool
 {
 protected:
@@ -116,7 +117,7 @@ class LLVertexBuffer : public LLRefCount
 
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
-	static void setupClientArrays(U32 data_mask);
+	static void setupClientArrays(U32 data_mask, U32& ref_mask = LLVertexBuffer::sLastMask);
 	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);
 
@@ -271,6 +272,10 @@ class LLVertexBuffer : public LLRefCount
 	S32		mUsage;			// GL usage
 	U32		mGLBuffer;		// GL VBO handle
 	U32		mGLIndices;		// GL IBO handle
+	U32		mGLArray;		// GL VAO handle
+	U32		mLastMask;		
+	mutable void*   mLastPointer[LL_MAX_VERTEX_ATTRIB_LOCATION];
+
 	U8*		mMappedData;	// pointer to currently mapped data (NULL if unmapped)
 	U8*		mMappedIndexData;	// pointer to currently mapped indices (NULL if unmapped)
 	BOOL	mVertexLocked;			// if TRUE, vertex buffer is being or has been written to in client memory
@@ -307,6 +312,7 @@ class LLVertexBuffer : public LLRefCount
 	static S32 sTypeSize[TYPE_MAX];
 	static U32 sGLMode[LLRender::NUM_MODES];
 	static U32 sGLRenderBuffer;
+	static U32 sGLRenderArray;
 	static U32 sGLRenderIndices;
 	static BOOL sVBOActive;
 	static BOOL sIBOActive;
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 2ba14f8f6efd4659a984daab40f979689e313a4d..bac23279cc1482c4863f7d0cf926c586403cbdcf 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -41,6 +41,7 @@
 #include "llgl.h"
 #include "llstring.h"
 #include "lldir.h"
+#include "llglslshader.h"
 
 // System includes
 #include <commdlg.h>
@@ -1121,34 +1122,6 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 	}
 
 	gGLManager.initWGL();
-
-	if (wglCreateContextAttribsARB && LLRender::sGLCoreProfile)
-	{
-		S32 attribs[] = 
-		{
-			WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
-			WGL_CONTEXT_MINOR_VERSION_ARB, 0,
-			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
-			0
-		};
-
-		HGLRC res = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
-
-		if (!res)
-		{
-			attribs[1] = 3;
-			attribs[3] = 1;
-
-			res = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
-		}
-
-		if (res)
-		{
-			wglMakeCurrent(mhDC, res);
-			wglDeleteContext(mhRC);
-			mhRC = res;
-		}
-	}
 	
 	if (wglChoosePixelFormatARB)
 	{
@@ -1406,7 +1379,35 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 		return FALSE;
 	}
 
-	if (!(mhRC = wglCreateContext(mhDC)))
+	mhRC = 0;
+	if (wglCreateContextAttribsARB)
+	{ //attempt to create a non-compatibility profile context
+		S32 attribs[] = 
+		{
+			WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
+			WGL_CONTEXT_MINOR_VERSION_ARB, 0,
+			WGL_CONTEXT_PROFILE_MASK_ARB,  LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+			WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
+			0
+		};
+
+		mhRC = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
+
+		if (!mhRC)
+		{
+			attribs[1] = 3;
+			attribs[3] = 3;
+
+			mhRC = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
+		}
+
+		if (mhRC)
+		{ //success, disable fixed function calls
+			LLGLSLShader::sNoFixedFunction = true;
+		}
+	}
+
+	if (!mhRC && !(mhRC = wglCreateContext(mhDC)))
 	{
 		close();
 		OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
@@ -1426,7 +1427,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 		OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK);
 		return FALSE;
 	}
-
+	
 	// Disable vertical sync for swap
 	if (disable_vsync && wglSwapIntervalEXT)
 	{
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 32d4097ff36ea40ee5ea0681990a28f72c98549b..a8a7b165a3c10ff2103b40cb48459a2e5df03d59 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7681,7 +7681,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
   <key>RenderDebugNormalScale</key>
   <map>
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index 5078da02e3908ab274afb4979d831e63f2202a67..d503d935d0dceac313631b5afbd4e140ede5f0a5 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -62,13 +62,16 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) :
 	LLFacePool(POOL_TERRAIN),
 	mTexturep(texturep)
 {
+	U32 format = GL_ALPHA8;
+	U32 int_format = GL_ALPHA;
+
 	// Hack!
 	sDetailScale = 1.f/gSavedSettings.getF32("RenderTerrainScale");
 	sDetailMode = gSavedSettings.getS32("RenderTerrainDetail");
 	mAlphaRampImagep = LLViewerTextureManager::getFetchedTextureFromFile("alpha_gradient.tga", 
 													TRUE, LLViewerTexture::BOOST_UI, 
 													LLViewerTexture::FETCHED_TEXTURE,
-													GL_ALPHA8, GL_ALPHA,
+													format, int_format,
 													LLUUID("e97cf410-8e61-7005-ec06-629eba4cd1fb"));
 
 	//gGL.getTexUnit(0)->bind(mAlphaRampImagep.get());
@@ -77,7 +80,7 @@ LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) :
 	m2DAlphaRampImagep = LLViewerTextureManager::getFetchedTextureFromFile("alpha_gradient_2d.j2c", 
 													TRUE, LLViewerTexture::BOOST_UI, 
 													LLViewerTexture::FETCHED_TEXTURE,
-													GL_ALPHA8, GL_ALPHA,
+													format, int_format,
 													LLUUID("38b86f85-2575-52a9-a531-23108d8da837"));
 
 	//gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get());
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 81d7fe70c15b545bfc5d0a6fcf377202fed2e277..db5e4a2fb5ccb9344985630f9740d66d703df6ad 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -261,7 +261,6 @@ void LLSpatialGroup::buildOcclusion()
 {
 	if (mOcclusionVerts.isNull())
 	{
-
 		mOcclusionVerts = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 
 			LLVertexBuffer::sUseStreamDraw ? mBufferUsage : 0); //if GL has a hard time with VBOs, don't use them for occlusion culling.
 		mOcclusionVerts->allocateBuffer(8, 64, true);
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 20ee4759393c9569551d4f38df5c2e54d89ccc68..59835028a17888fc123d317ee871e6ca60983a31 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -537,7 +537,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 
 	stop_glerror();
 	
-	LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), mFace->getPool()->getVertexShaderLevel() > 0 ? 0.f : mShiny);
+	LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), (mFace->getPool()->getVertexShaderLevel() > 0 || LLGLSLShader::sNoFixedFunction) ? 0.f : mShiny);
 
 	//----------------------------------------------------------------
 	// setup current texture
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 23351fc9945752ce0132b787ef21a76ca5305b0c..d1d3334fed953506747e5fbdaceafd2837233e2e 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -443,6 +443,20 @@ void LLViewerShaderMgr::setShaders()
 		return;
 	}
 
+	if (LLRender::sGLCoreProfile)
+	{ 
+		if (!gSavedSettings.getBOOL("VertexShaderEnable"))
+		{ //vertex shaders MUST be enabled to use core profile
+			gSavedSettings.setBOOL("VertexShaderEnable", TRUE);
+		}
+		
+		if (!gSavedSettings.getBOOL("RenderTransparentWater"))
+		{ //non-transparent water uses fixed function
+			gSavedSettings.setBOOL("RenderTransparentWater", TRUE);
+		}
+	}
+
+
 	//setup preprocessor definitions
 	LLShaderMgr::instance()->mDefinitions["samples"] = llformat("%d", gGLManager.getNumFBOFSAASamples(gSavedSettings.getU32("RenderFSAASamples")));
 	LLShaderMgr::instance()->mDefinitions["NUM_TEX_UNITS"] = llformat("%d", gGLManager.mNumTextureImageUnits);
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 59883e0bb19be9867331c0a0c9194a5603d2dd10..581912f8449141948e6672845785fc6221a199be 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2558,7 +2558,7 @@ void LLVOAvatarSelf::deleteScratchTextures()
 			LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
 			total_tex_size -= tex_size ;
 		}
-		if( sScratchTexNames.checkData( GL_LUMINANCE_ALPHA ) )
+		if( sScratchTexNames.checkData( LLRender::sGLCoreProfile ? GL_RG : GL_LUMINANCE_ALPHA ) )
 		{
 			LLImageGL::decTextureCounter(tex_size, 2, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
 			total_tex_size -= 2 * tex_size ;
@@ -2600,89 +2600,6 @@ void LLVOAvatarSelf::deleteScratchTextures()
 	}
 }
 
-BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format )
-{
-	U32 texture_bytes = 0;
-	S32 components = 0; 
-	GLuint gl_name = getScratchTexName( format, components, &texture_bytes );
-	if( gl_name )
-	{
-		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name);
-		stop_glerror();
-
-		F32* last_bind_time = sScratchTexLastBindTime.getIfThere( format );
-		if( last_bind_time )
-		{
-			if( *last_bind_time != LLImageGL::sLastFrameTime )
-			{
-				*last_bind_time = LLImageGL::sLastFrameTime;
-				LLImageGL::updateBoundTexMem(texture_bytes, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
-			}
-		}
-		else
-		{
-			LLImageGL::updateBoundTexMem(texture_bytes, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
-			sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) );
-		}
-		return TRUE;
-	}
-	return FALSE;
-}
-
-LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, S32& components, U32* texture_bytes )
-{	
-	GLenum internal_format;
-	switch( format )
-	{
-		case GL_LUMINANCE:			components = 1; internal_format = GL_LUMINANCE8;		break;
-		case GL_ALPHA:				components = 1; internal_format = GL_ALPHA8;			break;
-		case GL_LUMINANCE_ALPHA:	components = 2; internal_format = GL_LUMINANCE8_ALPHA8;	break;
-		case GL_RGB:				components = 3; internal_format = GL_RGB8;				break;
-		case GL_RGBA:				components = 4; internal_format = GL_RGBA8;				break;
-		default:	llassert(0);	components = 4; internal_format = GL_RGBA8;				break;
-	}
-
-	*texture_bytes = components * SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT;
-	
-	if( sScratchTexNames.checkData( format ) )
-	{
-		return *( sScratchTexNames.getData( format ) );
-	}
-
-	LLGLSUIDefault gls_ui;
-
-	U32 name = 0;
-	LLImageGL::generateTextures(1, &name );
-	stop_glerror();
-
-	gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, name);
-	stop_glerror();
-
-	LLImageGL::setManualImage(
-		GL_TEXTURE_2D, 0, internal_format, 
-		SCRATCH_TEX_WIDTH, SCRATCH_TEX_HEIGHT,
-		format, GL_UNSIGNED_BYTE, NULL );
-	stop_glerror();
-
-	gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
-	gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
-	stop_glerror();
-
-	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	stop_glerror();
-
-	sScratchTexNames.addData( format, new LLGLuint( name ) );
-
-	sScratchTexBytes += *texture_bytes;
-	LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes;
-
-	if(gAuditTexture)
-	{
-		LLImageGL::incTextureCounter(SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
-	}
-	return name;
-}
-
 // static 
 void LLVOAvatarSelf::dumpScratchTextureByteCount()
 {
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 51f06dee5f5246e3572e1e434c6b8baecaeb14f5..74ff47a3e4b1b57d9487c4e7e52e12fd2f5fbedb 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -249,10 +249,7 @@ class LLVOAvatarSelf :
 	// Scratch textures (used for compositing)
 	//--------------------------------------------------------------------
 public:
-	BOOL			bindScratchTexture(LLGLenum format);
 	static void		deleteScratchTextures();
-protected:
-	LLGLuint		getScratchTexName(LLGLenum format, S32& components, U32* texture_bytes);
 private:
 	static S32 		sScratchTexBytes;
 	static LLMap< LLGLenum, LLGLuint*> sScratchTexNames;
diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp
index 39c9945fb4f976093c2f316dd9575312e56116b0..824cb8a15f04be252d2d6ae82e5fab28f07119c6 100644
--- a/indra/newview/llvowlsky.cpp
+++ b/indra/newview/llvowlsky.cpp
@@ -485,7 +485,7 @@ void LLVOWLSky::drawStars(void)
 	if (mStarsVerts.notNull())
 	{
 		mStarsVerts->setBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK);
-		mStarsVerts->drawArrays(LLRender::QUADS, 0, getStarsNumVerts()*4);
+		mStarsVerts->drawArrays(LLRender::TRIANGLES, 0, getStarsNumVerts()*4);
 	}
 }
 
@@ -772,7 +772,7 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable)
 	if (mStarsVerts.isNull())
 	{
 		mStarsVerts = new LLVertexBuffer(LLDrawPoolWLSky::STAR_VERTEX_DATA_MASK, GL_DYNAMIC_DRAW);
-		mStarsVerts->allocateBuffer(getStarsNumVerts()*4, 0, TRUE);
+		mStarsVerts->allocateBuffer(getStarsNumVerts()*6, 0, TRUE);
 	}
  
 	BOOL success = mStarsVerts->getVertexStrider(verticesp)
@@ -807,17 +807,23 @@ BOOL LLVOWLSky::updateStarGeometry(LLDrawable *drawable)
 		*(verticesp++)  = mStarVertices[vtx];
 		*(verticesp++) = mStarVertices[vtx]+left;
 		*(verticesp++) = mStarVertices[vtx]+left+up;
+		*(verticesp++) = mStarVertices[vtx]+left;
+		*(verticesp++) = mStarVertices[vtx]+left+up;
 		*(verticesp++) = mStarVertices[vtx]+up;
 
 		*(texcoordsp++) = LLVector2(0,0);
 		*(texcoordsp++) = LLVector2(0,1);
 		*(texcoordsp++) = LLVector2(1,1);
+		*(texcoordsp++) = LLVector2(0,1);
+		*(texcoordsp++) = LLVector2(1,1);
 		*(texcoordsp++) = LLVector2(1,0);
 
 		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
 		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
 		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
 		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
+		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
+		*(colorsp++)    = LLColor4U(mStarColors[vtx]);
 	}
 
 	mStarsVerts->setBuffer(0);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 2248d181551fbc0825b07b58508f7b096e21b87d..0ca28eb03bd82d4a2a0cbd17c879a1771509ada2 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -106,26 +106,6 @@
 #include "llnotifications.h"
 
 
-void check_stack_depth(S32 stack_depth)
-{
-	if (gDebugGL || gDebugSession)
-	{
-		GLint depth;
-		glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
-		if (depth != stack_depth)
-		{
-			if (gDebugSession)
-			{
-				ll_fail("GL matrix stack corrupted.");
-			}
-			else
-			{
-				llerrs << "GL matrix stack corrupted!" << llendl;
-			}
-		}
-	}
-}
-	
 #ifdef _DEBUG
 // Debug indices is disabled for now for debug performance - djs 4/24/02
 //#define DEBUG_INDICES
@@ -701,7 +681,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		// As of OS X 10.6.7, Apple doesn't support multiple color formats in a single FBO
 		if (!mEdgeMap.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
 #else
-		if (!mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
+		if (!mEdgeMap.allocate(resX, resY, LLRender::sGLCoreProfile ? GL_RGBA : GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;
 #endif
 
 		if (shadow_detail > 0 || ssao)
@@ -916,6 +896,7 @@ void LLPipeline::releaseScreenBuffers()
 
 void LLPipeline::createGLBuffers()
 {
+	stop_glerror();
 	LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS);
 	assertInitialized();
 
@@ -1020,7 +1001,7 @@ void LLPipeline::createGLBuffers()
 
 			LLImageGL::generateTextures(1, &mLightFunc);
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
-			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg);
+			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, lg);
 			gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
 
@@ -3597,13 +3578,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 		}
 	}
 
-	S32 stack_depth = 0;
-
-	if (gDebugGL)
-	{
-		glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &stack_depth);
-	}
-
 	///////////////////////////////////////////
 	//
 	// Sync and verify GL state
@@ -3731,7 +3705,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 					LLVertexBuffer::unbind();
 					if (gDebugGL)
 					{
-						check_stack_depth(stack_depth);
 						std::string msg = llformat("pass %d", i);
 						LLGLState::checkStates(msg);
 						//LLGLState::checkTextureChannels(msg);
@@ -3907,12 +3880,6 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 
 				if (gDebugGL || gDebugPipeline)
 				{
-					GLint depth;
-					glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
-					if (depth > 3)
-					{
-						llerrs << "GL matrix stack corrupted!" << llendl;
-					}
 					LLGLState::checkStates();
 				}
 			}
@@ -4000,12 +3967,6 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 
 				if (gDebugGL || gDebugPipeline)
 				{
-					GLint depth;
-					glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
-					if (depth > 3)
-					{
-						llerrs << "GL matrix stack corrupted!" << llendl;
-					}
 					LLGLState::checkStates();
 				}
 			}