diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index 5f84be2c5d3f2009b1178cb1e649f4cd32d54748..c9fb8534f189e93b3170e8fdc718a8f7b48ce76d 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -38,7 +38,7 @@
 LLStringTable LLCharacter::sVisualParamNames(1024);
 
 std::vector< LLCharacter* > LLCharacter::sInstances;
-
+BOOL LLCharacter::sAllowInstancesChange = TRUE ;
 
 //-----------------------------------------------------------------------------
 // LLCharacter()
@@ -51,8 +51,10 @@ LLCharacter::LLCharacter()
 	mAppearanceSerialNum( 0 ),
 	mSkeletonSerialNum( 0 )
 {
-	mMotionController.setCharacter( this );
+	llassert_always(sAllowInstancesChange) ;
 	sInstances.push_back(this);
+
+	mMotionController.setCharacter( this );	
 	mPauseRequest = new LLPauseRequestHandle();
 }
 
@@ -62,18 +64,29 @@ LLCharacter::LLCharacter()
 // Class Destructor
 //-----------------------------------------------------------------------------
 LLCharacter::~LLCharacter()
-{
+{	
 	for (LLVisualParam *param = getFirstVisualParam(); 
 		param;
 		param = getNextVisualParam())
 	{
 		delete param;
 	}
-	std::vector<LLCharacter*>::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
-	if (iter != sInstances.end())
+
+	U32 i ;
+	U32 size = sInstances.size() ;
+	for(i = 0 ; i < size ; i++)
 	{
-		sInstances.erase(iter);
+		if(sInstances[i] == this)
+		{
+			break ;
+		}
 	}
+
+	llassert_always(i < size) ;
+
+	llassert_always(sAllowInstancesChange) ;
+	sInstances[i] = sInstances[size - 1] ;
+	sInstances.pop_back() ;
 }
 
 
diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h
index a6347fcc3ce1ca7f4d03c1fcf65ff4628119701a..e81a27c2bc1c8895fb37388429f6bfbcf2bc2e36 100644
--- a/indra/llcharacter/llcharacter.h
+++ b/indra/llcharacter/llcharacter.h
@@ -266,6 +266,7 @@ class LLCharacter
 	void			setSkeletonSerialNum( U32 num )	{ mSkeletonSerialNum = num; }
 
 	static std::vector< LLCharacter* > sInstances;
+	static BOOL sAllowInstancesChange ; //debug use
 
 protected:
 	LLMotionController	mMotionController;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index a3aed4dd8abba758d7247fcbe436ed77b4f3faad..c224ab0e9bb20a8c6aefb7517315e1c9cf1a6180 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -568,6 +568,13 @@ bool LLGLManager::initGL()
 		glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
 	}
 
+#if LL_WINDOWS
+	if (mIsATI)
+	{ //using multisample textures on ATI results in black screen for some reason
+		mHasTextureMultisample = FALSE;
+	}
+#endif
+
 	if (mHasFramebufferObject)
 	{
 		glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 8e99f62de680ead157709bd7a895724d2b995153..ad2c662dfcacf784d89fa681003cb956d4bd3d6d 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -109,6 +109,11 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 	// Create program
 	mProgramObject = glCreateProgramObjectARB();
 	
+	if (gGLManager.mGLVersion < 3.1f)
+	{ //force indexed texture channels to 1 if GL version is old (performance improvement for drivers with poor branching shader model support)
+		mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
+	}
+
 	//compile new source
 	vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
 	for ( ; fileIter != mShaderFiles.end(); fileIter++ )
@@ -131,6 +136,11 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 		return FALSE;
 	}
 
+	if (gGLManager.mGLVersion < 3.1f)
+	{ //attachShaderFeatures may have set the number of indexed texture channels, so set to 1 again
+		mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
+	}
+
 	// Map attributes and uniforms
 	if (success)
 	{
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index bdc103b9170526602ae58aca40cd0dca6cb855a5..751b250d9687f6f78183a29a096120e01bda4ec1 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -462,7 +462,11 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 	GLcharARB* text[1024];
 	GLuint count = 0;
 
-	if (gGLManager.mGLVersion < 3.f)
+	if (gGLManager.mGLVersion < 2.1f)
+	{
+		text[count++] = strdup("#version 110\n");
+	}
+	else if (gGLManager.mGLVersion < 3.f)
 	{
 		//set version to 1.20
 		text[count++] = strdup("#version 120\n");
@@ -524,7 +528,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 		text[count++] = strdup("{\n");
 		
 		
-		if (gGLManager.mGLVersion >= 3.f)
+		if (texture_index_channels == 1)
+		{ //don't use flow control, that's silly
+			text[count++] = strdup("return texture2D(tex0, texcoord);\n");
+			text[count++] = strdup("}\n");
+		}
+		else if (gGLManager.mGLVersion >= 3.f)
 		{ 
 			text[count++] = strdup("\tswitch (int(vary_texture_index+0.25))\n");
 			text[count++] = strdup("\t{\n");
@@ -537,6 +546,8 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 			}
 
 			text[count++] = strdup("\t}\n");
+			text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
+			text[count++] = strdup("}\n");
 		}
 		else
 		{
@@ -557,10 +568,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 				std::string if_str = llformat("if (ti == %d) return texture2D(tex%d, texcoord);\n", i, i);
 				text[count++] = strdup(if_str.c_str());
 			}
-		}			
 
-		text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
-		text[count++] = strdup("}\n");
+			text[count++] = strdup("\treturn vec4(0,0,0,0);\n");
+			text[count++] = strdup("}\n");
+		}			
 	}
 
 	//copy file into memory
@@ -605,11 +616,6 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 		}
 	}
 		
-	//free memory
-	for (GLuint i = 0; i < count; i++)
-	{
-		free(text[i]);
-	}
 	if (error == GL_NO_ERROR)
 	{
 		//check for errors
@@ -623,6 +629,16 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 				//an error occured, print log
 				LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
 				dumpObjectLog(ret);
+
+				std::stringstream ostr;
+				//dump shader source for debugging
+				for (GLuint i = 0; i < count; i++)
+				{
+					ostr << i << ": " << text[i];
+				}
+
+				LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
+
 				ret = 0;
 			}
 		}
@@ -633,6 +649,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 	}
 	stop_glerror();
 
+	//free memory
+	for (GLuint i = 0; i < count; i++)
+	{
+		free(text[i]);
+	}
+
 	//successfully loaded, save results
 	if (ret)
 	{
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 4da155efdab1c5f9fa7396a4762ba7b4418d27a2..5384660d4ca8f16a067cf34e68fdf80159ac36bb 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 29
+version 30
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -297,6 +297,7 @@ RenderDeferred				0	0
 
 list Intel
 RenderAnisotropic			1	0
+RenderVBOEnable				1	0
 
 list GeForce2
 RenderAnisotropic			1	0
diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt
index abe4ec99285d9aa3dc4774d963ba90fa3e46ad28..ce2adac221640015e9d3879ef9128e540ee10b51 100644
--- a/indra/newview/featuretable_xp.txt
+++ b/indra/newview/featuretable_xp.txt
@@ -1,4 +1,4 @@
-version 29
+version 30
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -295,6 +295,7 @@ RenderDeferred				0	0
 
 list Intel
 RenderAnisotropic			1	0
+RenderVBOEnable				1	0
 
 list GeForce2
 RenderAnisotropic			1	0
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index da4d0548d02811699e19ca28df1d2457167253ab..592923ee0749b7558954890bd6f6d5d6754e18c9 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -722,6 +722,11 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	shaders.reserve(13);
 	S32 ch = gGLManager.mNumTextureImageUnits-1;
 
+	if (gGLManager.mGLVersion < 3.1f)
+	{ //force to 1 texture index channel for old drivers
+		ch = 1;
+	}
+
 	std::vector<S32> index_channels;
 	index_channels.push_back(-1);	 shaders.push_back( make_pair( "windlight/atmosphericsVarsF.glsl",		mVertexShaderLevel[SHADER_WINDLIGHT] ) );
 	index_channels.push_back(-1);	 shaders.push_back( make_pair( "windlight/gammaF.glsl",					mVertexShaderLevel[SHADER_WINDLIGHT]) );
@@ -1209,7 +1214,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		{
 			if (multisample)
 			{
-				fragment = "deferred/sunlightSSAOMSF.glsl";
+				fragment = "deferred/sunLightSSAOMSF.glsl";
 			}
 			else
 			{
@@ -1220,7 +1225,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		{
 			if (multisample)
 			{
-				fragment = "deferred/sunlightMSF.glsl";
+				fragment = "deferred/sunLightMSF.glsl";
 			}
 			else
 			{
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index a1d9434d44e353af5e692fc3f8a277f37b20699e..d24174adeae4552368b4c70da3c55d687fb02234 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -76,7 +76,6 @@ LLStat LLViewerTextureList::sFormattedMemStat(32, TRUE);
 LLViewerTextureList gTextureList;
 static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images");
 
-U32 LLViewerTextureList::sRenderThreadID = 0 ;
 ///////////////////////////////////////////////////////////////////////////////
 
 LLViewerTextureList::LLViewerTextureList() 
@@ -90,7 +89,6 @@ LLViewerTextureList::LLViewerTextureList()
 
 void LLViewerTextureList::init()
 {			
-	sRenderThreadID = LLThread::currentID() ;
 	mInitialized = TRUE ;
 	sNumImages = 0;
 	mUpdateStats = TRUE;
@@ -502,10 +500,9 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id)
 	return iter->second;
 }
 
-void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image, U32 thread_id)
+void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 {
 	llassert_always(mInitialized) ;
-	llassert_always(sRenderThreadID == thread_id);
 	llassert(image);
 	if (image->isInImageList())
 	{
@@ -519,10 +516,9 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image, U32 thre
 	image->setInImageList(TRUE) ;
 }
 
-void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image, U32 thread_id)
+void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 {
 	llassert_always(mInitialized) ;
-	llassert_always(sRenderThreadID == thread_id);
 	llassert(image);
 	if (!image->isInImageList())
 	{
@@ -659,10 +655,7 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 			const F32 LAZY_FLUSH_TIMEOUT = 30.f; // stop decoding
 			const F32 MAX_INACTIVE_TIME  = 50.f; // actually delete
 			S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference
-			if (imagep->hasCallbacks())
-			{
-				min_refs++; // Add an extra reference if we're on the loaded callback list
-			}
+			
 			S32 num_refs = imagep->getNumRefs();
 			if (num_refs == min_refs)
 			{
@@ -719,9 +712,9 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 			if ((decode_priority_test < old_priority_test * .8f) ||
 				(decode_priority_test > old_priority_test * 1.25f))
 			{
-				removeImageFromList(imagep, sRenderThreadID);
+				removeImageFromList(imagep);
 				imagep->setDecodePriority(decode_priority);
-				addImageToList(imagep, sRenderThreadID);
+				addImageToList(imagep);
 			}
 			update_counter--;
 		}
@@ -893,8 +886,6 @@ void LLViewerTextureList::decodeAllImages(F32 max_time)
 {
 	LLTimer timer;
 
-	llassert_always(sRenderThreadID == LLThread::currentID());
-
 	// Update texture stats and priorities
 	std::vector<LLPointer<LLViewerFetchedTexture> > image_list;
 	for (image_priority_list_t::iterator iter = mImageList.begin();
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index d02b6be6b5d8ec73b6d00677ad9c652f9c3a6fcc..7f4dd0ae8898bf00d40bef251bb4376c079e2eaf 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -121,8 +121,8 @@ class LLViewerTextureList
 	void addImage(LLViewerFetchedTexture *image);
 	void deleteImage(LLViewerFetchedTexture *image);
 
-	void addImageToList(LLViewerFetchedTexture *image, U32 thread_id = LLThread::currentID());
-	void removeImageFromList(LLViewerFetchedTexture *image, U32 thread_id = LLThread::currentID());
+	void addImageToList(LLViewerFetchedTexture *image);
+	void removeImageFromList(LLViewerFetchedTexture *image);
 
 	LLViewerFetchedTexture * getImage(const LLUUID &image_id,									 
 									 BOOL usemipmap = TRUE,
@@ -208,9 +208,6 @@ class LLViewerTextureList
 private:
 	static S32 sNumImages;
 	static void (*sUUIDCallback)(void**, const LLUUID &);
-
-	//debug use
-	static U32 sRenderThreadID;
 };
 
 class LLUIImageList : public LLImageProviderInterface, public LLSingleton<LLUIImageList>
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 1b53348b43b46836c050c16c1caa84ddbd297253..8eda6346b0335bccc7426fb581142f135dcfaf47 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -8242,6 +8242,8 @@ U32 LLVOAvatar::getPartitionType() const
 //static
 void LLVOAvatar::updateImpostors() 
 {
+	LLCharacter::sAllowInstancesChange = FALSE ;
+
 	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
 		 iter != LLCharacter::sInstances.end(); ++iter)
 	{
@@ -8251,6 +8253,8 @@ void LLVOAvatar::updateImpostors()
 			gPipeline.generateImpostor(avatar);
 		}
 	}
+
+	LLCharacter::sAllowInstancesChange = TRUE ;
 }
 
 BOOL LLVOAvatar::isImpostor() const
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c5e2c56e4b298a8de20d4a09a0c0f525c33160de..e6da8eb89d8ec90617d1f70d354adff65008b19e 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4495,6 +4495,11 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 
 	S32 texture_index_channels = gGLManager.mNumTextureImageUnits-1; //always reserve one for shiny for now just for simplicity
 	
+	if (gGLManager.mGLVersion < 3.1f)
+	{
+		texture_index_channels = 1;
+	}
+
 	if (LLPipeline::sRenderDeferred && distance_sort)
 	{
 		texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels;