diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 98eeed09b3a7448bbf504dadb27a80bbce469f16..00baf626d20a86f37ffcbf0ec902f675eda24156 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -69,6 +69,7 @@ if (WINDOWS)
       /Oy-
       /Zc:wchar_t-
       /arch:SSE2
+      /fp:fast
       )
      
   # Are we using the crummy Visual Studio KDU build workaround?
diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp
index c9fb8534f189e93b3170e8fdc718a8f7b48ce76d..0a6a8f9fa6b4a095d404085ed4900264c0aa32d1 100644
--- a/indra/llcharacter/llcharacter.cpp
+++ b/indra/llcharacter/llcharacter.cpp
@@ -189,6 +189,7 @@ void LLCharacter::requestStopMotion( LLMotion* motion)
 //-----------------------------------------------------------------------------
 static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation");
 static LLFastTimer::DeclareTimer FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim");
+static LLFastTimer::DeclareTimer FTM_UPDATE_MOTIONS("Update Motions");
 
 void LLCharacter::updateMotions(e_update_t update_type)
 {
@@ -206,7 +207,10 @@ void LLCharacter::updateMotions(e_update_t update_type)
 			mMotionController.unpauseAllMotions();
 		}
 		bool force_update = (update_type == FORCE_UPDATE);
-		mMotionController.updateMotions(force_update);
+		{
+			LLFastTimer t(FTM_UPDATE_MOTIONS);
+			mMotionController.updateMotions(force_update);
+		}
 	}
 }
 
diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index bb892f4a7f18555d81f6b9b54ccb5662f31ed9cf..4f6351709ede6eb70ddc24df82aaaa17fcaa8ba6 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -542,6 +542,8 @@ void LLMotionController::updateIdleActiveMotions()
 //-----------------------------------------------------------------------------
 // updateMotionsByType()
 //-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_MOTION_ON_UPDATE("Motion onUpdate");
+
 void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type)
 {
 	BOOL update_result = TRUE;
@@ -699,7 +701,10 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty
 			}
 
 			// perform motion update
-			update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
+			{
+				LLFastTimer t(FTM_MOTION_ON_UPDATE);
+				update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature);
+			}
 		}
 
 		//**********************
@@ -810,7 +815,7 @@ void LLMotionController::updateMotions(bool force_update)
 
 	// Always cap the number of loaded motions
 	purgeExcessMotions();
-	
+		
 	// Update timing info for this time step.
 	if (!mPaused)
 	{
@@ -832,6 +837,7 @@ void LLMotionController::updateMotions(bool force_update)
 				}
 
 				updateLoadingMotions();
+				
 				return;
 			}
 			
@@ -850,7 +856,7 @@ void LLMotionController::updateMotions(bool force_update)
 	}
 
 	updateLoadingMotions();
-
+	
 	resetJointSignatures();
 
 	if (mPaused && !force_update)
@@ -861,11 +867,12 @@ void LLMotionController::updateMotions(bool force_update)
 	{
 		// update additive motions
 		updateAdditiveMotions();
+				
 		resetJointSignatures();
-
+		
 		// update all regular motions
 		updateRegularMotions();
-
+		
 		if (use_quantum)
 		{
 			mPoseBlender.blendAndCache(TRUE);
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index e295e3c621d7788fc6ac1475fe57965e7da463a9..8276ec836a77399ed164ff02d4ec65a3286aafb5 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -269,6 +269,7 @@ namespace
 		virtual LLSD::UUID		asUUID() const	{ return LLUUID(mValue); }
 		virtual LLSD::Date		asDate() const	{ return LLDate(mValue); }
 		virtual LLSD::URI		asURI() const	{ return LLURI(mValue); }
+		virtual int				size() const	{ return mValue.size(); }
 	};
 	
 	LLSD::Integer	ImplString::asInteger() const
diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h
index f4c43bac61f80e731842b260fd291e0c57422805..ed9284d2c51de8b227d49298f82752d1e4bab8b8 100644
--- a/indra/llcommon/llstrider.h
+++ b/indra/llcommon/llstrider.h
@@ -44,6 +44,15 @@ template <class Object> class LLStrider
 	const LLStrider<Object>& operator =  (Object *first)    { mObjectp = first; return *this;}
 	void setStride (S32 skipBytes)	{ mSkip = (skipBytes ? skipBytes : sizeof(Object));}
 
+	LLStrider<Object> operator+(const S32& index) 
+	{
+		LLStrider<Object> ret;
+		ret.mBytep = mBytep + mSkip*index;
+		ret.mSkip = mSkip;
+
+		return ret;
+	}
+
 	void skip(const U32 index)     { mBytep += mSkip*index;}
 	U32 getSkip() const			   { return mSkip; }
 	Object* get()                  { return mObjectp; }
@@ -51,6 +60,7 @@ template <class Object> class LLStrider
 	Object& operator *()           { return *mObjectp; }
 	Object* operator ++(int)       { Object* old = mObjectp; mBytep += mSkip; return old; }
 	Object* operator +=(int i)     { mBytep += mSkip*i; return mObjectp; }
+
 	Object& operator[](U32 index)  { return *(Object*)(mBytep + (mSkip * index)); }
 };
 
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 1b11e83b4af369cd4119d19e81d79f486f90014d..6c768863a6ad68e689bfc6e85a1fa71a7269602b 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -31,7 +31,6 @@
 #include "v3math.h"
 #include "llvector4a.h"
 #include <vector>
-#include <set>
 
 #define OCT_ERRS LL_WARNS("OctreeErrors")
 
@@ -79,11 +78,13 @@ class LLOctreeNode : public LLTreeNode<T>
 
 	typedef LLOctreeTraveler<T>									oct_traveler;
 	typedef LLTreeTraveler<T>									tree_traveler;
-	typedef typename std::set<LLPointer<T> >					element_list;
-	typedef typename element_list::iterator						element_iter;
-	typedef typename element_list::const_iterator	const_element_iter;
+	typedef LLPointer<T>*										element_list;
+	typedef LLPointer<T>*										element_iter;
+	typedef const LLPointer<T>*									const_element_iter;
 	typedef typename std::vector<LLTreeListener<T>*>::iterator	tree_listener_iter;
-	typedef typename std::vector<LLOctreeNode<T>* >				child_list;
+	typedef LLOctreeNode<T>**									child_list;
+	typedef LLOctreeNode<T>**									child_iter;
+
 	typedef LLTreeNode<T>		BaseType;
 	typedef LLOctreeNode<T>		oct_node;
 	typedef LLOctreeListener<T>	oct_listener;
@@ -105,6 +106,9 @@ class LLOctreeNode : public LLTreeNode<T>
 	:	mParent((oct_node*)parent), 
 		mOctant(octant) 
 	{ 
+		mData = NULL;
+		mDataEnd = NULL;
+
 		mCenter = center;
 		mSize = size;
 
@@ -123,6 +127,16 @@ class LLOctreeNode : public LLTreeNode<T>
 	{ 
 		BaseType::destroyListeners(); 
 		
+		for (U32 i = 0; i < mElementCount; ++i)
+		{
+			mData[i]->setBinIndex(-1);
+			mData[i] = NULL;
+		}
+
+		free(mData);
+		mData = NULL;
+		mDataEnd = NULL;
+
 		for (U32 i = 0; i < getChildCount(); i++)
 		{
 			delete getChild(i);
@@ -219,12 +233,17 @@ class LLOctreeNode : public LLTreeNode<T>
 	}
 
 	void accept(oct_traveler* visitor)				{ visitor->visit(this); }
-	virtual bool isLeaf() const						{ return mChild.empty(); }
+	virtual bool isLeaf() const						{ return mChildCount == 0; }
 	
 	U32 getElementCount() const						{ return mElementCount; }
+	bool isEmpty() const							{ return mElementCount == 0; }
 	element_list& getData()							{ return mData; }
 	const element_list& getData() const				{ return mData; }
-	
+	element_iter getDataBegin()						{ return mData; }
+	element_iter getDataEnd()						{ return mDataEnd; }
+	const_element_iter getDataBegin() const			{ return mData; }
+	const_element_iter getDataEnd() const			{ return mDataEnd; }
+		
 	U32 getChildCount()	const						{ return mChildCount; }
 	oct_node* getChild(U32 index)					{ return mChild[index]; }
 	const oct_node* getChild(U32 index) const		{ return mChild[index]; }
@@ -289,7 +308,7 @@ class LLOctreeNode : public LLTreeNode<T>
 	
 	virtual bool insert(T* data)
 	{
-		if (data == NULL)
+		if (data == NULL || data->getBinIndex() != -1)
 		{
 			OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
 			return false;
@@ -302,13 +321,16 @@ class LLOctreeNode : public LLTreeNode<T>
 			if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) ||
 				(data->getBinRadius() > getSize()[0] &&	parent && parent->getElementCount() >= gOctreeMaxCapacity))) 
 			{ //it belongs here
-				//if this is a redundant insertion, error out (should never happen)
-				llassert(mData.find(data) == mData.end());
+				mElementCount++;
+				mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
 
-				mData.insert(data);
-				BaseType::insert(data);
+				//avoid unref on uninitialized memory
+				memset(mData+mElementCount-1, 0, sizeof(LLPointer<T>));
 
-				mElementCount = mData.size();
+				mData[mElementCount-1] = data;
+				mDataEnd = mData + mElementCount;
+				data->setBinIndex(mElementCount-1);
+				BaseType::insert(data);
 				return true;
 			}
 			else
@@ -342,10 +364,16 @@ class LLOctreeNode : public LLTreeNode<T>
 
 				if( lt == 0x7 )
 				{
-					mData.insert(data);
-					BaseType::insert(data);
+					mElementCount++;
+					mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
+
+					//avoid unref on uninitialized memory
+					memset(mData+mElementCount-1, 0, sizeof(LLPointer<T>));
 
-					mElementCount = mData.size();
+					mData[mElementCount-1] = data;
+					mDataEnd = mData + mElementCount;
+					data->setBinIndex(mElementCount-1);
+					BaseType::insert(data);
 					return true;
 				}
 
@@ -394,23 +422,59 @@ class LLOctreeNode : public LLTreeNode<T>
 		return false;
 	}
 
+	void _remove(T* data, S32 i)
+	{ //precondition -- mElementCount > 0, idx is in range [0, mElementCount)
+
+		mElementCount--;
+		data->setBinIndex(-1); 
+		
+		if (mElementCount > 0)
+		{
+			if (mElementCount != i)
+			{
+				mData[i] = mData[mElementCount]; //might unref data, do not access data after this point
+				mData[i]->setBinIndex(i);
+			}
+
+			mData[mElementCount] = NULL; //needed for unref
+			mData = (element_list) realloc(mData, sizeof(LLPointer<T>)*mElementCount);
+			mDataEnd = mData+mElementCount;
+		}
+		else
+		{
+			mData[0] = NULL; //needed for unref
+			free(mData);
+			mData = NULL;
+			mDataEnd = NULL;
+		}
+
+		notifyRemoval(data);
+		checkAlive();
+	}
+
 	bool remove(T* data)
 	{
-		if (mData.find(data) != mData.end())
-		{	//we have data
-			mData.erase(data);
-			mElementCount = mData.size();
-			notifyRemoval(data);
-			checkAlive();
-			return true;
-		}
-		else if (isInside(data))
+		S32 i = data->getBinIndex();
+
+		if (i >= 0 && i < mElementCount)
+		{
+			if (mData[i] == data)
+			{ //found it
+				_remove(data, i);
+				llassert(data->getBinIndex() == -1);
+				return true;
+			}
+		}
+		
+		if (isInside(data))
 		{
 			oct_node* dest = getNodeAt(data);
 
 			if (dest != this)
 			{
-				return dest->remove(data);
+				bool ret = dest->remove(data);
+				llassert(data->getBinIndex() == -1);
+				return ret;
 			}
 		}
 
@@ -429,19 +493,20 @@ class LLOctreeNode : public LLTreeNode<T>
 		//node is now root
 		llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
 		node->removeByAddress(data);
+		llassert(data->getBinIndex() == -1);
 		return true;
 	}
 
 	void removeByAddress(T* data)
 	{
-        if (mData.find(data) != mData.end())
+        for (U32 i = 0; i < mElementCount; ++i)
 		{
-			mData.erase(data);
-			mElementCount = mData.size();
-			notifyRemoval(data);
-			llwarns << "FOUND!" << llendl;
-			checkAlive();
-			return;
+			if (mData[i] == data)
+			{ //we have data
+				_remove(data, i);
+				llwarns << "FOUND!" << llendl;
+				return;
+			}
 		}
 		
 		for (U32 i = 0; i < getChildCount(); i++)
@@ -453,8 +518,8 @@ class LLOctreeNode : public LLTreeNode<T>
 
 	void clearChildren()
 	{
-		mChild.clear();
 		mChildCount = 0;
+
 		U32* foo = (U32*) mChildMap;
 		foo[0] = foo[1] = 0xFFFFFFFF;
 	}
@@ -516,7 +581,7 @@ class LLOctreeNode : public LLTreeNode<T>
 
 		mChildMap[child->getOctant()] = mChildCount;
 
-		mChild.push_back(child);
+		mChild[mChildCount] = child;
 		++mChildCount;
 		child->setParent(this);
 
@@ -543,9 +608,12 @@ class LLOctreeNode : public LLTreeNode<T>
 			mChild[index]->destroy();
 			delete mChild[index];
 		}
-		mChild.erase(mChild.begin() + index);
+
 		--mChildCount;
 
+		mChild[index] = mChild[mChildCount];
+		
+
 		//rebuild child map
 		U32* foo = (U32*) mChildMap;
 		foo[0] = foo[1] = 0xFFFFFFFF;
@@ -601,11 +669,12 @@ class LLOctreeNode : public LLTreeNode<T>
 	oct_node* mParent;
 	U8 mOctant;
 
-	child_list mChild;
+	LLOctreeNode<T>* mChild[8];
 	U8 mChildMap[8];
 	U32 mChildCount;
 
 	element_list mData;
+	element_iter mDataEnd;
 	U32 mElementCount;
 		
 }; 
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index cc9744756fd4d4ba19ffb11c83229f9b3f4a0d1a..06ac0aa1f67ca3efc724a767b670a43822a28ad2 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -328,16 +328,16 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle
 		LLVector4a& min = node->mExtents[0];
 		LLVector4a& max = node->mExtents[1];
 
-		if (!branch->getData().empty())
+		if (!branch->isEmpty())
 		{ //node has data, find AABB that binds data set
-			const LLVolumeTriangle* tri = *(branch->getData().begin());
+			const LLVolumeTriangle* tri = *(branch->getDataBegin());
 			
 			//initialize min/max to first available vertex
 			min = *(tri->mV[0]);
 			max = *(tri->mV[0]);
 			
 			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
-				branch->getData().begin(); iter != branch->getData().end(); ++iter)
+				branch->getDataBegin(); iter != branch->getDataEnd(); ++iter)
 			{ //for each triangle in node
 
 				//stretch by triangles in node
@@ -352,7 +352,7 @@ class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle
 				max.setMax(max, *tri->mV[2]);
 			}
 		}
-		else if (!branch->getChildren().empty())
+		else if (!branch->isLeaf())
 		{ //no data, but child nodes exist
 			LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
 
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 76cf9de613e3fc3d6c98d82d819436506c4659ce..2e6f9e2f719e4745e03bf7b73e8fb4075b6f2bd5 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -54,6 +54,7 @@ class LLVolumeTriangle;
 #include "llstrider.h"
 #include "v4coloru.h"
 #include "llrefcount.h"
+#include "llpointer.h"
 #include "llfile.h"
 
 //============================================================================
@@ -919,6 +920,10 @@ class LLVolumeFace
 	LLVector2*  mTexCoords;
 	U16* mIndices;
 
+	//vertex buffer filled in by LLFace to cache this volume face geometry in vram 
+	// (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer)
+	mutable LLPointer<LLRefCount> mVertexBuffer; 
+
 	std::vector<S32>	mEdge;
 
 	//list of skin weights for rigged volumes
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp
index b5a935c2b54133710c8d39c1369cce3de9eca07a..cc83cb7235868bc4102f219806583c9b9e5e30a7 100644
--- a/indra/llmath/llvolumeoctree.cpp
+++ b/indra/llmath/llvolumeoctree.cpp
@@ -131,7 +131,7 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>
 void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* node)
 {
 	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
-			node->getData().begin(); iter != node->getData().end(); ++iter)
+			node->getDataBegin(); iter != node->getDataEnd(); ++iter)
 	{
 		const LLVolumeTriangle* tri = *iter;
 
@@ -236,8 +236,8 @@ void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
 	}
 
 	//children fit, check data
-	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin(); 
-			iter != branch->getData().end(); ++iter)
+	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin(); 
+			iter != branch->getDataEnd(); ++iter)
 	{
 		const LLVolumeTriangle* tri = *iter;
 
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index 688d91dc40b6c0f805187d808d45e1e9644aba42..ed54fe08350157be9fe978b104339edd852ea9fd 100644
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -39,7 +39,7 @@ class LLVolumeTriangle : public LLRefCount
 public:
 	LLVolumeTriangle()
 	{
-		
+		mBinIndex = -1;	
 	}
 
 	LLVolumeTriangle(const LLVolumeTriangle& rhs)
@@ -64,9 +64,16 @@ class LLVolumeTriangle : public LLRefCount
 	U16 mIndex[3];
 
 	F32 mRadius;
+	mutable S32 mBinIndex;
+
 
 	virtual const LLVector4a& getPositionGroup() const;
 	virtual const F32& getBinRadius() const;
+	
+	S32 getBinIndex() const { return mBinIndex; }
+	void setBinIndex(S32 idx) const { mBinIndex = idx; }
+
+
 };
 
 class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp
index 3d8ca2ad9f19c3a58a7271598c32f8612ad8419a..a6fccd2a5660c21209289681467c6d84aa3d558b 100644
--- a/indra/llmessage/llsdmessagereader.cpp
+++ b/indra/llmessage/llsdmessagereader.cpp
@@ -276,7 +276,7 @@ S32 getElementSize(const LLSD& llsd)
 	case LLSD::TypeReal:
 		return sizeof(F64);
 	case LLSD::TypeString:
-		return llsd.asString().size();
+		return llsd.size();
 	case LLSD::TypeUUID:
 		return sizeof(LLUUID);
 	case LLSD::TypeDate:
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 45a3b18179a8aff6b2646aaf02e5aea96bf05add..362452d837fac8e6815c14fe4e93752ca8f9e62d 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -81,7 +81,7 @@ void LLCubeMap::initGL()
 		{
 			U32 texname = 0;
 			
-			LLImageGL::generateTextures(1, &texname);
+			LLImageGL::generateTextures(LLTexUnit::TT_CUBE_MAP, GL_RGB8, 1, &texname);
 
 			for (int i = 0; i < 6; i++)
 			{
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 628a8d6131e1621dc51e6db2cd93a18127ee4f37..0b56b3889c90eed03253981e3bc18ed81496ed30 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -249,6 +249,12 @@ PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample = NULL;
 PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv = NULL;
 PFNGLSAMPLEMASKIPROC glSampleMaski = NULL;
 
+//transform feedback (4.0 core)
+PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings = NULL;
+PFNGLBINDBUFFERRANGEPROC glBindBufferRange = NULL;
+
 //GL_ARB_debug_output
 PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB = NULL;
 PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB = NULL;
@@ -421,6 +427,7 @@ LLGLManager::LLGLManager() :
 	mHasDrawBuffers(FALSE),
 	mHasTextureRectangle(FALSE),
 	mHasTextureMultisample(FALSE),
+	mHasTransformFeedback(FALSE),
 	mMaxSampleMaskWords(0),
 	mMaxColorTextureSamples(0),
 	mMaxDepthTextureSamples(0),
@@ -558,7 +565,8 @@ bool LLGLManager::initGL()
 	parse_gl_version( &mDriverVersionMajor, 
 		&mDriverVersionMinor, 
 		&mDriverVersionRelease, 
-		&mDriverVersionVendorString );
+		&mDriverVersionVendorString,
+		&mGLVersionString);
 
 	mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f;
 
@@ -938,7 +946,6 @@ void LLGLManager::initExtensions()
 	mHasMultitexture = glh_init_extensions("GL_ARB_multitexture");
 	mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts);
 	mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts);
-	mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap");
 	mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color");
 	mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic");
 	glh_init_extensions("GL_ARB_texture_cube_map");
@@ -963,11 +970,14 @@ void LLGLManager::initExtensions()
 							ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
 #endif
 	
+	mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f;
+
 	mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
 	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);
+	mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
 #if !LL_DARWIN
 	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
 #endif
@@ -1207,7 +1217,14 @@ void LLGLManager::initExtensions()
 		glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) GLH_EXT_GET_PROC_ADDRESS("glTexImage3DMultisample");
 		glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) GLH_EXT_GET_PROC_ADDRESS("glGetMultisamplefv");
 		glSampleMaski = (PFNGLSAMPLEMASKIPROC) GLH_EXT_GET_PROC_ADDRESS("glSampleMaski");
-	}	
+	}
+	if (mHasTransformFeedback)
+	{
+		glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glBeginTransformFeedback");
+		glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) GLH_EXT_GET_PROC_ADDRESS("glEndTransformFeedback");
+		glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) GLH_EXT_GET_PROC_ADDRESS("glTransformFeedbackVaryings");
+		glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) GLH_EXT_GET_PROC_ADDRESS("glBindBufferRange");
+	}
 	if (mHasDebugOutput)
 	{
 		glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDebugMessageControlARB");
@@ -1964,6 +1981,7 @@ LLGLState::LLGLState(LLGLenum state, S32 enabled) :
 			case GL_COLOR_MATERIAL:
 			case GL_FOG:
 			case GL_LINE_STIPPLE:
+			case GL_POLYGON_STIPPLE:
 				mState = 0;
 				break;
 		}
@@ -2052,7 +2070,7 @@ void LLGLManager::initGLStates()
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific )
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string )
 {
 	// GL_VERSION returns a null-terminated string with the format: 
 	// <major>.<minor>[.<release>] [<vendor specific>]
@@ -2068,6 +2086,8 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor
 		return;
 	}
 
+	version_string->assign(version);
+
 	std::string ver_copy( version );
 	S32 len = (S32)strlen( version );	/* Flawfinder: ignore */
 	S32 i = 0;
@@ -2429,3 +2449,65 @@ LLGLSquashToFarClip::~LLGLSquashToFarClip()
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
 }
 
+
+	
+LLGLSyncFence::LLGLSyncFence()
+{
+#ifdef GL_ARB_sync
+	mSync = 0;
+#endif
+}
+
+LLGLSyncFence::~LLGLSyncFence()
+{
+#ifdef GL_ARB_sync
+	if (mSync)
+	{
+		glDeleteSync(mSync);
+	}
+#endif
+}
+
+void LLGLSyncFence::placeFence()
+{
+#ifdef GL_ARB_sync
+	if (mSync)
+	{
+		glDeleteSync(mSync);
+	}
+	mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+#endif
+}
+
+bool LLGLSyncFence::isCompleted()
+{
+	bool ret = true;
+#ifdef GL_ARB_sync
+	if (mSync)
+	{
+		GLenum status = glClientWaitSync(mSync, 0, 1);
+		if (status == GL_TIMEOUT_EXPIRED)
+		{
+			ret = false;
+		}
+	}
+#endif
+	return ret;
+}
+
+void LLGLSyncFence::wait()
+{
+#ifdef GL_ARB_sync
+	if (mSync)
+	{
+		while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
+		{ //track the number of times we've waited here
+			static S32 waits = 0;
+			waits++;
+		}
+	}
+#endif
+}
+
+
+
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 5a33c98708356aa974c4bced60f4a91e89a0921b..964495a3abce301eae301d196b1e3d917d0820db 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -104,6 +104,7 @@ class LLGLManager
 	BOOL mHasDepthClamp;
 	BOOL mHasTextureRectangle;
 	BOOL mHasTextureMultisample;
+	BOOL mHasTransformFeedback;
 	S32 mMaxSampleMaskWords;
 	S32 mMaxColorTextureSamples;
 	S32 mMaxDepthTextureSamples;
@@ -141,6 +142,7 @@ class LLGLManager
 	S32 mGLSLVersionMajor;
 	S32 mGLSLVersionMinor;
 	std::string mDriverVersionVendorString;
+	std::string mGLVersionString;
 
 	S32 mVRAM; // VRAM in MB
 	S32 mGLMaxVertexRange;
@@ -417,13 +419,38 @@ class LLGLUpdate
 	virtual void updateGL() = 0;
 };
 
+const U32 FENCE_WAIT_TIME_NANOSECONDS = 1000;  //1 ms
+
+class LLGLFence
+{
+public:
+	virtual void placeFence() = 0;
+	virtual bool isCompleted() = 0;
+	virtual void wait() = 0;
+};
+
+class LLGLSyncFence : public LLGLFence
+{
+public:
+#ifdef GL_ARB_sync
+	GLsync mSync;
+#endif
+	
+	LLGLSyncFence();
+	virtual ~LLGLSyncFence();
+
+	void placeFence();
+	bool isCompleted();
+	void wait();
+};
+
 extern LLMatrix4 gGLObliqueProjectionInverse;
 
 #include "llglstates.h"
 
 void init_glstates();
 
-void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific );
+void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor_specific, std::string* version_string );
 
 extern BOOL gClothRipple;
 extern BOOL gHeadlessClient;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index d61ec707f06c56f9c6c6ad3a56b0e0b480cfd5cd..a0727b8686dbbb2661a70b6e88a91d163c28924f 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -528,6 +528,13 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
 extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
 extern PFNGLSAMPLEMASKIPROC glSampleMaski;
 
+//transform feedback (4.0 core)
+extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
+extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
+extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
+extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+
+
 #elif LL_WINDOWS
 //----------------------------------------------------------------------------
 // LL_WINDOWS
@@ -759,6 +766,12 @@ extern PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
 extern PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
 extern PFNGLSAMPLEMASKIPROC glSampleMaski;
 
+//transform feedback (4.0 core)
+extern PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
+extern PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
+extern PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
+extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
+
 //GL_ARB_debug_output
 extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
 extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 4b7e639aed38da9f71478844dd993d983c8a424e..7cbf39096ec8fbbf9993e4fcd99e556037ee74ca 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -129,7 +129,9 @@ void LLGLSLShader::unload()
 }
 
 BOOL LLGLSLShader::createShader(vector<string> * attributes,
-								vector<string> * uniforms)
+								vector<string> * uniforms,
+								U32 varying_count,
+								const char** varyings)
 {
 	//reloading, reset matrix hash values
 	for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
@@ -172,6 +174,13 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 		mFeatures.mIndexedTextureChannels = llmin(mFeatures.mIndexedTextureChannels, 1);
 	}
 
+#ifdef GL_INTERLEAVED_ATTRIBS
+	if (varying_count > 0 && varyings)
+	{
+		glTransformFeedbackVaryings(mProgramObject, varying_count, varyings, GL_INTERLEAVED_ATTRIBS);
+	}
+#endif
+
 	// Map attributes and uniforms
 	if (success)
 	{
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 7873fe3c4ee8e8d27bc0834a82f4fe5c70442d23..5c68cb46eb3b79a9811bc16a9cb146af902a6dc5 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -76,7 +76,9 @@ class LLGLSLShader
 
 	void unload();
 	BOOL createShader(std::vector<std::string> * attributes,
-						std::vector<std::string> * uniforms);
+						std::vector<std::string> * uniforms,
+						U32 varying_count = 0,
+						const char** varyings = NULL);
 	BOOL attachObject(std::string object);
 	void attachObject(GLhandleARB object);
 	void attachObjects(GLhandleARB* objects = NULL, S32 count = 0);
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index c04a3f6b4182d5693bf14f926ed160260c475f56..a84221176435912164d8a0cb63df23664011ad1b 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -42,6 +42,10 @@
 //----------------------------------------------------------------------------
 const F32 MIN_TEXTURE_LIFETIME = 10.f;
 
+//which power of 2 is i?
+//assumes i is a power of 2 > 0
+U32 wpo2(U32 i);
+
 //statics
 
 U32 LLImageGL::sUniqueCount				= 0;
@@ -50,7 +54,8 @@ S32 LLImageGL::sGlobalTextureMemoryInBytes		= 0;
 S32 LLImageGL::sBoundTextureMemoryInBytes		= 0;
 S32 LLImageGL::sCurBoundTextureMemory	= 0;
 S32 LLImageGL::sCount					= 0;
-std::list<U32> LLImageGL::sDeadTextureList;
+LLImageGL::dead_texturelist_t LLImageGL::sDeadTextureList[LLTexUnit::TT_NONE];
+U32 LLImageGL::sCurTexName = 1;
 
 BOOL LLImageGL::sGlobalUseAnisotropic	= FALSE;
 F32 LLImageGL::sLastFrameTime			= 0.f;
@@ -232,9 +237,11 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)
 
 //----------------------------------------------------------------------------
 
+static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_STATS("Image Stats");
 // static
 void LLImageGL::updateStats(F32 current_time)
 {
+	LLFastTimer t(FTM_IMAGE_UPDATE_STATS);
 	sLastFrameTime = current_time;
 	sBoundTextureMemoryInBytes = sCurBoundTextureMemory;
 	sCurBoundTextureMemory = 0;
@@ -416,6 +423,7 @@ void LLImageGL::init(BOOL usemipmaps)
 	mTarget = GL_TEXTURE_2D;
 	mBindTarget = LLTexUnit::TT_TEXTURE;
 	mHasMipMaps = false;
+	mMipLevels = -1;
 
 	mIsResident = 0;
 
@@ -606,8 +614,24 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		is_compressed = true;
 	}
 
+	
+	
+	if (mUseMipMaps)
+	{
+		//set has mip maps to true before binding image so tex parameters get set properly
+		gGL.getTexUnit(0)->unbind(mBindTarget);
+		mHasMipMaps = true;
+		mTexOptionsDirty = true;
+		setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+	}
+	else
+	{
+		mHasMipMaps = false;
+	}
+	
 	llverify(gGL.getTexUnit(0)->bind(this));
 	
+	
 	if (mUseMipMaps)
 	{
 		if (data_hasmips)
@@ -620,6 +644,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 				S32 w = getWidth(d);
 				S32 h = getHeight(d);
 				S32 gl_level = d-mCurrentDiscardLevel;
+
+				mMipLevels = llmax(mMipLevels, gl_level);
+
 				if (d > mCurrentDiscardLevel)
 				{
 					data_in -= dataFormatBytes(mFormatPrimary, w, h); // see above comment
@@ -662,10 +689,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		{
 			if (mAutoGenMips)
 			{
-				if (!gGLManager.mHasFramebufferObject)
-				{
-					glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE);
-				}
 				stop_glerror();
 				{
 // 					LLFastTimer t2(FTM_TEMP4);
@@ -679,6 +702,11 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 					S32 w = getWidth(mCurrentDiscardLevel);
 					S32 h = getHeight(mCurrentDiscardLevel);
 
+					mMipLevels = wpo2(llmax(w, h));
+
+					//use legacy mipmap generation mode
+					glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE);
+					
 					LLImageGL::setManualImage(mTarget, 0, mFormatInternal,
 								 w, h, 
 								 mFormatPrimary, mFormatType,
@@ -694,16 +722,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 						stop_glerror();
 					}
 				}
-
-				if (gGLManager.mHasFramebufferObject)
-				{
-					glGenerateMipmap(LLTexUnit::getInternalType(mBindTarget));
-				}
 			}
 			else
 			{
 				// Create mips by hand
-				// about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
 				// ~4x faster than gluBuild2DMipmaps
 				S32 width = getWidth(mCurrentDiscardLevel);
 				S32 height = getHeight(mCurrentDiscardLevel);
@@ -713,6 +735,9 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 				const U8* cur_mip_data = 0;
 				S32 prev_mip_size = 0;
 				S32 cur_mip_size = 0;
+				
+				mMipLevels = nummips;
+
 				for (int m=0; m<nummips; m++)
 				{
 					if (m==0)
@@ -777,10 +802,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 		{
 			llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
 		}
-		mHasMipMaps = true;
 	}
 	else
 	{
+		mMipLevels = 0;
 		S32 w = getWidth();
 		S32 h = getHeight();
 		if (is_compressed)
@@ -812,7 +837,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 			}
 
 		}
-		mHasMipMaps = false;
 	}
 	stop_glerror();
 	mGLTextureCreated = true;
@@ -1025,23 +1049,65 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 }
 
 // static
-void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
+void LLImageGL::generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures)
 {
-	glGenTextures(numTextures, (GLuint*)textures);
+	bool empty = true;
+
+	dead_texturelist_t::iterator iter = sDeadTextureList[type].find(format);
+	
+	if (iter != sDeadTextureList[type].end())
+	{
+		empty = iter->second.empty();
+	}
+	
+	for (S32 i = 0; i < numTextures; ++i)
+	{
+		if (!empty)
+		{
+			textures[i] = iter->second.front();
+			iter->second.pop_front();
+			empty = iter->second.empty();
+		}
+		else
+		{
+			textures[i] = sCurTexName++;
+		}
+	}
 }
 
 // static
-void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
+void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate)
 {
-	for (S32 i = 0; i < numTextures; i++)
+	if (gGLManager.mInited)
 	{
-		sDeadTextureList.push_back(textures[i]);
-	}
+		if (format == 0 ||  type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1)
+		{ //unknown internal format or unknown number of mip levels, not safe to reuse
+			glDeleteTextures(numTextures, textures);
+		}
+		else
+		{
+			for (S32 i = 0; i < numTextures; ++i)
+			{ //remove texture from VRAM by setting its size to zero
+				for (S32 j = 0; j <= mip_levels; j++)
+				{
+					gGL.getTexUnit(0)->bindManual(type, textures[i]);
+
+					glTexImage2D(LLTexUnit::getInternalType(type), j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+				}
+
+				llassert(std::find(sDeadTextureList[type][format].begin(),
+								   sDeadTextureList[type][format].end(), textures[i]) == 
+								   sDeadTextureList[type][format].end());
 
-	if (immediate)
+				sDeadTextureList[type][format].push_back(textures[i]);
+			}	
+		}
+	}
+	
+	/*if (immediate)
 	{
 		LLImageGL::deleteDeadTextures();
-	}
+	}*/
 }
 
 // static
@@ -1166,10 +1232,11 @@ BOOL LLImageGL::createGLTexture()
 
 	if(mTexName)
 	{
-		glDeleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ;
+		LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, (reinterpret_cast<GLuint*>(&mTexName))) ;
 	}
 	
-	glGenTextures(1, (GLuint*)&mTexName);
+
+	LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName);
 	stop_glerror();
 	if (!mTexName)
 	{
@@ -1282,7 +1349,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	}
 	else
 	{
-		LLImageGL::generateTextures(1, &mTexName);
+		LLImageGL::generateTextures(mBindTarget, mFormatInternal, 1, &mTexName);
 		stop_glerror();
 		{
 			llverify(gGL.getTexUnit(0)->bind(this));
@@ -1327,7 +1394,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	{
 		sGlobalTextureMemoryInBytes -= mTextureMemory;
 
-		LLImageGL::deleteTextures(1, &old_name);
+		LLImageGL::deleteTextures(mBindTarget, mFormatInternal, mMipLevels, 1, &old_name);
 
 		stop_glerror();
 	}
@@ -1456,7 +1523,7 @@ void LLImageGL::deleteDeadTextures()
 {
 	bool reset = false;
 
-	while (!sDeadTextureList.empty())
+	/*while (!sDeadTextureList.empty())
 	{
 		GLuint tex = sDeadTextureList.front();
 		sDeadTextureList.pop_front();
@@ -1478,7 +1545,7 @@ void LLImageGL::deleteDeadTextures()
 		
 		glDeleteTextures(1, &tex);
 		stop_glerror();
-	}
+	}*/
 
 	if (reset)
 	{
@@ -1496,7 +1563,7 @@ void LLImageGL::destroyGLTexture()
 			mTextureMemory = 0;
 		}
 		
-		LLImageGL::deleteTextures(1, &mTexName);			
+		LLImageGL::deleteTextures(mBindTarget,  mFormatInternal, mMipLevels, 1, &mTexName);			
 		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
 		mTexName = 0;		
 		mGLTextureCreated = FALSE ;
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index f34b9fa91a9302c638a953c31d53eeec2d2dc20f..e118c28c1ba2e4a9d26ad2920399f1e9e6a43f4e 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -45,8 +45,16 @@ class LLImageGL : public LLRefCount
 {
 	friend class LLTexUnit;
 public:
-	static std::list<U32> sDeadTextureList;
+	static U32 sCurTexName;
 
+	//previously used but now available texture names
+	// sDeadTextureList[<usage>][<internal format>]
+	typedef std::map<U32, std::list<U32> > dead_texturelist_t;
+	static dead_texturelist_t sDeadTextureList[LLTexUnit::TT_NONE];
+
+	// These 2 functions replace glGenTextures() and glDeleteTextures()
+	static void generateTextures(LLTexUnit::eTextureType type, U32 format, S32 numTextures, U32 *textures);
+	static void deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip_levels, S32 numTextures, U32 *textures, bool immediate = false);
 	static void deleteDeadTextures();
 
 	// Size calculation
@@ -96,10 +104,6 @@ class LLImageGL : public LLRefCount
 	void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;}
 	void setAllowCompression(bool allow) { mAllowCompression = allow; }
 
-	// These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() 
-	// for tracking purposes and will be deprecated in the future
-	static void generateTextures(S32 numTextures, U32 *textures);
-	static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false);
 	static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true);
 
 	BOOL createGLTexture() ;
@@ -217,7 +221,8 @@ class LLImageGL : public LLRefCount
 	LLGLenum mTarget;		// Normally GL_TEXTURE2D, sometimes something else (ex. cube maps)
 	LLTexUnit::eTextureType mBindTarget;	// Normally TT_TEXTURE, sometimes something else (ex. cube maps)
 	bool mHasMipMaps;
-	
+	S32 mMipLevels;
+
 	LLGLboolean mIsResident;
 	
 	S8 mComponents;
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 93bac4c779e765bc4142eb0ed525833a5b1c9d83..348c1eb1b7ab5b2076c8b75afa768d0afbc1f0a0 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -408,12 +408,14 @@ void LLTexUnit::unbind(eTextureType type)
 
 	if (mIndex < 0) return;
 
+	//always flush and activate for consistency 
+	//   some code paths assume unbind always flushes and sets the active texture
+	gGL.flush();
+	activate();
+
 	// Disabled caching of binding state.
 	if (mCurrTexType == type)
 	{
-		gGL.flush();
-
-		activate();
 		mCurrTexture = 0;
 		if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE)
 		{
@@ -464,11 +466,25 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
 	} 
 	else if (option >= TFO_BILINEAR)
 	{
-		glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		if (mHasMipMaps)
+		{
+			glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+		}
+		else
+		{
+			glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		}
 	}
 	else
 	{
-		glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		if (mHasMipMaps)
+		{
+			glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+		}
+		else
+		{
+			glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+		}
 	}
 
 	if (gGLManager.mHasAnisotropic)
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 780f1dc484ef082504a454416710e6432a3e43e1..cc5c2323809b40c43b79f843fe19fbd0997558e2 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -55,7 +55,6 @@ bool LLRenderTarget::sUseFBO = false;
 LLRenderTarget::LLRenderTarget() :
 	mResX(0),
 	mResY(0),
-	mTex(0),
 	mFBO(0),
 	mDepth(0),
 	mStencil(0),
@@ -70,6 +69,42 @@ LLRenderTarget::~LLRenderTarget()
 	release();
 }
 
+void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
+{ 
+	//for accounting, get the number of pixels added/subtracted
+	S32 pix_diff = (resx*resy)-(mResX*mResY);
+		
+	mResX = resx;
+	mResY = resy;
+
+	for (U32 i = 0; i < mTex.size(); ++i)
+	{ //resize color attachments
+		gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
+		LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+		sBytesAllocated += pix_diff*4;
+	}
+
+	if (mDepth)
+	{ //resize depth attachment
+		if (mStencil)
+		{
+			//use render buffers where stencil buffers are in play
+			glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
+			glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
+			glBindRenderbuffer(GL_RENDERBUFFER, 0);
+		}
+		else
+		{
+			gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
+			U32 internal_type = LLTexUnit::getInternalType(mUsage);
+			LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
+		}
+
+		sBytesAllocated += pix_diff*4;
+	}
+}
+	
+
 bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples)
 {
 	stop_glerror();
@@ -135,7 +170,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
 	}
 
 	U32 tex;
-	LLImageGL::generateTextures(1, &tex);
+	LLImageGL::generateTextures(mUsage, color_fmt, 1, &tex);
 	gGL.getTexUnit(0)->bindManual(mUsage, tex);
 
 	stop_glerror();
@@ -193,6 +228,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
 	}
 
 	mTex.push_back(tex);
+	mInternalFormat.push_back(color_fmt);
 
 	if (gDebugGL)
 	{ //bind and unbind to validate target
@@ -217,7 +253,7 @@ bool LLRenderTarget::allocateDepth()
 	}
 	else
 	{
-		LLImageGL::generateTextures(1, &mDepth);
+		LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth);
 		gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
 		
 		U32 internal_type = LLTexUnit::getInternalType(mUsage);
@@ -294,7 +330,7 @@ void LLRenderTarget::release()
 		}
 		else
 		{
-			LLImageGL::deleteTextures(1, &mDepth, true);
+			LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true);
 			stop_glerror();
 		}
 		mDepth = 0;
@@ -326,8 +362,9 @@ void LLRenderTarget::release()
 	if (mTex.size() > 0)
 	{
 		sBytesAllocated -= mResX*mResY*4*mTex.size();
-		LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
+		LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true);
 		mTex.clear();
+		mInternalFormat.clear();
 	}
 	
 	mResX = mResY = 0;
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 2735ab21c560d2c676f8c2ce1bb28d46f859a40f..e1a51304f1747f0be9a10c00450f2f3355c370ee 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -57,8 +57,6 @@
 
 */
 
-class LLMultisampleBuffer;
-
 class LLRenderTarget
 {
 public:
@@ -74,6 +72,12 @@ class LLRenderTarget
 	//multiple calls will release previously allocated resources
 	bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0);
 
+	//resize existing attachments to use new resolution and color format
+	// CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined
+	// DO NOT use for screen space buffers or for scratch space for an image that might be uploaded
+	// DO use for render targets that resize often and aren't likely to ruin someone's day if they break
+	void resize(U32 resx, U32 resy, U32 color_fmt);
+
 	//add color buffer attachment
 	//limit of 4 color attachments per render target
 	bool addColorAttachment(U32 color_fmt);
@@ -142,6 +146,7 @@ class LLRenderTarget
 	U32 mResX;
 	U32 mResY;
 	std::vector<U32> mTex;
+	std::vector<U32> mInternalFormat;
 	U32 mFBO;
 	U32 mDepth;
 	bool mStencil;
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 5a6e6cab3e41f5388bceaa854ad552d4590fdc5c..d3b2d9fa740aaa31efd37b42508bd1e43df5eea5 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -1026,6 +1026,9 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("size");
 	mReservedUniforms.push_back("falloff");
 
+	mReservedUniforms.push_back("box_center");
+	mReservedUniforms.push_back("box_size");
+
 
 	mReservedUniforms.push_back("minLuminance");
 	mReservedUniforms.push_back("maxExtractAlpha");
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index f792faa8f0f43e7100a974fe9e0f486ac259ca60..7a16b7c20fd6585b042476ce5d29173af3ab3567 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -97,6 +97,8 @@ class LLShaderMgr
 		LIGHT_CENTER,
 		LIGHT_SIZE,
 		LIGHT_FALLOFF,
+		BOX_CENTER,
+		BOX_SIZE,
 
 		GLOW_MIN_LUMINANCE,
 		GLOW_MAX_EXTRACT_ALPHA,
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 823c6b9dc510d2019dff2307a5b11ae8de6edba2..0092df6587d0dab275271570aa1bcf37f8f76b03 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -38,12 +38,6 @@
 #include "llglslshader.h"
 #include "llmemory.h"
 
-#if LL_DARWIN
-#define LL_VBO_POOLING 1
-#else
-#define LL_VBO_POOLING 0
-#endif
-
 //Next Highest Power Of Two
 //helper function, returns first number > v that is a power of 2, or v if v is already a power of 2
 U32 nhpo2(U32 v)
@@ -71,6 +65,7 @@ U32 wpo2(U32 i)
 
 
 const U32 LL_VBO_BLOCK_SIZE = 2048;
+const U32 LL_VBO_POOL_MAX_SEED_SIZE = 256*1024;
 
 U32 vbo_block_size(U32 size)
 { //what block size will fit size?
@@ -83,6 +78,7 @@ U32 vbo_block_index(U32 size)
 	return vbo_block_size(size)/LL_VBO_BLOCK_SIZE;
 }
 
+const U32 LL_VBO_POOL_SEED_COUNT = vbo_block_index(LL_VBO_POOL_MAX_SEED_SIZE);
 
 
 //============================================================================
@@ -95,6 +91,11 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_
 
 U32 LLVBOPool::sBytesPooled = 0;
 U32 LLVBOPool::sIndexBytesPooled = 0;
+U32 LLVBOPool::sCurGLName = 1;
+
+std::list<U32> LLVertexBuffer::sAvailableVAOName;
+U32 LLVertexBuffer::sCurVAOName = 1;
+
 U32 LLVertexBuffer::sAllocatedIndexBytes = 0;
 U32 LLVertexBuffer::sIndexCount = 0;
 
@@ -119,69 +120,55 @@ bool LLVertexBuffer::sUseStreamDraw = true;
 bool LLVertexBuffer::sUseVAO = false;
 bool LLVertexBuffer::sPreferStreamDraw = false;
 
-const U32 FENCE_WAIT_TIME_NANOSECONDS = 10000;  //1 ms
 
-class LLGLSyncFence : public LLGLFence
+U32 LLVBOPool::genBuffer()
 {
-public:
-#ifdef GL_ARB_sync
-	GLsync mSync;
-#endif
-	
-	LLGLSyncFence()
-	{
-#ifdef GL_ARB_sync
-		mSync = 0;
-#endif
-	}
+	U32 ret = 0;
 
-	virtual ~LLGLSyncFence()
+	if (mGLNamePool.empty())
 	{
-#ifdef GL_ARB_sync
-		if (mSync)
-		{
-			glDeleteSync(mSync);
-		}
-#endif
+		ret = sCurGLName++;
 	}
-
-	void placeFence()
+	else
 	{
-#ifdef GL_ARB_sync
-		if (mSync)
-		{
-			glDeleteSync(mSync);
-		}
-		mSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-#endif
+		ret = mGLNamePool.front();
+		mGLNamePool.pop_front();
 	}
 
-	void wait()
+	return ret;
+}
+
+void LLVBOPool::deleteBuffer(U32 name)
+{
+	if (gGLManager.mInited)
 	{
-#ifdef GL_ARB_sync
-		if (mSync)
-		{
-			while (glClientWaitSync(mSync, 0, FENCE_WAIT_TIME_NANOSECONDS) == GL_TIMEOUT_EXPIRED)
-			{ //track the number of times we've waited here
-				static S32 waits = 0;
-				waits++;
-			}
-		}
-#endif
-	}
+		LLVertexBuffer::unbind();
 
+		glBindBufferARB(mType, name);
+		glBufferDataARB(mType, 0, NULL, mUsage);
 
-};
+		llassert(std::find(mGLNamePool.begin(), mGLNamePool.end(), name) == mGLNamePool.end());
+
+		mGLNamePool.push_back(name);
+
+		glBindBufferARB(mType, 0);
+	}
+}
 
 
-volatile U8* LLVBOPool::allocate(U32& name, U32 size)
+LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType)
+: mUsage(vboUsage), mType(vboType)
+{
+	mMissCount.resize(LL_VBO_POOL_SEED_COUNT);
+	std::fill(mMissCount.begin(), mMissCount.end(), 0);
+}
+
+volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed)
 {
 	llassert(vbo_block_size(size) == size);
 	
 	volatile U8* ret = NULL;
 
-#if LL_VBO_POOLING
-
 	U32 i = vbo_block_index(size);
 
 	if (mFreeList.size() <= i)
@@ -189,12 +176,18 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
 		mFreeList.resize(i+1);
 	}
 
-	if (mFreeList[i].empty())
+	if (mFreeList[i].empty() || for_seed)
 	{
 		//make a new buffer
-		glGenBuffersARB(1, &name);
+		name = genBuffer();
+		
 		glBindBufferARB(mType, name);
 
+		if (!for_seed && i < LL_VBO_POOL_SEED_COUNT)
+		{ //record this miss
+			mMissCount[i]++;	
+		}
+
 		if (mType == GL_ARRAY_BUFFER_ARB)
 		{
 			LLVertexBuffer::sAllocatedBytes += size;
@@ -215,6 +208,25 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
 		}
 
 		glBindBufferARB(mType, 0);
+
+		if (for_seed)
+		{ //put into pool for future use
+			llassert(mFreeList.size() > i);
+
+			Record rec;
+			rec.mGLName = name;
+			rec.mClientData = ret;
+	
+			if (mType == GL_ARRAY_BUFFER_ARB)
+			{
+				sBytesPooled += size;
+			}
+			else
+			{
+				sIndexBytesPooled += size;
+			}
+			mFreeList[i].push_back(rec);
+		}
 	}
 	else
 	{
@@ -232,33 +244,6 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size)
 
 		mFreeList[i].pop_front();
 	}
-#else //no pooling
-
-	glGenBuffersARB(1, &name);
-	glBindBufferARB(mType, name);
-
-	if (mType == GL_ARRAY_BUFFER_ARB)
-	{
-		LLVertexBuffer::sAllocatedBytes += size;
-	}
-	else
-	{
-		LLVertexBuffer::sAllocatedIndexBytes += size;
-	}
-
-	if (LLVertexBuffer::sDisableVBOMapping || mUsage != GL_DYNAMIC_DRAW_ARB)
-	{
-		glBufferDataARB(mType, size, 0, mUsage);
-		ret = (U8*) ll_aligned_malloc_16(size);
-	}
-	else
-	{ //always use a true hint of static draw when allocating non-client-backed buffers
-		glBufferDataARB(mType, size, 0, GL_STATIC_DRAW_ARB);
-	}
-
-	glBindBufferARB(mType, 0);
-
-#endif
 
 	return ret;
 }
@@ -267,50 +252,47 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size)
 {
 	llassert(vbo_block_size(size) == size);
 
-#if LL_VBO_POOLING
-
-	U32 i = vbo_block_index(size);
-
-	llassert(mFreeList.size() > i);
+	deleteBuffer(name);
+	ll_aligned_free_16((U8*) buffer);
 
-	Record rec;
-	rec.mGLName = name;
-	rec.mClientData = buffer;
-	
-	if (buffer == NULL)
+	if (mType == GL_ARRAY_BUFFER_ARB)
 	{
-		glDeleteBuffersARB(1, &rec.mGLName);
+		LLVertexBuffer::sAllocatedBytes -= size;
 	}
 	else
 	{
-		if (mType == GL_ARRAY_BUFFER_ARB)
-		{
-			sBytesPooled += size;
-		}
-		else
-		{
-			sIndexBytesPooled += size;
-		}
-		mFreeList[i].push_back(rec);
+		LLVertexBuffer::sAllocatedIndexBytes -= size;
 	}
-#else //no pooling
-	glDeleteBuffersARB(1, &name);
-	ll_aligned_free_16((U8*) buffer);
+}
 
-	if (mType == GL_ARRAY_BUFFER_ARB)
+void LLVBOPool::seedPool()
+{
+	U32 dummy_name = 0;
+
+	if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT)
 	{
-		LLVertexBuffer::sAllocatedBytes -= size;
+		mFreeList.resize(LL_VBO_POOL_SEED_COUNT);
 	}
-	else
+
+	for (U32 i = 0; i < LL_VBO_POOL_SEED_COUNT; i++)
 	{
-		LLVertexBuffer::sAllocatedIndexBytes -= size;
+		if (mMissCount[i] > mFreeList[i].size())
+		{ 
+			U32 size = i*LL_VBO_BLOCK_SIZE;
+		
+			S32 count = mMissCount[i] - mFreeList[i].size();
+			for (U32 j = 0; j < count; ++j)
+			{
+				allocate(dummy_name, size, true);
+			}
+		}
 	}
-#endif
 }
 
+
 void LLVBOPool::cleanup()
 {
-	U32 size = 1;
+	U32 size = LL_VBO_BLOCK_SIZE;
 
 	for (U32 i = 0; i < mFreeList.size(); ++i)
 	{
@@ -320,8 +302,8 @@ void LLVBOPool::cleanup()
 		{
 			Record& r = l.front();
 
-			glDeleteBuffersARB(1, &r.mGLName);
-
+			deleteBuffer(r.mGLName);
+			
 			if (r.mClientData)
 			{
 				ll_aligned_free_16((void*) r.mClientData);
@@ -341,8 +323,11 @@ void LLVBOPool::cleanup()
 			}
 		}
 
-		size *= 2;
+		size += LL_VBO_BLOCK_SIZE;
 	}
+
+	//reset miss counts
+	std::fill(mMissCount.begin(), mMissCount.end(), 0);
 }
 
 
@@ -376,6 +361,41 @@ U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] =
 	GL_LINE_LOOP,
 };
 
+//static
+U32 LLVertexBuffer::getVAOName()
+{
+	U32 ret = 0;
+
+	if (!sAvailableVAOName.empty())
+	{
+		ret = sAvailableVAOName.front();
+		sAvailableVAOName.pop_front();
+	}
+	else
+	{
+#ifdef GL_ARB_vertex_array_object
+		glGenVertexArrays(1, &ret);
+#endif
+	}
+
+	return ret;		
+}
+
+//static
+void LLVertexBuffer::releaseVAOName(U32 name)
+{
+	sAvailableVAOName.push_back(name);
+}
+
+
+//static
+void LLVertexBuffer::seedPools()
+{
+	sStreamVBOPool.seedPool();
+	sDynamicVBOPool.seedPool();
+	sStreamIBOPool.seedPool();
+	sDynamicIBOPool.seedPool();
+}
 
 //static
 void LLVertexBuffer::setupClientArrays(U32 data_mask)
@@ -985,7 +1005,7 @@ LLVertexBuffer::~LLVertexBuffer()
 	if (mGLArray)
 	{
 #if GL_ARB_vertex_array_object
-		glDeleteVertexArrays(1, &mGLArray);
+		releaseVAOName(mGLArray);
 #endif
 	}
 
@@ -1211,10 +1231,10 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
 
 	llassert(nverts >= 0);
 
-	if (nverts >= 65535)
+	if (nverts > 65536)
 	{
 		llwarns << "Vertex buffer overflow!" << llendl;
-		nverts = 65535;
+		nverts = 65536;
 	}
 
 	U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
@@ -1270,7 +1290,7 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 		if (gGLManager.mHasVertexArrayObject && useVBOs() && (LLRender::sGLCoreProfile || sUseVAO))
 		{
 #if GL_ARB_vertex_array_object
-			glGenVertexArrays(1, &mGLArray);
+			mGLArray = getVAOName();
 #endif
 			setupVertexArray();
 		}
@@ -2140,6 +2160,16 @@ void LLVertexBuffer::flush()
 	}
 }
 
+// bind for transform feedback (quick 'n dirty)
+void LLVertexBuffer::bindForFeedback(U32 channel, U32 type, U32 index, U32 count)
+{
+#ifdef GL_TRANSFORM_FEEDBACK_BUFFER
+	U32 offset = mOffsets[type] + sTypeSize[type]*index;
+	U32 size= (sTypeSize[type]*count);
+	glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, channel, mGLBuffer, offset, size);
+#endif
+}
+
 // Set for rendering
 void LLVertexBuffer::setBuffer(U32 data_mask)
 {
@@ -2291,10 +2321,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 	stop_glerror();
 	volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
 
-	/*if ((data_mask & mTypeMask) != data_mask)
+	if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
 	{
 		llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
-	}*/
+	}
 
 	if (LLGLSLShader::sNoFixedFunction)
 	{
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 7477dec3adaab878c054cae88abbfe38516128b2..11fa4ab6a0da3b7862298801072572cf9dd0b3dd 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -57,23 +57,28 @@ class LLVBOPool
 	static U32 sBytesPooled;
 	static U32 sIndexBytesPooled;
 	
-	LLVBOPool(U32 vboUsage, U32 vboType)
-		: mUsage(vboUsage)
-		, mType(vboType)
-	{}
+	static U32 sCurGLName;
 
+	LLVBOPool(U32 vboUsage, U32 vboType);
+		
 	const U32 mUsage;
 	const U32 mType;
 
 	//size MUST be a power of 2
-	volatile U8* allocate(U32& name, U32 size);
+	volatile U8* allocate(U32& name, U32 size, bool for_seed = false);
 	
 	//size MUST be the size provided to allocate that returned the given name
 	void release(U32 name, volatile U8* buffer, U32 size);
 	
+	//batch allocate buffers to be provided to the application on demand
+	void seedPool();
+
 	//destroy all records in mFreeList
 	void cleanup();
 
+	U32 genBuffer();
+	void deleteBuffer(U32 name);
+
 	class Record
 	{
 	public:
@@ -81,17 +86,15 @@ class LLVBOPool
 		volatile U8* mClientData;
 	};
 
+	std::list<U32> mGLNamePool;
+
 	typedef std::list<Record> record_list_t;
 	std::vector<record_list_t> mFreeList;
-};
+	std::vector<U32> mMissCount;
 
-class LLGLFence
-{
-public:
-	virtual void placeFence() = 0;
-	virtual void wait() = 0;
 };
 
+
 //============================================================================
 // base class 
 class LLPrivateMemoryPool;
@@ -125,13 +128,22 @@ class LLVertexBuffer : public LLRefCount
 	static LLVBOPool sStreamIBOPool;
 	static LLVBOPool sDynamicIBOPool;
 
+	static std::list<U32> sAvailableVAOName;
+	static U32 sCurVAOName;
+
 	static bool	sUseStreamDraw;
 	static bool sUseVAO;
 	static bool	sPreferStreamDraw;
 
+	static void seedPools();
+
+	static U32 getVAOName();
+	static void releaseVAOName(U32 name);
+
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
 	static void setupClientArrays(U32 data_mask);
+	static void pushPositions(U32 mode, const LLVector4a* pos, U32 count);
 	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
 	static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp);
 
@@ -208,7 +220,6 @@ class LLVertexBuffer : public LLRefCount
 	void 	destroyGLIndices();
 	void	updateNumVerts(S32 nverts);
 	void	updateNumIndices(S32 nindices); 
-	bool	useVBOs() const;
 	void	unmapBuffer();
 		
 public:
@@ -218,6 +229,8 @@ class LLVertexBuffer : public LLRefCount
 	volatile U8*		mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range);
 	volatile U8*		mapIndexBuffer(S32 index, S32 count, bool map_range);
 
+	void bindForFeedback(U32 channel, U32 type, U32 index, U32 count);
+
 	// set for rendering
 	virtual void	setBuffer(U32 data_mask); 	// calls  setupVertexBuffer() if data_mask is not 0
 	void flush(); //flush pending data to GL memory
@@ -240,12 +253,14 @@ class LLVertexBuffer : public LLRefCount
 	bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+	bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getWeightStrider(LLStrider<F32>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	
 
+	bool useVBOs() const;
 	bool isEmpty() const					{ return mEmpty; }
 	bool isLocked() const					{ return mVertexLocked || mIndexLocked; }
 	S32 getNumVerts() const					{ return mNumVerts; }
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index 7aeeae298f754407abcf026372b21c6d6935ba8b..104481cbfc72aecc181bb98542950d32b8e362ca 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -280,12 +280,23 @@ bool LLTextBase::truncate()
 	if (getLength() >= S32(mMaxTextByteLength / 4))
 	{	
 		// Have to check actual byte size
-		LLWString text(getWText());
-		S32 utf8_byte_size = wstring_utf8_length(text);
+		S32 utf8_byte_size = 0;
+		LLSD value = getViewModel()->getValue();
+		if (value.type() == LLSD::TypeString)
+		{
+			// save a copy for strings.
+			utf8_byte_size = value.size();
+		}
+		else
+		{
+			// non string LLSDs need explicit conversion to string
+			utf8_byte_size = value.asString().size();
+		}
+
 		if ( utf8_byte_size > mMaxTextByteLength )
 		{
 			// Truncate safely in UTF-8
-			std::string temp_utf8_text = wstring_to_utf8str(text);
+			std::string temp_utf8_text = value.asString();
 			temp_utf8_text = utf8str_truncate( temp_utf8_text, mMaxTextByteLength );
 			LLWString text = utf8str_to_wstring( temp_utf8_text );
 			// remove extra bit of current string, to preserve formatting, etc.
@@ -592,8 +603,7 @@ void LLTextBase::drawText()
 
 S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::segment_vec_t* segments )
 {
-	LLWString text(getWText());
-	S32 old_len = text.length();		// length() returns character length
+	S32 old_len = getLength();		// length() returns character length
 	S32 insert_len = wstr.length();
 
 	pos = getEditableIndex(pos, true);
@@ -653,8 +663,7 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
 		}
 	}
 
-	text.insert(pos, wstr);
-	getViewModel()->setDisplay(text);
+	getViewModel()->getEditableDisplay().insert(pos, wstr);
 
 	if ( truncate() )
 	{
@@ -669,7 +678,6 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
 
 S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
 {
-	LLWString text(getWText());
 	segment_set_t::iterator seg_iter = getSegIterContaining(pos);
 	while(seg_iter != mSegments.end())
 	{
@@ -715,8 +723,7 @@ S32 LLTextBase::removeStringNoUndo(S32 pos, S32 length)
 		++seg_iter;
 	}
 
-	text.erase(pos, length);
-	getViewModel()->setDisplay(text);
+	getViewModel()->getEditableDisplay().erase(pos, length);
 
 	// recreate default segment in case we erased everything
 	createDefaultSegment();
@@ -733,9 +740,7 @@ S32 LLTextBase::overwriteCharNoUndo(S32 pos, llwchar wc)
 	{
 		return 0;
 	}
-	LLWString text(getWText());
-	text[pos] = wc;
-	getViewModel()->setDisplay(text);
+	getViewModel()->getEditableDisplay()[pos] = wc;
 
 	onValueChange(pos, pos + 1);
 	needsReflow(pos);
@@ -1685,6 +1690,8 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name)
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_PARSE_HTML("Parse HTML");
+
 void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params)
 {
 	LLStyle::Params style_params(input_params);
@@ -1693,6 +1700,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
 	S32 part = (S32)LLTextParser::WHOLE;
 	if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358).
 	{
+		LLFastTimer _(FTM_PARSE_HTML);
 		S32 start=0,end=0;
 		LLUrlMatch match;
 		std::string text = new_text;
@@ -1760,8 +1768,11 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_APPEND_TEXT("Append Text");
+
 void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params)
 {
+	LLFastTimer _(FTM_APPEND_TEXT);
 	if (new_text.empty()) 
 		return;
 
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index 6a905b7ec0e952f5775a863c0aaad73472b9ab12..11cfa1d2632cf5223f2308d02050b3211b62a16f 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -150,7 +150,7 @@ S32 LLTextBox::getTextPixelHeight()
 
 LLSD LLTextBox::getValue() const
 {
-	return LLSD(getText());
+	return getViewModel()->getValue();
 }
 
 BOOL LLTextBox::setTextArg( const std::string& key, const LLStringExplicit& text )
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index b5e27616b72c74261820f8bae9078e44fe8bd24d..87bf518aa17ca6c46b891627f344bc57eb9b7f7f 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -831,7 +831,11 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL
 
 	gGL.flush();
 	glLineWidth(2.5f);
-	glLineStipple(2, 0x3333 << shift);
+
+	if (!LLGLSLShader::sNoFixedFunction)
+	{
+		glLineStipple(2, 0x3333 << shift);
+	}
 
 	gGL.begin(LLRender::LINES);
 	{
diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h
index 763af5d8a2caacf26ec3cafc650d255885510b22..ef2e3147992801c9d60fc2bf301983df28797201 100644
--- a/indra/llui/llviewmodel.h
+++ b/indra/llui/llviewmodel.h
@@ -102,6 +102,7 @@ class LLTextViewModel: public LLViewModel
 	// New functions
     /// Get the stored value in string form
     const LLWString& getDisplay() const { return mDisplay; }
+	LLWString& getEditableDisplay() { mDirty = true; mUpdateFromDisplay = true; return mDisplay; }
 
     /**
      * Set the display string directly (see LLTextEditor). What the user is
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index e07fbddb944536c073a4848e6f4e294070992f3e..6f0d90be06765fa03801977592efdbddc86a8793 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -367,6 +367,10 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 U32 fsaa_samples)
 	: LLWindow(callbacks, fullscreen, flags)
 {
+	
+	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways 
+	LoadLibrary(L"opengl32.dll");
+
 	mFSAASamples = fsaa_samples;
 	mIconResource = gIconResource;
 	mOverrideAspectRatio = 0.f;
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index c9b4de014097f001ba1bf2e16f1312d3469a120c..1928e5369952451fa0cd7ac8d3f6732cd0afc921 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -148,7 +148,7 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>ApplyTextureImmediately</key>
+    <key>TextureLivePreview</key>
     <map>
       <key>Comment</key>
       <string>Preview selections in texture picker immediately</string>
@@ -7274,7 +7274,7 @@
     <key>WebContentWindowLimit</key>
     <map>
       <key>Comment</key>
-      <string>Maximum number of web brower windows that can be open at once in the Web content floater (0 for no limit)</string>
+      <string>Maximum number of web browser windows that can be open at once in the Web content floater (0 for no limit)</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -8093,6 +8093,18 @@
     <real>0</real>
   </map>
 
+  <key>RenderDepthPrePass</key>
+  <map>
+    <key>Comment</key>
+    <string>EXPERIMENTAL: Prime the depth buffer with simple prim geometry before rendering with textures.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  
   <key>RenderDepthOfField</key>
   <map>
     <key>Comment</key>
@@ -9172,7 +9184,7 @@
     <key>RenderUseVAO</key>
     <map>
       <key>Comment</key>
-      <string>Use GL Vertex Array Objects</string>
+      <string>[EXPERIMENTAL] Use GL Vertex Array Objects</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -9180,7 +9192,19 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>RenderVBOMappingDisable</key>
+  <key>RenderUseTransformFeedback</key>
+  <map>
+    <key>Comment</key>
+    <string>[EXPERIMENTAL] Use transform feedback shaders for LoD updates</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>
       <string>Disable VBO glMapBufferARB</string>
@@ -12227,6 +12251,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+  <key>RenderSynchronousOcclusion</key>
+  <map>
+    <key>Comment</key>
+    <string>Don't let occlusion queries get more than one frame behind (block until they complete).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
     <key>RenderDelayVBUpdate</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl
index cb87b754b429e06c52c5999ece6570be92bd7950..1113a9845b275ca01562a597b60167b2c180f848 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedNoColorF.glsl
@@ -31,6 +31,8 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
+uniform float minimum_alpha;
+
 uniform sampler2DRect depthMap;
 uniform sampler2D diffuseMap;
 
@@ -70,9 +72,15 @@ void main()
 	
 	vec4 diff= texture2D(diffuseMap,vary_texcoord0.xy);
 
+	if (diff.a < minimum_alpha)
+	{
+		discard;
+	}
+
 	vec4 col = vec4(vary_ambient + vary_directional.rgb, 1.0);
 	vec4 color = diff * col;
 	
+	
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
index 75de47614cfadb6547351436aacab2e917a56609..bff87cb6aac7499a1ae030a8b6fac365c9ee19e2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
@@ -55,8 +55,6 @@ uniform float far_clip;
 
 uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
 uniform float sun_wash;
-uniform int proj_shadow_idx;
-uniform float shadow_fade;
 
 uniform vec3 center;
 uniform vec3 color;
@@ -143,7 +141,8 @@ void main()
 		discard;
 	}
 		
-	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0, norm.z);
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index 19800a8b8e16be7369e3c23376124c79dd45c2b2..f671d5b750e3123895d09710f4e6262a105036d6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -42,12 +42,13 @@ uniform sampler2DRect depthMap;
 uniform vec3 env_mat[3];
 uniform float sun_wash;
 
-uniform vec3 center;
 uniform vec3 color;
 uniform float falloff;
 uniform float size;
 
 VARYING vec4 vary_fragcoord;
+VARYING vec3 trans_center;
+
 uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
@@ -74,7 +75,7 @@ void main()
 	frag.xy *= screen_res;
 	
 	vec3 pos = getPosition(frag.xy).xyz;
-	vec3 lv = center.xyz-pos;
+	vec3 lv = trans_center.xyz-pos;
 	float dist2 = dot(lv,lv);
 	dist2 /= size;
 	if (dist2 > 1.0)
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
index cb14e6d4e8b164235c9c53ecbb72081ea167b1fd..9491421236d49d0ad05f8220274498c75809a54e 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
@@ -24,16 +24,22 @@
  */
 
 uniform mat4 modelview_projection_matrix;
+uniform mat4 modelview_matrix;
 
 ATTRIBUTE vec3 position;
 
+uniform vec3 center;
+uniform float size;
+
 VARYING vec4 vary_fragcoord;
+VARYING vec3 trans_center;
 
 void main()
 {
 	//transform vertex
-	vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0);
+	vec3 p = position*sqrt(size)+center;
+	vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0);
 	vary_fragcoord = pos;
-		
+	trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz;
 	gl_Position = pos;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..6195e2f1ecb30ff4d115595edae972e96f673184
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
@@ -0,0 +1,44 @@
+/** 
+ * @file shadowCubeV.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+
+VARYING vec4 post_pos;
+
+uniform vec3 box_center;
+uniform vec3 box_size;
+
+void main()
+{
+	//transform vertex
+	vec3 p = position*box_size+box_center;
+	vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0);
+	
+	post_pos = pos;
+	
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
index 7ed8ed33701ed891d78ca2a7edd16d2e400d1c23..cca63872de2142faa13bce99ad2b4e703e1a73bc 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -24,18 +24,21 @@
  */
 
  
-#extension GL_ARB_texture_rectangle : enable
-
 #ifdef DEFINE_GL_FRAGCOLOR
 out vec4 frag_color;
 #else
 #define frag_color gl_FragColor
 #endif
 
+//class 1 -- no shadows
+
+#extension GL_ARB_texture_rectangle : enable
+
 uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
 uniform sampler2DRect depthMap;
 uniform sampler2DRect normalMap;
+uniform samplerCube environmentMap;
 uniform sampler2D noiseMap;
 uniform sampler2D projectionMap;
 
@@ -46,6 +49,7 @@ uniform vec3 proj_n;
 uniform float proj_focus; //distance from plane to begin blurring
 uniform float proj_lod;  //(number of mips in proj map)
 uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
 uniform float proj_ambiance;
 uniform float near_clip;
 uniform float far_clip;
@@ -53,19 +57,66 @@ uniform float far_clip;
 uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
 uniform float sun_wash;
 
-uniform vec3 center;
 uniform vec3 color;
 uniform float falloff;
 uniform float size;
 
 VARYING vec4 vary_fragcoord;
+VARYING vec3 trans_center;
+
 uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
@@ -84,16 +135,16 @@ void main()
 	frag.xy *= screen_res;
 	
 	vec3 pos = getPosition(frag.xy).xyz;
-	vec3 lv = center.xyz-pos.xyz;
+	vec3 lv = trans_center.xyz-pos.xyz;
 	float dist2 = dot(lv,lv);
 	dist2 /= size;
 	if (dist2 > 1.0)
 	{
 		discard;
 	}
-	
+		
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+	norm = vec3((norm.xy-0.5)*2.0, norm.z);
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -107,7 +158,11 @@ void main()
 	proj_tc.xyz /= proj_tc.w;
 	
 	float fa = falloff+1.0;
-	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	if (dist_atten <= 0.0)
+	{
+		discard;
+	}
 	
 	lv = proj_origin-pos.xyz;
 	lv = normalize(lv);
@@ -125,32 +180,32 @@ void main()
 		proj_tc.y > 0.0)
 	{
 		float lit = 0.0;
+		float amb_da = proj_ambiance;
+		
 		if (da > 0.0)
 		{
 			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
 			float lod = diff * proj_lod;
 			
-			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
 		
 			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
 			
 			lit = da * dist_atten * noise;
 			
 			col = lcol*lit*diff_tex;
+			amb_da += (da*0.5)*proj_ambiance;
 		}
 		
-		float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
-		float lod = diff * proj_lod;
-		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
-		//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
-		float amb_da = proj_ambiance;
-		
+		//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+		vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
+							
 		amb_da += (da*da*0.5+0.5)*proj_ambiance;
-			
+				
 		amb_da *= dist_atten * noise;
-		
+			
 		amb_da = min(amb_da, 1.0-lit);
-		
+			
 		col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
 	}
 	
@@ -168,18 +223,22 @@ void main()
 		{
 			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
 			
-			vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
+			vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
 
 			if (stc.z > 0.0)
 			{
-				stc.xy /= stc.z+proj_near;
-					
+				stc.xy /= stc.w;
+
+				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+				stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
 				if (stc.x < 1.0 &&
 					stc.y < 1.0 &&
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
 					col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb;
 				}
 			}
diff --git a/indra/newview/app_settings/shaders/class1/interface/clipF.glsl b/indra/newview/app_settings/shaders/class1/interface/clipF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..ac2bc8703b9530cf6804c18d4bc705e8425fab80
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/clipF.glsl
@@ -0,0 +1,46 @@
+/** 
+ * @file debugF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform vec4 color;
+uniform vec4 clip_plane;
+
+VARYING vec3 vary_position;
+
+
+void main() 
+{
+	if (dot(vary_position,clip_plane.xyz)+clip_plane.w < 0.0)
+	{
+		discard;
+	}
+
+	frag_color = color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/clipV.glsl b/indra/newview/app_settings/shaders/class1/interface/clipV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..e376b25a71fe27e9391a1551b60d94039ca98786
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/clipV.glsl
@@ -0,0 +1,38 @@
+/** 
+ * @file debugV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 modelview_projection_matrix;
+uniform mat4 modelview_matrix;
+
+ATTRIBUTE vec3 position;
+
+VARYING vec3 vary_position;
+
+void main()
+{
+	vary_position = (modelview_matrix*vec4(position.xyz,1.0)).xyz;
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl b/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..5c479d27a91cbb7f74e04686d500919cfe7dd775
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/occlusionCubeV.glsl
@@ -0,0 +1,38 @@
+/** 
+ * @file occlusionCubeV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+
+uniform vec3 box_center;
+uniform vec3 box_size;
+
+void main()
+{
+	vec3 p = position*box_size+box_center;
+	gl_Position = modelview_projection_matrix * vec4(p.xyz, 1.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..44f1aa34a0313f0451b26df3c6a78afd8dbb2364
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl
@@ -0,0 +1,36 @@
+/**
+ * @file binormalV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat3 normal_matrix;
+
+ATTRIBUTE vec3 binormal;
+
+VARYING vec4 binormal_out;
+
+void main()
+{
+	binormal_out = vec4(normal_matrix * binormal, 0.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/transform/colorV.glsl b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..59c4a7d8958435eb1a1ddeabac33e45b8bcc2b19
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/transform/colorV.glsl
@@ -0,0 +1,36 @@
+/**
+ * @file colorV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform int color_in;
+
+ATTRIBUTE vec3 position;
+
+VARYING int color_out;
+
+void main()
+{
+	color_out = color_in;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/transform/normalV.glsl b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..a213aa0ae8500604e5c961ca411337d2d9956dc2
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/transform/normalV.glsl
@@ -0,0 +1,36 @@
+/**
+ * @file normalV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat3 normal_matrix;
+
+ATTRIBUTE vec3 normal;
+
+VARYING vec4 normal_out;
+
+void main()
+{
+	normal_out = vec4(normalize(normal_matrix * normal), 0.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/transform/positionV.glsl b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..01eed18de431e81be84eb44a1cc0d4e13cccce6c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/transform/positionV.glsl
@@ -0,0 +1,40 @@
+/**
+ * @file positionV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+uniform mat4 modelview_matrix;
+
+uniform int texture_index_in;
+
+ATTRIBUTE vec3 position;
+
+VARYING vec3 position_out;
+VARYING int texture_index_out;
+
+void main()
+{
+	texture_index_out = texture_index_in;
+	position_out = (modelview_matrix*vec4(position, 1.0)).xyz;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..0e074f3cec6b33139b39419b6e213603a6925bd0
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/transform/texcoordV.glsl
@@ -0,0 +1,35 @@
+/**
+ * @file texcoordV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec2 texcoord_out;
+
+void main()
+{
+	texcoord_out = texcoord0;
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl
index ba6f3ace53f175bf91c683281f11208da5a60b6f..2093fc37dc3330a24b9971ce0718805de407444c 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl
@@ -31,6 +31,8 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
+uniform float minimum_alpha;
+
 uniform sampler2DRectShadow shadowMap0;
 uniform sampler2DRectShadow shadowMap1;
 uniform sampler2DRectShadow shadowMap2;
@@ -97,6 +99,13 @@ void main()
 	float shadow = 0.0;
 	vec4 pos = vec4(vary_position, 1.0);
 	
+	vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
+
+	if (diff.a < minimum_alpha)
+	{
+		discard;
+	}
+	
 	vec4 spos = pos;
 		
 	if (spos.z > -shadow_clip.w)
@@ -164,8 +173,6 @@ void main()
 		shadow = 1.0;
 	}
 	
-	vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
-
 	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, 1.0);
 	vec4 color = diff * col;
 	
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
index 99a277fbfcced0456bafad4b1af369a961c4eb11..ab077d9e026a50751235a098e08fb8d4116c1c09 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -31,8 +31,6 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
-VARYING vec4 vertex_color;
-
 uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
 uniform sampler2DRect depthMap;
@@ -49,6 +47,7 @@ uniform vec3 proj_n;
 uniform float proj_focus; //distance from plane to begin blurring
 uniform float proj_lod;  //(number of mips in proj map)
 uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
 uniform float proj_ambiance;
 uniform float near_clip;
 uniform float far_clip;
@@ -58,16 +57,65 @@ uniform float sun_wash;
 uniform int proj_shadow_idx;
 uniform float shadow_fade;
 
-VARYING vec4 vary_light;
+uniform float size;
+uniform vec3 color;
+uniform float falloff;
 
+VARYING vec3 trans_center;
 VARYING vec4 vary_fragcoord;
 uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
@@ -85,6 +133,15 @@ void main()
 	frag.xyz = frag.xyz*0.5+0.5;
 	frag.xy *= screen_res;
 	
+	vec3 pos = getPosition(frag.xy).xyz;
+	vec3 lv = trans_center.xyz-pos.xyz;
+	float dist2 = dot(lv,lv);
+	dist2 /= size;
+	if (dist2 > 1.0)
+	{
+		discard;
+	}
+	
 	float shadow = 1.0;
 	
 	if (proj_shadow_idx >= 0)
@@ -96,15 +153,6 @@ void main()
 		shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0);
 	}
 	
-	vec3 pos = getPosition(frag.xy).xyz;
-	vec3 lv = vary_light.xyz-pos.xyz;
-	float dist2 = dot(lv,lv);
-	dist2 /= vary_light.w;
-	if (dist2 > 1.0)
-	{
-		discard;
-	}
-	
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
 	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	
@@ -119,8 +167,12 @@ void main()
 	
 	proj_tc.xyz /= proj_tc.w;
 	
-	float fa = vertex_color.a+1.0;
-	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+	float fa = falloff+1.0;
+	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	if (dist_atten <= 0.0)
+	{
+		discard;
+	}
 	
 	lv = proj_origin-pos.xyz;
 	lv = normalize(lv);
@@ -138,37 +190,33 @@ void main()
 		proj_tc.y > 0.0)
 	{
 		float lit = 0.0;
+		float amb_da = proj_ambiance;
+		
 		if (da > 0.0)
 		{
 			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
 			float lod = diff * proj_lod;
 			
-			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
 		
-			vec3 lcol = vertex_color.rgb * plcol.rgb * plcol.a;
+			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
 			
 			lit = da * dist_atten * noise;
 			
 			col = lcol*lit*diff_tex*shadow;
-		}
-		
-		float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
-		float lod = diff * proj_lod;
-		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
-		//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
-		float amb_da = proj_ambiance;
-		if (da > 0.0)
-		{
 			amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
 		}
 		
+		//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+		vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
+							
 		amb_da += (da*da*0.5+0.5)*proj_ambiance;
-			
+				
 		amb_da *= dist_atten * noise;
-		
+			
 		amb_da = min(amb_da, 1.0-lit);
-		
-		col += amb_da*vertex_color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+			
+		col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
 	}
 	
 	
@@ -185,19 +233,23 @@ void main()
 		{
 			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
 			
-			vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
+			vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
 
 			if (stc.z > 0.0)
 			{
-				stc.xy /= stc.z+proj_near;
-					
+				stc.xy /= stc.w;
+
+				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+				stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
 				if (stc.x < 1.0 &&
 					stc.y < 1.0 &&
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
-					col += dist_atten*scol.rgb*vertex_color.rgb*scol.a*spec.rgb*shadow;
+					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow;
 				}
 			}
 		}
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index e8a109e66150961b43419ab017527faf7ca0d363..eeb632acaf2f590fdf0b84fed0fd0b2e7f6f2bba 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -520,6 +520,7 @@ Disregard128DefaultDrawDistance	1	0
 list ATIOldDriver
 RenderAvatarVP				0	0
 RenderAvatarCloth			0	0
+RenderVBOEnable				1	0
 
 // ATI cards generally perform better when not using VBOs for streaming data
 
diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt
index 398a64378e0d6969dd0838fd95ff5ff3d1ea0899..a945f7a6938d7938b861bc82d4fed78c969f6deb 100644
--- a/indra/newview/featuretable_xp.txt
+++ b/indra/newview/featuretable_xp.txt
@@ -517,6 +517,7 @@ Disregard128DefaultDrawDistance	1	0
 list ATIOldDriver
 RenderAvatarVP				0	0
 RenderAvatarCloth			0	0
+RenderVBOEnable				1	0
 
 // ATI cards generally perform better when not using VBOs for streaming data
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index ed04b5bf383bf5bbbc640dd539c39da912f70e9c..062551a3e88024f5680e696660607a19fac73e39 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -89,6 +89,7 @@
 #include "lllogininstance.h"
 #include "llprogressview.h"
 #include "llvocache.h"
+#include "llvopartgroup.h"
 #include "llweb.h"
 #include "llsecondlifeurls.h"
 #include "llupdaterservice.h"
@@ -675,6 +676,9 @@ bool LLAppViewer::init()
 	// initialize SSE options
 	LLVector4a::initClass();
 
+	//initialize particle index pool
+	LLVOPartGroup::initClass();
+
 	// Need to do this initialization before we do anything else, since anything
 	// that touches files should really go through the lldir API
 	gDirUtilp->initAppDirs("SecondLife");
@@ -1162,6 +1166,8 @@ void LLAppViewer::checkMemory()
 
 static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
 static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep");
+static LLFastTimer::DeclareTimer FTM_YIELD("Yield");
+
 static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache");
 static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode");
 static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread");
@@ -1347,6 +1353,7 @@ bool LLAppViewer::mainLoop()
 				// yield some time to the os based on command line option
 				if(mYieldTime >= 0)
 				{
+					LLFastTimer t(FTM_YIELD);
 					ms_sleep(mYieldTime);
 				}
 
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index f530d10ddc525aec066d78a1550f9824035d2940..84e73e96fa01213c6405d11859c31f4d5deada34 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -495,7 +495,7 @@ class LLChatHistoryHeader: public LLPanel
 
 	void showInfoCtrl()
 	{
-		if (mAvatarID.isNull() || mFrom.empty() || SYSTEM_FROM == mFrom) return;
+		if (mAvatarID.isNull() || mFrom.empty() || CHAT_SOURCE_SYSTEM == mSourceType) return;
 				
 		if (!sInfoCtrl)
 		{
@@ -689,8 +689,11 @@ void LLChatHistory::clear()
 	mLastFromID = LLUUID::null;
 }
 
+static LLFastTimer::DeclareTimer FTM_APPEND_MESSAGE("Append Chat Message");
+
 void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LLStyle::Params& input_append_params)
 {
+	LLFastTimer _(FTM_APPEND_MESSAGE);
 	bool use_plain_text_chat_history = args["use_plain_text_chat_history"].asBoolean();
 
 	llassert(mEditor);
@@ -783,7 +786,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 			timestamp_style.color(timestamp_color);
 			timestamp_style.readonly_color(timestamp_color);
 		}
-		mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getText().size() != 0, timestamp_style);
+		mEditor->appendText("[" + chat.mTimeStr + "] ", mEditor->getLength() != 0, timestamp_style);
 
 		if (utf8str_trim(chat.mFromName).size() != 0)
 		{
@@ -842,7 +845,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
 		else
 		{
 			view = getHeader(chat, style_params, args);
-			if (mEditor->getText().size() == 0)
+			if (mEditor->getLength() == 0)
 				p.top_pad = 0;
 			else
 				p.top_pad = mTopHeaderPad;
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 21b21c152a6b981f929e21784da6c36b0db839a3..563b9b9cabd99fffc8be960861df1fd6b9ca15b8 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -57,6 +57,8 @@ const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f;
 
 static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound");
 
+extern bool gShiftFrame;
+
 
 ////////////////////////
 //
@@ -108,6 +110,8 @@ void LLDrawable::init()
 	
 	mGeneration = -1;
 	mBinRadius = 1.f;
+	mBinIndex = -1;
+
 	mSpatialBridge = NULL;
 }
 
@@ -450,7 +454,7 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
 {
 	if (isState(ACTIVE))
 	{
-		clearState(ACTIVE);
+		clearState(ACTIVE | ANIMATED_CHILD);
 
 		if (mParent.notNull() && mParent->isActive() && warning_enabled)
 		{
@@ -538,9 +542,9 @@ F32 LLDrawable::updateXform(BOOL undamped)
 			target_rot = new_rot;
 			target_scale = new_scale;
 		}
-		else
+		else if (mVObjp->getAngularVelocity().isExactlyZero())
 		{
-			// snap to final position
+			// snap to final position (only if no target omega is applied)
 			dist_squared = 0.0f;
 			if (getVOVolume() && !isRoot())
 			{ //child prim snapping to some position, needs a rebuild
@@ -549,15 +553,25 @@ F32 LLDrawable::updateXform(BOOL undamped)
 		}
 	}
 
-	if ((mCurrentScale != target_scale) ||
-		(!isRoot() && 
-		 (dist_squared >= MIN_INTERPOLATE_DISTANCE_SQUARED || 
-		 !mVObjp->getAngularVelocity().isExactlyZero() ||
-		 target_pos != mXform.getPosition() ||
-		 target_rot != mXform.getRotation())))
-	{ //child prim moving or scale change requires immediate rebuild
+	LLVector3 vec = mCurrentScale-target_scale;
+	
+	if (vec*vec > MIN_INTERPOLATE_DISTANCE_SQUARED)
+	{ //scale change requires immediate rebuild
+		mCurrentScale = target_scale;
 		gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
 	}
+	else if (!isRoot() && 
+		 (!mVObjp->getAngularVelocity().isExactlyZero() ||
+			dist_squared > 0.f))
+	{ //child prim moving relative to parent, tag as needing to be rendered atomically and rebuild
+		dist_squared = 1.f; //keep this object on the move list
+		if (!isState(LLDrawable::ANIMATED_CHILD))
+		{			
+			setState(LLDrawable::ANIMATED_CHILD);
+			gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE);
+			mVObjp->dirtySpatialGroup();
+		}
+	}
 	else if (!getVOVolume() && !isAvatar())
 	{
 		movePartition();
@@ -568,9 +582,7 @@ F32 LLDrawable::updateXform(BOOL undamped)
 	mXform.setRotation(target_rot);
 	mXform.setScale(LLVector3(1,1,1)); //no scale in drawable transforms (IT'S A RULE!)
 	mXform.updateMatrix();
-	
-	mCurrentScale = target_scale;
-	
+
 	if (mSpatialBridge)
 	{
 		gPipeline.markMoved(mSpatialBridge, FALSE);
@@ -596,7 +608,11 @@ void LLDrawable::moveUpdatePipeline(BOOL moved)
 	// Update the face centers.
 	for (S32 i = 0; i < getNumFaces(); i++)
 	{
-		getFace(i)->updateCenterAgent();
+		LLFace* face = getFace(i);
+		if (face)
+		{
+			face->updateCenterAgent();
+		}
 	}
 }
 
@@ -651,7 +667,6 @@ BOOL LLDrawable::updateMoveUndamped()
 	}
 
 	mVObjp->clearChanged(LLXform::MOVED);
-	
 	return TRUE;
 }
 
@@ -703,6 +718,11 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 		return;
 	}
 
+	if (gShiftFrame)
+	{
+		return;
+	}
+
 	//switch LOD with the spatial group to avoid artifacts
 	//LLSpatialGroup* sg = getSpatialGroup();
 
@@ -727,7 +747,8 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 				for (S32 i = 0; i < getNumFaces(); i++)
 				{
 					LLFace* facep = getFace(i);
-					if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)
+					if (facep && 
+						(force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA))
 					{
 						LLVector4a box;
 						box.setSub(facep->mExtents[1], facep->mExtents[0]);
@@ -811,14 +832,19 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector)
 		mXform.setPosition(mVObjp->getPositionAgent());
 	}
 
-	mXform.setRotation(mVObjp->getRotation());
-	mXform.setScale(1,1,1);
 	mXform.updateMatrix();
 
 	if (isStatic())
 	{
 		LLVOVolume* volume = getVOVolume();
-		if (!volume)
+
+		bool rebuild = (!volume && 
+						getRenderType() != LLPipeline::RENDER_TYPE_TREE &&
+						getRenderType() != LLPipeline::RENDER_TYPE_TERRAIN &&
+						getRenderType() != LLPipeline::RENDER_TYPE_SKY &&
+						getRenderType() != LLPipeline::RENDER_TYPE_GROUND);
+
+		if (rebuild)
 		{
 			gPipeline.markRebuild(this, LLDrawable::REBUILD_ALL, TRUE);
 		}
@@ -826,13 +852,16 @@ void LLDrawable::shiftPos(const LLVector4a &shift_vector)
 		for (S32 i = 0; i < getNumFaces(); i++)
 		{
 			LLFace *facep = getFace(i);
-			facep->mCenterAgent += LLVector3(shift_vector.getF32ptr());
-			facep->mExtents[0].add(shift_vector);
-			facep->mExtents[1].add(shift_vector);
-			
-			if (!volume && facep->hasGeometry())
+			if (facep)
 			{
-				facep->clearVertexBuffer();
+				facep->mCenterAgent += LLVector3(shift_vector.getF32ptr());
+				facep->mExtents[0].add(shift_vector);
+				facep->mExtents[1].add(shift_vector);
+			
+				if (rebuild && facep->hasGeometry())
+				{
+					facep->clearVertexBuffer();
+				}
 			}
 		}
 		
@@ -940,6 +969,12 @@ void LLDrawable::updateUVMinMax()
 {
 }
 
+LLSpatialGroup* LLDrawable::getSpatialGroup() const
+{ 
+	llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1);
+	return mSpatialGroupp; 
+}
+
 void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
 {
 /*if (mSpatialGroupp && (groupp != mSpatialGroupp))
@@ -954,11 +989,16 @@ void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
 		for (S32 i = 0; i < getNumFaces(); ++i)
 		{
 			LLFace* facep = getFace(i);
-			facep->clearVertexBuffer();
+			if (facep)
+			{
+				facep->clearVertexBuffer();
+			}
 		}
 	}
 
 	mSpatialGroupp = groupp;
+
+	llassert((mSpatialGroupp == NULL) ? getBinIndex() == -1 : getBinIndex() != -1);
 }
 
 LLSpatialPartition* LLDrawable::getSpatialPartition()
@@ -1081,6 +1121,8 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat
 	mDrawable = root;
 	root->setSpatialBridge(this);
 	
+	mBinIndex = -1;
+
 	mRenderType = mDrawable->mRenderType;
 	mDrawableType = mDrawable->mRenderType;
 	
@@ -1384,6 +1426,11 @@ void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update)
 		markDead();
 		return;
 	}
+	
+	if (gShiftFrame)
+	{
+		return;
+	}
 
 	if (mDrawable->getVObj())
 	{
@@ -1462,7 +1509,13 @@ void LLSpatialBridge::cleanupReferences()
 	LLDrawable::cleanupReferences();
 	if (mDrawable)
 	{
-		mDrawable->setSpatialGroup(NULL);
+		LLSpatialGroup* group = mDrawable->getSpatialGroup();
+		if (group)
+		{
+			group->mOctreeNode->remove(mDrawable);
+			mDrawable->setSpatialGroup(NULL);
+		}
+		
 		if (mDrawable->getVObj())
 		{
 			LLViewerObject::const_child_list_t& child_list = mDrawable->getVObj()->getChildren();
@@ -1473,7 +1526,12 @@ void LLSpatialBridge::cleanupReferences()
 				LLDrawable* drawable = child->mDrawable;					
 				if (drawable)
 				{
-					drawable->setSpatialGroup(NULL);
+					LLSpatialGroup* group = drawable->getSpatialGroup();
+					if (group)
+					{
+						group->mOctreeNode->remove(drawable);
+						drawable->setSpatialGroup(NULL);
+					}
 				}
 			}
 		}
@@ -1529,10 +1587,10 @@ BOOL LLDrawable::isAnimating() const
 		return TRUE;
 	}
 
-	if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
-	{
+	/*if (!isRoot() && !mVObjp->getAngularVelocity().isExactlyZero())
+	{ //target omega
 		return TRUE;
-	}
+	}*/
 
 	return FALSE;
 }
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index e268640a21cdf806415bd68bea90e9f719da88df..bc4b301ebb532905d351ffed120dfc3cdba977fd 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -109,6 +109,9 @@ class LLDrawable : public LLRefCount
 	F32			          getIntensity() const			{ return llmin(mXform.getScale().mV[0], 4.f); }
 	S32					  getLOD() const				{ return mVObjp ? mVObjp->getLOD() : 1; }
 	F32					  getBinRadius() const			{ return mBinRadius; }
+	S32					  getBinIndex() const			{ return mBinIndex; }
+	void				  setBinIndex(S32 index) const	{ mBinIndex = index; }
+
 	void  getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); }
 	LLXformMatrix*		getXform() { return &mXform; }
 
@@ -194,7 +197,7 @@ class LLDrawable : public LLRefCount
 	S32 findReferences(LLDrawable *drawablep); // Not const because of @#$! iterators...
 
 	void setSpatialGroup(LLSpatialGroup *groupp);
-	LLSpatialGroup *getSpatialGroup() const			{ return mSpatialGroupp; }
+	LLSpatialGroup *getSpatialGroup() const;
 	LLSpatialPartition* getSpatialPartition();
 	
 	// Statics
@@ -277,6 +280,7 @@ class LLDrawable : public LLRefCount
 		HAS_ALPHA		= 0x04000000,
 		RIGGED			= 0x08000000,
 		PARTITION_MOVE	= 0x10000000,
+		ANIMATED_CHILD  = 0x20000000,
 	} EDrawableFlags;
 
 private: //aligned members
@@ -314,6 +318,7 @@ class LLDrawable : public LLRefCount
 	mutable U32		mVisible;
 	F32				mRadius;
 	F32				mBinRadius;
+	mutable S32		mBinIndex;
 	S32				mGeneration;
 	
 	LLVector3		mCurrentScale;
@@ -333,12 +338,14 @@ inline LLFace* LLDrawable::getFace(const S32 i) const
 
 	if ((U32) i >= mFaces.size())
 	{
-		llerrs << "Invalid face index." << llendl;
+		llwarns << "Invalid face index." << llendl;
+		return NULL;
 	}
 
 	if (!mFaces[i])
 	{
-		llerrs << "Null face found." << llendl;
+		llwarns << "Null face found." << llendl;
+		return NULL;
 	}
 	
 	return mFaces[i];
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 35f8a8579671ef3ac9ccaed54c22323a7d6dc032..6c0be0a5c29142eba9e05a6e59e7a4efb6c929e4 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -253,48 +253,6 @@ void LLFacePool::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures
 {
 }
 
-// static
-S32 LLFacePool::drawLoop(face_array_t& face_list)
-{
-	S32 res = 0;
-	if (!face_list.empty())
-	{
-		for (std::vector<LLFace*>::iterator iter = face_list.begin();
-			 iter != face_list.end(); iter++)
-		{
-			LLFace *facep = *iter;
-			res += facep->renderIndexed();
-		}
-	}
-	return res;
-}
-
-// static
-S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage)
-{
-	S32 res = 0;
-	if (!face_list.empty())
-	{
-		for (std::vector<LLFace*>::iterator iter = face_list.begin();
-			 iter != face_list.end(); iter++)
-		{
-			LLFace *facep = *iter;
-			gGL.getTexUnit(stage)->bind(facep->getTexture(), TRUE) ;
-			gGL.getTexUnit(0)->activate();
-			res += facep->renderIndexed();
-		}
-	}
-	return res;
-}
-
-void LLFacePool::drawLoop()
-{
-	if (!mDrawFace.empty())
-	{
-		drawLoop(mDrawFace);
-	}
-}
-
 void LLFacePool::enqueue(LLFace* facep)
 {
 	mDrawFace.push_back(facep);
@@ -442,7 +400,7 @@ void LLRenderPass::renderTexture(U32 type, U32 mask)
 
 void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
 {
-	for (LLCullResult::drawinfo_list_t::iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
+	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
 		if (pparams) 
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 64774d06df78ca0a2f86dcafa30d7c8a1ba5c295..e0f2da41d72702d34425ccfd4629d1ccafa0f352 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -186,10 +186,6 @@ class LLFacePool : public LLDrawPool
 
 	void buildEdges();
 
-	static S32 drawLoop(face_array_t& face_list);
-	static S32 drawLoopSetTex(face_array_t& face_list, S32 stage);
-	void drawLoop();
-
 	void addFaceReference(LLFace *facep);
 	void removeFaceReference(LLFace *facep);
 
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 5b62dbc560c197bc558585544f54bda5a00343be..313b310e1e87769b87bedf3de987eee8c60dd53a 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -348,7 +348,7 @@ void LLDrawPoolAlpha::render(S32 pass)
 
 void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 {
-	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
+	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
 		if (group->mSpatialPartition->mRenderByGroup &&
@@ -385,7 +385,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 	
 	BOOL use_shaders = gPipeline.canUseVertexShaders();
 		
-	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
+	for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
 		llassert(group);
@@ -405,6 +405,12 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 			{
 				LLDrawInfo& params = **k;
 
+				if ((params.mVertexBuffer->getTypeMask() & mask) != mask)
+				{ //FIXME!
+					llwarns << "Missing required components, skipping render batch." << llendl;
+					continue;
+				}
+
 				LLRenderPass::applyModelMatrix(params);
 
 				
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 0103373fd21a0432dd4e518a0c48a6ebdbbe3f81..730ad1a364b105484254777ca5c485de35ed930d 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -261,7 +261,9 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha()
 	sRenderingSkinned = TRUE;
 
 	gPipeline.bindDeferredShader(*sVertexProgram);
-	
+
+	sVertexProgram->setMinimumAlpha(0.2f);
+
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 }
 
@@ -1034,9 +1036,13 @@ void LLDrawPoolAvatar::endDeferredSkinned()
 	gGL.getTexUnit(0)->activate();
 }
 
+static LLFastTimer::DeclareTimer FTM_RENDER_AVATARS("renderAvatars");
+
 
 void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 {
+	LLFastTimer t(FTM_RENDER_AVATARS);
+
 	if (pass == -1)
 	{
 		for (S32 i = 1; i < getNumPasses(); i++)
@@ -1193,15 +1199,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 
 	if (pass >= 7 && pass < 9)
 	{
-		LLGLEnable blend(GL_BLEND);
-
-		gGL.setColorMask(true, true);
-		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
-					  LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
-					  LLRender::BF_ZERO,
-					  LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
-
-		
 		if (pass == 7)
 		{
 			renderRiggedAlpha(avatarp);
@@ -1217,20 +1214,8 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 
 	if (pass == 9)
 	{
-		LLGLEnable blend(GL_BLEND);
-		LLGLDisable test(GL_ALPHA_TEST);
-		gGL.flush();
-
-		LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
-		glPolygonOffset(-1.0f, -1.0f);
-		gGL.setSceneBlendType(LLRender::BT_ADD);
-
-		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-		gGL.setColorMask(false, true);
-
 		renderRiggedGlow(avatarp);
-		gGL.setColorMask(true, false);
-		gGL.setSceneBlendType(LLRender::BT_ALPHA);
+		
 		return;
 	}
 	
@@ -1428,7 +1413,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
 
 void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 {
-	if (avatar->isSelf() && !gAgent.needsRenderAvatar() || !gMeshRepo.meshRezEnabled())
+	if (avatar->isSelf() && !gAgent.needsRenderAvatar())
 	{
 		return;
 	}
@@ -1557,8 +1542,12 @@ void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
 	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
 }
 
+static LLFastTimer::DeclareTimer FTM_RIGGED_VBO("Rigged VBO");
+
 void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
 {
+	LLFastTimer t(FTM_RIGGED_VBO);
+
 	//update rigged vertex buffers
 	for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type)
 	{
@@ -1630,17 +1619,56 @@ void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar)
 
 void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
 {
-	renderRigged(avatar, RIGGED_ALPHA);
+	if (!mRiggedFace[RIGGED_ALPHA].empty())
+	{
+		LLGLEnable blend(GL_BLEND);
+
+		gGL.setColorMask(true, true);
+		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
+						LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
+						LLRender::BF_ZERO,
+						LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+
+		renderRigged(avatar, RIGGED_ALPHA);
+	}
 }
 
 void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
 {
-	renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
+	if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty())
+	{
+		LLGLEnable blend(GL_BLEND);
+
+		gGL.setColorMask(true, true);
+		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
+						LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
+						LLRender::BF_ZERO,
+						LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+
+		renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
+	}
 }
 
 void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
 {
-	renderRigged(avatar, RIGGED_GLOW, true);
+	if (!mRiggedFace[RIGGED_GLOW].empty())
+	{
+		LLGLEnable blend(GL_BLEND);
+		LLGLDisable test(GL_ALPHA_TEST);
+		gGL.flush();
+
+		LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
+		glPolygonOffset(-1.0f, -1.0f);
+		gGL.setSceneBlendType(LLRender::BT_ADD);
+
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+		gGL.setColorMask(false, true);
+
+		renderRigged(avatar, RIGGED_GLOW, true);
+
+		gGL.setColorMask(true, false);
+		gGL.setSceneBlendType(LLRender::BT_ALPHA);
+	}
 }
 
 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 6f71e6ebc8a22fc32bddfaa36b894758d95054b4..a264eae30263c14ffd60d04491e92ad7eb909d8e 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -847,12 +847,12 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
 	LLFastTimer ftm(FTM_RENDER_BUMP);
 
 	U32 type = LLRenderPass::PASS_BUMP;
-	LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type);
-	LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type);
+	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
 	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
 	
-	for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i)	
+	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
 	{
 		LLDrawInfo& params = **i;
 
@@ -1448,10 +1448,10 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 
 void LLDrawPoolBump::renderBump(U32 type, U32 mask)
 {	
-	LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type);
-	LLCullResult::drawinfo_list_t::iterator end = gPipeline.endRenderMap(type);
+	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
-	for (LLCullResult::drawinfo_list_t::iterator i = begin; i != end; ++i)	
+	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
 	{
 		LLDrawInfo& params = **i;
 
diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp
index b95d8296fa0b3057fb3edc37e99074deb8ead479..7fc78fb382f08e66334ad8a792998de92a4f0a3d 100644
--- a/indra/newview/lldrawpoolterrain.cpp
+++ b/indra/newview/lldrawpoolterrain.cpp
@@ -294,6 +294,34 @@ void LLDrawPoolTerrain::renderShadow(S32 pass)
 	//glCullFace(GL_BACK);
 }
 
+
+void LLDrawPoolTerrain::drawLoop()
+{
+	if (!mDrawFace.empty())
+	{
+		for (std::vector<LLFace*>::iterator iter = mDrawFace.begin();
+			 iter != mDrawFace.end(); iter++)
+		{
+			LLFace *facep = *iter;
+
+			LLMatrix4* model_matrix = &(facep->getDrawable()->getRegion()->mRenderMatrix);
+
+			if (model_matrix != gGLLastMatrix)
+			{
+				gGLLastMatrix = model_matrix;
+				gGL.loadMatrix(gGLModelView);
+				if (model_matrix)
+				{
+					gGL.multMatrix((GLfloat*) model_matrix->mMatrix);
+				}
+				gPipeline.mMatrixOpCount++;
+			}
+
+			facep->renderIndexed();
+		}
+	}
+}
+
 void LLDrawPoolTerrain::renderFullShader()
 {
 	// Hack! Get the region that this draw pool is rendering from!
diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h
index 283ed87f1ad6b2785d1f424cae442c0546f19d8d..2163d087e16555dd1c0582817a3b10ccdd2a1b9f 100644
--- a/indra/newview/lldrawpoolterrain.h
+++ b/indra/newview/lldrawpoolterrain.h
@@ -83,6 +83,7 @@ class LLDrawPoolTerrain : public LLFacePool
 	void renderFull2TU();
 	void renderFull4TU();
 	void renderFullShader();
+	void drawLoop();
 };
 
 #endif // LL_LLDRAWPOOLSIMPLE_H
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 3165a3516c004669d7cc3b946266b33a604faeee..83f04e45a8f95b02d033d5808fb35945df8f3d99 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -37,6 +37,7 @@
 #include "llviewershadermgr.h"
 #include "llrender.h"
 #include "llviewercontrol.h"
+#include "llviewerregion.h"
 
 S32 LLDrawPoolTree::sDiffTex = 0;
 static LLGLSLShader* shader = NULL;
@@ -104,8 +105,22 @@ void LLDrawPoolTree::render(S32 pass)
 	{
 		LLFace *face = *iter;
 		LLVertexBuffer* buff = face->getVertexBuffer();
+
 		if(buff)
 		{
+			LLMatrix4* model_matrix = &(face->getDrawable()->getRegion()->mRenderMatrix);
+
+			if (model_matrix != gGLLastMatrix)
+			{
+				gGLLastMatrix = model_matrix;
+				gGL.loadMatrix(gGLModelView);
+				if (model_matrix)
+				{
+					gGL.multMatrix((GLfloat*) model_matrix->mMatrix);
+				}
+				gPipeline.mMatrixOpCount++;
+			}
+
 			buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK);
 			buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); 
 			gPipeline.addTrianglesDrawn(buff->getNumIndices());
diff --git a/indra/newview/lldriverparam.cpp b/indra/newview/lldriverparam.cpp
index 64eb11fc9b2e90becc78c29777f0c57fe771180c..885cae1737003f2f489139ca583b2c0251f405fc 100644
--- a/indra/newview/lldriverparam.cpp
+++ b/indra/newview/lldriverparam.cpp
@@ -155,6 +155,7 @@ LLDriverParam::LLDriverParam(LLVOAvatar *avatarp) :
 	mAvatarp(avatarp), 
 	mWearablep(NULL)
 {
+	mDefaultVec.clear();
 }
 
 LLDriverParam::LLDriverParam(LLWearable *wearablep) : 
@@ -162,6 +163,7 @@ LLDriverParam::LLDriverParam(LLWearable *wearablep) :
 	mAvatarp(NULL), 
 	mWearablep(wearablep)
 {
+	mDefaultVec.clear();
 }
 
 LLDriverParam::~LLDriverParam()
@@ -341,18 +343,19 @@ F32	LLDriverParam::getTotalDistortion()
 	return sum; 
 }
 
-const LLVector3	&LLDriverParam::getAvgDistortion()	
+const LLVector4a	&LLDriverParam::getAvgDistortion()	
 {
 	// It's not actually correct to take the average of averages, but it good enough here.
-	LLVector3 sum;
+	LLVector4a sum;
+	sum.clear();
 	S32 count = 0;
 	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
 	{
 		LLDrivenEntry* driven = &(*iter);
-		sum += driven->mParam->getAvgDistortion();
+		sum.add(driven->mParam->getAvgDistortion());
 		count++;
 	}
-	sum /= (F32)count;
+	sum.mul( 1.f/(F32)count);
 
 	mDefaultVec = sum;
 	return mDefaultVec; 
@@ -375,21 +378,22 @@ F32	LLDriverParam::getMaxDistortion()
 }
 
 
-LLVector3	LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
+LLVector4a	LLDriverParam::getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)
 {
-	LLVector3 sum;
+	LLVector4a sum;
+	sum.clear();
 	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
 	{
 		LLDrivenEntry* driven = &(*iter);
-		sum += driven->mParam->getVertexDistortion( index, poly_mesh );
+		sum.add(driven->mParam->getVertexDistortion( index, poly_mesh ));
 	}
 	return sum;
 }
 
-const LLVector3*	LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
+const LLVector4a*	LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
 {
 	mCurrentDistortionParam = NULL;
-	const LLVector3* v = NULL;
+	const LLVector4a* v = NULL;
 	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )
 	{
 		LLDrivenEntry* driven = &(*iter);
@@ -404,7 +408,7 @@ const LLVector3*	LLDriverParam::getFirstDistortion(U32 *index, LLPolyMesh **poly
 	return v;
 };
 
-const LLVector3*	LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
+const LLVector4a*	LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
 {
 	llassert( mCurrentDistortionParam );
 	if( !mCurrentDistortionParam )
@@ -432,7 +436,7 @@ const LLVector3*	LLDriverParam::getNextDistortion(U32 *index, LLPolyMesh **poly_
 	}
 
 	// We're already in the middle of a param's distortions, so get the next one.
-	const LLVector3* v = driven->mParam->getNextDistortion( index, poly_mesh );
+	const LLVector4a* v = driven->mParam->getNextDistortion( index, poly_mesh );
 	if( (!v) && (iter != mDriven.end()) )
 	{
 		// This param is finished, so start the next param.  It might not have any
diff --git a/indra/newview/lldriverparam.h b/indra/newview/lldriverparam.h
index fb1b44458ce76a4eedf162517f278a646abccd17..7a4d711d4e808876b055b89f1b6d06bbf1584d06 100644
--- a/indra/newview/lldriverparam.h
+++ b/indra/newview/lldriverparam.h
@@ -105,18 +105,18 @@ class LLDriverParam : public LLViewerVisualParam
 	
 	// LLViewerVisualParam Virtual functions
 	/*virtual*/ F32					getTotalDistortion();
-	/*virtual*/ const LLVector3&	getAvgDistortion();
+	/*virtual*/ const LLVector4a&	getAvgDistortion();
 	/*virtual*/ F32					getMaxDistortion();
-	/*virtual*/ LLVector3			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
-	/*virtual*/ const LLVector3*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
-	/*virtual*/ const LLVector3*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
+	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
+	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
+	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
 
 protected:
 	F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight);
 	void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake);
 
 
-	LLVector3	mDefaultVec; // temp holder
+	LLVector4a	mDefaultVec; // temp holder
 	typedef std::vector<LLDrivenEntry> entry_list_t;
 	entry_list_t mDriven;
 	LLViewerVisualParam* mCurrentDistortionParam;
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 4108d69e820de82ad5b674ca935f9884883f7a27..f5b217d5392793a0a31e18afc3c2b79ea71e5475 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -44,11 +44,14 @@
 #include "llsky.h"
 #include "llviewercamera.h"
 #include "llviewertexturelist.h"
+#include "llvopartgroup.h"
 #include "llvosky.h"
 #include "llvovolume.h"
 #include "pipeline.h"
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
+#include "llviewershadermgr.h"
+
 
 #define LL_MAX_INDICES_COUNT 1000000
 
@@ -56,7 +59,6 @@ BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE
 
 #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2])
 
-
 /*
 For each vertex, given:
 	B - binormal
@@ -161,7 +163,10 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mGeomCount		= 0;
 	mGeomIndex		= 0;
 	mIndicesCount	= 0;
-	mIndicesIndex	= 0;
+
+	//special value to indicate uninitialized position
+	mIndicesIndex	= 0xFFFFFFFF;
+	
 	mIndexInTex = 0;
 	mTexture		= NULL;
 	mTEOffset		= -1;
@@ -177,12 +182,6 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 
 	mFaceColor = LLColor4(1,0,0,1);
 
-	mLastVertexBuffer = mVertexBuffer;
-	mLastGeomCount = mGeomCount;
-	mLastGeomIndex = mGeomIndex;
-	mLastIndicesCount = mIndicesCount;
-	mLastIndicesIndex = mIndicesIndex;
-
 	mImportanceToCamera = 0.f ;
 	mBoundingSphereRadius = 0.0f ;
 
@@ -203,6 +202,12 @@ void LLFace::destroy()
 		mTexture->removeFace(this) ;
 	}
 	
+	if (isState(LLFace::PARTICLE))
+	{
+		LLVOPartGroup::freeVBSlot(getGeomIndex()/4);
+		clearState(LLFace::PARTICLE);
+	}
+
 	if (mDrawPoolp)
 	{
 		if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)
@@ -372,7 +377,6 @@ void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align)
 		mGeomCount    = num_vertices;
 		mIndicesCount = num_indices;
 		mVertexBuffer = NULL;
-		mLastVertexBuffer = NULL;
 	}
 
 	llassert(verify());
@@ -765,12 +769,6 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 		LLMatrix4a mat_normal;
 		mat_normal.loadu(mat_normal_in);
 
-		//if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
-		//{ //vertex buffer no longer valid
-		//	mVertexBuffer = NULL;
-		//	mLastVertexBuffer = NULL;
-		//}
-
 		//VECTORIZE THIS
 		LLVector4a min,max;
 	
@@ -1032,30 +1030,13 @@ bool LLFace::calcAlignedPlanarTE(const LLFace* align_to,  LLVector2* res_st_offs
 
 void LLFace::updateRebuildFlags()
 {
-	if (!mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
-	{
-		BOOL moved = TRUE;
-		if (mLastVertexBuffer == mVertexBuffer && 
-			!mVertexBuffer->isEmpty())
-		{	//this face really doesn't need to be regenerated, try real hard not to do so
-			if (mLastGeomCount == mGeomCount &&
-				mLastGeomIndex == mGeomIndex &&
-				mLastIndicesCount == mIndicesCount &&
-				mLastIndicesIndex == mIndicesIndex)
-			{ //data is in same location in vertex buffer
-				moved = FALSE;
-			}
-		}
-		mLastMoveTime = gFrameTimeSeconds;
-		
-		if (moved)
-		{
-			mDrawablep->setState(LLDrawable::REBUILD_VOLUME);
-		}
+	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
+	{ //this rebuild is zero overhead (direct consequence of some change that affects this face)
+		mLastUpdateTime = gFrameTimeSeconds;
 	}
 	else
-	{
-		mLastUpdateTime = gFrameTimeSeconds;
+	{ //this rebuild is overhead (side effect of some change that does not affect this face)
+		mLastMoveTime = gFrameTimeSeconds;
 	}
 }
 
@@ -1094,6 +1075,73 @@ bool LLFace::canRenderAsMask()
 }
 
 
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_VOLUME("Volume VB Cache");
+
+//static 
+void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
+{
+	LLFastTimer t(FTM_FACE_GEOM_VOLUME);
+	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 |
+				LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL;
+	
+	if (vf.mWeights)
+	{
+		mask |= LLVertexBuffer::MAP_WEIGHT4;
+	}
+
+	LLVertexBuffer* buff = new LLVertexBuffer(mask, GL_STATIC_DRAW_ARB);
+	vf.mVertexBuffer = buff;
+
+	buff->allocateBuffer(vf.mNumVertices, 0, true);
+
+	LLStrider<LLVector4a> f_vert;
+	LLStrider<LLVector3> f_binorm;
+	LLStrider<LLVector3> f_norm;
+	LLStrider<LLVector2> f_tc;
+
+	buff->getBinormalStrider(f_binorm);
+	buff->getVertexStrider(f_vert);
+	buff->getNormalStrider(f_norm);
+	buff->getTexCoord0Strider(f_tc);
+
+	for (U32 i = 0; i < vf.mNumVertices; ++i)
+	{
+		*f_vert++ = vf.mPositions[i];
+		(*f_binorm++).set(vf.mBinormals[i].getF32ptr());
+		*f_tc++ = vf.mTexCoords[i];
+		(*f_norm++).set(vf.mNormals[i].getF32ptr());
+	}
+
+	if (vf.mWeights)
+	{
+		LLStrider<LLVector4> f_wght;
+		buff->getWeight4Strider(f_wght);
+		for (U32 i = 0; i < vf.mNumVertices; ++i)
+		{
+			(*f_wght++).set(vf.mWeights[i].getF32ptr());
+		}
+	}
+
+	buff->flush();
+}
+
+//helper function for pushing primitives for transform shaders and cleaning up
+//uninitialized data on the tail, plus tracking number of expected primitives
+void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count)
+{
+	if (source_count > 0 && dest_count >= source_count) //protect against possible U32 wrapping
+	{
+		//push source primitives
+		buff->drawArrays(LLRender::POINTS, 0, source_count);
+		U32 tail = dest_count-source_count;
+		for (U32 i = 0; i < tail; ++i)
+		{ //copy last source primitive into each element in tail
+			buff->drawArrays(LLRender::POINTS, source_count-1, 1);
+		}
+		gPipeline.mTransformFeedbackPrimitives += dest_count;
+	}
+}
+
 static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_POSITION("Position");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_NORMAL("Normal");
@@ -1111,7 +1159,6 @@ static LLFastTimer::DeclareTimer FTM_FACE_TEX_DEFAULT("Default");
 static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK("Quick");
 static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_NO_XFORM("No Xform");
 static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_XFORM("Xform");
-
 static LLFastTimer::DeclareTimer FTM_FACE_TEX_QUICK_PLANAR("Quick Planar");
 
 BOOL LLFace::getGeometryVolume(const LLVolume& volume,
@@ -1139,21 +1186,25 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	{
 		if (num_indices + (S32) mIndicesIndex > mVertexBuffer->getNumIndices())
 		{
-			llwarns	<< "Index buffer overflow!" << llendl;
-			llwarns << "Indices Count: " << mIndicesCount
-					<< " VF Num Indices: " << num_indices
-					<< " Indices Index: " << mIndicesIndex
-					<< " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl;
-			llwarns	<< "Last Indices Count: " << mLastIndicesCount
-					<< " Last Indices Index: " << mLastIndicesIndex
-					<< " Face Index: " << f
-					<< " Pool Type: " << mPoolType << llendl;
+			if (gDebugGL)
+			{
+				llwarns	<< "Index buffer overflow!" << llendl;
+				llwarns << "Indices Count: " << mIndicesCount
+						<< " VF Num Indices: " << num_indices
+						<< " Indices Index: " << mIndicesIndex
+						<< " VB Num Indices: " << mVertexBuffer->getNumIndices() << llendl;
+				llwarns	<< " Face Index: " << f
+						<< " Pool Type: " << mPoolType << llendl;
+			}
 			return FALSE;
 		}
 
 		if (num_vertices + mGeomIndex > mVertexBuffer->getNumVerts())
 		{
-			llwarns << "Vertex buffer overflow!" << llendl;
+			if (gDebugGL)
+			{
+				llwarns << "Vertex buffer overflow!" << llendl;
+			}
 			return FALSE;
 		}
 	}
@@ -1284,17 +1335,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	LLMatrix4a mat_normal;
 	mat_normal.loadu(mat_norm_in);
 	
-	//if it's not fullbright and has no normals, bake sunlight based on face normal
-	//bool bake_sunlight = !getTextureEntry()->getFullbright() &&
-	//  !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
-
 	F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
-
+	bool do_xform = false;
 	if (rebuild_tcoord)
 	{
-		LLFastTimer t(FTM_FACE_GEOM_TEXTURE);
-		bool do_xform;
-			
 		if (tep)
 		{
 			r  = tep->getRotation();
@@ -1323,599 +1367,759 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		{
 			do_xform = false;
 		}
+	}
+	
+	static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback");
+
+#ifdef GL_TRANSFORM_FEEDBACK_BUFFER
+	if (use_transform_feedback &&
+		gTransformPositionProgram.mProgramObject && //transform shaders are loaded
+		mVertexBuffer->useVBOs() && //target buffer is in VRAM
+		!rebuild_weights && //TODO: add support for weights
+		!volume.isUnique()) //source volume is NOT flexi
+	{ //use transform feedback to pack vertex buffer
+
+		LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
+
+		if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices)
+		{
+			mVObjp->getVolume()->genBinormals(f);
+			LLFace::cacheFaceInVRAM(vf);
+			buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
+		}		
+
+		LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr;
+		
+		gGL.pushMatrix();
+		gGL.loadMatrix((GLfloat*) mat_vert_in.mMatrix);
+
+		if (rebuild_pos)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_POSITION);
+			gTransformPositionProgram.bind();
+
+			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount);
+
+			U8 index = mTextureIndex < 255 ? mTextureIndex : 0;
+
+			S32 val = 0;
+			U8* vp = (U8*) &val;
+			vp[0] = index;
+			vp[1] = 0;
+			vp[2] = 0;
+			vp[3] = 0;
+			
+			gTransformPositionProgram.uniform1i("texture_index_in", val);
+			glBeginTransformFeedback(GL_POINTS);
+			buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+			push_for_transform(buff, vf.mNumVertices, mGeomCount);
+
+			glEndTransformFeedback();
+		}
+
+		if (rebuild_color)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_COLOR);
+			gTransformColorProgram.bind();
+			
+			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount);
+
+			S32 val = *((S32*) color.mV);
+
+			gTransformColorProgram.uniform1i("color_in", val);
+			glBeginTransformFeedback(GL_POINTS);
+			buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+			push_for_transform(buff, vf.mNumVertices, mGeomCount);
+			glEndTransformFeedback();
+		}
+
+		if (rebuild_emissive)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_EMISSIVE);
+			gTransformColorProgram.bind();
+			
+			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount);
+
+			U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255);
+
+			S32 glow32 = glow |
+						 (glow << 8) |
+						 (glow << 16) |
+						 (glow << 24);
+
+			gTransformColorProgram.uniform1i("color_in", glow32);
+			glBeginTransformFeedback(GL_POINTS);
+			buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+			push_for_transform(buff, vf.mNumVertices, mGeomCount);
+			glEndTransformFeedback();
+		}
+
+		if (rebuild_normal)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_NORMAL);
+			gTransformNormalProgram.bind();
+			
+			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount);
 						
-		//bump setup
-		LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
-		LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f);
-		LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f);
+			glBeginTransformFeedback(GL_POINTS);
+			buff->setBuffer(LLVertexBuffer::MAP_NORMAL);
+			push_for_transform(buff, vf.mNumVertices, mGeomCount);
+			glEndTransformFeedback();
+		}
 
-		LLQuaternion bump_quat;
-		if (mDrawablep->isActive())
+		if (rebuild_binormal)
 		{
-			bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
+			LLFastTimer t(FTM_FACE_GEOM_BINORMAL);
+			gTransformBinormalProgram.bind();
+			
+			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_BINORMAL, mGeomIndex, mGeomCount);
+						
+			glBeginTransformFeedback(GL_POINTS);
+			buff->setBuffer(LLVertexBuffer::MAP_BINORMAL);
+			push_for_transform(buff, vf.mNumVertices, mGeomCount);
+			glEndTransformFeedback();
 		}
-		
-		if (bump_code)
+
+		if (rebuild_tcoord)
 		{
-			mVObjp->getVolume()->genBinormals(f);
-			F32 offset_multiple; 
-			switch( bump_code )
-			{
-				case BE_NO_BUMP:
-				offset_multiple = 0.f;
-				break;
-				case BE_BRIGHTNESS:
-				case BE_DARKNESS:
-				if( mTexture.notNull() && mTexture->hasGLTexture())
-				{
-					// Offset by approximately one texel
-					S32 cur_discard = mTexture->getDiscardLevel();
-					S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() );
-					max_size <<= cur_discard;
-					const F32 ARTIFICIAL_OFFSET = 2.f;
-					offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size;
-				}
-				else
-				{
-					offset_multiple = 1.f/256;
-				}
-				break;
+			LLFastTimer t(FTM_FACE_GEOM_TEXTURE);
+			gTransformTexCoordProgram.bind();
+			
+			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount);
+						
+			glBeginTransformFeedback(GL_POINTS);
+			buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0);
+			push_for_transform(buff, vf.mNumVertices, mGeomCount);
+			glEndTransformFeedback();
 
-				default:  // Standard bumpmap textures.  Assumed to be 256x256
-				offset_multiple = 1.f / 256;
-				break;
-			}
+			bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1);
 
-			F32 s_scale = 1.f;
-			F32 t_scale = 1.f;
-			if( tep )
+			if (do_bump)
 			{
-				tep->getScale( &s_scale, &t_scale );
-			}
-			// Use the nudged south when coming from above sun angle, such
-			// that emboss mapping always shows up on the upward faces of cubes when 
-			// it's noon (since a lot of builders build with the sun forced to noon).
-			LLVector3   sun_ray  = gSky.mVOSkyp->mBumpSunDir;
-			LLVector3   moon_ray = gSky.getMoonDirection();
-			LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray;
-
-			bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV);
-			bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV);
+				mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD1, mGeomIndex, mGeomCount);
+				glBeginTransformFeedback(GL_POINTS);
+				buff->setBuffer(LLVertexBuffer::MAP_TEXCOORD0);
+				push_for_transform(buff, vf.mNumVertices, mGeomCount);
+				glEndTransformFeedback();
+			}				
 		}
 
-		U8 texgen = getTextureEntry()->getTexGen();
-		if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
-		{ //planar texgen needs binormals
-			mVObjp->getVolume()->genBinormals(f);
+		glBindBufferARB(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
+
+		gGL.popMatrix();
+
+		if (cur_shader)
+		{
+			cur_shader->bind();
 		}
+	}
+	else
+#endif
+	{
+		//if it's not fullbright and has no normals, bake sunlight based on face normal
+		//bool bake_sunlight = !getTextureEntry()->getFullbright() &&
+		//  !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
 
-		U8 tex_mode = 0;
-	
-		if (isState(TEXTURE_ANIM))
+		if (rebuild_tcoord)
 		{
-			LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;	
-			tex_mode = vobj->mTexAnimMode;
+			LLFastTimer t(FTM_FACE_GEOM_TEXTURE);
+									
+			//bump setup
+			LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
+			LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f);
+			LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f);
 
-			if (!tex_mode)
+			LLQuaternion bump_quat;
+			if (mDrawablep->isActive())
 			{
-				clearState(TEXTURE_ANIM);
+				bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
 			}
-			else
+		
+			if (bump_code)
 			{
-				os = ot = 0.f;
-				r = 0.f;
-				cos_ang = 1.f;
-				sin_ang = 0.f;
-				ms = mt = 1.f;
+				mVObjp->getVolume()->genBinormals(f);
+				F32 offset_multiple; 
+				switch( bump_code )
+				{
+					case BE_NO_BUMP:
+					offset_multiple = 0.f;
+					break;
+					case BE_BRIGHTNESS:
+					case BE_DARKNESS:
+					if( mTexture.notNull() && mTexture->hasGLTexture())
+					{
+						// Offset by approximately one texel
+						S32 cur_discard = mTexture->getDiscardLevel();
+						S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() );
+						max_size <<= cur_discard;
+						const F32 ARTIFICIAL_OFFSET = 2.f;
+						offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size;
+					}
+					else
+					{
+						offset_multiple = 1.f/256;
+					}
+					break;
 
-				do_xform = false;
+					default:  // Standard bumpmap textures.  Assumed to be 256x256
+					offset_multiple = 1.f / 256;
+					break;
+				}
+
+				F32 s_scale = 1.f;
+				F32 t_scale = 1.f;
+				if( tep )
+				{
+					tep->getScale( &s_scale, &t_scale );
+				}
+				// Use the nudged south when coming from above sun angle, such
+				// that emboss mapping always shows up on the upward faces of cubes when 
+				// it's noon (since a lot of builders build with the sun forced to noon).
+				LLVector3   sun_ray  = gSky.mVOSkyp->mBumpSunDir;
+				LLVector3   moon_ray = gSky.getMoonDirection();
+				LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray;
+
+				bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV);
+				bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV);
 			}
 
-			if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
-			{ //don't override texture transform during tc bake
-				tex_mode = 0;
+			U8 texgen = getTextureEntry()->getTexGen();
+			if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+			{ //planar texgen needs binormals
+				mVObjp->getVolume()->genBinormals(f);
 			}
-		}
 
-		LLVector4a scalea;
-		scalea.load3(scale.mV);
+			U8 tex_mode = 0;
+	
+			if (isState(TEXTURE_ANIM))
+			{
+				LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;	
+				tex_mode = vobj->mTexAnimMode;
+
+				if (!tex_mode)
+				{
+					clearState(TEXTURE_ANIM);
+				}
+				else
+				{
+					os = ot = 0.f;
+					r = 0.f;
+					cos_ang = 1.f;
+					sin_ang = 0.f;
+					ms = mt = 1.f;
+
+					do_xform = false;
+				}
 
-		bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1);
-		bool do_tex_mat = tex_mode && mTextureMatrix;
+				if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
+				{ //don't override texture transform during tc bake
+					tex_mode = 0;
+				}
+			}
 
-		if (!in_atlas && !do_bump)
-		{ //not in atlas or not bump mapped, might be able to do a cheap update
-			mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount);
+			LLVector4a scalea;
+			scalea.load3(scale.mV);
 
-			if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
-			{
-				LLFastTimer t(FTM_FACE_TEX_QUICK);
-				if (!do_tex_mat)
+			bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1);
+			bool do_tex_mat = tex_mode && mTextureMatrix;
+
+			if (!in_atlas && !do_bump)
+			{ //not in atlas or not bump mapped, might be able to do a cheap update
+				mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount);
+
+				if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
 				{
-					if (!do_xform)
-					{
-						LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM);
-						LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
-					}
-					else
+					LLFastTimer t(FTM_FACE_TEX_QUICK);
+					if (!do_tex_mat)
 					{
-						LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM);
-						F32* dst = (F32*) tex_coords.get();
-						LLVector4a* src = (LLVector4a*) vf.mTexCoords;
+						if (!do_xform)
+						{
+							LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM);
+							LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2*sizeof(F32));
+						}
+						else
+						{
+							LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM);
+							F32* dst = (F32*) tex_coords.get();
+							LLVector4a* src = (LLVector4a*) vf.mTexCoords;
 
-						LLVector4a trans;
-						trans.splat(-0.5f);
+							LLVector4a trans;
+							trans.splat(-0.5f);
 
-						LLVector4a rot0;
-						rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang);
+							LLVector4a rot0;
+							rot0.set(cos_ang, -sin_ang, cos_ang, -sin_ang);
 
-						LLVector4a rot1;
-						rot1.set(sin_ang, cos_ang, sin_ang, cos_ang);
+							LLVector4a rot1;
+							rot1.set(sin_ang, cos_ang, sin_ang, cos_ang);
 
-						LLVector4a scale;
-						scale.set(ms, mt, ms, mt);
+							LLVector4a scale;
+							scale.set(ms, mt, ms, mt);
 
-						LLVector4a offset;
-						offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f);
+							LLVector4a offset;
+							offset.set(os+0.5f, ot+0.5f, os+0.5f, ot+0.5f);
 
-						LLVector4Logical mask;
-						mask.clear();
-						mask.setElement<2>();
-						mask.setElement<3>();
+							LLVector4Logical mask;
+							mask.clear();
+							mask.setElement<2>();
+							mask.setElement<3>();
 
-						U32 count = num_vertices/2 + num_vertices%2;
+							U32 count = num_vertices/2 + num_vertices%2;
 
-						for (S32 i = 0; i < count; i++)
+							for (S32 i = 0; i < count; i++)
+							{	
+								LLVector4a res = *src++;
+								xform4a(res, trans, mask, rot0, rot1, offset, scale);
+								res.store4a(dst);
+								dst += 4;
+							}
+						}
+					}
+					else
+					{ //do tex mat, no texgen, no atlas, no bump
+						for (S32 i = 0; i < num_vertices; i++)
 						{	
-							LLVector4a res = *src++;
-							xform4a(res, trans, mask, rot0, rot1, offset, scale);
-							res.store4a(dst);
-							dst += 4;
+							LLVector2 tc(vf.mTexCoords[i]);
+							//LLVector4a& norm = vf.mNormals[i];
+							//LLVector4a& center = *(vf.mCenter);
+
+							LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+							tmp = tmp * *mTextureMatrix;
+							tc.mV[0] = tmp.mV[0];
+							tc.mV[1] = tmp.mV[1];
+							*tex_coords++ = tc;	
 						}
 					}
 				}
 				else
-				{ //do tex mat, no texgen, no atlas, no bump
-					for (S32 i = 0; i < num_vertices; i++)
-					{	
-						LLVector2 tc(vf.mTexCoords[i]);
-						//LLVector4a& norm = vf.mNormals[i];
-						//LLVector4a& center = *(vf.mCenter);
-
-						LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
-						tmp = tmp * *mTextureMatrix;
-						tc.mV[0] = tmp.mV[0];
-						tc.mV[1] = tmp.mV[1];
-						*tex_coords++ = tc;	
-					}
-				}
-			}
-			else
-			{ //no bump, no atlas, tex gen planar
-				LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR);
-				if (do_tex_mat)
-				{
-					for (S32 i = 0; i < num_vertices; i++)
-					{	
-						LLVector2 tc(vf.mTexCoords[i]);
-						LLVector4a& norm = vf.mNormals[i];
-						LLVector4a& center = *(vf.mCenter);
-						LLVector4a vec = vf.mPositions[i];	
-						vec.mul(scalea);
-						planarProjection(tc, norm, center, vec);
+				{ //no bump, no atlas, tex gen planar
+					LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR);
+					if (do_tex_mat)
+					{
+						for (S32 i = 0; i < num_vertices; i++)
+						{	
+							LLVector2 tc(vf.mTexCoords[i]);
+							LLVector4a& norm = vf.mNormals[i];
+							LLVector4a& center = *(vf.mCenter);
+							LLVector4a vec = vf.mPositions[i];	
+							vec.mul(scalea);
+							planarProjection(tc, norm, center, vec);
 						
-						LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
-						tmp = tmp * *mTextureMatrix;
-						tc.mV[0] = tmp.mV[0];
-						tc.mV[1] = tmp.mV[1];
+							LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+							tmp = tmp * *mTextureMatrix;
+							tc.mV[0] = tmp.mV[0];
+							tc.mV[1] = tmp.mV[1];
 				
-						*tex_coords++ = tc;	
+							*tex_coords++ = tc;	
+						}
 					}
-				}
-				else
-				{
-					for (S32 i = 0; i < num_vertices; i++)
-					{	
-						LLVector2 tc(vf.mTexCoords[i]);
-						LLVector4a& norm = vf.mNormals[i];
-						LLVector4a& center = *(vf.mCenter);
-						LLVector4a vec = vf.mPositions[i];	
-						vec.mul(scalea);
-						planarProjection(tc, norm, center, vec);
+					else
+					{
+						for (S32 i = 0; i < num_vertices; i++)
+						{	
+							LLVector2 tc(vf.mTexCoords[i]);
+							LLVector4a& norm = vf.mNormals[i];
+							LLVector4a& center = *(vf.mCenter);
+							LLVector4a vec = vf.mPositions[i];	
+							vec.mul(scalea);
+							planarProjection(tc, norm, center, vec);
 						
-						xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+							xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
 
-						*tex_coords++ = tc;	
+							*tex_coords++ = tc;	
+						}
 					}
 				}
-			}
 
-			if (map_range)
-			{
-				mVertexBuffer->flush();
+				if (map_range)
+				{
+					mVertexBuffer->flush();
+				}
 			}
-		}
-		else
-		{ //either bump mapped or in atlas, just do the whole expensive loop
-			LLFastTimer t(FTM_FACE_TEX_DEFAULT);
-			mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range);
+			else
+			{ //either bump mapped or in atlas, just do the whole expensive loop
+				LLFastTimer t(FTM_FACE_TEX_DEFAULT);
+				mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range);
 
-			std::vector<LLVector2> bump_tc;
+				std::vector<LLVector2> bump_tc;
 		
-			for (S32 i = 0; i < num_vertices; i++)
-			{	
-				LLVector2 tc(vf.mTexCoords[i]);
+				for (S32 i = 0; i < num_vertices; i++)
+				{	
+					LLVector2 tc(vf.mTexCoords[i]);
 			
-				LLVector4a& norm = vf.mNormals[i];
+					LLVector4a& norm = vf.mNormals[i];
 				
-				LLVector4a& center = *(vf.mCenter);
+					LLVector4a& center = *(vf.mCenter);
 		   
-				if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
-				{
-					LLVector4a vec = vf.mPositions[i];
+					if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+					{
+						LLVector4a vec = vf.mPositions[i];
 				
-					vec.mul(scalea);
+						vec.mul(scalea);
 
-					switch (texgen)
+						switch (texgen)
+						{
+							case LLTextureEntry::TEX_GEN_PLANAR:
+								planarProjection(tc, norm, center, vec);
+								break;
+							case LLTextureEntry::TEX_GEN_SPHERICAL:
+								sphericalProjection(tc, norm, center, vec);
+								break;
+							case LLTextureEntry::TEX_GEN_CYLINDRICAL:
+								cylindricalProjection(tc, norm, center, vec);
+								break;
+							default:
+								break;
+						}		
+					}
+
+					if (tex_mode && mTextureMatrix)
 					{
-						case LLTextureEntry::TEX_GEN_PLANAR:
-							planarProjection(tc, norm, center, vec);
+						LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+						tmp = tmp * *mTextureMatrix;
+						tc.mV[0] = tmp.mV[0];
+						tc.mV[1] = tmp.mV[1];
+					}
+					else
+					{
+						xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+					}
+
+					if(in_atlas)
+					{
+						//
+						//manually calculate tex-coord per vertex for varying address modes.
+						//should be removed if shader can handle this.
+						//
+
+						S32 int_part = 0 ;
+						switch(mTexture->getAddressMode())
+						{
+						case LLTexUnit::TAM_CLAMP:
+							if(tc.mV[0] < 0.f)
+							{
+								tc.mV[0] = 0.f ;
+							}
+							else if(tc.mV[0] > 1.f)
+							{
+								tc.mV[0] = 1.f;
+							}
+
+							if(tc.mV[1] < 0.f)
+							{
+								tc.mV[1] = 0.f ;
+							}
+							else if(tc.mV[1] > 1.f)
+							{
+								tc.mV[1] = 1.f;
+							}
 							break;
-						case LLTextureEntry::TEX_GEN_SPHERICAL:
-							sphericalProjection(tc, norm, center, vec);
+						case LLTexUnit::TAM_MIRROR:
+							if(tc.mV[0] < 0.f)
+							{
+								tc.mV[0] = -tc.mV[0] ;
+							}
+							int_part = (S32)tc.mV[0] ;
+							if(int_part & 1) //odd number
+							{
+								tc.mV[0] = int_part + 1 - tc.mV[0] ;
+							}
+							else //even number
+							{
+								tc.mV[0] -= int_part ;
+							}
+
+							if(tc.mV[1] < 0.f)
+							{
+								tc.mV[1] = -tc.mV[1] ;
+							}
+							int_part = (S32)tc.mV[1] ;
+							if(int_part & 1) //odd number
+							{
+								tc.mV[1] = int_part + 1 - tc.mV[1] ;
+							}
+							else //even number
+							{
+								tc.mV[1] -= int_part ;
+							}
 							break;
-						case LLTextureEntry::TEX_GEN_CYLINDRICAL:
-							cylindricalProjection(tc, norm, center, vec);
+						case LLTexUnit::TAM_WRAP:
+							if(tc.mV[0] > 1.f)
+								tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
+							else if(tc.mV[0] < -1.f)
+								tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
+
+							if(tc.mV[1] > 1.f)
+								tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
+							else if(tc.mV[1] < -1.f)
+								tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
+
+							if(tc.mV[0] < 0.f)
+							{
+								tc.mV[0] = 1.0f + tc.mV[0] ;
+							}
+							if(tc.mV[1] < 0.f)
+							{
+								tc.mV[1] = 1.0f + tc.mV[1] ;
+							}
 							break;
 						default:
 							break;
-					}		
-				}
+						}
+				
+						tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
+						tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
+					}
+				
 
-				if (tex_mode && mTextureMatrix)
-				{
-					LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
-					tmp = tmp * *mTextureMatrix;
-					tc.mV[0] = tmp.mV[0];
-					tc.mV[1] = tmp.mV[1];
+					*tex_coords++ = tc;
+					if (do_bump)
+					{
+						bump_tc.push_back(tc);
+					}
 				}
-				else
+
+				if (map_range)
 				{
-					xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+					mVertexBuffer->flush();
 				}
 
-				if(in_atlas)
+				if (do_bump)
 				{
-					//
-					//manually calculate tex-coord per vertex for varying address modes.
-					//should be removed if shader can handle this.
-					//
-
-					S32 int_part = 0 ;
-					switch(mTexture->getAddressMode())
+					mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range);
+		
+					for (S32 i = 0; i < num_vertices; i++)
 					{
-					case LLTexUnit::TAM_CLAMP:
-						if(tc.mV[0] < 0.f)
-						{
-							tc.mV[0] = 0.f ;
-						}
-						else if(tc.mV[0] > 1.f)
-						{
-							tc.mV[0] = 1.f;
-						}
-
-						if(tc.mV[1] < 0.f)
-						{
-							tc.mV[1] = 0.f ;
-						}
-						else if(tc.mV[1] > 1.f)
-						{
-							tc.mV[1] = 1.f;
-						}
-						break;
-					case LLTexUnit::TAM_MIRROR:
-						if(tc.mV[0] < 0.f)
-						{
-							tc.mV[0] = -tc.mV[0] ;
-						}
-						int_part = (S32)tc.mV[0] ;
-						if(int_part & 1) //odd number
-						{
-							tc.mV[0] = int_part + 1 - tc.mV[0] ;
-						}
-						else //even number
+						LLVector4a tangent;
+						tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]);
+
+						LLMatrix4a tangent_to_object;
+						tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]);
+						LLVector4a t;
+						tangent_to_object.rotate(binormal_dir, t);
+						LLVector4a binormal;
+						mat_normal.rotate(t, binormal);
+						
+						//VECTORIZE THIS
+						if (mDrawablep->isActive())
 						{
-							tc.mV[0] -= int_part ;
+							LLVector3 t;
+							t.set(binormal.getF32ptr());
+							t *= bump_quat;
+							binormal.load3(t.mV);
 						}
 
-						if(tc.mV[1] < 0.f)
-						{
-							tc.mV[1] = -tc.mV[1] ;
-						}
-						int_part = (S32)tc.mV[1] ;
-						if(int_part & 1) //odd number
-						{
-							tc.mV[1] = int_part + 1 - tc.mV[1] ;
-						}
-						else //even number
-						{
-							tc.mV[1] -= int_part ;
-						}
-						break;
-					case LLTexUnit::TAM_WRAP:
-						if(tc.mV[0] > 1.f)
-							tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
-						else if(tc.mV[0] < -1.f)
-							tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
-
-						if(tc.mV[1] > 1.f)
-							tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
-						else if(tc.mV[1] < -1.f)
-							tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
-
-						if(tc.mV[0] < 0.f)
-						{
-							tc.mV[0] = 1.0f + tc.mV[0] ;
-						}
-						if(tc.mV[1] < 0.f)
-						{
-							tc.mV[1] = 1.0f + tc.mV[1] ;
-						}
-						break;
-					default:
-						break;
+						binormal.normalize3fast();
+						LLVector2 tc = bump_tc[i];
+						tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() );
+					
+						*tex_coords2++ = tc;
 					}
-				
-					tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
-					tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
-				}
-				
 
-				*tex_coords++ = tc;
-				if (do_bump)
-				{
-					bump_tc.push_back(tc);
-				}
-			}
-
-			if (map_range)
-			{
-				mVertexBuffer->flush();
-			}
-
-			if (do_bump)
-			{
-				mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range);
-		
-				for (S32 i = 0; i < num_vertices; i++)
-				{
-					LLVector4a tangent;
-					tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]);
-
-					LLMatrix4a tangent_to_object;
-					tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]);
-					LLVector4a t;
-					tangent_to_object.rotate(binormal_dir, t);
-					LLVector4a binormal;
-					mat_normal.rotate(t, binormal);
-						
-					//VECTORIZE THIS
-					if (mDrawablep->isActive())
+					if (map_range)
 					{
-						LLVector3 t;
-						t.set(binormal.getF32ptr());
-						t *= bump_quat;
-						binormal.load3(t.mV);
+						mVertexBuffer->flush();
 					}
-
-					binormal.normalize3fast();
-					LLVector2 tc = bump_tc[i];
-					tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() );
-					
-					*tex_coords2++ = tc;
-				}
-
-				if (map_range)
-				{
-					mVertexBuffer->flush();
 				}
 			}
 		}
-	}
 
-	if (rebuild_pos)
-	{
-		LLFastTimer t(FTM_FACE_GEOM_POSITION);
-		llassert(num_vertices > 0);
+		if (rebuild_pos)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_POSITION);
+			llassert(num_vertices > 0);
 		
-		mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
+			mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range);
 			
 
-		LLMatrix4a mat_vert;
-		mat_vert.loadu(mat_vert_in);
+			LLMatrix4a mat_vert;
+			mat_vert.loadu(mat_vert_in);
 
-		LLVector4a* src = vf.mPositions;
-		volatile F32* dst = (volatile F32*) vert.get();
+			LLVector4a* src = vf.mPositions;
+			volatile F32* dst = (volatile F32*) vert.get();
 
-		volatile F32* end = dst+num_vertices*4;
-		LLVector4a res;
+			volatile F32* end = dst+num_vertices*4;
+			LLVector4a res;
 
-		LLVector4a texIdx;
+			LLVector4a texIdx;
 
-		U8 index = mTextureIndex < 255 ? mTextureIndex : 0;
+			U8 index = mTextureIndex < 255 ? mTextureIndex : 0;
 
-		F32 val = 0.f;
-		U8* vp = (U8*) &val;
-		vp[0] = index;
-		vp[1] = 0;
-		vp[2] = 0;
-		vp[3] = 0;
+			F32 val = 0.f;
+			U8* vp = (U8*) &val;
+			vp[0] = index;
+			vp[1] = 0;
+			vp[2] = 0;
+			vp[3] = 0;
 
-		llassert(index <= LLGLSLShader::sIndexedTextureChannels-1);
+			llassert(index <= LLGLSLShader::sIndexedTextureChannels-1);
 
-		LLVector4Logical mask;
-		mask.clear();
-		mask.setElement<3>();
+			LLVector4Logical mask;
+			mask.clear();
+			mask.setElement<3>();
 		
-		texIdx.set(0,0,0,val);
+			texIdx.set(0,0,0,val);
 
-		{
-			LLFastTimer t(FTM_FACE_POSITION_STORE);
-			LLVector4a tmp;
-
-			do
-			{	
-				mat_vert.affineTransform(*src++, res);
-				tmp.setSelectWithMask(mask, texIdx, res);
-				tmp.store4a((F32*) dst);
-				dst += 4;
+			{
+				LLFastTimer t(FTM_FACE_POSITION_STORE);
+				LLVector4a tmp;
+
+				do
+				{	
+					mat_vert.affineTransform(*src++, res);
+					tmp.setSelectWithMask(mask, texIdx, res);
+					tmp.store4a((F32*) dst);
+					dst += 4;
+				}
+				while(dst < end);
 			}
-			while(dst < end);
-		}
 
-		{
-			LLFastTimer t(FTM_FACE_POSITION_PAD);
-			S32 aligned_pad_vertices = mGeomCount - num_vertices;
-			res.set(res[0], res[1], res[2], 0.f);
+			{
+				LLFastTimer t(FTM_FACE_POSITION_PAD);
+				S32 aligned_pad_vertices = mGeomCount - num_vertices;
+				res.set(res[0], res[1], res[2], 0.f);
 
-			while (aligned_pad_vertices > 0)
+				while (aligned_pad_vertices > 0)
+				{
+					--aligned_pad_vertices;
+					res.store4a((F32*) dst);
+					dst += 4;
+				}
+			}
+
+			if (map_range)
 			{
-				--aligned_pad_vertices;
-				res.store4a((F32*) dst);
-				dst += 4;
+				mVertexBuffer->flush();
 			}
 		}
 
-		if (map_range)
-		{
-			mVertexBuffer->flush();
-		}
-	}
 		
-	if (rebuild_normal)
-	{
-		LLFastTimer t(FTM_FACE_GEOM_NORMAL);
-		mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
-		F32* normals = (F32*) norm.get();
+		if (rebuild_normal)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_NORMAL);
+			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
+			F32* normals = (F32*) norm.get();
 	
-		for (S32 i = 0; i < num_vertices; i++)
-		{	
-			LLVector4a normal;
-			mat_normal.rotate(vf.mNormals[i], normal);
-			normal.normalize3fast();
-			normal.store4a(normals);
-			normals += 4;
-		}
+			for (S32 i = 0; i < num_vertices; i++)
+			{	
+				LLVector4a normal;
+				mat_normal.rotate(vf.mNormals[i], normal);
+				normal.normalize3fast();
+				normal.store4a(normals);
+				normals += 4;
+			}
 
-		if (map_range)
-		{
-			mVertexBuffer->flush();
+			if (map_range)
+			{
+				mVertexBuffer->flush();
+			}
 		}
-	}
 		
-	if (rebuild_binormal)
-	{
-		LLFastTimer t(FTM_FACE_GEOM_BINORMAL);
-		mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range);
-		F32* binormals = (F32*) binorm.get();
+		if (rebuild_binormal)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_BINORMAL);
+			mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range);
+			F32* binormals = (F32*) binorm.get();
 		
-		for (S32 i = 0; i < num_vertices; i++)
-		{	
-			LLVector4a binormal;
-			mat_normal.rotate(vf.mBinormals[i], binormal);
-			binormal.normalize3fast();
-			binormal.store4a(binormals);
-			binormals += 4;
-		}
+			for (S32 i = 0; i < num_vertices; i++)
+			{	
+				LLVector4a binormal;
+				mat_normal.rotate(vf.mBinormals[i], binormal);
+				binormal.normalize3fast();
+				binormal.store4a(binormals);
+				binormals += 4;
+			}
 
-		if (map_range)
-		{
-			mVertexBuffer->flush();
+			if (map_range)
+			{
+				mVertexBuffer->flush();
+			}
 		}
-	}
 	
-	if (rebuild_weights && vf.mWeights)
-	{
-		LLFastTimer t(FTM_FACE_GEOM_WEIGHTS);
-		mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
-		F32* weights = (F32*) wght.get();
-		LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
-		if (map_range)
+		if (rebuild_weights && vf.mWeights)
 		{
-			mVertexBuffer->flush();
+			LLFastTimer t(FTM_FACE_GEOM_WEIGHTS);
+			mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range);
+			F32* weights = (F32*) wght.get();
+			LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32));
+			if (map_range)
+			{
+				mVertexBuffer->flush();
+			}
 		}
-	}
 
-	if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) )
-	{
-		LLFastTimer t(FTM_FACE_GEOM_COLOR);
-		mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
+		if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) )
+		{
+			LLFastTimer t(FTM_FACE_GEOM_COLOR);
+			mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range);
 
-		LLVector4a src;
+			LLVector4a src;
 
-		U32 vec[4];
-		vec[0] = vec[1] = vec[2] = vec[3] = color.mAll;
+			U32 vec[4];
+			vec[0] = vec[1] = vec[2] = vec[3] = color.mAll;
 		
-		src.loadua((F32*) vec);
+			src.loadua((F32*) vec);
 
-		F32* dst = (F32*) colors.get();
-		S32 num_vecs = num_vertices/4;
-		if (num_vertices%4 > 0)
-		{
-			++num_vecs;
-		}
+			F32* dst = (F32*) colors.get();
+			S32 num_vecs = num_vertices/4;
+			if (num_vertices%4 > 0)
+			{
+				++num_vecs;
+			}
 
-		for (S32 i = 0; i < num_vecs; i++)
-		{	
-			src.store4a(dst);
-			dst += 4;
-		}
+			for (S32 i = 0; i < num_vecs; i++)
+			{	
+				src.store4a(dst);
+				dst += 4;
+			}
 
-		if (map_range)
-		{
-			mVertexBuffer->flush();
+			if (map_range)
+			{
+				mVertexBuffer->flush();
+			}
 		}
-	}
 
-	if (rebuild_emissive)
-	{
-		LLFastTimer t(FTM_FACE_GEOM_EMISSIVE);
-		LLStrider<LLColor4U> emissive;
-		mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range);
+		if (rebuild_emissive)
+		{
+			LLFastTimer t(FTM_FACE_GEOM_EMISSIVE);
+			LLStrider<LLColor4U> emissive;
+			mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range);
 
-		U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255);
+			U8 glow = (U8) llclamp((S32) (getTextureEntry()->getGlow()*255), 0, 255);
 
-		LLVector4a src;
+			LLVector4a src;
 
 		
-		U32 glow32 = glow |
-					 (glow << 8) |
-					 (glow << 16) |
-					 (glow << 24);
+			U32 glow32 = glow |
+						 (glow << 8) |
+						 (glow << 16) |
+						 (glow << 24);
 
-		U32 vec[4];
-		vec[0] = vec[1] = vec[2] = vec[3] = glow32;
+			U32 vec[4];
+			vec[0] = vec[1] = vec[2] = vec[3] = glow32;
 		
-		src.loadua((F32*) vec);
+			src.loadua((F32*) vec);
 
-		F32* dst = (F32*) emissive.get();
-		S32 num_vecs = num_vertices/4;
-		if (num_vertices%4 > 0)
-		{
-			++num_vecs;
-		}
+			F32* dst = (F32*) emissive.get();
+			S32 num_vecs = num_vertices/4;
+			if (num_vertices%4 > 0)
+			{
+				++num_vecs;
+			}
 
-		for (S32 i = 0; i < num_vecs; i++)
-		{	
-			src.store4a(dst);
-			dst += 4;
-		}
+			for (S32 i = 0; i < num_vecs; i++)
+			{	
+				src.store4a(dst);
+				dst += 4;
+			}
 
-		if (map_range)
-		{
-			mVertexBuffer->flush();
+			if (map_range)
+			{
+				mVertexBuffer->flush();
+			}
 		}
 	}
+
 	if (rebuild_tcoord)
 	{
 		mTexExtents[0].setVec(0,0);
@@ -1932,12 +2136,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	}
 
 
-	mLastVertexBuffer = mVertexBuffer;
-	mLastGeomCount = mGeomCount;
-	mLastGeomIndex = mGeomIndex;
-	mLastIndicesCount = mIndicesCount;
-	mLastIndicesIndex = mIndicesIndex;
-
 	return TRUE;
 }
 
@@ -2516,7 +2714,6 @@ void LLFace::setVertexBuffer(LLVertexBuffer* buffer)
 void LLFace::clearVertexBuffer()
 {
 	mVertexBuffer = NULL;
-	mLastVertexBuffer = NULL;
 }
 
 //static
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 82e4ab61b7d9d5695afbe08f0c929327eca019e6..3babc13c2edffafa8d57a31bf3af2b9e8a00df93 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -79,10 +79,13 @@ class LLFace
 		USE_FACE_COLOR	= 0x0010,
 		TEXTURE_ANIM	= 0x0020, 
 		RIGGED			= 0x0040,
+		PARTICLE		= 0x0080,
 	};
 
 	static void initClass();
 
+	static void cacheFaceInVRAM(const LLVolumeFace& vf);
+
 public:
 	LLFace(LLDrawable* drawablep, LLViewerObject* objp)   { init(drawablep, objp); }
 	~LLFace()  { destroy(); }
@@ -222,7 +225,7 @@ class LLFace
 
 	//vertex buffer tracking
 	void setVertexBuffer(LLVertexBuffer* buffer);
-	void clearVertexBuffer(); //sets mVertexBuffer and mLastVertexBuffer to NULL
+	void clearVertexBuffer(); //sets mVertexBuffer to NULL
 	LLVertexBuffer* getVertexBuffer()	const	{ return mVertexBuffer; }
 	U32 getRiggedVertexBufferDataMask() const;
 	S32 getRiggedIndex(U32 type) const;
@@ -255,8 +258,7 @@ class LLFace
 
 private:
 	LLPointer<LLVertexBuffer> mVertexBuffer;
-	LLPointer<LLVertexBuffer> mLastVertexBuffer;
-	
+		
 	U32			mState;
 	LLFacePool*	mDrawPoolp;
 	U32			mPoolType;
@@ -269,12 +271,6 @@ class LLFace
 	U32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
 	S32         mIndexInTex ;
 
-	//previous rebuild's geometry info
-	U16			mLastGeomCount;
-	U16			mLastGeomIndex;
-	U32			mLastIndicesCount;
-	U32			mLastIndicesIndex;
-
 	LLXformMatrix* mXform;
 	LLPointer<LLViewerTexture> mTexture;
 	LLPointer<LLDrawable> mDrawablep;
diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp
index 575b613ccfcce44e41e09484073f2a19f2ffce0f..4cbc9cab4a1311628dcf1b88d9a68b3f0c0d5df9 100644
--- a/indra/newview/llfavoritesbar.cpp
+++ b/indra/newview/llfavoritesbar.cpp
@@ -1191,7 +1191,7 @@ void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata)
 	}
 	else if (action == "paste")
 	{
-		pastFromClipboard();
+		pasteFromClipboard();
 	}
 	else if (action == "delete")
 	{
@@ -1239,7 +1239,7 @@ BOOL LLFavoritesBarCtrl::isClipboardPasteable() const
 	return TRUE;
 }
 
-void LLFavoritesBarCtrl::pastFromClipboard() const
+void LLFavoritesBarCtrl::pasteFromClipboard() const
 {
 	LLInventoryModel* model = &gInventory;
 	if(model && isClipboardPasteable())
diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h
index 2f75b3bb0eec119a4b66a660c6dd4a2abd5ea656..447d30f1f41d299c455180780613794164df61de 100644
--- a/indra/newview/llfavoritesbar.h
+++ b/indra/newview/llfavoritesbar.h
@@ -90,7 +90,7 @@ class LLFavoritesBarCtrl : public LLUICtrl, public LLInventoryObserver
 	bool enableSelected(const LLSD& userdata);
 	void doToSelected(const LLSD& userdata);
 	BOOL isClipboardPasteable() const;
-	void pastFromClipboard() const;
+	void pasteFromClipboard() const;
 	
 	void showDropDownMenu();
 
diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index 32a533570a2669a06727b9f554109863d2604d85..c4dca4cb79beffd77e263f238d0cf3378a75abaf 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -65,7 +65,7 @@ LLVolumeImplFlexible::LLVolumeImplFlexible(LLViewerObject* vo, LLFlexibleObjectD
 	mFrameNum = 0;
 	mCollisionSphereRadius = 0.f;
 	mRenderRes = 1;
-
+	
 	if(mVO->mDrawable.notNull())
 	{
 		mVO->mDrawable->makeActive() ;
@@ -255,50 +255,28 @@ void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, cons
 {
 }
 
-//---------------------------------------------------------------------------------
-// This calculates the physics of the flexible object. Note that it has to be 0
-// updated every time step. In the future, perhaps there could be an 
-// optimization similar to what Havok does for objects that are stationary. 
-//---------------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies");
-BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
-{
-	if (mVO->mDrawable.isNull())
-	{
-		// Don't do anything until we have a drawable
-		return FALSE; // (we are not initialized or updated)
-	}
-
-	BOOL force_update = mSimulateRes == 0 ? TRUE : FALSE;
 
-	//flexible objects never go static
-	mVO->mDrawable->mQuietCount = 0;
-	if (!mVO->mDrawable->isRoot())
-	{
-		LLViewerObject* parent = (LLViewerObject*) mVO->getParent();
-		parent->mDrawable->mQuietCount = 0;
-	}
+void LLVolumeImplFlexible::updateRenderRes()
+{
+	LLDrawable* drawablep = mVO->mDrawable;
 
-	LLFastTimer ftm(FTM_FLEXIBLE_UPDATE);
-		
 	S32 new_res = mAttributes->getSimulateLOD();
 
-	//number of segments only cares about z axis
-	F32 app_angle = llround((F32) atan2( mVO->getScale().mV[2]*2.f, mVO->mDrawable->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
+#if 1 //optimal approximation of previous behavior that doesn't rely on atan2
+	F32 app_angle = mVO->getScale().mV[2]/drawablep->mDistanceWRTCamera;
 
 	// Rendering sections increases with visible angle on the screen
-	mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/LLViewerCamera::getInstance()->getView());
-	if (mRenderRes > FLEXIBLE_OBJECT_MAX_SECTIONS)
-	{
-		mRenderRes = FLEXIBLE_OBJECT_MAX_SECTIONS;
-	}
-
+	mRenderRes = (S32) (12.f*app_angle);
+#else //legacy behavior
+	//number of segments only cares about z axis
+	F32 app_angle = llround((F32) atan2( mVO->getScale().mV[2]*2.f, drawablep->mDistanceWRTCamera) * RAD_TO_DEG, 0.01f);
 
-	// Bottom cap at 1/4 the original number of sections
-	if (mRenderRes < mAttributes->getSimulateLOD()-1)
-	{
-		mRenderRes = mAttributes->getSimulateLOD()-1;
-	}
+ 	// Rendering sections increases with visible angle on the screen
+	mRenderRes = (S32)(FLEXIBLE_OBJECT_MAX_SECTIONS*4*app_angle*DEG_TO_RAD/LLViewerCamera::getInstance()->getView());
+#endif
+		
+	mRenderRes = llclamp(mRenderRes, new_res-1, (S32) FLEXIBLE_OBJECT_MAX_SECTIONS);
+		
 	// Throttle back simulation of segments we're not rendering
 	if (mRenderRes < new_res)
 	{
@@ -311,43 +289,65 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6
 		setAttributesOfAllSections();
 		mInitialized = TRUE;
 	}
-	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE))
-	{
-		return FALSE; // (we are not initialized or updated)
-	}
-
-	bool visible = mVO->mDrawable->isVisible();
+}
+//---------------------------------------------------------------------------------
+// This calculates the physics of the flexible object. Note that it has to be 0
+// updated every time step. In the future, perhaps there could be an 
+// optimization similar to what Havok does for objects that are stationary. 
+//---------------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies");
+void LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
+{
+	LLDrawable* drawablep = mVO->mDrawable;
 
-	if (force_update && visible)
+	if (drawablep)
 	{
-		gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE);
-	}
-	else if	(visible &&
-		!mVO->mDrawable->isState(LLDrawable::IN_REBUILD_Q1) &&
-		mVO->getPixelArea() > 256.f)
-	{
-		U32 id;
-		F32 pixel_area = mVO->getPixelArea();
+		//LLFastTimer ftm(FTM_FLEXIBLE_UPDATE);
 
-		if (mVO->isRootEdit())
+		//flexible objects never go static
+		drawablep->mQuietCount = 0;
+		if (!drawablep->isRoot())
 		{
-			id = mID;
+			LLViewerObject* parent = (LLViewerObject*) mVO->getParent();
+			parent->mDrawable->mQuietCount = 0;
 		}
-		else
+
+		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE))
 		{
-			LLVOVolume* parent = (LLVOVolume*) mVO->getParent();
-			id = parent->getVolumeInterfaceID();
-		}
+			bool visible = drawablep->isVisible();
 
-		U32 update_period = (U32) (LLViewerCamera::getInstance()->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f)))+1;
+			if ((mSimulateRes == 0) && visible)
+			{
+				updateRenderRes();
+				gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION, FALSE);
+			}
+			else if	(visible &&
+				!drawablep->isState(LLDrawable::IN_REBUILD_Q1) &&
+				mVO->getPixelArea() > 256.f)
+			{
+				U32 id;
+				F32 pixel_area = mVO->getPixelArea();
 
-		if ((LLDrawable::getCurrentFrame()+id)%update_period == 0)
-		{
-			gPipeline.markRebuild(mVO->mDrawable, LLDrawable::REBUILD_POSITION, FALSE);
+				if (mVO->isRootEdit())
+				{
+					id = mID;
+				}
+				else
+				{
+					LLVOVolume* parent = (LLVOVolume*) mVO->getParent();
+					id = parent->getVolumeInterfaceID();
+				}
+
+				U32 update_period = (U32) (LLViewerCamera::getInstance()->getScreenPixelArea()*0.01f/(pixel_area*(sUpdateFactor+1.f)))+1;
+
+				if ((LLDrawable::getCurrentFrame()+id)%update_period == 0)
+				{
+					updateRenderRes();
+					gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_POSITION, FALSE);
+				}
+			}
 		}
 	}
-	
-	return force_update;
 }
 
 inline S32 log2(S32 x)
@@ -368,8 +368,10 @@ void LLVolumeImplFlexible::doFlexibleUpdate()
 	LLPath *path = &volume->getPath();
 	if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) 
 	{
-		mVO->markForUpdate(TRUE);
-		if (!doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0))
+		//mVO->markForUpdate(TRUE);
+		doIdleUpdate(gAgent, *LLWorld::getInstance(), 0.0);
+
+		if (mSimulateRes == 0)
 		{
 			return;	// we did not get updated or initialized, proceeding without can be dangerous
 		}
@@ -729,7 +731,11 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable)
 	else if (!mUpdated || rotated)
 	{
 		volume->mDrawable->setState(LLDrawable::REBUILD_POSITION);
-		volume->dirtyMesh();
+		LLSpatialGroup* group = volume->mDrawable->getSpatialGroup();
+		if (group)
+		{
+			group->dirtyMesh();
+		}
 		volume->genBBoxes(isVolumeGlobal());
 	}
 			
@@ -814,15 +820,17 @@ LLQuaternion LLVolumeImplFlexible::getEndRotation()
 }//------------------------------------------------------------------
 
 
-void LLVolumeImplFlexible::updateRelativeXform()
+void LLVolumeImplFlexible::updateRelativeXform(bool force_identity)
 {
 	LLQuaternion delta_rot;
 	LLVector3 delta_pos, delta_scale;
 	LLVOVolume* vo = (LLVOVolume*) mVO;
 
+	bool use_identity = vo->mDrawable->isSpatialRoot() || force_identity;
+
 	//matrix from local space to parent relative/global space
-	delta_rot = vo->mDrawable->isSpatialRoot() ? LLQuaternion() : vo->mDrawable->getRotation();
-	delta_pos = vo->mDrawable->isSpatialRoot() ? LLVector3(0,0,0) : vo->mDrawable->getPosition();
+	delta_rot = use_identity ? LLQuaternion() : vo->mDrawable->getRotation();
+	delta_pos = use_identity ? LLVector3(0,0,0) : vo->mDrawable->getPosition();
 	delta_scale = LLVector3(1,1,1);
 
 	// Vertex transform (4x4)
diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h
index fef43d464d2dccb9dbffe439effe1246a0e8f514..56d579d86f940eb48b824499faddebdeba0174f6 100644
--- a/indra/newview/llflexibleobject.h
+++ b/indra/newview/llflexibleobject.h
@@ -78,7 +78,8 @@ class LLVolumeImplFlexible : public LLVolumeInterface
 		LLVector3 getFramePosition() const;
 		LLQuaternion getFrameRotation() const;
 		LLVolumeInterfaceType getInterfaceType() const		{ return INTERFACE_FLEXIBLE; }
-		BOOL doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
+		void updateRenderRes();
+		void doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 		BOOL doUpdateGeometry(LLDrawable *drawable);
 		LLVector3 getPivotPosition() const;
 		void onSetVolume(const LLVolumeParams &volume_params, const S32 detail);
@@ -89,7 +90,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface
 		bool isVolumeGlobal() const { return true; }
 		bool isActive() const { return true; }
 		const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const;
-		void updateRelativeXform();
+		void updateRelativeXform(bool force_identity);
 		void doFlexibleUpdate(); // Called to update the simulation
 		void doFlexibleRebuild(); // Called to rebuild the geometry
 		void preRebuild();
@@ -128,7 +129,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface
 		LLVector3					mCollisionSpherePosition;
 		F32							mCollisionSphereRadius;
 		U32							mID;
-
+		
 		//--------------------------------------
 		// private methods
 		//--------------------------------------
diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp
index bca4b5e447188a64526b73266771923ac3e2b194..809d344d0162a1bbcc9aa56c68967ed5f315476d 100644
--- a/indra/newview/llfloaterbuycontents.cpp
+++ b/indra/newview/llfloaterbuycontents.cpp
@@ -211,8 +211,8 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj,
 
 		BOOL item_is_multi = FALSE;
 		if ((inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED
-			|| inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
-			&& !(inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK))
+		     || inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
+		     && !(inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK))
 		{
 			item_is_multi = TRUE;
 		}
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index ac33a05f425a1d36064d2efd5d2989489bf9d314..fa0ad20fdb09a310f5170f68f0513f321cc4e83c 100644
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -1124,9 +1124,13 @@ BOOL	LLPreviewAnimation::render()
 		LLVertexBuffer::unbind();
 		LLGLDepthTest gls_depth(GL_TRUE);
 
-		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool();
-		avatarp->dirtyMesh();
-		avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
+		LLFace* face = avatarp->mDrawable->getFace(0);
+		if (face)
+		{
+			LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)face->getPool();
+			avatarp->dirtyMesh();
+			avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
+		}
 	}
 
 	gGL.color4f(1,1,1,1);
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 92ee8ddac6a54dc94d8519b1d787fd481c9bead9..6b2492d92758096e08d7427ecd41f55736b5e515 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -704,9 +704,13 @@ BOOL LLImagePreviewAvatar::render()
 		// make sure alpha=0 shows avatar material color
 		LLGLDisable no_blend(GL_BLEND);
 
-		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)avatarp->mDrawable->getFace(0)->getPool();
-		gPipeline.enableLightsPreview();
-		avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
+		LLFace* face = avatarp->mDrawable->getFace(0);
+		if (face)
+		{
+			LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)face->getPool();
+			gPipeline.enableLightsPreview();
+			avatarPoolp->renderAvatars(avatarp);  // renders only one avatar
+		}
 	}
 
 	gGL.popUIMatrix();
diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp
index ee18c95b34745f00afbb1bda96268608aa953f58..cc7c9a5bdabc931e5166035b4dbeedbdfb9e8fb4 100644
--- a/indra/newview/llfloaterland.cpp
+++ b/indra/newview/llfloaterland.cpp
@@ -1901,6 +1901,7 @@ BOOL LLPanelLandOptions::postBuild()
 		mSnapshotCtrl->setCommitCallback( onCommitAny, this );
 		mSnapshotCtrl->setAllowNoTexture ( TRUE );
 		mSnapshotCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+		mSnapshotCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
 		mSnapshotCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
 	}
 	else
@@ -2226,8 +2227,8 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata)
 	BOOL allow_damage		= !self->mCheckSafe->get();
 	BOOL allow_fly			= self->mCheckFly->get();
 	BOOL allow_landmark		= TRUE; // cannot restrict landmark creation
-	BOOL allow_group_scripts	= self->mCheckGroupScripts->get() || self->mCheckOtherScripts->get();
 	BOOL allow_other_scripts	= self->mCheckOtherScripts->get();
+	BOOL allow_group_scripts	= self->mCheckGroupScripts->get() || allow_other_scripts;
 	BOOL allow_publish		= FALSE;
 	BOOL mature_publish		= self->mMatureCtrl->get();
 	BOOL push_restriction	= self->mPushRestrictionCtrl->get();
@@ -2240,11 +2241,16 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata)
 	LLViewerRegion* region;
 	region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
 
-	if (!allow_other_scripts && region && region->getAllowDamage())
-	{
-
-		LLNotificationsUtil::add("UnableToDisableOutsideScripts");
-		return;
+	if (region && region->getAllowDamage())
+	{	// Damage is allowed on the region - server will always allow scripts
+		if ( (!allow_other_scripts && parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS)) ||
+			 (!allow_group_scripts && parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS)) )
+		{	// Don't allow turning off "Run Scripts" if damage is allowed in the region
+			self->mCheckOtherScripts->set(parcel->getParcelFlag(PF_ALLOW_OTHER_SCRIPTS));	// Restore UI to actual settings
+			self->mCheckGroupScripts->set(parcel->getParcelFlag(PF_ALLOW_GROUP_SCRIPTS));
+			LLNotificationsUtil::add("UnableToDisableOutsideScripts");
+			return;
+		}
 	}
 
 	// Push data into current parcel
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 7448f2bb2a9fc5ade568d00f43c4ba45de0a393f..40d2157e285f17485a5ab88e59f6a4fb9f0989af 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -396,7 +396,6 @@ mCalculateBtn(NULL)
 	sInstance = this;
 	mLastMouseX = 0;
 	mLastMouseY = 0;
-	mGLName = 0;
 	mStatusLock = new LLMutex(NULL);
 	mModelPreview = NULL;
 
@@ -538,11 +537,6 @@ LLFloaterModelPreview::~LLFloaterModelPreview()
 		delete mModelPreview;
 	}
 
-	if (mGLName)
-	{
-		LLImageGL::deleteTextures(1, &mGLName );
-	}
-
 	delete mStatusLock;
 	mStatusLock = NULL;
 }
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 64324854a55e82415ce91c0f8afb1d8498cc5f21..981f9b0f72de0194cc00334cb29b62a4112c8430 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -256,7 +256,6 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase
 	S32				mLastMouseX;
 	S32				mLastMouseY;
 	LLRect			mPreviewRect;
-	U32				mGLName;
 	static S32		sUploadAmount;
 	
 	std::set<LLPointer<DecompRequest> > mCurRequest;
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index 1fa194ab1918b41bb8d9a1c01ff1c1113ef2bf8c..0965b7b533de821e09cb3d2ef0d26f48082539a3 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -2236,12 +2236,16 @@ void LLFolderView::doIdle()
 		arrangeAll();
 	}
 
+	mNeedsAutoSelect = mFilter->hasFilterString() &&
+							!(gFocusMgr.childHasKeyboardFocus(this) || gFocusMgr.getMouseCapture());
+
+		
 	if (mFilter->isModified() && mFilter->isNotDefault())
 	{
 		mNeedsAutoSelect = TRUE;
 	}
 	mFilter->clearModified();
-
+			
 	// filter to determine visibility before arranging
 	filterFromRoot();
 
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 8092f3bf36bbcfe7cf5898847b4532ca9dbe503a..6e23d7c70139e5ed863067121f224af7d68032ac 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -822,6 +822,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item)
 			{
 				parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
 				new_item->setParent(parent_id);
+				LLInventoryModel::update_list_t update;
+				LLInventoryModel::LLCategoryUpdate new_folder(parent_id, 1);
+				update.push_back(new_folder);
+				accountForUpdate(update);
+
 			}
 			item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id);
 			if(item_array)
diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp
index 3a88fbd96deab76c4a0a8811d5f5497071cc6f43..f8088d04b406c67deefc248fe960c79848801fa4 100644
--- a/indra/newview/llmaniptranslate.cpp
+++ b/indra/newview/llmaniptranslate.cpp
@@ -60,6 +60,7 @@
 #include "llworld.h"
 #include "llui.h"
 #include "pipeline.h"
+#include "llviewershadermgr.h"
 
 const S32 NUM_AXES = 3;
 const S32 MOUSE_DRAG_SLOP = 2;       // pixels
@@ -1580,7 +1581,11 @@ void LLManipTranslate::renderSnapGuides()
 					LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GREATER);
 					LLGLEnable stipple(GL_LINE_STIPPLE);
 					gGL.flush();
-					glLineStipple(1, 0x3333);
+
+					if (!LLGLSLShader::sNoFixedFunction)
+					{
+						glLineStipple(1, 0x3333);
+					}
 		
 					switch (mManipPart)
 					{
@@ -1645,17 +1650,28 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 											 LLQuaternion grid_rotation, 
 											 LLColor4 inner_color)
 {
-	if (!gSavedSettings.getBOOL("GridCrossSections"))
+	if (!gSavedSettings.getBOOL("GridCrossSections") || !LLGLSLShader::sNoFixedFunction)
 	{
 		return;
 	}
 	
+	
+	LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+
+	
 	U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_ALPHA, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY };
 	U32 num_types = LL_ARRAY_SIZE(types);
 
 	GLuint stencil_mask = 0xFFFFFFFF;
 	//stencil in volumes
+
 	gGL.flush();
+
+	if (shader)
+	{
+		gClipProgram.bind();
+	}
+		
 	{
 		glStencilMask(stencil_mask);
 		glClearStencil(1);
@@ -1666,6 +1682,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 		glStencilFunc(GL_ALWAYS, 0, stencil_mask);
 		gGL.setColorMask(false, false);
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
 		gGL.diffuseColor4f(1,1,1,1);
 
 		//setup clip plane
@@ -1675,10 +1692,12 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 			normal = -normal;
 		}
 		F32 d = -(selection_center * normal);
-		F64 plane[] = { normal.mV[0], normal.mV[1], normal.mV[2], d };
-		LLGLEnable clip(GL_CLIP_PLANE0);
-		glClipPlane(GL_CLIP_PLANE0, plane);
+		glh::vec4f plane(normal.mV[0], normal.mV[1], normal.mV[2], d );
+
+		gGL.getModelviewMatrix().inverse().mult_vec_matrix(plane);
 
+		gClipProgram.uniform4fv("clip_plane", 1, plane.v);
+		
 		BOOL particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
 		BOOL clouds = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS);
 		
@@ -1729,6 +1748,11 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal,
 	F32 sz = mGridSizeMeters;
 	F32 tiles = sz;
 
+	if (shader)
+	{
+		shader->bind();
+	}
+
 	//draw volume/plane intersections
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index c899e8991e195360d0aa89cf7ed10408068f26a8..bc7f522848e8423c61efe10037ef7eb79d982797 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1659,7 +1659,7 @@ void LLMeshUploadThread::requestWholeModelFee()
 		mCurlRequest->process();
 		//sleep for 10ms to prevent eating a whole core
 		apr_sleep(10000);
-	} while (mCurlRequest->getQueued() > 0);
+	} while (!LLApp::isQuitting() && mCurlRequest->getQueued() > 0);
 
 	delete mCurlRequest;
 	mCurlRequest = NULL;
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 03404e816b11a2581e81707c1a39bf563787e36f..d58d6d536c0da5580cab4187b411af7989f0f6e2 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -574,6 +574,7 @@ static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const L
                 texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture);
                 // Don't allow (no copy) or (notransfer) textures to be selected.
                 texture_ctrl->setImmediateFilterPermMask(PERM_NONE);
+                texture_ctrl->setDnDFilterPermMask(PERM_NONE);
                 texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);
         }
 }
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 7301b305b2d54182110e48c6caf68e360a47c379..3e298054466bbc367ce90cd60252ad9882270193 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -38,6 +38,7 @@
 #include "llfontgl.h"
 
 // project includes
+#include "llagentdata.h"
 #include "llbutton.h"
 #include "llcheckboxctrl.h"
 #include "llcolorswatch.h"
@@ -46,6 +47,7 @@
 #include "llface.h"
 #include "lllineeditor.h"
 #include "llmediaentry.h"
+#include "llnotificationsutil.h"
 #include "llresmgr.h"
 #include "llselectmgr.h"
 #include "llspinctrl.h"
@@ -104,27 +106,11 @@ BOOL	LLPanelFace::postBuild()
 		mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) );
 		mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) );
 		mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2));
+		mTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1));
 		mTextureCtrl->setFollowsTop();
 		mTextureCtrl->setFollowsLeft();
-		// Don't allow (no copy) or (no transfer) textures to be selected during immediate mode
-		mTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
-		// Allow any texture to be used during non-immediate mode.
-		mTextureCtrl->setNonImmediateFilterPermMask(PERM_NONE);
-		LLAggregatePermissions texture_perms;
-		if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms))
-		{
-			BOOL can_copy = 
-				texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || 
-				texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL;
-			BOOL can_transfer = 
-				texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || 
-				texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL;
-			mTextureCtrl->setCanApplyImmediately(can_copy && can_transfer);
-		}
-		else
-		{
-			mTextureCtrl->setCanApplyImmediately(FALSE);
-		}
+		mTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+		mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
 	}
 
 	mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
@@ -595,28 +581,6 @@ void LLPanelFace::getState()
 		}
 
 		
-		LLAggregatePermissions texture_perms;
-		if(texture_ctrl)
-		{
-// 			texture_ctrl->setValid( editable );
-		
-			if (LLSelectMgr::getInstance()->selectGetAggregateTexturePermissions(texture_perms))
-			{
-				BOOL can_copy = 
-					texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY || 
-					texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL;
-				BOOL can_transfer = 
-					texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY || 
-					texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL;
-				texture_ctrl->setCanApplyImmediately(can_copy && can_transfer);
-			}
-			else
-			{
-				texture_ctrl->setCanApplyImmediately(FALSE);
-			}
-		}
-
-
 		// planar align
 		bool align_planar = false;
 		bool identical_planar_aligned = false;
@@ -1190,3 +1154,35 @@ void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata)
 	self->sendTextureInfo();
 }
 
+void LLPanelFace::onTextureSelectionChanged(LLInventoryItem* itemp)
+{
+	LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control");
+	if (texture_ctrl)
+	{
+		LLUUID obj_owner_id;
+		std::string obj_owner_name;
+		LLSelectMgr::instance().selectGetOwner(obj_owner_id, obj_owner_name);
+
+		LLSaleInfo sale_info;
+		LLSelectMgr::instance().selectGetSaleInfo(sale_info);
+
+		bool can_copy = itemp->getPermissions().allowCopyBy(gAgentID); // do we have perm to copy this texture?
+		bool can_transfer = itemp->getPermissions().allowOperationBy(PERM_TRANSFER, gAgentID); // do we have perm to transfer this texture?
+		bool is_object_owner = gAgentID == obj_owner_id; // does object for which we are going to apply texture belong to the agent?
+		bool not_for_sale = !sale_info.isForSale(); // is object for which we are going to apply texture not for sale?
+
+		if (can_copy && can_transfer)
+		{
+			texture_ctrl->setCanApply(true, true);
+			return;
+		}
+
+		// if texture has (no-transfer) attribute it can be applied only for object which we own and is not for sale
+		texture_ctrl->setCanApply(false, can_transfer ? true : is_object_owner && not_for_sale);
+
+		if (gSavedSettings.getBOOL("TextureLivePreview"))
+		{
+			LLNotificationsUtil::add("LivePreviewUnavailable");
+		}
+	}
+}
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 42be9b257f9b0e21938d40a14214255dc72f4090..3b5a9b1398c8d0fb111abb67215f8664cf1735c8 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -91,6 +91,15 @@ class LLPanelFace : public LLPanel
 	static void		onClickAutoFix(void*);
 	static F32      valueGlow(LLViewerObject* object, S32 face);
 
+private:
+
+	/*
+	 * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object.
+	 * If agent selects texture which is not allowed to be applied for the currently selected object,
+	 * all controls of the floater texture picker which allow to apply the texture will be disabled.
+	 */
+	void onTextureSelectionChanged(LLInventoryItem* itemp);
+
 };
 
 #endif
diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp
index b3adfac8a246eb87737c567e4438220209cf3d76..26cd3ff1c19b509fe65cf726258b6bec772b6d96 100644
--- a/indra/newview/llpanellandmedia.cpp
+++ b/indra/newview/llpanellandmedia.cpp
@@ -85,6 +85,7 @@ BOOL LLPanelLandMedia::postBuild()
 	mMediaTextureCtrl->setCommitCallback( onCommitAny, this );
 	mMediaTextureCtrl->setAllowNoTexture ( TRUE );
 	mMediaTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+	mMediaTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
 	mMediaTextureCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
 
 	mMediaAutoScaleCheck = getChild<LLCheckBoxCtrl>("media_auto_scale");
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 1f77e7a602e069fd5b0e761b69c9379c8a857265..7dfe529b73f373569d4adda1fe269ce83cd70816 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -245,6 +245,7 @@ BOOL	LLPanelObject::postBuild()
 		mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 ));
 		// Don't allow (no copy) or (no transfer) textures to be selected during immediate mode
 		mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+		mCtrlSculptTexture->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
 		// Allow any texture to be used during non-immediate mode.
 		mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE);
 		LLAggregatePermissions texture_perms;
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index e124916c48095131afcec1dc09e9bb0e78a02139..cb6989c9dde1c42c7bb8c1d1a084ab36c573b515 100644
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -67,6 +67,19 @@ inline F64 llsgn(const F64 a)
 class LLPhysicsMotion
 {
 public:
+	typedef enum
+	{
+		SMOOTHING = 0,
+		MASS,
+		GRAVITY,
+		SPRING,
+		GAIN,
+		DAMPING,
+		DRAG,
+		MAX_EFFECT,
+		NUM_PARAMS
+	} eParamName;
+
         /*
           param_driver_name: The param that controls the params that are being affected by the physics.
           joint_name: The joint that the body part is attached to.  The joint is
@@ -98,6 +111,11 @@ class LLPhysicsMotion
                 mPositionLastUpdate_local(0)
         {
                 mJointState = new LLJointState;
+
+				for (U32 i = 0; i < NUM_PARAMS; ++i)
+				{
+					mParamCache[i] = NULL;
+				}
         }
 
         BOOL initialize();
@@ -111,16 +129,43 @@ class LLPhysicsMotion
                 return mJointState;
         }
 protected:
-        F32 getParamValue(const std::string& controller_key)
-        {
-                const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key);
+
+		F32 getParamValue(eParamName param)
+		{
+			static std::string controller_key[] = 
+			{
+				"Smoothing",
+				"Mass",
+				"Gravity",
+				"Spring",
+				"Gain",
+				"Damping",
+				"Drag",
+				"MaxEffect"
+			};
+
+			if (!mParamCache[param])
+			{
+				const controller_map_t::const_iterator& entry = mParamControllers.find(controller_key[param]);
                 if (entry == mParamControllers.end())
                 {
-                        return sDefaultController[controller_key];
+                        return sDefaultController[controller_key[param]];
                 }
                 const std::string& param_name = (*entry).second.c_str();
-                return mCharacter->getVisualParamWeight(param_name.c_str());
-        }
+                mParamCache[param] = mCharacter->getVisualParam(param_name.c_str());
+			}
+				
+			if (mParamCache[param])
+			{
+				return mParamCache[param]->getWeight();
+			}
+			else
+			{
+				return sDefaultController[controller_key[param]];
+			}
+		}
+
+        
         void setParamValue(LLViewerVisualParam *param,
                            const F32 new_value_local,
                                                    F32 behavior_maxeffect);
@@ -150,6 +195,8 @@ class LLPhysicsMotion
 
         F32 mLastTime;
         
+		LLVisualParam* mParamCache[NUM_PARAMS];
+
         static default_controller_map_t sDefaultController;
 };
 
@@ -427,7 +474,6 @@ BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask)
         return TRUE;
 }
 
-
 // Return TRUE if character has to update visual params.
 BOOL LLPhysicsMotion::onUpdate(F32 time)
 {
@@ -471,15 +517,16 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)
 
         LLJoint *joint = mJointState->getJoint();
 
-        const F32 behavior_mass = getParamValue("Mass");
-        const F32 behavior_gravity = getParamValue("Gravity");
-        const F32 behavior_spring = getParamValue("Spring");
-        const F32 behavior_gain = getParamValue("Gain");
-        const F32 behavior_damping = getParamValue("Damping");
-        const F32 behavior_drag = getParamValue("Drag");
-        const BOOL physics_test = FALSE; // Enable this to simulate bouncing on all parts.
+		const F32 behavior_mass = getParamValue(MASS);
+		const F32 behavior_gravity = getParamValue(GRAVITY);
+		const F32 behavior_spring = getParamValue(SPRING);
+		const F32 behavior_gain = getParamValue(GAIN);
+		const F32 behavior_damping = getParamValue(DAMPING);
+		const F32 behavior_drag = getParamValue(DRAG);
+		F32 behavior_maxeffect = getParamValue(MAX_EFFECT);
+		
+		const BOOL physics_test = FALSE; // Enable this to simulate bouncing on all parts.
         
-        F32 behavior_maxeffect = getParamValue("MaxEffect");
         if (physics_test)
                 behavior_maxeffect = 1.0f;
 
diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp
index 450f9b2be7238a61f594dee75d7a1a3416f3a46e..3baa1eccc804cf278e7acbb0a0f447b410a8d84b 100644
--- a/indra/newview/llpolymesh.cpp
+++ b/indra/newview/llpolymesh.cpp
@@ -229,15 +229,18 @@ U32 LLPolyMeshSharedData::getNumKB()
 BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
 {
         U32 i;
-        mBaseCoords = new LLVector3[ numVertices ];
-        mBaseNormals = new LLVector3[ numVertices ];
-        mBaseBinormals = new LLVector3[ numVertices ];
+        mBaseCoords = new LLVector4a[ numVertices ];
+        mBaseNormals = new LLVector4a[ numVertices ];
+        mBaseBinormals = new LLVector4a[ numVertices ];
         mTexCoords = new LLVector2[ numVertices ];
         mDetailTexCoords = new LLVector2[ numVertices ];
         mWeights = new F32[ numVertices ];
         for (i = 0; i < numVertices; i++)
         {
-                mWeights[i] = 0.f;
+			mBaseCoords[i].clear();
+			mBaseNormals[i].clear();
+			mBaseBinormals[i].clear();
+            mWeights[i] = 0.f;
         }
         mNumVertices = numVertices;
         return TRUE;
@@ -408,39 +411,47 @@ BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
 
                         allocateVertexData( numVertices );      
 
-                        //----------------------------------------------------------------
-                        // Coords
-                        //----------------------------------------------------------------
-                        numRead = fread(mBaseCoords, 3*sizeof(float), numVertices, fp);
-                        llendianswizzle(mBaseCoords, sizeof(float), 3*numVertices);
-                        if (numRead != numVertices)
-                        {
-                                llerrs << "can't read Coordinates from " << fileName << llendl;
-                                return FALSE;
-                        }
-
-                        //----------------------------------------------------------------
-                        // Normals
-                        //----------------------------------------------------------------
-                        numRead = fread(mBaseNormals, 3*sizeof(float), numVertices, fp);
-                        llendianswizzle(mBaseNormals, sizeof(float), 3*numVertices);
-                        if (numRead != numVertices)
-                        {
-                                llerrs << " can't read Normals from " << fileName << llendl;
-                                return FALSE;
-                        }
-
-                        //----------------------------------------------------------------
-                        // Binormals
-                        //----------------------------------------------------------------
-                        numRead = fread(mBaseBinormals, 3*sizeof(float), numVertices, fp);
-                        llendianswizzle(mBaseBinormals, sizeof(float), 3*numVertices);
-                        if (numRead != numVertices)
-                        {
-                                llerrs << " can't read Binormals from " << fileName << llendl;
-                                return FALSE;
-                        }
-
+						for (U16 i = 0; i < numVertices; ++i)
+						{
+							//----------------------------------------------------------------
+							// Coords
+							//----------------------------------------------------------------
+							numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp);
+							llendianswizzle(&mBaseCoords[i], sizeof(float), 3);
+							if (numRead != 3)
+							{
+									llerrs << "can't read Coordinates from " << fileName << llendl;
+									return FALSE;
+							}
+						}
+
+						for (U16 i = 0; i < numVertices; ++i)
+						{
+							//----------------------------------------------------------------
+							// Normals
+							//----------------------------------------------------------------
+							numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp);
+							llendianswizzle(&mBaseNormals[i], sizeof(float), 3);
+							if (numRead != 3)
+							{
+									llerrs << " can't read Normals from " << fileName << llendl;
+									return FALSE;
+							}
+						}
+
+						for (U16 i = 0; i < numVertices; ++i)
+						{
+							//----------------------------------------------------------------
+							// Binormals
+							//----------------------------------------------------------------
+							numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp);
+							llendianswizzle(&mBaseBinormals[i], sizeof(float), 3);
+							if (numRead != 3)
+							{
+									llerrs << " can't read Binormals from " << fileName << llendl;
+									return FALSE;
+							}
+						}
 
                         //----------------------------------------------------------------
                         // TexCoords
@@ -767,21 +778,28 @@ LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_
 	{
 		// Allocate memory without initializing every vector
 		// NOTE: This makes asusmptions about the size of LLVector[234]
-		int nverts = mSharedData->mNumVertices;
-		int nfloats = nverts * (2*4 + 3*3 + 2 + 4);
+		S32 nverts = mSharedData->mNumVertices;
+		//make sure it's an even number of verts for alignment
+		nverts += nverts%2;
+		S32 nfloats = nverts * (
+					4 + //coords
+					4 + //normals
+					4 + //weights
+					2 + //coords
+					4 + //scaled normals
+					4 + //binormals
+					4); //scaled binormals
+
 		//use 16 byte aligned vertex data to make LLPolyMesh SSE friendly
 		mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
-		int offset = 0;
-		mCoords				= 	(LLVector4*)(mVertexData + offset); offset += 4*nverts;
-		mNormals			=	(LLVector4*)(mVertexData + offset); offset += 4*nverts;
-		mClothingWeights	= 	(LLVector4*)(mVertexData + offset); offset += 4*nverts;
-		mTexCoords			= 	(LLVector2*)(mVertexData + offset); offset += 2*nverts;
-
-		// these members don't need to be 16-byte aligned, but the first one might be
-		// read during an aligned memcpy of mTexCoords
-		mScaledNormals =                (LLVector3*)(mVertexData + offset); offset += 3*nverts;
-		mBinormals =                    (LLVector3*)(mVertexData + offset); offset += 3*nverts;
-		mScaledBinormals =              (LLVector3*)(mVertexData + offset); offset += 3*nverts; 
+		S32 offset = 0;
+		mCoords				= 	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mNormals			=	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mClothingWeights	= 	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mTexCoords			= 	(LLVector2*)(mVertexData + offset);  offset += 2*nverts;
+		mScaledNormals		=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mBinormals			=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mScaledBinormals	=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts; 
 		initializeForMorph();
 	}
 }
@@ -906,7 +924,7 @@ void LLPolyMesh::dumpDiagInfo()
 //-----------------------------------------------------------------------------
 // getWritableCoords()
 //-----------------------------------------------------------------------------
-LLVector4 *LLPolyMesh::getWritableCoords()
+LLVector4a *LLPolyMesh::getWritableCoords()
 {
         return mCoords;
 }
@@ -914,7 +932,7 @@ LLVector4 *LLPolyMesh::getWritableCoords()
 //-----------------------------------------------------------------------------
 // getWritableNormals()
 //-----------------------------------------------------------------------------
-LLVector4 *LLPolyMesh::getWritableNormals()
+LLVector4a *LLPolyMesh::getWritableNormals()
 {
         return mNormals;
 }
@@ -922,7 +940,7 @@ LLVector4 *LLPolyMesh::getWritableNormals()
 //-----------------------------------------------------------------------------
 // getWritableBinormals()
 //-----------------------------------------------------------------------------
-LLVector3 *LLPolyMesh::getWritableBinormals()
+LLVector4a *LLPolyMesh::getWritableBinormals()
 {
         return mBinormals;
 }
@@ -931,7 +949,7 @@ LLVector3 *LLPolyMesh::getWritableBinormals()
 //-----------------------------------------------------------------------------
 // getWritableClothingWeights()
 //-----------------------------------------------------------------------------
-LLVector4       *LLPolyMesh::getWritableClothingWeights()
+LLVector4a       *LLPolyMesh::getWritableClothingWeights()
 {
         return mClothingWeights;
 }
@@ -947,7 +965,7 @@ LLVector2       *LLPolyMesh::getWritableTexCoords()
 //-----------------------------------------------------------------------------
 // getScaledNormals()
 //-----------------------------------------------------------------------------
-LLVector3 *LLPolyMesh::getScaledNormals()
+LLVector4a *LLPolyMesh::getScaledNormals()
 {
         return mScaledNormals;
 }
@@ -955,7 +973,7 @@ LLVector3 *LLPolyMesh::getScaledNormals()
 //-----------------------------------------------------------------------------
 // getScaledBinormals()
 //-----------------------------------------------------------------------------
-LLVector3 *LLPolyMesh::getScaledBinormals()
+LLVector4a *LLPolyMesh::getScaledBinormals()
 {
         return mScaledBinormals;
 }
@@ -966,17 +984,17 @@ LLVector3 *LLPolyMesh::getScaledBinormals()
 //-----------------------------------------------------------------------------
 void LLPolyMesh::initializeForMorph()
 {
-    for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
+    LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
+
+	for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
 	{
-		mCoords[i] = LLVector4(mSharedData->mBaseCoords[i]);
-		mNormals[i] = LLVector4(mSharedData->mBaseNormals[i]);
+		mClothingWeights[i].clear();
 	}
-
-	memcpy(mScaledNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices);	/*Flawfinder: ignore*/
-	memcpy(mBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices);	/*Flawfinder: ignore*/
-	memcpy(mScaledBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices);		/*Flawfinder: ignore*/
-	memcpy(mTexCoords, mSharedData->mTexCoords, sizeof(LLVector2) * mSharedData->mNumVertices);		/*Flawfinder: ignore*/
-	memset(mClothingWeights, 0, sizeof(LLVector4) * mSharedData->mNumVertices);
 }
 
 //-----------------------------------------------------------------------------
@@ -1098,7 +1116,7 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
 LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLVOAvatar *avatarp)
 {
         mAvatar = avatarp;
-        mDefaultVec.setVec(0.001f, 0.001f, 0.001f);
+        mDefaultVec.splat(0.001f);
 }
 
 //-----------------------------------------------------------------------------
@@ -1171,8 +1189,12 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
 //-----------------------------------------------------------------------------
 // apply()
 //-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
+
 void LLPolySkeletalDistortion::apply( ESex avatar_sex )
 {
+	LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
+
         F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
 
         LLJoint* joint;
@@ -1228,11 +1250,14 @@ LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
 {
         LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
         cloned_morph_data->mName = name;
+		LLVector4a dir;
+		dir.load3(direction.mV);
+
         for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
         {
-                cloned_morph_data->mCoords[v] = direction;
-                cloned_morph_data->mNormals[v] = LLVector3(0,0,0);
-                cloned_morph_data->mBinormals[v] = LLVector3(0,0,0);
+                cloned_morph_data->mCoords[v] = dir;
+                cloned_morph_data->mNormals[v].clear();
+                cloned_morph_data->mBinormals[v].clear();
         }
         return cloned_morph_data;
 }
@@ -1243,17 +1268,27 @@ LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
 {
         LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
         cloned_morph_data->mName = name;
+
+		LLVector4a sc;
+		sc.splat(scale);
+
+		LLVector4a nsc;
+		nsc.set(scale, -scale, scale, scale);
+
         for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
         {
-                cloned_morph_data->mCoords[v] = src_data->mCoords[v]*scale;
-                cloned_morph_data->mNormals[v] = src_data->mNormals[v]*scale;
-                cloned_morph_data->mBinormals[v] = src_data->mBinormals[v]*scale;
-                if (cloned_morph_data->mCoords[v][1] < 0)
-                {
-                        cloned_morph_data->mCoords[v][1] *= -1;
-                        cloned_morph_data->mNormals[v][1] *= -1;
-                        cloned_morph_data->mBinormals[v][1] *= -1;
-                }
+            if (cloned_morph_data->mCoords[v][1] < 0)
+            {
+                cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
+				cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
+				cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
+			}
+			else
+			{
+				cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
+				cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
+				cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
+			}
         }
         return cloned_morph_data;
 }
diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h
index ba2bf85570379834083d498a7adef65c4cf6dee9..ffb11a3f7ea7261590b8e74e3f681ca40a7c7f7f 100644
--- a/indra/newview/llpolymesh.h
+++ b/indra/newview/llpolymesh.h
@@ -73,9 +73,9 @@ class LLPolyMeshSharedData
 							
 	// vertex data			
 	S32						mNumVertices;
-	LLVector3				*mBaseCoords;
-	LLVector3				*mBaseNormals;
-	LLVector3				*mBaseBinormals;
+	LLVector4a				*mBaseCoords;
+	LLVector4a				*mBaseNormals;
+	LLVector4a				*mBaseBinormals;
 	LLVector2				*mTexCoords;
 	LLVector2				*mDetailTexCoords;
 	F32						*mWeights;
@@ -217,41 +217,41 @@ class LLPolyMesh
 	}
 
 	// Get coords
-	const LLVector4	*getCoords() const{
+	const LLVector4a	*getCoords() const{
 		return mCoords;
 	}
 
 	// non const version
-	LLVector4 *getWritableCoords();
+	LLVector4a *getWritableCoords();
 
 	// Get normals
-	const LLVector4	*getNormals() const{ 
+	const LLVector4a	*getNormals() const{ 
 		return mNormals; 
 	}
 
 	// Get normals
-	const LLVector3	*getBinormals() const{ 
+	const LLVector4a	*getBinormals() const{ 
 		return mBinormals; 
 	}
 
 	// Get base mesh normals
-	const LLVector3 *getBaseNormals() const{
+	const LLVector4a *getBaseNormals() const{
 		llassert(mSharedData);
 		return mSharedData->mBaseNormals;
 	}
 
 	// Get base mesh normals
-	const LLVector3 *getBaseBinormals() const{
+	const LLVector4a *getBaseBinormals() const{
 		llassert(mSharedData);
 		return mSharedData->mBaseBinormals;
 	}
 
 	// intermediate morphed normals and output normals
-	LLVector4 *getWritableNormals();
-	LLVector3 *getScaledNormals();
+	LLVector4a *getWritableNormals();
+	LLVector4a *getScaledNormals();
 
-	LLVector3 *getWritableBinormals();
-	LLVector3 *getScaledBinormals();
+	LLVector4a *getWritableBinormals();
+	LLVector4a *getScaledBinormals();
 
 	// Get texCoords
 	const LLVector2	*getTexCoords() const { 
@@ -275,9 +275,9 @@ class LLPolyMesh
 
 	F32			*getWritableWeights() const;
 
-	LLVector4	*getWritableClothingWeights();
+	LLVector4a	*getWritableClothingWeights();
 
-	const LLVector4		*getClothingWeights()
+	const LLVector4a		*getClothingWeights()
 	{
 		return mClothingWeights;	
 	}
@@ -341,17 +341,17 @@ class LLPolyMesh
 	// Single array of floats for allocation / deletion
 	F32						*mVertexData;
 	// deformed vertices (resulting from application of morph targets)
-	LLVector4				*mCoords;
+	LLVector4a				*mCoords;
 	// deformed normals (resulting from application of morph targets)
-	LLVector3				*mScaledNormals;
+	LLVector4a				*mScaledNormals;
 	// output normals (after normalization)
-	LLVector4				*mNormals;
+	LLVector4a				*mNormals;
 	// deformed binormals (resulting from application of morph targets)
-	LLVector3				*mScaledBinormals;
+	LLVector4a				*mScaledBinormals;
 	// output binormals (after normalization)
-	LLVector3				*mBinormals;
+	LLVector4a				*mBinormals;
 	// weight values that mark verts as clothing/skin
-	LLVector4				*mClothingWeights;
+	LLVector4a				*mClothingWeights;
 	// output texture coordinates
 	LLVector2				*mTexCoords;
 	
@@ -419,17 +419,17 @@ class LLPolySkeletalDistortion : public LLViewerVisualParam
 	
 	// LLViewerVisualParam Virtual functions
 	/*virtual*/ F32					getTotalDistortion() { return 0.1f; }
-	/*virtual*/ const LLVector3&	getAvgDistortion()	{ return mDefaultVec; }
+	/*virtual*/ const LLVector4a&	getAvgDistortion()	{ return mDefaultVec; }
 	/*virtual*/ F32					getMaxDistortion() { return 0.1f; }
-	/*virtual*/ LLVector3			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector3(0.001f, 0.001f, 0.001f);}
-	/*virtual*/ const LLVector3*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
-	/*virtual*/ const LLVector3*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
+	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
+	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
+	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
 
 protected:
 	typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
 	joint_vec_map_t mJointScales;
 	joint_vec_map_t mJointOffsets;
-	LLVector3	mDefaultVec;
+	LLVector4a	mDefaultVec;
 	// Backlink only; don't make this an LLPointer.
 	LLVOAvatar *mAvatar;
 };
diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp
index cefd7df3febf7d1496de7fa630aa53078e0adbe8..d25d1420ee07ad8e54c3451b03bee0ca19864265 100644
--- a/indra/newview/llpolymorph.cpp
+++ b/indra/newview/llpolymorph.cpp
@@ -48,7 +48,7 @@ LLPolyMorphData::LLPolyMorphData(const std::string& morph_name)
 	mNumIndices = 0;
 	mCurrentIndex = 0;
 	mTotalDistortion = 0.f;
-	mAvgDistortion.zeroVec();
+	mAvgDistortion.clear();
 	mMaxDistortion = 0.f;
 	mVertexIndices = NULL;
 	mCoords = NULL;
@@ -73,9 +73,9 @@ LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) :
 {
 	const S32 numVertices = mNumIndices;
 
-	mCoords = new LLVector3[numVertices];
-	mNormals = new LLVector3[numVertices];
-	mBinormals = new LLVector3[numVertices];
+	mCoords = new LLVector4a[numVertices];
+	mNormals = new LLVector4a[numVertices];
+	mBinormals = new LLVector4a[numVertices];
 	mTexCoords = new LLVector2[numVertices];
 	mVertexIndices = new U32[numVertices];
 	
@@ -121,16 +121,16 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
 	//-------------------------------------------------------------------------
 	// allocate vertices
 	//-------------------------------------------------------------------------
-	mCoords = new LLVector3[numVertices];
-	mNormals = new LLVector3[numVertices];
-	mBinormals = new LLVector3[numVertices];
+	mCoords = new LLVector4a[numVertices];
+	mNormals = new LLVector4a[numVertices];
+	mBinormals = new LLVector4a[numVertices];
 	mTexCoords = new LLVector2[numVertices];
 	// Actually, we are allocating more space than we need for the skiplist
 	mVertexIndices = new U32[numVertices];
 	mNumIndices = 0;
 	mTotalDistortion = 0.f;
 	mMaxDistortion = 0.f;
-	mAvgDistortion.zeroVec();
+	mAvgDistortion.clear();
 	mMesh = mesh;
 
 	//-------------------------------------------------------------------------
@@ -152,36 +152,36 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
 		}
 
 
-		numRead = fread(&mCoords[v].mV, sizeof(F32), 3, fp);
-		llendianswizzle(&mCoords[v].mV, sizeof(F32), 3);
+		numRead = fread(&mCoords[v], sizeof(F32), 3, fp);
+		llendianswizzle(&mCoords[v], sizeof(F32), 3);
 		if (numRead != 3)
 		{
 			llwarns << "Can't read morph target vertex coordinates" << llendl;
 			return FALSE;
 		}
 
-		F32 magnitude = mCoords[v].magVec();
+		F32 magnitude = mCoords[v].getLength3().getF32();
 		
 		mTotalDistortion += magnitude;
-		mAvgDistortion.mV[VX] += fabs(mCoords[v].mV[VX]);
-		mAvgDistortion.mV[VY] += fabs(mCoords[v].mV[VY]);
-		mAvgDistortion.mV[VZ] += fabs(mCoords[v].mV[VZ]);
+		LLVector4a t;
+		t.setAbs(mCoords[v]);
+		mAvgDistortion.add(t);
 		
 		if (magnitude > mMaxDistortion)
 		{
 			mMaxDistortion = magnitude;
 		}
 
-		numRead = fread(&mNormals[v].mV, sizeof(F32), 3, fp);
-		llendianswizzle(&mNormals[v].mV, sizeof(F32), 3);
+		numRead = fread(&mNormals[v], sizeof(F32), 3, fp);
+		llendianswizzle(&mNormals[v], sizeof(F32), 3);
 		if (numRead != 3)
 		{
 			llwarns << "Can't read morph target normal" << llendl;
 			return FALSE;
 		}
 
-		numRead = fread(&mBinormals[v].mV, sizeof(F32), 3, fp);
-		llendianswizzle(&mBinormals[v].mV, sizeof(F32), 3);
+		numRead = fread(&mBinormals[v], sizeof(F32), 3, fp);
+		llendianswizzle(&mBinormals[v], sizeof(F32), 3);
 		if (numRead != 3)
 		{
 			llwarns << "Can't read morph target binormal" << llendl;
@@ -200,8 +200,8 @@ BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
 		mNumIndices++;
 	}
 
-	mAvgDistortion = mAvgDistortion * (1.f/(F32)mNumIndices);
-	mAvgDistortion.normVec();
+	mAvgDistortion.mul(1.f/(F32)mNumIndices);
+	mAvgDistortion.normalize3fast();
 
 	return TRUE;
 }
@@ -367,9 +367,9 @@ BOOL LLPolyMorphTarget::parseData(LLXmlTreeNode* node)
 //-----------------------------------------------------------------------------
 // getVertexDistortion()
 //-----------------------------------------------------------------------------
-LLVector3 LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
+LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
 {
-	if (!mMorphData || mMesh != mesh) return LLVector3::zero;
+	if (!mMorphData || mMesh != mesh) return LLVector4a::getZero();
 
 	for(U32 index = 0; index < mMorphData->mNumIndices; index++)
 	{
@@ -379,17 +379,17 @@ LLVector3 LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh
 		}
 	}
 
-	return LLVector3::zero;
+	return LLVector4a::getZero();
 }
 
 //-----------------------------------------------------------------------------
 // getFirstDistortion()
 //-----------------------------------------------------------------------------
-const LLVector3 *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
+const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
 {
-	if (!mMorphData) return &LLVector3::zero;
+	if (!mMorphData) return &LLVector4a::getZero();
 
-	LLVector3* resultVec;
+	LLVector4a* resultVec;
 	mMorphData->mCurrentIndex = 0;
 	if (mMorphData->mNumIndices)
 	{
@@ -411,11 +411,11 @@ const LLVector3 *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **
 //-----------------------------------------------------------------------------
 // getNextDistortion()
 //-----------------------------------------------------------------------------
-const LLVector3 *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
+const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
 {
-	if (!mMorphData) return &LLVector3::zero;
+	if (!mMorphData) return &LLVector4a::getZero();
 
-	LLVector3* resultVec;
+	LLVector4a* resultVec;
 	mMorphData->mCurrentIndex++;
 	if (mMorphData->mCurrentIndex < mMorphData->mNumIndices)
 	{
@@ -451,7 +451,7 @@ F32	LLPolyMorphTarget::getTotalDistortion()
 //-----------------------------------------------------------------------------
 // getAvgDistortion()
 //-----------------------------------------------------------------------------
-const LLVector3& LLPolyMorphTarget::getAvgDistortion()	
+const LLVector4a& LLPolyMorphTarget::getAvgDistortion()	
 {
 	if (mMorphData) 
 	{
@@ -459,7 +459,7 @@ const LLVector3& LLPolyMorphTarget::getAvgDistortion()
 	}
 	else 
 	{
-		return LLVector3::zero;
+		return LLVector4a::getZero();
 	}
 }
 
@@ -481,6 +481,8 @@ F32	LLPolyMorphTarget::getMaxDistortion()
 //-----------------------------------------------------------------------------
 // apply()
 //-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_APPLY_MORPH_TARGET("Apply Morph");
+
 void LLPolyMorphTarget::apply( ESex avatar_sex )
 {
 	if (!mMorphData || mNumMorphMasksPending > 0)
@@ -488,6 +490,8 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 		return;
 	}
 
+	LLFastTimer t(FTM_APPLY_MORPH_TARGET);
+
 	mLastSex = avatar_sex;
 
 	// Check for NaN condition (NaN is detected if a variable doesn't equal itself.
@@ -508,15 +512,15 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 	if (delta_weight != 0.f)
 	{
 		llassert(!mMesh->isLOD());
-		LLVector4 *coords = mMesh->getWritableCoords();
+		LLVector4a *coords = mMesh->getWritableCoords();
 
-		LLVector3 *scaled_normals = mMesh->getScaledNormals();
-		LLVector4 *normals = mMesh->getWritableNormals();
+		LLVector4a *scaled_normals = mMesh->getScaledNormals();
+		LLVector4a *normals = mMesh->getWritableNormals();
 
-		LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
-		LLVector3 *binormals = mMesh->getWritableBinormals();
+		LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
+		LLVector4a *binormals = mMesh->getWritableBinormals();
 
-		LLVector4 *clothing_weights = mMesh->getWritableClothingWeights();
+		LLVector4a *clothing_weights = mMesh->getWritableClothingWeights();
 		LLVector2 *tex_coords = mMesh->getWritableTexCoords();
 
 		F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
@@ -531,31 +535,38 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 				maskWeight = maskWeightArray[vert_index_morph];
 			}
 
-			coords[vert_index_mesh] += LLVector4(mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight);
+
+			LLVector4a pos = mMorphData->mCoords[vert_index_morph];
+			pos.mul(delta_weight*maskWeight);
+			coords[vert_index_mesh].add(pos);
 
 			if (getInfo()->mIsClothingMorph && clothing_weights)
 			{
-				LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight;
-				LLVector4* clothing_weight = &clothing_weights[vert_index_mesh];
-				clothing_weight->mV[VX] += clothing_offset.mV[VX];
-				clothing_weight->mV[VY] += clothing_offset.mV[VY];
-				clothing_weight->mV[VZ] += clothing_offset.mV[VZ];
-				clothing_weight->mV[VW] = maskWeight;
+				LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph];
+				clothing_offset.mul(delta_weight * maskWeight);
+				LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh];
+				clothing_weight->add(clothing_offset);
+				clothing_weight->getF32ptr()[VW] = maskWeight;
 			}
 
 			// calculate new normals based on half angles
-			scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
-			LLVector3 normalized_normal = scaled_normals[vert_index_mesh];
-			normalized_normal.normVec();
-			normals[vert_index_mesh] = LLVector4(normalized_normal);
+			LLVector4a norm = mMorphData->mNormals[vert_index_morph];
+			norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
+			scaled_normals[vert_index_mesh].add(norm);
+			norm = scaled_normals[vert_index_mesh];
+			norm.normalize3fast();
+			normals[vert_index_mesh] = norm;
 
 			// calculate new binormals
-			scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
-			LLVector3 tangent = scaled_binormals[vert_index_mesh] % normalized_normal;
-			LLVector3 normalized_binormal = normalized_normal % tangent; 
-			normalized_binormal.normVec();
-			binormals[vert_index_mesh] = normalized_binormal;
-
+			LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
+			binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
+			scaled_binormals[vert_index_mesh].add(binorm);
+			LLVector4a tangent;
+			tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
+			LLVector4a& normalized_binormal = binormals[vert_index_mesh];
+			normalized_binormal.setCross3(norm, tangent); 
+			normalized_binormal.normalize3fast();
+			
 			tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
 		}
 
@@ -582,7 +593,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 //-----------------------------------------------------------------------------
 void	LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert)
 {
-	LLVector4 *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
+	LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
 
 	if (!mVertMask)
 	{
@@ -596,29 +607,47 @@ void	LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3
 
 		if (maskWeights)
 		{
-			LLVector4 *coords = mMesh->getWritableCoords();
-			LLVector3 *scaled_normals = mMesh->getScaledNormals();
-			LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
+			LLVector4a *coords = mMesh->getWritableCoords();
+			LLVector4a *scaled_normals = mMesh->getScaledNormals();
+			LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
 			LLVector2 *tex_coords = mMesh->getWritableTexCoords();
 
+			LLVector4Logical clothing_mask;
+			clothing_mask.clear();
+			clothing_mask.setElement<0>();
+			clothing_mask.setElement<1>();
+			clothing_mask.setElement<2>();
+
+
 			for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++)
 			{
 				F32 lastMaskWeight = mLastWeight * maskWeights[vert];
 				S32 out_vert = mMorphData->mVertexIndices[vert];
 
 				// remove effect of existing masked morph
-				coords[out_vert] -= LLVector4(mMorphData->mCoords[vert]) * lastMaskWeight;
-				scaled_normals[out_vert] -= mMorphData->mNormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
-				scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
+				LLVector4a t;
+				t = mMorphData->mCoords[vert];
+				t.mul(lastMaskWeight);
+				coords[out_vert].sub(t);
+
+				t = mMorphData->mNormals[vert];
+				t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
+				scaled_normals[out_vert].sub(t);
+
+				t = mMorphData->mBinormals[vert];
+				t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
+				scaled_binormals[out_vert].sub(t);
+
 				tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
 
 				if (clothing_weights)
 				{
-					LLVector3 clothing_offset = mMorphData->mCoords[vert] * lastMaskWeight;
-					LLVector4* clothing_weight = &clothing_weights[out_vert];
-					clothing_weight->mV[VX] -= clothing_offset.mV[VX];
-					clothing_weight->mV[VY] -= clothing_offset.mV[VY];
-					clothing_weight->mV[VZ] -= clothing_offset.mV[VZ];
+					LLVector4a clothing_offset = mMorphData->mCoords[vert];
+					clothing_offset.mul(lastMaskWeight);
+					LLVector4a* clothing_weight = &clothing_weights[out_vert];
+					LLVector4a t;
+					t.setSub(*clothing_weight, clothing_offset);
+					clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight);
 				}
 			}
 		}
@@ -654,7 +683,7 @@ LLPolyVertexMask::~LLPolyVertexMask()
 //-----------------------------------------------------------------------------
 // generateMask()
 //-----------------------------------------------------------------------------
-void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4 *clothing_weights)
+void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights)
 {
 // RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)
 //	BOOL debugImg = FALSE; 
@@ -698,7 +727,7 @@ void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height,
 
 		if (clothing_weights)
 		{
-			clothing_weights[vertIndex].mV[VW] = mWeights[index];
+			clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index];
 		}
 	}
 	mWeightsGenerated = TRUE;
diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h
index 8a024f2e9e05c55b83bb987f0f36a2d98ff3d86a..46e23b7792a499a435e6ee9d2f7ab6c22b8814fc 100644
--- a/indra/newview/llpolymorph.h
+++ b/indra/newview/llpolymorph.h
@@ -58,14 +58,14 @@ class LLPolyMorphData
 	U32					mNumIndices;
 	U32*				mVertexIndices;
 	U32					mCurrentIndex;
-	LLVector3*			mCoords;
-	LLVector3*			mNormals;
-	LLVector3*			mBinormals;
+	LLVector4a*			mCoords;
+	LLVector4a*			mNormals;
+	LLVector4a*			mBinormals;
 	LLVector2*			mTexCoords;
 
 	F32					mTotalDistortion;	// vertex distortion summed over entire morph
 	F32					mMaxDistortion;		// maximum single vertex distortion in a given morph
-	LLVector3			mAvgDistortion;		// average vertex distortion, to infer directionality of the morph
+	LLVector4a			mAvgDistortion;		// average vertex distortion, to infer directionality of the morph
 	LLPolyMeshSharedData*	mMesh;
 };
 
@@ -78,7 +78,7 @@ class LLPolyVertexMask
 	LLPolyVertexMask(LLPolyMorphData* morph_data);
 	~LLPolyVertexMask();
 
-	void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4 *clothing_weights);
+	void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights);
 	F32* getMorphMaskWeights();
 
 
@@ -157,11 +157,11 @@ class LLPolyMorphTarget : public LLViewerVisualParam
 	
 	// LLViewerVisualParam Virtual functions
 	/*virtual*/ F32					getTotalDistortion();
-	/*virtual*/ const LLVector3&	getAvgDistortion();
+	/*virtual*/ const LLVector4a&	getAvgDistortion();
 	/*virtual*/ F32					getMaxDistortion();
-	/*virtual*/ LLVector3			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
-	/*virtual*/ const LLVector3*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
-	/*virtual*/ const LLVector3*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
+	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
+	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
+	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
 
 	void	applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert);
 	void	addPendingMorphMask() { mNumMorphMasksPending++; }
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index eec2c0a5211fac95f6fc372b6355c804574c1bdb..a55565909f3649a69c7b805395a67eebe269e0fc 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -1508,6 +1508,49 @@ struct LLSelectMgrSendFunctor : public LLSelectedObjectFunctor
 	}
 };
 
+void LLObjectSelection::applyNoCopyTextureToTEs(LLViewerInventoryItem* item)
+{
+	if (!item)
+	{
+		return;
+	}
+	LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID());
+
+	for (iterator iter = begin(); iter != end(); ++iter)
+	{
+		LLSelectNode* node = *iter;
+		LLViewerObject* object = (*iter)->getObject();
+		if (!object)
+		{
+			continue;
+		}
+
+		S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces());
+		bool texture_copied = false;
+		for (S32 te = 0; te < num_tes; ++te)
+		{
+			if (node->isTESelected(te))
+			{
+				//(no-copy) textures must be moved to the object's inventory only once
+				// without making any copies
+				if (!texture_copied)
+				{
+					LLToolDragAndDrop::handleDropTextureProtections(object, item, LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null);
+					texture_copied = true;
+				}
+
+				// apply texture for the selected faces
+				LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
+				object->setTEImage(te, image);
+				dialog_refresh_all();
+
+				// send the update to the simulator
+				object->sendTEUpdate();
+			}
+		}
+	}
+}
+
 //-----------------------------------------------------------------------------
 // selectionSetImage()
 //-----------------------------------------------------------------------------
@@ -1559,8 +1602,18 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
 			}
 			return true;
 		}
-	} setfunc(item, imageid);
-	getSelection()->applyToTEs(&setfunc);
+	};
+
+	if (item && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID()))
+	{
+		getSelection()->applyNoCopyTextureToTEs(item);
+	}
+	else
+	{
+		f setfunc(item, imageid);
+		getSelection()->applyToTEs(&setfunc);
+	}
+
 
 	struct g : public LLSelectedObjectFunctor
 	{
@@ -5583,7 +5636,7 @@ void pushWireframe(LLDrawable* drawable)
 			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 			{
 				const LLVolumeFace& face = volume->getVolumeFace(i);
-				LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, face.mTexCoords, face.mNumIndices, face.mIndices);
+				LLVertexBuffer::drawElements(LLRender::TRIANGLES, face.mPositions, NULL, face.mNumIndices, face.mIndices);
 			}
 		}
 
@@ -5610,7 +5663,7 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color)
 
 	if (shader)
 	{
-		gHighlightProgram.bind();
+		gDebugProgram.bind();
 	}
 
 	gGL.matrixMode(LLRender::MM_MODELVIEW);
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 87ada5ac6b6cbe3acc9535519a0356343e2a1f4d..94606b9fba6739fc962fff86192fb9594459c505 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -307,6 +307,15 @@ class LLObjectSelection : public LLRefCount
 	bool applyToRootNodes(LLSelectedNodeFunctor* func, bool firstonly = false);
 	bool applyToNodes(LLSelectedNodeFunctor* func, bool firstonly = false);
 
+	/*
+	 * Used to apply (no-copy) textures to the selected object or
+	 * selected face/faces of the object.
+	 * This method moves (no-copy) texture to the object's inventory
+	 * and doesn't make copy of the texture for each face.
+	 * Then this only texture is used for all selected faces.
+	 */
+	void applyNoCopyTextureToTEs(LLViewerInventoryItem* item);
+
 	ESelectType getSelectType() const { return mSelectType; }
 
 private:
diff --git a/indra/newview/llsidepaneliteminfo.cpp b/indra/newview/llsidepaneliteminfo.cpp
index 1ce05da8497f171b630d1c76585c26bd26fc3ae6..92c2863ffdf49124f54c38ee7b28f74412e7e8ac 100644
--- a/indra/newview/llsidepaneliteminfo.cpp
+++ b/indra/newview/llsidepaneliteminfo.cpp
@@ -352,7 +352,7 @@ void LLSidepanelItemInfo::refreshFromItem(LLViewerInventoryItem* item)
 		getChildView("BtnCreator")->setEnabled(FALSE);
 		getChildView("LabelCreatorTitle")->setEnabled(FALSE);
 		getChildView("LabelCreatorName")->setEnabled(FALSE);
-		getChild<LLUICtrl>("LabelCreatorName")->setValue(getString("unknown"));
+		getChild<LLUICtrl>("LabelCreatorName")->setValue(getString("unknown_multiple"));
 	}
 
 	////////////////
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 8e62b79d7f21c8c4c9c11f7c402b1290e4e748b0..bd335576ba19a758c14e8eb49483a25eeadf3dbc 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -68,6 +68,7 @@ const F32 SG_OCCLUSION_FUDGE = 0.25f;
 #define assert_states_valid(x)
 #endif
 
+extern bool gShiftFrame;
 
 static U32 sZombieGroups = 0;
 U32 LLSpatialGroup::sNodeCount = 0;
@@ -85,12 +86,32 @@ static F32 sCurMaxTexPriority = 1.f;
 
 class LLOcclusionQueryPool : public LLGLNamePool
 {
+public:
+	LLOcclusionQueryPool()
+	{
+		mCurQuery = 1;
+	}
+
 protected:
+
+	std::list<GLuint> mAvailableName;
+	GLuint mCurQuery;
+		
 	virtual GLuint allocateName()
 	{
-		GLuint name;
-		glGenQueriesARB(1, &name);
-		return name;
+		GLuint ret = 0;
+
+		if (!mAvailableName.empty())
+		{
+			ret = mAvailableName.front();
+			mAvailableName.pop_front();
+		}
+		else
+		{
+			ret = mCurQuery++;
+		}
+
+		return ret;
 	}
 
 	virtual void releaseName(GLuint name)
@@ -98,7 +119,8 @@ class LLOcclusionQueryPool : public LLGLNamePool
 #if LL_TRACK_PENDING_OCCLUSION_QUERIES
 		LLSpatialGroup::sPendingQueries.erase(name);
 #endif
-		glDeleteQueriesARB(1, &name);
+		llassert(std::find(mAvailableName.begin(), mAvailableName.end(), name) == mAvailableName.end());
+		mAvailableName.push_back(name);
 	}
 };
 
@@ -259,79 +281,39 @@ U8* get_box_fan_indices_ptr(LLCamera* camera, const LLVector4a& center)
 	return (U8*) (sOcclusionIndices+cypher*8);
 }
 
-
-static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
-
-void LLSpatialGroup::buildOcclusion()
+//create a vertex buffer for efficiently rendering cubes
+LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage)
 {
-	//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);
-	
-		LLStrider<U16> idx;
-		mOcclusionVerts->getIndexStrider(idx);
-		for (U32 i = 0; i < 64; i++)
-		{
-			*idx++ = sOcclusionIndices[i];
-		}
-	}
+	LLVertexBuffer* ret = new LLVertexBuffer(type_mask, usage);
 
-	LLVector4a fudge;
-	fudge.splat(SG_OCCLUSION_FUDGE);
-
-	LLVector4a r;
-	r.setAdd(mBounds[1], fudge);
+	ret->allocateBuffer(8, 64, true);
 
 	LLStrider<LLVector3> pos;
-	
-	{
-		LLFastTimer t(FTM_BUILD_OCCLUSION);
-		mOcclusionVerts->getVertexStrider(pos);
-	}
+	LLStrider<U16> idx;
 
-	{
-		LLVector4a* v = (LLVector4a*) pos.get();
+	ret->getVertexStrider(pos);
+	ret->getIndexStrider(idx);
 
-		const LLVector4a& c = mBounds[0];
-		const LLVector4a& s = r;
-		
-		static const LLVector4a octant[] =
-		{
-			LLVector4a(-1.f, -1.f, -1.f),
-			LLVector4a(-1.f, -1.f, 1.f),
-			LLVector4a(-1.f, 1.f, -1.f),
-			LLVector4a(-1.f, 1.f, 1.f),
-
-			LLVector4a(1.f, -1.f, -1.f),
-			LLVector4a(1.f, -1.f, 1.f),
-			LLVector4a(1.f, 1.f, -1.f),
-			LLVector4a(1.f, 1.f, 1.f),
-		};
-
-		//vertex positions are encoded so the 3 bits of their vertex index 
-		//correspond to their axis facing, with bit position 3,2,1 matching
-		//axis facing x,y,z, bit set meaning positive facing, bit clear 
-		//meaning negative facing
-		
-		for (S32 i = 0; i < 8; ++i)
-		{
-			LLVector4a p;
-			p.setMul(s, octant[i]);
-			p.add(c);
-			v[i] = p;
-		}
-	}
-	
+	pos[0] = LLVector3(-1,-1,-1);
+	pos[1] = LLVector3(-1,-1, 1);
+	pos[2] = LLVector3(-1, 1,-1);
+	pos[3] = LLVector3(-1, 1, 1);
+	pos[4] = LLVector3( 1,-1,-1);
+	pos[5] = LLVector3( 1,-1, 1);
+	pos[6] = LLVector3( 1, 1,-1);
+	pos[7] = LLVector3( 1, 1, 1);
+
+	for (U32 i = 0; i < 64; i++)
 	{
-		mOcclusionVerts->flush();
-		LLVertexBuffer::unbind();
+		idx[i] = sOcclusionIndices[i];
 	}
 
-	clearState(LLSpatialGroup::OCCLUSION_DIRTY);
+	ret->flush();
+
+	return ret;
 }
 
+static LLFastTimer::DeclareTimer FTM_BUILD_OCCLUSION("Build Occlusion");
 
 BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group);
 
@@ -394,8 +376,6 @@ LLSpatialGroup::~LLSpatialGroup()
 		}
 	}
 
-	mOcclusionVerts = NULL;
-
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	clearDrawMap();
 	clearAtlasList() ;
@@ -562,7 +542,7 @@ void LLSpatialGroup::validate()
 
 	validateDrawMap();
 
-	for (element_iter i = getData().begin(); i != getData().end(); ++i)
+	for (element_iter i = getDataBegin(); i != getDataEnd(); ++i)
 	{
 		LLDrawable* drawable = *i;
 		sg_assert(drawable->getSpatialGroup() == this);
@@ -687,6 +667,11 @@ void LLSpatialGroup::rebuildGeom()
 	if (!isDead())
 	{
 		mSpatialPartition->rebuildGeom(this);
+
+		if (isState(LLSpatialGroup::MESH_DIRTY))
+		{
+			gPipeline.markMeshDirty(this);
+		}
 	}
 }
 
@@ -699,6 +684,9 @@ void LLSpatialGroup::rebuildMesh()
 }
 
 static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
+static LLFastTimer::DeclareTimer FTM_ADD_GEOMETRY_COUNT("Add Geometry");
+static LLFastTimer::DeclareTimer FTM_CREATE_VB("Create VB");
+static LLFastTimer::DeclareTimer FTM_GET_GEOMETRY("Get Geometry");
 
 void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 {
@@ -720,27 +708,36 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group)
 	//get geometry count
 	U32 index_count = 0;
 	U32 vertex_count = 0;
-	
-	addGeometryCount(group, vertex_count, index_count);
+
+	{
+		LLFastTimer t(FTM_ADD_GEOMETRY_COUNT);
+		addGeometryCount(group, vertex_count, index_count);
+	}
 
 	if (vertex_count > 0 && index_count > 0)
 	{ //create vertex buffer containing volume geometry for this node
-		group->mBuilt = 1.f;
-		if (group->mVertexBuffer.isNull() ||
-			!group->mVertexBuffer->isWriteable() ||
-			(group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
 		{
-			group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
-			group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true);
-			stop_glerror();
+			LLFastTimer t(FTM_CREATE_VB);
+			group->mBuilt = 1.f;
+			if (group->mVertexBuffer.isNull() ||
+				!group->mVertexBuffer->isWriteable() ||
+				(group->mBufferUsage != group->mVertexBuffer->getUsage() && LLVertexBuffer::sEnableVBOs))
+			{
+				group->mVertexBuffer = createVertexBuffer(mVertexDataMask, group->mBufferUsage);
+				group->mVertexBuffer->allocateBuffer(vertex_count, index_count, true);
+				stop_glerror();
+			}
+			else
+			{
+				group->mVertexBuffer->resizeBuffer(vertex_count, index_count);
+				stop_glerror();
+			}
 		}
-		else
+
 		{
-			group->mVertexBuffer->resizeBuffer(vertex_count, index_count);
-			stop_glerror();
+			LLFastTimer t(FTM_GET_GEOMETRY);
+			getGeometry(group);
 		}
-		
-		getGeometry(group);
 	}
 	else
 	{
@@ -762,7 +759,7 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& ma
 {	
 	const OctreeNode* node = mOctreeNode;
 
-	if (node->getData().empty())
+	if (node->isEmpty())
 	{	//don't do anything if there are no objects
 		if (empty && mOctreeNode->getParent())
 		{	//only root is allowed to be empty
@@ -779,14 +776,14 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& ma
 		clearState(OBJECT_DIRTY);
 
 		//initialize bounding box to first element
-		OctreeNode::const_element_iter i = node->getData().begin();
+		OctreeNode::const_element_iter i = node->getDataBegin();
 		LLDrawable* drawablep = *i;
 		const LLVector4a* minMax = drawablep->getSpatialExtents();
 
 		newMin = minMax[0];
 		newMax = minMax[1];
 
-		for (++i; i != node->getData().end(); ++i)
+		for (++i; i != node->getDataEnd(); ++i)
 		{
 			drawablep = *i;
 			minMax = drawablep->getSpatialExtents();
@@ -927,16 +924,14 @@ void LLSpatialGroup::shift(const LLVector4a &offset)
 	mObjectExtents[0].add(offset);
 	mObjectExtents[1].add(offset);
 
-	//if (!mSpatialPartition->mRenderByGroup)
+	if (!mSpatialPartition->mRenderByGroup && 
+		mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TREE &&
+		mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_TERRAIN &&
+		mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_BRIDGE)
 	{
 		setState(GEOM_DIRTY);
 		gPipeline.markRebuild(this, TRUE);
 	}
-
-	if (mOcclusionVerts.notNull())
-	{
-		setState(OCCLUSION_DIRTY);
-	}
 }
 
 class LLSpatialSetState : public LLSpatialGroup::OctreeTraveler
@@ -1235,8 +1230,6 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 		mVisible[i] = 0;
 	}
 
-	mOcclusionVerts = NULL;
-
 	mRadius = 1;
 	mPixelArea = 1024.f;
 }
@@ -1249,13 +1242,18 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 		return;
 	}
 
+	if (gShiftFrame)
+	{
+		return;
+	}
+
 #if !LL_RELEASE_FOR_DOWNLOAD
 	if (isState(LLSpatialGroup::OBJECT_DIRTY))
 	{
 		llerrs << "Spatial group dirty on distance update." << llendl;
 	}
 #endif
-	if (!getData().empty())
+	if (!isEmpty())
 	{
 		mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].getLength3().getF32() :
 						(F32) mOctreeNode->getSize().getLength3().getF32();
@@ -1406,7 +1404,7 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	setState(DEAD);
 	
-	for (element_iter i = getData().begin(); i != getData().end(); ++i)
+	for (element_iter i = getDataBegin(); i != getDataEnd(); ++i)
 	{
 		LLDrawable* drawable = *i;
 		if (drawable->getSpatialGroup() == this)
@@ -1465,10 +1463,14 @@ void LLSpatialGroup::handleChildRemoval(const OctreeNode* parent, const OctreeNo
 	unbound();
 }
 
-void LLSpatialGroup::destroyGL() 
+void LLSpatialGroup::destroyGL(bool keep_occlusion) 
 {
 	setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
-	gPipeline.markRebuild(this, TRUE);
+
+	if (!keep_occlusion)
+	{ //going to need a rebuild
+		gPipeline.markRebuild(this, TRUE);
+	}
 
 	mLastUpdateTime = gFrameTimeSeconds;
 	mVertexBuffer = NULL;
@@ -1476,24 +1478,29 @@ void LLSpatialGroup::destroyGL()
 
 	clearDrawMap();
 
-	for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
+	if (!keep_occlusion)
 	{
-		if (mOcclusionQuery[i])
+		for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++)
 		{
-			sQueryPool.release(mOcclusionQuery[i]);
-			mOcclusionQuery[i] = 0;
+			if (mOcclusionQuery[i])
+			{
+				sQueryPool.release(mOcclusionQuery[i]);
+				mOcclusionQuery[i] = 0;
+			}
 		}
 	}
 
-	mOcclusionVerts = NULL;
 
-	for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
+	for (LLSpatialGroup::element_iter i = getDataBegin(); i != getDataEnd(); ++i)
 	{
 		LLDrawable* drawable = *i;
 		for (S32 j = 0; j < drawable->getNumFaces(); j++)
 		{
 			LLFace* facep = drawable->getFace(j);
-			facep->clearVertexBuffer();
+			if (facep)
+			{
+				facep->clearVertexBuffer();
+			}
 		}
 	}
 }
@@ -1556,15 +1563,13 @@ BOOL LLSpatialGroup::rebound()
 		mBounds[1].mul(0.5f);
 	}
 	
-	setState(OCCLUSION_DIRTY);
-	
 	clearState(DIRTY);
 
 	return TRUE;
 }
 
 static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion");
-static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Wait");
+static LLFastTimer::DeclareTimer FTM_OCCLUSION_WAIT("Occlusion Wait");
 
 void LLSpatialGroup::checkOcclusion()
 {
@@ -1584,7 +1589,9 @@ void LLSpatialGroup::checkOcclusion()
 			{
 				glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available);
 
-				if (mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
+				static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion");
+
+				if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount)
 				{ //query was issued last frame, wait until it's available
 					S32 max_loop = 1024;
 					LLFastTimer t(FTM_OCCLUSION_WAIT);
@@ -1635,7 +1642,9 @@ void LLSpatialGroup::checkOcclusion()
 				else
 				{
 					assert_states_valid(this);
+					
 					setOcclusionState(LLSpatialGroup::OCCLUDED, LLSpatialGroup::STATE_MODE_DIFF);
+					
 					assert_states_valid(this);
 				}
 
@@ -1690,12 +1699,6 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 						mOcclusionQuery[LLViewerCamera::sCurCameraID] = sQueryPool.allocate();
 					}
 
-					if (mOcclusionVerts.isNull() || isState(LLSpatialGroup::OCCLUSION_DIRTY))
-					{
-						LLFastTimer t(FTM_OCCLUSION_BUILD);
-						buildOcclusion();
-					}
-					
 					// Depth clamp all water to avoid it being culled as a result of being
 					// behind the far clip plane, and in the case of edge water to avoid
 					// it being culled while still visible.
@@ -1726,10 +1729,13 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 							glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
 						}
 					
-						{
-							LLFastTimer t(FTM_OCCLUSION_SET_BUFFER);
-							mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
-						}
+						LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
+						llassert(shader);
+
+						shader->uniform3fv(LLShaderMgr::BOX_CENTER, 1, mBounds[0].getF32ptr());
+						shader->uniform3f(LLShaderMgr::BOX_SIZE, mBounds[1][0]+SG_OCCLUSION_FUDGE, 
+																 mBounds[1][1]+SG_OCCLUSION_FUDGE, 
+																 mBounds[1][2]+SG_OCCLUSION_FUDGE);
 
 						if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER)
 						{
@@ -1738,12 +1744,12 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 							LLGLSquashToFarClip squash(glh_get_current_projection(), 1);
 							if (camera->getOrigin().isExactlyZero())
 							{ //origin is invalid, draw entire box
-								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
-								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
+								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
 							}
 							else
 							{
-								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
 							}
 						}
 						else
@@ -1751,12 +1757,12 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 							LLFastTimer t(FTM_OCCLUSION_DRAW);
 							if (camera->getOrigin().isExactlyZero())
 							{ //origin is invalid, draw entire box
-								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
-								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
+								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0);
+								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, b111*8);				
 							}
 							else
 							{
-								mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
+								gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, mBounds[0]));
 							}
 						}
 
@@ -1841,12 +1847,14 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	
-	drawablep->setSpatialGroup(NULL);
-
 	if (!curp->removeObject(drawablep))
 	{
 		OCT_ERRS << "Failed to remove drawable from octree!" << llendl;
 	}
+	else
+	{
+		drawablep->setSpatialGroup(NULL);
+	}
 
 	assert_octree_valid(mOctree);
 	
@@ -2117,7 +2125,7 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 
 	virtual void processGroup(LLSpatialGroup* group)
 	{
-		llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->getData().empty())
+		llassert(!group->isState(LLSpatialGroup::DIRTY) && !group->isEmpty())
 		
 		if (mRes < 2)
 		{
@@ -2184,7 +2192,7 @@ class LLOctreeSelect : public LLOctreeCull
 	{
 		LLSpatialGroup::OctreeNode* branch = group->mOctreeNode;
 
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
 			LLDrawable* drawable = *i;
 			
@@ -2308,7 +2316,7 @@ class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
 		LLSpatialGroup* group = (LLSpatialGroup*) state->getListener(0);
 		group->destroyGL();
 
-		for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 		{
 			LLDrawable* drawable = *i;
 			if (drawable->getVObj().notNull() && !group->mSpatialPartition->mRenderByGroup)
@@ -2480,18 +2488,21 @@ void pushVerts(LLSpatialGroup* group, U32 mask)
 
 void pushVerts(LLFace* face, U32 mask)
 {
-	llassert(face->verify());
+	if (face)
+	{
+		llassert(face->verify());
 
-	LLVertexBuffer* buffer = face->getVertexBuffer();
+		LLVertexBuffer* buffer = face->getVertexBuffer();
 
-	if (buffer && (face->getGeomCount() >= 3))
-	{
-		buffer->setBuffer(mask);
-		U16 start = face->getGeomStart();
-		U16 end = start + face->getGeomCount()-1;
-		U32 count = face->getIndicesCount();
-		U16 offset = face->getIndicesStart();
-		buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+		if (buffer && (face->getGeomCount() >= 3))
+		{
+			buffer->setBuffer(mask);
+			U16 start = face->getGeomStart();
+			U16 end = start + face->getGeomCount()-1;
+			U32 count = face->getIndicesCount();
+			U16 offset = face->getIndicesStart();
+			buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+		}
 	}
 }
 
@@ -2615,7 +2626,7 @@ void renderOctree(LLSpatialGroup* group)
 			gGL.flush();
 			glLineWidth(1.f);
 			gGL.flush();
-			for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 			{
 				LLDrawable* drawable = *i;
 				if (!group->mSpatialPartition->isBridge())
@@ -2628,7 +2639,7 @@ void renderOctree(LLSpatialGroup* group)
 				for (S32 j = 0; j < drawable->getNumFaces(); j++)
 				{
 					LLFace* face = drawable->getFace(j);
-					if (face->getVertexBuffer())
+					if (face && face->getVertexBuffer())
 					{
 						if (gFrameTimeSeconds - face->mLastUpdateTime < 0.5f)
 						{
@@ -2661,7 +2672,7 @@ void renderOctree(LLSpatialGroup* group)
 	}
 	else
 	{
-		if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->getData().empty() 
+		if (group->mBufferUsage == GL_STATIC_DRAW_ARB && !group->isEmpty() 
 			&& group->mSpatialPartition->mRenderByGroup)
 		{
 			col.setVec(0.8f, 0.4f, 0.1f, 0.1f);
@@ -2729,7 +2740,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
 	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
-							!group->getData().empty();
+							!group->isEmpty();
 
 	if (render_objects)
 	{
@@ -2757,19 +2768,6 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 			gGL.diffuseColor4f(0.f, 0.75f, 0.f, 0.5f);
 			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
 		}
-		/*else if (camera && group->mOcclusionVerts.notNull())
-		{
-			LLVertexBuffer::unbind();
-			group->mOcclusionVerts->setBuffer(LLVertexBuffer::MAP_VERTEX);
-			
-			gGL.diffuseColor4f(1.0f, 0.f, 0.f, 0.5f);
-			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
-			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-			
-			gGL.diffuseColor4f(1.0f, 1.f, 1.f, 1.0f);
-			group->mOcclusionVerts->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, group->mBounds[0]));
-			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-		}*/
 	}
 }
 
@@ -2999,15 +2997,17 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
 	for (S32 i = 0; i < drawable->getNumFaces(); i++)
 	{
 		LLFace* facep = drawable->getFace(i);
+		if (facep)
+		{
+			ext = facep->mExtents;
 
-		ext = facep->mExtents;
-
-		pos.setAdd(ext[0], ext[1]);
-		pos.mul(0.5f);
-		size.setSub(ext[1], ext[0]);
-		size.mul(0.5f);
+			pos.setAdd(ext[0], ext[1]);
+			pos.mul(0.5f);
+			size.setSub(ext[1], ext[0]);
+			size.mul(0.5f);
 		
-		drawBoxOutline(pos,size);
+			drawBoxOutline(pos,size);
+		}
 	}
 
 	//render drawable bounding box
@@ -3471,7 +3471,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 
 void renderPhysicsShapes(LLSpatialGroup* group)
 {
-	for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+	for (LLSpatialGroup::OctreeNode::const_element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
 		LLDrawable* drawable = *i;
 		LLVOVolume* volume = drawable->getVOVolume();
@@ -3499,18 +3499,21 @@ void renderPhysicsShapes(LLSpatialGroup* group)
 				for (S32 i = 0; i < drawable->getNumFaces(); ++i)
 				{
 					LLFace* face = drawable->getFace(i);
-					LLVertexBuffer* buff = face->getVertexBuffer();
-					if (buff)
+					if (face)
 					{
-						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+						LLVertexBuffer* buff = face->getVertexBuffer();
+						if (buff)
+						{
+							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
-						buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
-						gGL.diffuseColor3f(0.2f, 0.5f, 0.3f);
-						buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+							buff->setBuffer(LLVertexBuffer::MAP_VERTEX);
+							gGL.diffuseColor3f(0.2f, 0.5f, 0.3f);
+							buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
 									
-						gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
-						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-						buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+							gGL.diffuseColor3f(0.2f, 1.f, 0.3f);
+							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+							buff->draw(LLRender::TRIANGLES, buff->getNumIndices(), 0);
+						}
 					}
 				}
 			}
@@ -3534,6 +3537,7 @@ void renderTexturePriority(LLDrawable* drawable)
 		
 		//LLViewerTexture* imagep = facep->getTexture();
 		//if (imagep)
+		if (facep)
 		{
 				
 			//F32 vsize = imagep->mMaxVirtualSize;
@@ -3586,7 +3590,11 @@ void renderPoints(LLDrawable* drawablep)
 		gGL.diffuseColor3f(1,1,1);
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 		{
-			gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
+			LLFace * face = drawablep->getFace(i);
+			if (face)
+			{
+				gGL.vertex3fv(face->mCenterLocal.mV);
+			}
 		}
 		gGL.end();
 	}
@@ -3767,7 +3775,11 @@ void renderLights(LLDrawable* drawablep)
 
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 		{
-			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
+			LLFace * face = drawablep->getFace(i);
+			if (face)
+			{
+				pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+			}
 		}
 
 		const LLVector4a* ext = drawablep->getSpatialExtents();
@@ -3808,7 +3820,7 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
 
 		LLVector3 center, size;
 		
-		if (branch->getData().empty())
+		if (branch->isEmpty())
 		{
 			gGL.diffuseColor3f(1.f,0.2f,0.f);
 			center.set(branch->getCenter().getF32ptr());
@@ -3844,8 +3856,8 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
 			}
 
 			gGL.begin(LLRender::TRIANGLES);
-			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
-					iter != branch->getData().end();
+			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getDataBegin();
+					iter != branch->getDataEnd();
 					++iter)
 			{
 				const LLVolumeTriangle* tri = *iter;
@@ -4082,7 +4094,7 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 
 		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
 		{
-			if (!group->getData().empty())
+			if (!group->isEmpty())
 			{
 				gGL.diffuseColor3f(0,0,1);
 				drawBoxOutline(group->mObjectBounds[0],
@@ -4090,7 +4102,7 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			}
 		}
 
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
 			LLDrawable* drawable = *i;
 					
@@ -4169,18 +4181,21 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 				for (U32 i = 0; i < drawable->getNumFaces(); ++i)
 				{
 					LLFace* facep = drawable->getFace(i);
-					U8 index = facep->getTextureIndex();
-					if (facep->mDrawInfo)
+					if (facep)
 					{
-						if (index < 255)
+						U8 index = facep->getTextureIndex();
+						if (facep->mDrawInfo)
 						{
-							if (facep->mDrawInfo->mTextureList.size() <= index)
-							{
-								llerrs << "Face texture index out of bounds." << llendl;
-							}
-							else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture())
+							if (index < 255)
 							{
-								llerrs << "Face texture index incorrect." << llendl;
+								if (facep->mDrawInfo->mTextureList.size()<= index)
+								{
+									llerrs << "Face texture index out of bounds." << llendl;
+								}
+								else if (facep->mDrawInfo->mTextureList[index] != facep->getTexture())
+								{
+									llerrs << "Face texture index incorrect." << llendl;
+								}
 							}
 						}
 					}
@@ -4276,7 +4291,7 @@ class LLOctreePushBBoxVerts : public LLOctreeTraveler<LLDrawable>
 			return;
 		}
 
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
 			LLDrawable* drawable = *i;
 						
@@ -4500,7 +4515,7 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 	
 	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 	{	
-		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getData().begin(); i != branch->getData().end(); ++i)
+		for (LLSpatialGroup::OctreeNode::const_element_iter i = branch->getDataBegin(); i != branch->getDataEnd(); ++i)
 		{
 			check(*i);
 		}
@@ -4686,28 +4701,62 @@ LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
 
 LLCullResult::LLCullResult() 
 {
+	mVisibleGroupsAllocated = 0;
+	mAlphaGroupsAllocated = 0;
+	mOcclusionGroupsAllocated = 0;
+	mDrawableGroupsAllocated = 0;
+	mVisibleListAllocated = 0;
+	mVisibleBridgeAllocated = 0;
+
+	mVisibleGroups = NULL;
+	mVisibleGroupsEnd = NULL;
+	mAlphaGroups = NULL;
+	mAlphaGroupsEnd = NULL;
+	mOcclusionGroups = NULL;
+	mOcclusionGroupsEnd = NULL;
+	mDrawableGroups = NULL;
+	mDrawableGroupsEnd = NULL;
+	mVisibleList = NULL;
+	mVisibleListEnd = NULL;
+	mVisibleBridge = NULL;
+	mVisibleBridgeEnd = NULL;
+
+	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
+	{
+		mRenderMap[i] = NULL;
+		mRenderMapEnd[i] = NULL;
+		mRenderMapAllocated[i] = 0;
+	}
+
 	clear();
 }
 
+void LLCullResult::pushBack(void**& head, U32& count, void* val)
+{
+	count++;
+	head = (void**) realloc((void*) head, sizeof(void*) * count);
+	head[count-1] = val;
+}
+
 void LLCullResult::clear()
 {
 	mVisibleGroupsSize = 0;
-	mVisibleGroupsEnd = mVisibleGroups.begin();
+	mVisibleGroupsEnd = mVisibleGroups;
 
 	mAlphaGroupsSize = 0;
-	mAlphaGroupsEnd = mAlphaGroups.begin();
+	mAlphaGroupsEnd = mAlphaGroups;
 
 	mOcclusionGroupsSize = 0;
-	mOcclusionGroupsEnd = mOcclusionGroups.begin();
+	mOcclusionGroupsEnd = mOcclusionGroups;
 
 	mDrawableGroupsSize = 0;
-	mDrawableGroupsEnd = mDrawableGroups.begin();
+	mDrawableGroupsEnd = mDrawableGroups;
 
 	mVisibleListSize = 0;
-	mVisibleListEnd = mVisibleList.begin();
+	mVisibleListEnd = mVisibleList;
 
 	mVisibleBridgeSize = 0;
-	mVisibleBridgeEnd = mVisibleBridge.begin();
+	mVisibleBridgeEnd = mVisibleBridge;
 
 
 	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
@@ -4717,176 +4766,176 @@ void LLCullResult::clear()
 			mRenderMap[i][j] = 0;
 		}
 		mRenderMapSize[i] = 0;
-		mRenderMapEnd[i] = mRenderMap[i].begin();
+		mRenderMapEnd[i] = mRenderMap[i];
 	}
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups()
+LLCullResult::sg_iterator LLCullResult::beginVisibleGroups()
 {
-	return mVisibleGroups.begin();
+	return mVisibleGroups;
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups()
+LLCullResult::sg_iterator LLCullResult::endVisibleGroups()
 {
 	return mVisibleGroupsEnd;
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups()
+LLCullResult::sg_iterator LLCullResult::beginAlphaGroups()
 {
-	return mAlphaGroups.begin();
+	return mAlphaGroups;
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups()
+LLCullResult::sg_iterator LLCullResult::endAlphaGroups()
 {
 	return mAlphaGroupsEnd;
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups()
+LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups()
 {
-	return mOcclusionGroups.begin();
+	return mOcclusionGroups;
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups()
+LLCullResult::sg_iterator LLCullResult::endOcclusionGroups()
 {
 	return mOcclusionGroupsEnd;
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups()
+LLCullResult::sg_iterator LLCullResult::beginDrawableGroups()
 {
-	return mDrawableGroups.begin();
+	return mDrawableGroups;
 }
 
-LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups()
+LLCullResult::sg_iterator LLCullResult::endDrawableGroups()
 {
 	return mDrawableGroupsEnd;
 }
 
-LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList()
+LLCullResult::drawable_iterator LLCullResult::beginVisibleList()
 {
-	return mVisibleList.begin();
+	return mVisibleList;
 }
 
-LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList()
+LLCullResult::drawable_iterator LLCullResult::endVisibleList()
 {
 	return mVisibleListEnd;
 }
 
-LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge()
+LLCullResult::bridge_iterator LLCullResult::beginVisibleBridge()
 {
-	return mVisibleBridge.begin();
+	return mVisibleBridge;
 }
 
-LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge()
+LLCullResult::bridge_iterator LLCullResult::endVisibleBridge()
 {
 	return mVisibleBridgeEnd;
 }
 
-LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type)
+LLCullResult::drawinfo_iterator LLCullResult::beginRenderMap(U32 type)
 {
-	return mRenderMap[type].begin();
+	return mRenderMap[type];
 }
 
-LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type)
+LLCullResult::drawinfo_iterator LLCullResult::endRenderMap(U32 type)
 {
 	return mRenderMapEnd[type];
 }
 
 void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
 {
-	if (mVisibleGroupsSize < mVisibleGroups.size())
+	if (mVisibleGroupsSize < mVisibleGroupsAllocated)
 	{
 		mVisibleGroups[mVisibleGroupsSize] = group;
 	}
 	else
 	{
-		mVisibleGroups.push_back(group);
+		pushBack((void**&) mVisibleGroups, mVisibleGroupsAllocated, (void*) group);
 	}
 	++mVisibleGroupsSize;
-	mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize;
+	mVisibleGroupsEnd = mVisibleGroups+mVisibleGroupsSize;
 }
 
 void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
 {
-	if (mAlphaGroupsSize < mAlphaGroups.size())
+	if (mAlphaGroupsSize < mAlphaGroupsAllocated)
 	{
 		mAlphaGroups[mAlphaGroupsSize] = group;
 	}
 	else
 	{
-		mAlphaGroups.push_back(group);
+		pushBack((void**&) mAlphaGroups, mAlphaGroupsAllocated, (void*) group);
 	}
 	++mAlphaGroupsSize;
-	mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize;
+	mAlphaGroupsEnd = mAlphaGroups+mAlphaGroupsSize;
 }
 
 void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
 {
-	if (mOcclusionGroupsSize < mOcclusionGroups.size())
+	if (mOcclusionGroupsSize < mOcclusionGroupsAllocated)
 	{
 		mOcclusionGroups[mOcclusionGroupsSize] = group;
 	}
 	else
 	{
-		mOcclusionGroups.push_back(group);
+		pushBack((void**&) mOcclusionGroups, mOcclusionGroupsAllocated, (void*) group);
 	}
 	++mOcclusionGroupsSize;
-	mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize;
+	mOcclusionGroupsEnd = mOcclusionGroups+mOcclusionGroupsSize;
 }
 
 void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
 {
-	if (mDrawableGroupsSize < mDrawableGroups.size())
+	if (mDrawableGroupsSize < mDrawableGroupsAllocated)
 	{
 		mDrawableGroups[mDrawableGroupsSize] = group;
 	}
 	else
 	{
-		mDrawableGroups.push_back(group);
+		pushBack((void**&) mDrawableGroups, mDrawableGroupsAllocated, (void*) group);
 	}
 	++mDrawableGroupsSize;
-	mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize;
+	mDrawableGroupsEnd = mDrawableGroups+mDrawableGroupsSize;
 }
 
 void LLCullResult::pushDrawable(LLDrawable* drawable)
 {
-	if (mVisibleListSize < mVisibleList.size())
+	if (mVisibleListSize < mVisibleListAllocated)
 	{
 		mVisibleList[mVisibleListSize] = drawable;
 	}
 	else
 	{
-		mVisibleList.push_back(drawable);
+		pushBack((void**&) mVisibleList, mVisibleListAllocated, (void*) drawable);
 	}
 	++mVisibleListSize;
-	mVisibleListEnd = mVisibleList.begin()+mVisibleListSize;
+	mVisibleListEnd = mVisibleList+mVisibleListSize;
 }
 
 void LLCullResult::pushBridge(LLSpatialBridge* bridge)
 {
-	if (mVisibleBridgeSize < mVisibleBridge.size())
+	if (mVisibleBridgeSize < mVisibleBridgeAllocated)
 	{
 		mVisibleBridge[mVisibleBridgeSize] = bridge;
 	}
 	else
 	{
-		mVisibleBridge.push_back(bridge);
+		pushBack((void**&) mVisibleBridge, mVisibleBridgeAllocated, (void*) bridge);
 	}
 	++mVisibleBridgeSize;
-	mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize;
+	mVisibleBridgeEnd = mVisibleBridge+mVisibleBridgeSize;
 }
 
 void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
 {
-	if (mRenderMapSize[type] < mRenderMap[type].size())
+	if (mRenderMapSize[type] < mRenderMapAllocated[type])
 	{
 		mRenderMap[type][mRenderMapSize[type]] = draw_info;
 	}
 	else
 	{
-		mRenderMap[type].push_back(draw_info);
+		pushBack((void**&) mRenderMap[type], mRenderMapAllocated[type], (void*) draw_info);
 	}
 	++mRenderMapSize[type];
-	mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type];
+	mRenderMapEnd[type] = mRenderMap[type] + mRenderMapSize[type];
 }
 
 
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 1a93145cc5f4ccb2a896f1aaa7a0d5914d50cd78..e82c50b92b3ae5e60e7bf0aa60ae196a3bdc0ab7 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -263,11 +263,10 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 		SKIP_FRUSTUM_CHECK		= 0x00000020,
 		IN_IMAGE_QUEUE			= 0x00000040,
 		IMAGE_DIRTY				= 0x00000080,
-		OCCLUSION_DIRTY			= 0x00000100,
-		MESH_DIRTY				= 0x00000200,
-		NEW_DRAWINFO			= 0x00000400,
-		IN_BUILD_Q1				= 0x00000800,
-		IN_BUILD_Q2				= 0x00001000,
+		MESH_DIRTY				= 0x00000100,
+		NEW_DRAWINFO			= 0x00000200,
+		IN_BUILD_Q1				= 0x00000400,
+		IN_BUILD_Q2				= 0x00000800,
 		STATE_MASK				= 0x0000FFFF,
 	} eSpatialState;
 
@@ -313,10 +312,9 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax);
 	void unbound();
 	BOOL rebound();
-	void buildOcclusion(); //rebuild mOcclusionVerts
 	void checkOcclusion(); //read back last occlusion query (if any)
 	void doOcclusion(LLCamera* camera); //issue occlusion query
-	void destroyGL();
+	void destroyGL(bool keep_occlusion = false);
 	
 	void updateDistance(LLCamera& camera);
 	BOOL needsUpdate();
@@ -327,8 +325,13 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 
 	void dirtyGeom() { setState(GEOM_DIRTY); }
 	void dirtyMesh() { setState(MESH_DIRTY); }
+
+	//octree wrappers to make code more readable
 	element_list& getData() { return mOctreeNode->getData(); }
+	element_iter getDataBegin() { return mOctreeNode->getDataBegin(); }
+	element_iter getDataEnd() { return mOctreeNode->getDataEnd(); }
 	U32 getElementCount() const { return mOctreeNode->getElementCount(); }
+	bool isEmpty() const { return mOctreeNode->isEmpty(); }
 
 	void drawObjectBox(LLColor4 col);
 
@@ -415,7 +418,6 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	LLSpatialPartition* mSpatialPartition;
 	
 	LLPointer<LLVertexBuffer> mVertexBuffer;
-	LLPointer<LLVertexBuffer> mOcclusionVerts;
 	GLuint					mOcclusionQuery[LLViewerCamera::NUM_CAMERAS];
 
 	U32 mBufferUsage;
@@ -545,34 +547,39 @@ class LLCullResult
 public:
 	LLCullResult();
 
-	typedef std::vector<LLSpatialGroup*> sg_list_t;
-	typedef std::vector<LLDrawable*> drawable_list_t;
-	typedef std::vector<LLSpatialBridge*> bridge_list_t;
-	typedef std::vector<LLDrawInfo*> drawinfo_list_t;
+	typedef LLSpatialGroup** sg_list_t;
+	typedef LLDrawable** drawable_list_t;
+	typedef LLSpatialBridge** bridge_list_t;
+	typedef LLDrawInfo** drawinfo_list_t;
+
+	typedef LLSpatialGroup** sg_iterator;
+	typedef LLSpatialBridge** bridge_iterator;
+	typedef LLDrawInfo** drawinfo_iterator;
+	typedef LLDrawable** drawable_iterator;
 
 	void clear();
 	
-	sg_list_t::iterator beginVisibleGroups();
-	sg_list_t::iterator endVisibleGroups();
+	sg_iterator beginVisibleGroups();
+	sg_iterator endVisibleGroups();
 
-	sg_list_t::iterator beginAlphaGroups();
-	sg_list_t::iterator endAlphaGroups();
+	sg_iterator beginAlphaGroups();
+	sg_iterator endAlphaGroups();
 
 	bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; }
-	sg_list_t::iterator beginOcclusionGroups();
-	sg_list_t::iterator endOcclusionGroups();
+	sg_iterator beginOcclusionGroups();
+	sg_iterator endOcclusionGroups();
 
-	sg_list_t::iterator beginDrawableGroups();
-	sg_list_t::iterator endDrawableGroups();
+	sg_iterator beginDrawableGroups();
+	sg_iterator endDrawableGroups();
 
-	drawable_list_t::iterator beginVisibleList();
-	drawable_list_t::iterator endVisibleList();
+	drawable_iterator beginVisibleList();
+	drawable_iterator endVisibleList();
 
-	bridge_list_t::iterator beginVisibleBridge();
-	bridge_list_t::iterator endVisibleBridge();
+	bridge_iterator beginVisibleBridge();
+	bridge_iterator endVisibleBridge();
 
-	drawinfo_list_t::iterator beginRenderMap(U32 type);
-	drawinfo_list_t::iterator endRenderMap(U32 type);
+	drawinfo_iterator beginRenderMap(U32 type);
+	drawinfo_iterator endRenderMap(U32 type);
 
 	void pushVisibleGroup(LLSpatialGroup* group);
 	void pushAlphaGroup(LLSpatialGroup* group);
@@ -592,28 +599,41 @@ class LLCullResult
 	void assertDrawMapsEmpty();
 
 private:
+
+	void pushBack(void** &head, U32& count, void* val);
+
 	U32					mVisibleGroupsSize;
 	U32					mAlphaGroupsSize;
 	U32					mOcclusionGroupsSize;
 	U32					mDrawableGroupsSize;
 	U32					mVisibleListSize;
 	U32					mVisibleBridgeSize;
+
+	U32					mVisibleGroupsAllocated;
+	U32					mAlphaGroupsAllocated;
+	U32					mOcclusionGroupsAllocated;
+	U32					mDrawableGroupsAllocated;
+	U32					mVisibleListAllocated;
+	U32					mVisibleBridgeAllocated;
+
 	U32					mRenderMapSize[LLRenderPass::NUM_RENDER_TYPES];
 
 	sg_list_t			mVisibleGroups;
-	sg_list_t::iterator mVisibleGroupsEnd;
+	sg_iterator			mVisibleGroupsEnd;
 	sg_list_t			mAlphaGroups;
-	sg_list_t::iterator mAlphaGroupsEnd;
+	sg_iterator			mAlphaGroupsEnd;
 	sg_list_t			mOcclusionGroups;
-	sg_list_t::iterator	mOcclusionGroupsEnd;
+	sg_iterator			mOcclusionGroupsEnd;
 	sg_list_t			mDrawableGroups;
-	sg_list_t::iterator mDrawableGroupsEnd;
+	sg_iterator			mDrawableGroupsEnd;
 	drawable_list_t		mVisibleList;
-	drawable_list_t::iterator mVisibleListEnd;
+	drawable_iterator	mVisibleListEnd;
 	bridge_list_t		mVisibleBridge;
-	bridge_list_t::iterator mVisibleBridgeEnd;
+	bridge_iterator		mVisibleBridgeEnd;
 	drawinfo_list_t		mRenderMap[LLRenderPass::NUM_RENDER_TYPES];
-	drawinfo_list_t::iterator mRenderMapEnd[LLRenderPass::NUM_RENDER_TYPES];
+	U32					mRenderMapAllocated[LLRenderPass::NUM_RENDER_TYPES];
+	drawinfo_iterator mRenderMapEnd[LLRenderPass::NUM_RENDER_TYPES];
+
 };
 
 
@@ -657,6 +677,7 @@ class LLParticlePartition : public LLSpatialPartition
 {
 public:
 	LLParticlePartition();
+	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
 	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count);
 	virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);
@@ -671,10 +692,14 @@ class LLHUDParticlePartition : public LLParticlePartition
 };
 
 //spatial partition for grass (implemented in LLVOGrass.cpp)
-class LLGrassPartition : public LLParticlePartition
+class LLGrassPartition : public LLSpatialPartition
 {
 public:
 	LLGrassPartition();
+	virtual void getGeometry(LLSpatialGroup* group);
+	virtual void addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32& index_count);
+protected:
+	U32 mRenderPass;
 };
 
 //class for wrangling geometry out of volumes (implemented in LLVOVolume.cpp)
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index 66df7dae3ed5332c9ea2f4fcc35542496d5f425c..230e871b494992b8be84f553b0b009fe0ac6a376 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -56,6 +56,7 @@
 #include "lldrawable.h"
 
 extern LLPipeline gPipeline;
+extern bool gShiftFrame;
 
 LLColor4U MAX_WATER_COLOR(0, 48, 96, 240);
 
@@ -294,7 +295,7 @@ void LLSurface::initTextures()
 		mWaterObjp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, mRegionp);
 		gPipeline.createObject(mWaterObjp);
 		LLVector3d water_pos_global = from_region_handle(mRegionp->getHandle());
-		water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT);
+		water_pos_global += LLVector3d(128.0, 128.0, DEFAULT_WATER_HEIGHT);		// region doesn't have a valid water height yet
 		mWaterObjp->setPositionGlobal(water_pos_global);
 	}
 }
@@ -608,6 +609,11 @@ void LLSurface::moveZ(const S32 x, const S32 y, const F32 delta)
 
 void LLSurface::updatePatchVisibilities(LLAgent &agent) 
 {
+	if (gShiftFrame)
+	{
+		return;
+	}
+
 	LLVector3 pos_region = mRegionp->getPosRegionFromGlobal(gAgentCamera.getCameraPositionGlobal());
 
 	LLSurfacePatch *patchp;
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 5077c2c7e1f4bbdbd72ea6f642fecb0681bb8f08..a9ba2bce9c4ef2c8429796f0508b719c8545c5f3 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -43,6 +43,7 @@
 #include "lldrawpool.h"
 #include "noise.h"
 
+extern bool gShiftFrame;
 extern U64 gFrameTime;
 extern LLPipeline gPipeline;
 
@@ -218,7 +219,7 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
 	pos_agent.mV[VX] += x * mSurfacep->getMetersPerGrid();
 	pos_agent.mV[VY] += y * mSurfacep->getMetersPerGrid();
 	pos_agent.mV[VZ]  = *(mDataZ + point_offset);
-	*vertex     = pos_agent;
+	*vertex     = pos_agent-mVObjp->getRegion()->getOriginAgent();
 
 	LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent();
 	LLVector3 tex_pos = rel_pos * (1.f/surface_stride);
@@ -366,10 +367,13 @@ void LLSurfacePatch::updateCameraDistanceRegion(const LLVector3 &pos_region)
 {
 	if (LLPipeline::sDynamicLOD)
 	{
-		LLVector3 dv = pos_region;
-		dv -= mCenterRegion;
-		mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius))/
-			llmax(LLVOSurfacePatch::sLODFactor, 0.1f);
+		if (!gShiftFrame)
+		{
+			LLVector3 dv = pos_region;
+			dv -= mCenterRegion;
+			mVisInfo.mDistance = llmax(0.f, (F32)(dv.magVec() - mRadius))/
+				llmax(LLVOSurfacePatch::sLODFactor, 0.1f);
+		}
 	}
 	else
 	{
diff --git a/indra/newview/lltexlayerparams.h b/indra/newview/lltexlayerparams.h
index 74c22b0cdf83ee4ebb0492da500856cc8df6d773..2c0da60b4863424cabcd364f7b566c0c6056704c 100644
--- a/indra/newview/lltexlayerparams.h
+++ b/indra/newview/lltexlayerparams.h
@@ -76,11 +76,11 @@ class LLTexLayerParamAlpha : public LLTexLayerParam
 
 	// LLViewerVisualParam Virtual functions
 	/*virtual*/ F32					getTotalDistortion()									{ return 1.f; }
-	/*virtual*/ const LLVector3&	getAvgDistortion()										{ return mAvgDistortionVec; }
+	/*virtual*/ const LLVector4a&	getAvgDistortion()										{ return mAvgDistortionVec; }
 	/*virtual*/ F32					getMaxDistortion()										{ return 3.f; }
-	/*virtual*/ LLVector3			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)	{ return LLVector3(1.f, 1.f, 1.f);}
-	/*virtual*/ const LLVector3*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
-	/*virtual*/ const LLVector3*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return NULL;};
+	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)	{ return LLVector4a(1.f, 1.f, 1.f);}
+	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
+	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return NULL;};
 
 	// New functions
 	BOOL					render( S32 x, S32 y, S32 width, S32 height );
@@ -94,7 +94,7 @@ class LLTexLayerParamAlpha : public LLTexLayerParam
 	LLPointer<LLImageRaw>	mStaticImageRaw;
 	BOOL					mNeedsCreateTexture;
 	BOOL					mStaticImageInvalid;
-	LLVector3				mAvgDistortionVec;
+	LLVector4a				mAvgDistortionVec;
 	F32						mCachedEffectiveWeight;
 
 public:
@@ -155,18 +155,18 @@ class LLTexLayerParamColor : public LLTexLayerParam
 
 	// LLViewerVisualParam Virtual functions
 	/*virtual*/ F32					getTotalDistortion()									{ return 1.f; }
-	/*virtual*/ const LLVector3&	getAvgDistortion()										{ return mAvgDistortionVec; }
+	/*virtual*/ const LLVector4a&	getAvgDistortion()										{ return mAvgDistortionVec; }
 	/*virtual*/ F32					getMaxDistortion()										{ return 3.f; }
-	/*virtual*/ LLVector3			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)	{ return LLVector3(1.f, 1.f, 1.f); }
-	/*virtual*/ const LLVector3*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
-	/*virtual*/ const LLVector3*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return NULL;};
+	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh)	{ return LLVector4a(1.f, 1.f, 1.f); }
+	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return &mAvgDistortionVec;};
+	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)	{ index = 0; poly_mesh = NULL; return NULL;};
 
 	// New functions
 	LLColor4				getNetColor() const;
 protected:
 	virtual void onGlobalColorChanged(bool upload_bake) {}
 private:
-	LLVector3				mAvgDistortionVec;
+	LLVector4a				mAvgDistortionVec;
 };
 
 class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo
diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp
index d2e4b0173246a3ec04e1b812da026e91e8917ffc..f8c1bca8aed1097696f9609a5ce6040487ad2683 100644
--- a/indra/newview/lltextureatlas.cpp
+++ b/indra/newview/lltextureatlas.cpp
@@ -116,7 +116,6 @@ LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_
 		return 0 ;
 	}
 
-	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, TRUE);
 	glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h,
 						mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData());
 	
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index ed9faa070601ea72801cee172df5fecdd9bd58fb..6703ef4a41d8aa3a7735e456c4cd857e5fa3b6c4 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -97,6 +97,7 @@ class LLFloaterTexturePicker : public LLFloater
 		LLTextureCtrl* owner,
 		const std::string& label,
 		PermissionMask immediate_filter_perm_mask,
+		PermissionMask dnd_filter_perm_mask,
 		PermissionMask non_immediate_filter_perm_mask,
 		BOOL can_apply_immediately,
 		LLUIImagePtr fallback_image_name);
@@ -134,6 +135,9 @@ class LLFloaterTexturePicker : public LLFloater
 	
 	void onFilterEdit(const std::string& search_string );
 	
+	void setCanApply(bool can_preview, bool can_apply);
+	void setTextureSelectedCallback(texture_selected_callback cb) {mTextureSelectedCallback = cb;}
+
 	static void		onBtnSetToDefault( void* userdata );
 	static void		onBtnSelect( void* userdata );
 	static void		onBtnCancel( void* userdata );
@@ -175,6 +179,7 @@ class LLFloaterTexturePicker : public LLFloater
 	LLFilterEditor*		mFilterEdit;
 	LLInventoryPanel*	mInventoryPanel;
 	PermissionMask		mImmediateFilterPermMask;
+	PermissionMask		mDnDFilterPermMask;
 	PermissionMask		mNonImmediateFilterPermMask;
 	BOOL				mCanApplyImmediately;
 	BOOL				mNoCopyTextureSelected;
@@ -184,12 +189,18 @@ class LLFloaterTexturePicker : public LLFloater
 	
 	LLRadioGroup*		mModeSelector;
 	LLScrollListCtrl*	mLocalScrollCtrl;
+
+private:
+	bool mCanApply;
+	bool mCanPreview;
+	texture_selected_callback mTextureSelectedCallback;
 };
 
 LLFloaterTexturePicker::LLFloaterTexturePicker(	
 	LLTextureCtrl* owner,
 	const std::string& label,
 	PermissionMask immediate_filter_perm_mask,
+	PermissionMask dnd_filter_perm_mask,
 	PermissionMask non_immediate_filter_perm_mask,
 	BOOL can_apply_immediately,
 	LLUIImagePtr fallback_image)
@@ -205,9 +216,12 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 	mActive( TRUE ),
 	mFilterEdit(NULL),
 	mImmediateFilterPermMask(immediate_filter_perm_mask),
+	mDnDFilterPermMask(dnd_filter_perm_mask),
 	mNonImmediateFilterPermMask(non_immediate_filter_perm_mask),
 	mContextConeOpacity(0.f),
-	mSelectedItemPinned( FALSE )
+	mSelectedItemPinned( FALSE ),
+	mCanApply(true),
+	mCanPreview(true)
 {
 	buildFromFile("floater_texture_ctrl.xml");
 	mCanApplyImmediately = can_apply_immediately;
@@ -319,7 +333,7 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop(
 		if (xfer) item_perm_mask |= PERM_TRANSFER;
 		
 		//PermissionMask filter_perm_mask = getFilterPermMask();  Commented out due to no-copy texture loss.
-		PermissionMask filter_perm_mask = mImmediateFilterPermMask;
+		PermissionMask filter_perm_mask = mDnDFilterPermMask;
 		if ( (item_perm_mask & filter_perm_mask) == filter_perm_mask )
 		{
 			if (drop)
@@ -464,7 +478,7 @@ BOOL LLFloaterTexturePicker::postBuild()
 
 	mNoCopyTextureSelected = FALSE;
 
-	getChild<LLUICtrl>("apply_immediate_check")->setValue(gSavedSettings.getBOOL("ApplyTextureImmediately"));
+	getChild<LLUICtrl>("apply_immediate_check")->setValue(gSavedSettings.getBOOL("TextureLivePreview"));
 	childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this);
 
 	if (!mCanApplyImmediately)
@@ -546,7 +560,7 @@ void LLFloaterTexturePicker::draw()
 
 	// if we're inactive, gray out "apply immediate" checkbox
 	getChildView("show_folders_check")->setEnabled(mActive && mCanApplyImmediately && !mNoCopyTextureSelected);
-	getChildView("Select")->setEnabled(mActive);
+	getChildView("Select")->setEnabled(mActive && mCanApply);
 	getChildView("Pipette")->setEnabled(mActive);
 	getChild<LLUICtrl>("Pipette")->setValue(LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance());
 
@@ -702,8 +716,7 @@ PermissionMask LLFloaterTexturePicker::getFilterPermMask()
 
 void LLFloaterTexturePicker::commitIfImmediateSet()
 {
-	bool apply_immediate = getChild<LLUICtrl>("apply_immediate_check")->getValue().asBoolean();
-	if (!mNoCopyTextureSelected && apply_immediate && mOwner)
+	if (!mNoCopyTextureSelected && mOwner && mCanApply)
 	{
 		mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CHANGE);
 	}
@@ -713,6 +726,7 @@ void LLFloaterTexturePicker::commitIfImmediateSet()
 void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
 {
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+	self->setCanApply(true, true);
 	if (self->mOwner)
 	{
 		self->setImageID( self->mOwner->getDefaultImageAssetID() );
@@ -724,6 +738,7 @@ void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
 void LLFloaterTexturePicker::onBtnWhite(void* userdata)
 {
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
+	self->setCanApply(true, true);
 	self->setImageID( self->mWhiteImageAssetID );
 	self->commitIfImmediateSet();
 }
@@ -804,13 +819,14 @@ void LLFloaterTexturePicker::onSelectionChange(const std::deque<LLFolderViewItem
 		mNoCopyTextureSelected = FALSE;
 		if (itemp)
 		{
+			mTextureSelectedCallback(itemp);
 			if (!itemp->getPermissions().allowCopyBy(gAgent.getID()))
 			{
 				mNoCopyTextureSelected = TRUE;
 			}
 			mImageAssetID = itemp->getAssetUUID();
 			mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here?
-			if (user_action)
+			if (user_action && mCanPreview)
 			{
 				// only commit intentional selections, not implicit ones
 				commitIfImmediateSet();
@@ -947,7 +963,7 @@ void LLFloaterTexturePicker::onApplyImmediateCheck(LLUICtrl* ctrl, void *user_da
 	LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data;
 
 	LLCheckBoxCtrl* check_box = (LLCheckBoxCtrl*)ctrl;
-	gSavedSettings.setBOOL("ApplyTextureImmediately", check_box->get());
+	gSavedSettings.setBOOL("TextureLivePreview", check_box->get());
 
 	picker->updateFilterPermMask();
 	picker->commitIfImmediateSet();
@@ -958,6 +974,16 @@ void LLFloaterTexturePicker::updateFilterPermMask()
 	//mInventoryPanel->setFilterPermMask( getFilterPermMask() );  Commented out due to no-copy texture loss.
 }
 
+void LLFloaterTexturePicker::setCanApply(bool can_preview, bool can_apply)
+{
+	getChildRef<LLUICtrl>("Select").setEnabled(can_apply);
+	getChildRef<LLUICtrl>("preview_disabled").setVisible(!can_preview);
+	getChildRef<LLUICtrl>("apply_immediate_check").setVisible(can_preview);
+
+	mCanApply = can_apply;
+	mCanPreview = can_preview ? gSavedSettings.getBOOL("TextureLivePreview") : false;
+}
+
 void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string )
 {
 	std::string upper_case_search_string = search_string;
@@ -1108,6 +1134,15 @@ void LLTextureCtrl::setCanApplyImmediately(BOOL b)
 	}
 }
 
+void LLTextureCtrl::setCanApply(bool can_preview, bool can_apply)
+{
+	LLFloaterTexturePicker* floaterp = dynamic_cast<LLFloaterTexturePicker*>(mFloaterHandle.get());
+	if( floaterp )
+	{
+		floaterp->setCanApply(can_preview, can_apply);
+	}
+}
+
 void LLTextureCtrl::setVisible( BOOL visible ) 
 {
 	if( !visible )
@@ -1188,12 +1223,19 @@ void LLTextureCtrl::showPicker(BOOL take_focus)
 			this,
 			mLabel,
 			mImmediateFilterPermMask,
+			mDnDFilterPermMask,
 			mNonImmediateFilterPermMask,
 			mCanApplyImmediately,
 			mFallbackImage);
 
 		mFloaterHandle = floaterp->getHandle();
 
+		LLFloaterTexturePicker* texture_floaterp = dynamic_cast<LLFloaterTexturePicker*>(floaterp);
+		if (texture_floaterp && mOnTextureSelectedCallback)
+		{
+			texture_floaterp->setTextureSelectedCallback(mOnTextureSelectedCallback);
+		}
+
 		LLFloater* root_floater = gFloaterView->getParentFloater(this);
 		if (root_floater)
 			root_floater->addDependentFloater(floaterp);
@@ -1318,6 +1360,16 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op, LLUUID id)
 	}
 }
 
+void LLTextureCtrl::setOnTextureSelectedCallback(texture_selected_callback cb)
+{
+	mOnTextureSelectedCallback = cb;
+	LLFloaterTexturePicker* floaterp = dynamic_cast<LLFloaterTexturePicker*>(mFloaterHandle.get());
+	if (floaterp)
+	{
+		floaterp->setTextureSelectedCallback(cb);
+	}
+}
+
 void	LLTextureCtrl::setImageAssetName(const std::string& name)
 {
 	LLPointer<LLUIImage> imagep = LLUI::getUIImage(name);
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 3abe84dcc31a630ad2ea3c1903e37d9eb9d71c9c..599d9c70c521e656efabeb1ad12febb0b41094d1 100644
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -43,6 +43,7 @@ class LLViewerFetchedTexture;
 
 // used for setting drag & drop callbacks.
 typedef boost::function<BOOL (LLUICtrl*, LLInventoryItem*)> drag_n_drop_callback;
+typedef boost::function<void (LLInventoryItem*)> texture_selected_callback;
 
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -147,8 +148,12 @@ class LLTextureCtrl
 	void			setCaption(const std::string& caption);
 	void			setCanApplyImmediately(BOOL b);
 
+	void			setCanApply(bool can_preview, bool can_apply);
+
 	void			setImmediateFilterPermMask(PermissionMask mask)
 					{ mImmediateFilterPermMask = mask; }
+	void			setDnDFilterPermMask(PermissionMask mask)
+						{ mDnDFilterPermMask = mask; }
 	void			setNonImmediateFilterPermMask(PermissionMask mask)
 					{ mNonImmediateFilterPermMask = mask; }
 	PermissionMask	getImmediateFilterPermMask() { return mImmediateFilterPermMask; }
@@ -172,6 +177,11 @@ class LLTextureCtrl
 	
 	void setOnSelectCallback(commit_callback_t cb)	{ mOnSelectCallback = cb; }
 
+	/*
+	 * callback for changing texture selection in inventory list of texture floater
+	 */
+	void setOnTextureSelectedCallback(texture_selected_callback cb);
+
 	void setShowLoadingPlaceholder(BOOL showLoadingPlaceholder);
 
 	LLViewerFetchedTexture* getTexture() { return mTexturep; }
@@ -185,6 +195,7 @@ class LLTextureCtrl
 	drag_n_drop_callback	 	mDropCallback;
 	commit_callback_t		 	mOnCancelCallback;
 	commit_callback_t		 	mOnSelectCallback;
+	texture_selected_callback	mOnTextureSelectedCallback;
 	LLPointer<LLViewerFetchedTexture> mTexturep;
 	LLUIColor				 	mBorderColor;
 	LLUUID					 	mImageItemID;
@@ -198,6 +209,7 @@ class LLTextureCtrl
 	std::string				 	mLabel;
 	BOOL					 	mAllowNoTexture; // If true, the user can select "none" as an option
 	PermissionMask			 	mImmediateFilterPermMask;
+	PermissionMask				mDnDFilterPermMask;
 	PermissionMask			 	mNonImmediateFilterPermMask;
 	BOOL					 	mCanApplyImmediately;
 	BOOL					 	mCommitOnSelection;
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index 245c2a23e63b40d39325867d3b02351c9cc73e9c..41aee484dbc6dc3566b360d0cfacbb817946c68e 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -93,6 +93,13 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 
 	static S32 getOperationId() { return sOperationId; }
 
+	// deal with permissions of object, etc. returns TRUE if drop can
+	// proceed, otherwise FALSE.
+	static BOOL handleDropTextureProtections(LLViewerObject* hit_obj,
+						 LLInventoryItem* item,
+						 LLToolDragAndDrop::ESource source,
+						 const LLUUID& src_id);
+
 protected:
 	enum EDropTarget
 	{
@@ -219,13 +226,6 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 	// inventory items to determine if a drop would be ok.
 	static EAcceptance willObjectAcceptInventory(LLViewerObject* obj, LLInventoryItem* item);
 
-	// deal with permissions of object, etc. returns TRUE if drop can
-	// proceed, otherwise FALSE.
-	static BOOL handleDropTextureProtections(LLViewerObject* hit_obj,
-						 LLInventoryItem* item,
-						 LLToolDragAndDrop::ESource source,
-						 const LLUUID& src_id);
-
 public:
 	// helper functions
 	static BOOL isInventoryDropAcceptable(LLViewerObject* obj, LLInventoryItem* item) { return (ACCEPT_YES_COPY_SINGLE <= willObjectAcceptInventory(obj, item)); }
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index 718201e381ad43dbea301b0618632dbb76da10ee..0d5daf129fc51c471e59ef9242ea34111c4d62ef 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -225,7 +225,8 @@ BOOL LLVisualParamHint::render()
 
 	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
 
-	if (gAgentAvatarp->mDrawable.notNull())
+	if (gAgentAvatarp->mDrawable.notNull() &&
+		gAgentAvatarp->mDrawable->getFace(0))
 	{
 		LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool();
 		LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index f2712e7590880a38175ddcf9974dcdb13c1d86db..0d361a26463dc20b3e1aa3b75b4a81b80b7b6a1e 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -325,7 +325,7 @@ static bool handleJoystickChanged(const LLSD& newvalue)
 
 static bool handleUseOcclusionChanged(const LLSD& newvalue)
 {
-	LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery 
+	LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery && LLGLSLShader::sNoFixedFunction
 		&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && !gUseWireframe) ? 2 : 0;
 	return true;
 }
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 0adb187dd20411e21274e4fe5309498831ba678f..0ad2a6eb9b6a1618963a6d5440c0011012f8faa0 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -79,6 +79,7 @@
 #include "llpostprocess.h"
 
 extern LLPointer<LLViewerTexture> gStartTexture;
+extern bool gShiftFrame;
 
 LLPointer<LLViewerTexture> gDisconnectedImagep = NULL;
 
@@ -162,8 +163,11 @@ void display_startup()
 	glClear(GL_DEPTH_BUFFER_BIT);
 }
 
+static LLFastTimer::DeclareTimer FTM_UPDATE_CAMERA("Update Camera");
+
 void display_update_camera()
 {
+	LLFastTimer t(FTM_UPDATE_CAMERA);
 	LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA);
 	// TODO: cut draw distance down if customizing avatar?
 	// TODO: cut draw distance on per-parcel basis?
@@ -217,6 +221,11 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_CLASS("Class");
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_BUMP("Bump");
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_LIST("List");
 static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE_DELETE("Delete");
+static LLFastTimer::DeclareTimer FTM_RESIZE_WINDOW("Resize Window");
+static LLFastTimer::DeclareTimer FTM_HUD_UPDATE("HUD Update");
+static LLFastTimer::DeclareTimer FTM_DISPLAY_UPDATE_GEOM("Update Geom");
+static LLFastTimer::DeclareTimer FTM_TEXTURE_UNBIND("Texture Unbind");
+static LLFastTimer::DeclareTimer FTM_TELEPORT_DISPLAY("Teleport Display");
 
 // Paint the display!
 void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
@@ -226,6 +235,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 	if (gWindowResized)
 	{ //skip render on frames where window has been resized
+		LLFastTimer t(FTM_RESIZE_WINDOW);
 		gGL.flush();
 		glClear(GL_COLOR_BUFFER_BIT);
 		gViewerWindow->getWindow()->swapBuffers();
@@ -362,6 +372,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 	if (gTeleportDisplay)
 	{
+		LLFastTimer t(FTM_TELEPORT_DISPLAY);
 		LLAppViewer::instance()->pingMainloopTimeout("Display:Teleport");
 		const F32 TELEPORT_ARRIVAL_DELAY = 2.f; // Time to preload the world before raising the curtain after we've actually already arrived.
 
@@ -581,6 +592,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				
 		// *TODO: merge these two methods
 		{
+			LLFastTimer t(FTM_HUD_UPDATE);
 			LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD);
 			LLHUDManager::getInstance()->updateEffects();
 			LLHUDObject::updateAll();
@@ -588,6 +600,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		}
 
 		{
+			LLFastTimer t(FTM_DISPLAY_UPDATE_GEOM);
 			LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM);
 			const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time
 			gPipeline.createObjects(max_geom_update_time);
@@ -597,6 +610,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		}
 
 		gPipeline.updateGL();
+		
 		stop_glerror();
 
 		S32 water_clip = 0;
@@ -622,11 +636,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		LLSpatialGroup::sNoDelete = TRUE;
 		LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
 
-		/*if (LLPipeline::sUseOcclusion && LLPipeline::sRenderDeferred)
-		{ //force occlusion on for all render types if doing deferred render (tighter shadow frustum)
-			LLPipeline::sUseOcclusion = 3;
-		}*/
-
 		S32 occlusion = LLPipeline::sUseOcclusion;
 		if (gDepthDirty)
 		{ //depth buffer is invalid, don't overwrite occlusion state
@@ -755,12 +764,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 				gTextureList.updateImages(max_image_decode_time);
 			}
 
-			{
+			/*{
 				LLFastTimer t(FTM_IMAGE_UPDATE_DELETE);
 				//remove dead textures from GL
 				LLImageGL::deleteDeadTextures();
 				stop_glerror();
-			}
+			}*/
 		}
 
 		LLGLState::checkStates();
@@ -889,6 +898,28 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		{
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
 			LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM);
+
+			if (gSavedSettings.getBOOL("RenderDepthPrePass") && LLGLSLShader::sNoFixedFunction)
+			{
+				gGL.setColorMask(false, false);
+				
+				U32 types[] = { 
+					LLRenderPass::PASS_SIMPLE, 
+					LLRenderPass::PASS_FULLBRIGHT, 
+					LLRenderPass::PASS_SHINY 
+				};
+
+				U32 num_types = LL_ARRAY_SIZE(types);
+				gOcclusionProgram.bind();
+				for (U32 i = 0; i < num_types; i++)
+				{
+					gPipeline.renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
+				}
+
+				gOcclusionProgram.unbind();
+			}
+
+
 			gGL.setColorMask(true, false);
 			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 			{
@@ -911,14 +942,18 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			stop_glerror();
 		}
 
-		for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++)
-		{ //dummy cleanup of any currently bound textures
-			if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
-			{
-				gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
-				gGL.getTexUnit(i)->disable();
+		{
+			LLFastTimer t(FTM_TEXTURE_UNBIND);
+			for (U32 i = 0; i < gGLManager.mNumTextureImageUnits; i++)
+			{ //dummy cleanup of any currently bound textures
+				if (gGL.getTexUnit(i)->getCurrType() != LLTexUnit::TT_NONE)
+				{
+					gGL.getTexUnit(i)->unbind(gGL.getTexUnit(i)->getCurrType());
+					gGL.getTexUnit(i)->disable();
+				}
 			}
 		}
+
 		LLAppViewer::instance()->pingMainloopTimeout("Display:RenderFlush");		
 		
 		if (to_texture)
@@ -984,6 +1019,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	display_stats();
 				
 	LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
+
+	gShiftFrame = false;
 }
 
 void render_hud_attachments()
diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp
index 4e14824e69a3f726c575037a80eae56c93ad486c..3a04bbed4f9d0209113b0ce3adb2a04cc40e00a3 100644
--- a/indra/newview/llviewerjointattachment.cpp
+++ b/indra/newview/llviewerjointattachment.cpp
@@ -127,7 +127,11 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
 	{
 		for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++)
 		{
-			object->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER);
+			LLFace *face = object->mDrawable->getFace(face_num);
+			if (face)
+			{
+				face->setState(LLFace::HUD_RENDER);
+			}
 		}
 	}
 
@@ -146,7 +150,11 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object)
 			{
 				for (S32 face_num = 0; face_num < childp->mDrawable->getNumFaces(); face_num++)
 				{
-					childp->mDrawable->getFace(face_num)->setState(LLFace::HUD_RENDER);
+					LLFace * face = childp->mDrawable->getFace(face_num);
+					if (face)
+					{
+						face->setState(LLFace::HUD_RENDER);
+					}
 				}
 			}
 		}
@@ -254,7 +262,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 		{
 			for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++)
 			{
-				object->mDrawable->getFace(face_num)->clearState(LLFace::HUD_RENDER);
+				LLFace * face = object->mDrawable->getFace(face_num);
+				if (face)
+				{
+					face->clearState(LLFace::HUD_RENDER);
+				}
 			}
 		}
 	}
@@ -272,7 +284,11 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object)
 			{
 				for (S32 face_num = 0; face_num < childp->mDrawable->getNumFaces(); face_num++)
 				{
-					childp->mDrawable->getFace(face_num)->clearState(LLFace::HUD_RENDER);
+					LLFace * face = childp->mDrawable->getFace(face_num);
+					if (face)
+					{
+						face->clearState(LLFace::HUD_RENDER);
+					}
 				}
 			}
 		}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index a9bff67f40fed8589d8440abaec20e189d90e99f..d790fbc31ddcd59609ab1193c410524bcacc3642 100755
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -132,6 +132,7 @@ static const U32 LLREQUEST_PERMISSION_THROTTLE_LIMIT	= 5;     // requests
 static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL	= 10.0f; // seconds
 
 extern BOOL gDebugClicks;
+extern bool gShiftFrame;
 
 // function prototypes
 bool check_offer_throttle(const std::string& from_name, bool check_only);
@@ -2770,7 +2771,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 			chat.mSourceType = CHAT_SOURCE_OBJECT;
 
-			if(SYSTEM_FROM == name)
+			// To conclude that the source type of message is CHAT_SOURCE_SYSTEM it's not
+			// enough to check only from name (i.e. fromName = "Second Life"). For example
+			// source type of messages from objects called "Second Life" should not be CHAT_SOURCE_SYSTEM.
+			bool chat_from_system = (SYSTEM_FROM == name) && region_id.isNull() && position.isNull();
+			if(chat_from_system)
 			{
 				// System's UUID is NULL (fixes EXT-4766)
 				chat.mFromID = LLUUID::null;
@@ -2795,7 +2800,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 			// Note: lie to Nearby Chat, pretending that this is NOT an IM, because
 			// IMs from obejcts don't open IM sessions.
 			LLNearbyChat* nearby_chat = LLNearbyChat::getInstance();
-			if(SYSTEM_FROM != name && nearby_chat)
+			if(!chat_from_system && nearby_chat)
 			{
 				chat.mOwnerID = from_id;
 				LLSD args;
@@ -2814,7 +2819,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 
 
 			//Object IMs send with from name: 'Second Life' need to be displayed also in notification toasts (EXT-1590)
-			if (SYSTEM_FROM != name) break;
+			if (!chat_from_system) break;
 			
 			LLSD substitutions;
 			substitutions["NAME"] = name;
@@ -3734,6 +3739,7 @@ void process_avatar_init_complete(LLMessageSystem* msg, void**)
 
 void process_agent_movement_complete(LLMessageSystem* msg, void**)
 {
+	gShiftFrame = true;
 	gAgentMovementCompleted = true;
 
 	LLUUID agent_id;
@@ -4064,6 +4070,8 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 
 	head_rot_chg = dot(last_head_rot, head_rotation);
 
+	//static S32 msg_number = 0;		// Used for diagnostic log messages
+
 	if (force_send || 
 		(cam_center_chg.magVec() > TRANSLATE_THRESHOLD) || 
 		(head_rot_chg < THRESHOLD_HEAD_ROT_QDOT) ||	
@@ -4072,19 +4080,20 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 		control_flag_change != 0 ||
 		flag_change != 0)  
 	{
-/*
+		/* Diagnotics to show why we send the AgentUpdate message.  Also un-commment the msg_number code above and below this block
+		msg_number += 1;
 		if (head_rot_chg < THRESHOLD_HEAD_ROT_QDOT)
 		{
-			//LL_INFOS("Messaging") << "head rot " << head_rotation << LL_ENDL;
-			LL_INFOS("Messaging") << "head_rot_chg = " << head_rot_chg << LL_ENDL;
+			//LL_INFOS("Messaging") << " head rot " << head_rotation << LL_ENDL;
+			LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", head_rot_chg " << head_rot_chg << LL_ENDL;
 		}
 		if (cam_rot_chg.magVec() > ROTATION_THRESHOLD) 
 		{
-			LL_INFOS("Messaging") << "cam rot " <<  cam_rot_chg.magVec() << LL_ENDL;
+			LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam rot " <<  cam_rot_chg.magVec() << LL_ENDL;
 		}
 		if (cam_center_chg.magVec() > TRANSLATE_THRESHOLD)
 		{
-			LL_INFOS("Messaging") << "cam center " << cam_center_chg.magVec() << LL_ENDL;
+			LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", cam center " << cam_center_chg.magVec() << LL_ENDL;
 		}
 //		if (drag_delta_chg.magVec() > TRANSLATE_THRESHOLD)
 //		{
@@ -4092,9 +4101,9 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 //		}
 		if (control_flag_change)
 		{
-			LL_INFOS("Messaging") << "dcf = " << control_flag_change << LL_ENDL;
+			LL_INFOS("Messaging") << "msg " << msg_number << ", frame " << LLFrameTimer::getFrameCount() << ", dcf = " << control_flag_change << LL_ENDL;
 		}
-*/
+		*/
 
 		duplicate_count = 0;
 	}
@@ -4129,6 +4138,26 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 
 	if (duplicate_count < DUP_MSGS && !gDisconnected)
 	{
+		/* More diagnostics to count AgentUpdate messages
+		static S32 update_sec = 0;
+		static S32 update_count = 0;
+		static S32 max_update_count = 0;
+		S32 cur_sec = lltrunc( LLTimer::getTotalSeconds() );
+		update_count += 1;
+		if (cur_sec != update_sec)
+		{
+			if (update_sec != 0)
+			{
+				update_sec = cur_sec;
+				//msg_number = 0;
+				max_update_count = llmax(max_update_count, update_count);
+				llinfos << "Sent " << update_count << " AgentUpdate messages per second, max is " << max_update_count << llendl;
+			}
+			update_sec = cur_sec;
+			update_count = 0;
+		}
+		*/
+
 		LLFastTimer t(FTM_AGENT_UPDATE_SEND);
 		// Build the message
 		msg->newMessageFast(_PREHASH_AgentUpdate);
@@ -4297,8 +4326,6 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 			LL_DEBUGS("Messaging") << "Kill message for local " << local_id << LL_ENDL;
 		}
 
-		LLSelectMgr::getInstance()->removeObjectFromSelections(id);
-
 		// ...don't kill the avatar
 		if (!(id == gAgentID))
 		{
@@ -4321,6 +4348,12 @@ void process_kill_object(LLMessageSystem *mesgsys, void **user_data)
 				gObjectList.mNumUnknownKills++;
 			}
 		}
+
+		// We should remove the object from selection after it is marked dead by gObjectList to make LLToolGrab,
+        // which is using the object, release the mouse capture correctly when the object dies.
+        // See LLToolGrab::handleHoverActive() and LLToolGrab::handleHoverNonPhysical().
+		LLSelectMgr::getInstance()->removeObjectFromSelections(id);
+
 	}
 }
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index cd300accb7f74070ea0f940d7d7d459912393d25..af007743bf46145bbc8b150eac5989167f97eab4 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -199,6 +199,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mID(id),
 	mLocalID(0),
 	mTotalCRC(0),
+	mListIndex(-1),
 	mTEImages(NULL),
 	mGLName(0),
 	mbCanSelect(TRUE),
@@ -432,7 +433,9 @@ void LLViewerObject::dump() const
 	llinfos << "PositionAgent: " << getPositionAgent() << llendl;
 	llinfos << "PositionGlobal: " << getPositionGlobal() << llendl;
 	llinfos << "Velocity: " << getVelocity() << llendl;
-	if (mDrawable.notNull() && mDrawable->getNumFaces())
+	if (mDrawable.notNull() && 
+		mDrawable->getNumFaces() && 
+		mDrawable->getFace(0))
 	{
 		LLFacePool *poolp = mDrawable->getFace(0)->getPool();
 		if (poolp)
@@ -2169,8 +2172,8 @@ BOOL LLViewerObject::isActive() const
 
 BOOL LLViewerObject::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 {
-	static LLFastTimer::DeclareTimer ftm("Viewer Object");
-	LLFastTimer t(ftm);
+	//static LLFastTimer::DeclareTimer ftm("Viewer Object");
+	//LLFastTimer t(ftm);
 
 	if (mDead)
 	{
@@ -2798,6 +2801,23 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
 	   (object = gObjectList.findObject(ft->mTaskID)))
 	{
 		object->loadTaskInvFile(ft->mFilename);
+
+		LLInventoryObject::object_list_t::iterator it = object->mInventory->begin();
+		LLInventoryObject::object_list_t::iterator end = object->mInventory->end();
+		std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs;
+
+		for (; it != end && pending_lst.size(); ++it)
+		{
+			LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get());
+			if(item && item->getType() != LLAssetType::AT_CATEGORY)
+			{
+				std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID());
+				if (id_it != pending_lst.end())
+				{
+					pending_lst.erase(id_it);
+				}
+			}
+		}
 	}
 	else
 	{
@@ -2910,7 +2930,22 @@ void LLViewerObject::updateInventory(
 	bool is_new)
 {
 	LLMemType mt(LLMemType::MTYPE_OBJECT);
-	
+
+	std::list<LLUUID>::iterator begin = mPendingInventoryItemsIDs.begin();
+	std::list<LLUUID>::iterator end = mPendingInventoryItemsIDs.end();
+
+	bool is_fetching = std::find(begin, end, item->getAssetUUID()) != end;
+	bool is_fetched = getInventoryItemByAsset(item->getAssetUUID()) != NULL;
+
+	if (is_fetched || is_fetching)
+	{
+		return;
+	}
+	else
+	{
+		mPendingInventoryItemsIDs.push_back(item->getAssetUUID());
+	}
+
 	// This slices the object into what we're concerned about on the
 	// viewer. The simulator will take the permissions and transfer
 	// ownership.
@@ -4477,7 +4512,11 @@ U32 LLViewerObject::getNumVertices() const
 		num_faces = mDrawable->getNumFaces();
 		for (i = 0; i < num_faces; i++)
 		{
-			num_vertices += mDrawable->getFace(i)->getGeomCount();
+			LLFace * facep = mDrawable->getFace(i);
+			if (facep)
+			{
+				num_vertices += facep->getGeomCount();
+			}
 		}
 	}
 	return num_vertices;
@@ -4492,7 +4531,11 @@ U32 LLViewerObject::getNumIndices() const
 		num_faces = mDrawable->getNumFaces();
 		for (i = 0; i < num_faces; i++)
 		{
-			num_indices += mDrawable->getFace(i)->getIndicesCount();
+			LLFace * facep = mDrawable->getFace(i);
+			if (facep)
+			{
+				num_indices += facep->getIndicesCount();
+			}
 		}
 	}
 	return num_indices;
@@ -4769,9 +4812,11 @@ void LLViewerObject::deleteParticleSource()
 // virtual
 void LLViewerObject::updateDrawable(BOOL force_damped)
 {
-	if (mDrawable.notNull() && 
-		!mDrawable->isState(LLDrawable::ON_MOVE_LIST) &&
-		isChanged(MOVED))
+	if (!isChanged(MOVED))
+	{ //most common case, having an empty if case here makes for better branch prediction
+	}
+	else if (mDrawable.notNull() && 
+		!mDrawable->isState(LLDrawable::ON_MOVE_LIST))
 	{
 		BOOL damped_motion = 
 			!isChanged(SHIFTED) &&										// not shifted between regions this frame and...
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index c8152e1539db7e447b8c5664e7d2f349802f733d..30c3d03635484794bfe98c6fdbc3ba43700142d7 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -229,6 +229,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	const LLUUID &getID() const						{ return mID; }
 	U32 getLocalID() const							{ return mLocalID; }
 	U32 getCRC() const								{ return mTotalCRC; }
+	S32 getListIndex() const						{ return mListIndex; }
+	void setListIndex(S32 idx)						{ mListIndex = idx; }
 
 	virtual BOOL isFlexible() const					{ return FALSE; }
 	virtual BOOL isSculpted() const 				{ return FALSE; }
@@ -589,6 +591,9 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	// Last total CRC received from sim, used for caching
 	U32				mTotalCRC;
 
+	// index into LLViewerObjectList::mActiveObjects or -1 if not in list
+	S32				mListIndex;
+
 	LLPointer<LLViewerTexture> *mTEImages;
 
 	// Selection, picking and rendering variables
@@ -684,6 +689,10 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	F32				mAppAngle;	// Apparent visual arc in degrees
 	F32				mPixelArea; // Apparent area in pixels
 
+	// IDs of of all items in the object's content which are added to the object's content,
+	// but not updated on the server yet. After item was updated, its ID will be removed from this list.
+	std::list<LLUUID> mPendingInventoryItemsIDs;
+
 	// This is the object's inventory from the viewer's perspective.
 	LLInventoryObject::object_list_t* mInventory;
 	class LLInventoryCallbackInfo
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 54ccfb9aae4d44069429441866238425b30e0094..2fd8c87fc24e85cb3a4c9b4d288694d37dc61bf4 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -931,21 +931,30 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 	LLViewerObject *objectp = NULL;	
 	
 	// Make a copy of the list in case something in idleUpdate() messes with it
-	std::vector<LLViewerObject*> idle_list;
-	
+	static std::vector<LLViewerObject*> idle_list;
+
+	U32 idle_count = 0;
+		
 	static LLFastTimer::DeclareTimer idle_copy("Idle Copy");
 
 	{
 		LLFastTimer t(idle_copy);
-		idle_list.reserve( mActiveObjects.size() );
-
- 		for (std::set<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin();
+		
+ 		for (std::vector<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin();
 			active_iter != mActiveObjects.end(); active_iter++)
 		{
 			objectp = *active_iter;
 			if (objectp)
 			{
-				idle_list.push_back( objectp );
+				if (idle_count >= idle_list.size())
+				{
+					idle_list.push_back( objectp );
+				}
+				else
+				{
+					idle_list[idle_count] = objectp;
+				}
+				++idle_count;
 			}
 			else
 			{	// There shouldn't be any NULL pointers in the list, but they have caused
@@ -955,10 +964,13 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 		}
 	}
 
+	std::vector<LLViewerObject*>::iterator idle_end = idle_list.begin()+idle_count;
+
 	if (gSavedSettings.getBOOL("FreezeTime"))
 	{
+		
 		for (std::vector<LLViewerObject*>::iterator iter = idle_list.begin();
-			iter != idle_list.end(); iter++)
+			iter != idle_end; iter++)
 		{
 			objectp = *iter;
 			if (objectp->isAvatar())
@@ -970,17 +982,17 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world)
 	else
 	{
 		for (std::vector<LLViewerObject*>::iterator idle_iter = idle_list.begin();
-			idle_iter != idle_list.end(); idle_iter++)
+			idle_iter != idle_end; idle_iter++)
 		{
 			objectp = *idle_iter;
-			if (!objectp->idleUpdate(agent, world, frame_time))
+			if (objectp->idleUpdate(agent, world, frame_time))
 			{
-				//  If Idle Update returns false, kill object!
-				kill_list.push_back(objectp);
+				num_active_objects++;				
 			}
 			else
 			{
-				num_active_objects++;
+				//  If Idle Update returns false, kill object!
+				kill_list.push_back(objectp);
 			}
 		}
 		for (std::vector<LLViewerObject*>::iterator kill_iter = kill_list.begin();
@@ -1218,7 +1230,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 	{
 		//llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list in cleanupReferences." << llendl;
 		objectp->setOnActiveList(FALSE);
-		mActiveObjects.erase(objectp);
+		removeFromActiveList(objectp);
 	}
 
 	if (objectp->isOnMap())
@@ -1395,6 +1407,26 @@ void LLViewerObjectList::cleanDeadObjects(BOOL use_timer)
 	mNumDeadObjects = 0;
 }
 
+void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp)
+{
+	S32 idx = objectp->getListIndex();
+	if (idx != -1)
+	{ //remove by moving last element to this object's position
+		llassert(mActiveObjects[idx] == objectp);
+		
+		objectp->setListIndex(-1);
+
+		S32 last_index = mActiveObjects.size()-1;
+
+		if (idx != last_index)
+		{
+			mActiveObjects[idx] = mActiveObjects[last_index];
+			mActiveObjects[idx]->setListIndex(idx);
+			mActiveObjects.pop_back();
+		}
+	}
+}
+
 void LLViewerObjectList::updateActive(LLViewerObject *objectp)
 {
 	LLMemType mt(LLMemType::MTYPE_OBJECT);
@@ -1409,13 +1441,29 @@ void LLViewerObjectList::updateActive(LLViewerObject *objectp)
 		if (active)
 		{
 			//llinfos << "Adding " << objectp->mID << " " << objectp->getPCodeString() << " to active list." << llendl;
-			mActiveObjects.insert(objectp);
-			objectp->setOnActiveList(TRUE);
+			S32 idx = objectp->getListIndex();
+			if (idx <= -1)
+			{
+				mActiveObjects.push_back(objectp);
+				objectp->setListIndex(mActiveObjects.size()-1);
+				objectp->setOnActiveList(TRUE);
+			}
+			else
+			{
+				llassert(idx < mActiveObjects.size());
+				llassert(mActiveObjects[idx] == objectp);
+
+				if (idx >= mActiveObjects.size() ||
+					mActiveObjects[idx] != objectp)
+				{
+					llwarns << "Invalid object list index detected!" << llendl;
+				}
+			}
 		}
 		else
 		{
 			//llinfos << "Removing " << objectp->mID << " " << objectp->getPCodeString() << " from active list." << llendl;
-			mActiveObjects.erase(objectp);
+			removeFromActiveList(objectp);
 			objectp->setOnActiveList(FALSE);
 		}
 	}
@@ -1489,6 +1537,10 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id)
 	mPendingPhysicsFlags.erase(object_id);
 }
 
+static LLFastTimer::DeclareTimer FTM_SHIFT_OBJECTS("Shift Objects");
+static LLFastTimer::DeclareTimer FTM_PIPELINE_SHIFT("Pipeline Shift");
+static LLFastTimer::DeclareTimer FTM_REGION_SHIFT("Region Shift");
+
 void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 {
 	// This is called when we shift our origin when we cross region boundaries...
@@ -1500,6 +1552,8 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 		return;
 	}
 
+	LLFastTimer t(FTM_SHIFT_OBJECTS);
+
 	LLViewerObject *objectp;
 	for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter)
 	{
@@ -1516,8 +1570,15 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset)
 		}
 	}
 
-	gPipeline.shiftObjects(offset);
-	LLWorld::getInstance()->shiftRegions(offset);
+	{
+		LLFastTimer t(FTM_PIPELINE_SHIFT);
+		gPipeline.shiftObjects(offset);
+	}
+
+	{
+		LLFastTimer t(FTM_REGION_SHIFT);
+		LLWorld::getInstance()->shiftRegions(offset);
+	}
 }
 
 void LLViewerObjectList::repartitionObjects()
@@ -1721,7 +1782,10 @@ void LLViewerObjectList::generatePickList(LLCamera &camera)
 			LLViewerObject* last_objectp = NULL;
 			for (S32 face_num = 0; face_num < drawablep->getNumFaces(); face_num++)
 			{
-				LLViewerObject* objectp = drawablep->getFace(face_num)->getViewerObject();
+				LLFace * facep = drawablep->getFace(face_num);
+				if (!facep) continue;
+
+				LLViewerObject* objectp = facep->getViewerObject();
 
 				if (objectp && objectp != last_objectp)
 				{
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index 64925f46aeacea27376e964bd3587eb326d5f1c6..9936432a71e288c7e3e73942725fbe24ea6e5486 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -118,7 +118,9 @@ class LLViewerObjectList
 
 	void dirtyAllObjectInventory();
 
+	void removeFromActiveList(LLViewerObject* objectp);
 	void updateActive(LLViewerObject *objectp);
+	
 	void updateAvatarVisibility();
 
 	// Selection related stuff
@@ -197,7 +199,7 @@ class LLViewerObjectList
 	typedef std::vector<LLPointer<LLViewerObject> > vobj_list_t;
 
 	vobj_list_t mObjects;
-	std::set<LLPointer<LLViewerObject> > mActiveObjects;
+	std::vector<LLPointer<LLViewerObject> > mActiveObjects;
 
 	vobj_list_t mMapObjects;
 
diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index 6b3e04348a1c386fb8bd174d50945ae87165394e..345023dbfa42bf0138772bddb458a42a459a9c3f 100644
--- a/indra/newview/llviewerpartsim.cpp
+++ b/indra/newview/llviewerpartsim.cpp
@@ -476,7 +476,7 @@ void LLViewerPartSim::checkParticleCount(U32 size)
 LLViewerPartSim::LLViewerPartSim()
 {
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
-	sMaxParticleCount = gSavedSettings.getS32("RenderMaxPartCount");
+	sMaxParticleCount = llmin(gSavedSettings.getS32("RenderMaxPartCount"), LL_MAX_PARTICLE_COUNT);
 	static U32 id_seed = 0;
 	mID = ++id_seed;
 }
diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h
index 3e20f999c022a8695f0308c0d0ab642ab0b4291c..c9959c63ec23376039ff6b059eb2664577c09a6c 100644
--- a/indra/newview/llviewerpartsim.h
+++ b/indra/newview/llviewerpartsim.h
@@ -39,6 +39,8 @@ class LLViewerRegion;
 class LLViewerTexture;
 class LLVOPartGroup;
 
+#define LL_MAX_PARTICLE_COUNT 8192
+
 typedef void (*LLVPCallback)(LLViewerPart &part, const F32 dt);
 
 ///////////////////
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index e3cb985ddb3a35bab24412d0d2a6f5d20f9613b0..e4108e2cd1b13dc0c02ff32db595994679c44856 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1461,7 +1461,8 @@ void LLViewerRegion::unpackRegionHandshake()
 		// all of our terrain stuff, by
 		if (compp->getParamsReady())
 		{
-			getLand().dirtyAllPatches();
+			//this line creates frame stalls on region crossing and removing it appears to have no effect
+			//getLand().dirtyAllPatches();
 		}
 		else
 		{
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 10c61c01d5c17e671dd318c7a5fb7b7fc1dcca56..a6c564a6a10e7d97c6f406058d57cbd6da522656 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -63,8 +63,16 @@ bool				LLViewerShaderMgr::sSkipReload = false;
 
 LLVector4			gShinyOrigin;
 
+//transform shaders
+LLGLSLShader			gTransformPositionProgram;
+LLGLSLShader			gTransformTexCoordProgram;
+LLGLSLShader			gTransformNormalProgram;
+LLGLSLShader			gTransformColorProgram;
+LLGLSLShader			gTransformBinormalProgram;
+
 //utility shaders
 LLGLSLShader	gOcclusionProgram;
+LLGLSLShader	gOcclusionCubeProgram;
 LLGLSLShader	gCustomAlphaProgram;
 LLGLSLShader	gGlowCombineProgram;
 LLGLSLShader	gSplatTextureRectProgram;
@@ -72,6 +80,7 @@ LLGLSLShader	gGlowCombineFXAAProgram;
 LLGLSLShader	gTwoTextureAddProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
+LLGLSLShader	gClipProgram;
 LLGLSLShader	gAlphaMaskProgram;
 
 //object shaders
@@ -178,6 +187,7 @@ LLGLSLShader			gDeferredSunProgram;
 LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
 LLGLSLShader			gDeferredShadowProgram;
+LLGLSLShader			gDeferredShadowCubeProgram;
 LLGLSLShader			gDeferredShadowAlphaMaskProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
 LLGLSLShader			gDeferredAttachmentShadowProgram;
@@ -437,7 +447,8 @@ void LLViewerShaderMgr::setShaders()
 		S32 wl_class = 2;
 		S32 water_class = 2;
 		S32 deferred_class = 0;
-		
+		S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0;
+
 		if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
 		    gSavedSettings.getBOOL("RenderDeferred") &&
 			gSavedSettings.getBOOL("RenderAvatarVP") &&
@@ -475,6 +486,7 @@ void LLViewerShaderMgr::setShaders()
 			gSky.mVOSkyp->forceSkyUpdate();
 		}
 
+		
 		// Load lighting shaders
 		mVertexShaderLevel[SHADER_LIGHTING] = light_class;
 		mVertexShaderLevel[SHADER_INTERFACE] = light_class;
@@ -484,6 +496,7 @@ void LLViewerShaderMgr::setShaders()
 		mVertexShaderLevel[SHADER_EFFECT] = effect_class;
 		mVertexShaderLevel[SHADER_WINDLIGHT] = wl_class;
 		mVertexShaderLevel[SHADER_DEFERRED] = deferred_class;
+		mVertexShaderLevel[SHADER_TRANSFORM] = transform_class;
 
 		BOOL loaded = loadBasicShaders();
 
@@ -493,65 +506,109 @@ void LLViewerShaderMgr::setShaders()
 			gPipeline.mVertexShadersLoaded = 1;
 
 			// Load all shaders to set max levels
-			loadShadersEnvironment();
-			loadShadersWater();
-			loadShadersWindLight();
-			loadShadersEffects();
-			loadShadersInterface();
+			loaded = loadShadersEnvironment();
+
+			if (loaded)
+			{
+				loaded = loadShadersWater();
+			}
+
+			if (loaded)
+			{
+				loaded = loadShadersWindLight();
+			}
+
+			if (loaded)
+			{
+				loaded = loadShadersEffects();
+			}
+
+			if (loaded)
+			{
+				loaded = loadShadersInterface();
+			}
 			
-			// Load max avatar shaders to set the max level
-			mVertexShaderLevel[SHADER_AVATAR] = 3;
-			mMaxAvatarShaderLevel = 3;
-						
-			if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject())
-			{ //hardware skinning is enabled and rigged attachment shaders loaded correctly
-				BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
-				S32 avatar_class = 1;
-				
-				// cloth is a class3 shader
-				if(avatar_cloth)
-				{
-					avatar_class = 3;
-				}
+			if (loaded)
+			{
+				loaded = loadTransformShaders();
+			}
 
-				// Set the actual level
-				mVertexShaderLevel[SHADER_AVATAR] = avatar_class;
-				loadShadersAvatar();
-				if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class)
-				{
-					if (mVertexShaderLevel[SHADER_AVATAR] == 0)
+			if (loaded)
+			{
+				// Load max avatar shaders to set the max level
+				mVertexShaderLevel[SHADER_AVATAR] = 3;
+				mMaxAvatarShaderLevel = 3;
+				
+				if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject())
+				{ //hardware skinning is enabled and rigged attachment shaders loaded correctly
+					BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth");
+					S32 avatar_class = 1;
+				
+					// cloth is a class3 shader
+					if(avatar_cloth)
 					{
-						gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
+						avatar_class = 3;
 					}
-					if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3)
+
+					// Set the actual level
+					mVertexShaderLevel[SHADER_AVATAR] = avatar_class;
+					loadShadersAvatar();
+					if (mVertexShaderLevel[SHADER_AVATAR] != avatar_class)
 					{
-						avatar_cloth = true;
+						if (mVertexShaderLevel[SHADER_AVATAR] == 0)
+						{
+							gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
+						}
+						if(llmax(mVertexShaderLevel[SHADER_AVATAR]-1,0) >= 3)
+						{
+							avatar_cloth = true;
+						}
+						else
+						{
+							avatar_cloth = false;
+						}
+						gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth);
 					}
-					else
+				}
+				else
+				{ //hardware skinning not possible, neither is deferred rendering
+					mVertexShaderLevel[SHADER_AVATAR] = 0;
+					mVertexShaderLevel[SHADER_DEFERRED] = 0;
+
+					if (gSavedSettings.getBOOL("RenderAvatarVP"))
 					{
-						avatar_cloth = false;
+						gSavedSettings.setBOOL("RenderDeferred", FALSE);
+						gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
+						gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
 					}
-					gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth);
+
+					loadShadersAvatar(); // unloads
+
+					loaded = loadShadersObject();
 				}
 			}
-			else
-			{ //hardware skinning not possible, neither is deferred rendering
-				mVertexShaderLevel[SHADER_AVATAR] = 0;
-				mVertexShaderLevel[SHADER_DEFERRED] = 0;
-
-				if (gSavedSettings.getBOOL("RenderAvatarVP"))
-				{
-					gSavedSettings.setBOOL("RenderDeferred", FALSE);
-					gSavedSettings.setBOOL("RenderAvatarCloth", FALSE);
-					gSavedSettings.setBOOL("RenderAvatarVP", FALSE);
+
+			if (!loaded)
+			{ //some shader absolutely could not load, try to fall back to a simpler setting
+				if (gSavedSettings.getBOOL("WindLightUseAtmosShaders"))
+				{ //disable windlight and try again
+					gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE);
+					reentrance = false;
+					setShaders();
+					return;
 				}
 
-				loadShadersAvatar(); // unloads
-				loadShadersObject();
-			}
+				if (gSavedSettings.getBOOL("VertexShaderEnable"))
+				{ //disable shaders outright and try again
+					gSavedSettings.setBOOL("VertexShaderEnable", FALSE);
+					reentrance = false;
+					setShaders();
+					return;
+				}
+			}		
 
-			if (!loadShadersDeferred())
-			{
+			if (loaded && !loadShadersDeferred())
+			{ //everything else succeeded but deferred failed, disable deferred and try again
 				gSavedSettings.setBOOL("RenderDeferred", FALSE);
 				reentrance = false;
 				setShaders();
@@ -600,7 +657,9 @@ void LLViewerShaderMgr::setShaders()
 void LLViewerShaderMgr::unloadShaders()
 {
 	gOcclusionProgram.unload();
+	gOcclusionCubeProgram.unload();
 	gDebugProgram.unload();
+	gClipProgram.unload();
 	gAlphaMaskProgram.unload();
 	gUIProgram.unload();
 	gCustomAlphaProgram.unload();
@@ -692,6 +751,12 @@ void LLViewerShaderMgr::unloadShaders()
 	gDeferredSkinnedBumpProgram.unload();
 	gDeferredSkinnedAlphaProgram.unload();
 
+	gTransformPositionProgram.unload();
+	gTransformTexCoordProgram.unload();
+	gTransformNormalProgram.unload();
+	gTransformColorProgram.unload();
+	gTransformBinormalProgram.unload();
+
 	mVertexShaderLevel[SHADER_LIGHTING] = 0;
 	mVertexShaderLevel[SHADER_OBJECT] = 0;
 	mVertexShaderLevel[SHADER_AVATAR] = 0;
@@ -700,6 +765,7 @@ void LLViewerShaderMgr::unloadShaders()
 	mVertexShaderLevel[SHADER_INTERFACE] = 0;
 	mVertexShaderLevel[SHADER_EFFECT] = 0;
 	mVertexShaderLevel[SHADER_WINDLIGHT] = 0;
+	mVertexShaderLevel[SHADER_TRANSFORM] = 0;
 
 	gPipeline.mVertexShadersLoaded = 0;
 }
@@ -828,7 +894,7 @@ BOOL LLViewerShaderMgr::loadShadersEnvironment()
 	if (mVertexShaderLevel[SHADER_ENVIRONMENT] == 0)
 	{
 		gTerrainProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 
 	if (success)
@@ -868,7 +934,7 @@ BOOL LLViewerShaderMgr::loadShadersWater()
 		gWaterProgram.unload();
 		gUnderWaterProgram.unload();
 		gTerrainWaterProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 
 	if (success)
@@ -953,7 +1019,7 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 		gGlowExtractProgram.unload();
 		gPostColorFilterProgram.unload();	
 		gPostNightVisionProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 
 	if (success)
@@ -1013,6 +1079,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredBlurLightProgram.unload();
 		gDeferredSoftenProgram.unload();
 		gDeferredShadowProgram.unload();
+		gDeferredShadowCubeProgram.unload();
 		gDeferredShadowAlphaMaskProgram.unload();
 		gDeferredAvatarShadowProgram.unload();
 		gDeferredAttachmentShadowProgram.unload();
@@ -1200,7 +1267,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSpotLightProgram.mName = "Deferred SpotLight Shader";
 		gDeferredSpotLightProgram.mShaderFiles.clear();
 		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/spotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredSpotLightProgram.createShader(NULL, NULL);
 	}
@@ -1209,7 +1276,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	{
 		gDeferredMultiSpotLightProgram.mName = "Deferred MultiSpotLight Shader";
 		gDeferredMultiSpotLightProgram.mShaderFiles.clear();
-		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL);
@@ -1366,6 +1433,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredShadowProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredShadowCubeProgram.mName = "Deferred Shadow Cube Shader";
+		gDeferredShadowCubeProgram.mShaderFiles.clear();
+		gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowCubeV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShadowCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredShadowCubeProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredShadowAlphaMaskProgram.mName = "Deferred Shadow Alpha Mask Shader";
@@ -2410,7 +2487,7 @@ BOOL LLViewerShaderMgr::loadShadersAvatar()
 		gAvatarWaterProgram.unload();
 		gAvatarEyeballProgram.unload();
 		gAvatarPickProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 
 	if (success)
@@ -2504,7 +2581,7 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 	if (mVertexShaderLevel[SHADER_INTERFACE] == 0)
 	{
 		gHighlightProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 	
 	if (success)
@@ -2645,6 +2722,16 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		success = gOcclusionProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gOcclusionCubeProgram.mName = "Occlusion Cube Shader";
+		gOcclusionCubeProgram.mShaderFiles.clear();
+		gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionCubeV.glsl", GL_VERTEX_SHADER_ARB));
+		gOcclusionCubeProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gOcclusionCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gOcclusionCubeProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDebugProgram.mName = "Debug Shader";
@@ -2655,6 +2742,16 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		success = gDebugProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gClipProgram.mName = "Clip Shader";
+		gClipProgram.mShaderFiles.clear();
+		gClipProgram.mShaderFiles.push_back(make_pair("interface/clipV.glsl", GL_VERTEX_SHADER_ARB));
+		gClipProgram.mShaderFiles.push_back(make_pair("interface/clipF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gClipProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gClipProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gAlphaMaskProgram.mName = "Alpha Mask Shader";
@@ -2682,7 +2779,7 @@ BOOL LLViewerShaderMgr::loadShadersWindLight()
 	{
 		gWLSkyProgram.unload();
 		gWLCloudProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 
 	if (success)
@@ -2712,6 +2809,95 @@ BOOL LLViewerShaderMgr::loadShadersWindLight()
 	return success;
 }
 
+BOOL LLViewerShaderMgr::loadTransformShaders()
+{
+	BOOL success = TRUE;
+	
+	if (mVertexShaderLevel[SHADER_TRANSFORM] < 1)
+	{
+		gTransformPositionProgram.unload();
+		gTransformTexCoordProgram.unload();
+		gTransformNormalProgram.unload();
+		gTransformColorProgram.unload();
+		gTransformBinormalProgram.unload();
+		return TRUE;
+	}
+
+	if (success)
+	{
+		gTransformPositionProgram.mName = "Position Transform Shader";
+		gTransformPositionProgram.mShaderFiles.clear();
+		gTransformPositionProgram.mShaderFiles.push_back(make_pair("transform/positionV.glsl", GL_VERTEX_SHADER_ARB));
+		gTransformPositionProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM];
+
+		const char* varyings[] = {
+			"position_out",
+			"texture_index_out",
+		};
+	
+		success = gTransformPositionProgram.createShader(NULL, NULL, 2, varyings);
+	}
+
+	if (success)
+	{
+		gTransformTexCoordProgram.mName = "TexCoord Transform Shader";
+		gTransformTexCoordProgram.mShaderFiles.clear();
+		gTransformTexCoordProgram.mShaderFiles.push_back(make_pair("transform/texcoordV.glsl", GL_VERTEX_SHADER_ARB));
+		gTransformTexCoordProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM];
+
+		const char* varyings[] = {
+			"texcoord_out",
+		};
+	
+		success = gTransformTexCoordProgram.createShader(NULL, NULL, 1, varyings);
+	}
+
+	if (success)
+	{
+		gTransformNormalProgram.mName = "Normal Transform Shader";
+		gTransformNormalProgram.mShaderFiles.clear();
+		gTransformNormalProgram.mShaderFiles.push_back(make_pair("transform/normalV.glsl", GL_VERTEX_SHADER_ARB));
+		gTransformNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM];
+
+		const char* varyings[] = {
+			"normal_out",
+		};
+	
+		success = gTransformNormalProgram.createShader(NULL, NULL, 1, varyings);
+	}
+
+	if (success)
+	{
+		gTransformColorProgram.mName = "Color Transform Shader";
+		gTransformColorProgram.mShaderFiles.clear();
+		gTransformColorProgram.mShaderFiles.push_back(make_pair("transform/colorV.glsl", GL_VERTEX_SHADER_ARB));
+		gTransformColorProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM];
+
+		const char* varyings[] = {
+			"color_out",
+		};
+	
+		success = gTransformColorProgram.createShader(NULL, NULL, 1, varyings);
+	}
+
+	if (success)
+	{
+		gTransformBinormalProgram.mName = "Binormal Transform Shader";
+		gTransformBinormalProgram.mShaderFiles.clear();
+		gTransformBinormalProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB));
+		gTransformBinormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM];
+
+		const char* varyings[] = {
+			"binormal_out",
+		};
+	
+		success = gTransformBinormalProgram.createShader(NULL, NULL, 1, varyings);
+	}
+
+	
+	return success;
+}
+
 std::string LLViewerShaderMgr::getShaderDirPrefix(void)
 {
 	return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "shaders/class");
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 95eb551bf1ba6837f1c8e98762ae3863f41a99ec..8f7ff8dd2f7cdac011344848f4100c0ff9e25bc4 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -54,6 +54,7 @@ class LLViewerShaderMgr: public LLShaderMgr
 	BOOL loadShadersWater();
 	BOOL loadShadersInterface();
 	BOOL loadShadersWindLight();
+	BOOL loadTransformShaders();
 
 	std::vector<S32> mVertexShaderLevel;
 	S32	mMaxAvatarShaderLevel;
@@ -69,6 +70,7 @@ class LLViewerShaderMgr: public LLShaderMgr
 		SHADER_WINDLIGHT,
 		SHADER_WATER,
 		SHADER_DEFERRED,
+		SHADER_TRANSFORM,
 		SHADER_COUNT
 	};
 
@@ -209,13 +211,24 @@ inline bool operator != (LLViewerShaderMgr::shader_iter const & a, LLViewerShade
 
 extern LLVector4			gShinyOrigin;
 
+//transform shaders
+extern LLGLSLShader			gTransformPositionProgram;
+extern LLGLSLShader			gTransformTexCoordProgram;
+extern LLGLSLShader			gTransformNormalProgram;
+extern LLGLSLShader			gTransformColorProgram;
+extern LLGLSLShader			gTransformBinormalProgram;
+
+
+
 //utility shaders
 extern LLGLSLShader			gOcclusionProgram;
+extern LLGLSLShader			gOcclusionCubeProgram;
 extern LLGLSLShader			gCustomAlphaProgram;
 extern LLGLSLShader			gGlowCombineProgram;
 extern LLGLSLShader			gSplatTextureRectProgram;
 extern LLGLSLShader			gGlowCombineFXAAProgram;
 extern LLGLSLShader			gDebugProgram;
+extern LLGLSLShader			gClipProgram;
 extern LLGLSLShader			gAlphaMaskProgram;
 
 //output tex0[tc0] + tex1[tc1]
@@ -328,6 +341,7 @@ extern LLGLSLShader			gDeferredBlurLightProgram;
 extern LLGLSLShader			gDeferredAvatarProgram;
 extern LLGLSLShader			gDeferredSoftenProgram;
 extern LLGLSLShader			gDeferredShadowProgram;
+extern LLGLSLShader			gDeferredShadowCubeProgram;
 extern LLGLSLShader			gDeferredShadowAlphaMaskProgram;
 extern LLGLSLShader			gDeferredPostProgram;
 extern LLGLSLShader			gDeferredCoFProgram;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 497e95c5e3712286b376b608cc666fac4a6df5b4..28f4ec72f30a9097420dfaa20cf3f5c93c9587b3 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -789,6 +789,24 @@ void send_stats()
 	system["gpu_class"] = (S32)LLFeatureManager::getInstance()->getGPUClass();
 	system["gpu_vendor"] = gGLManager.mGLVendorShort;
 	system["gpu_version"] = gGLManager.mDriverVersionVendorString;
+	system["opengl_version"] = gGLManager.mGLVersionString;
+
+	S32 shader_level = 0;
+	if (LLPipeline::sRenderDeferred)
+	{
+		shader_level = 3;
+	}
+	else if (gPipeline.canUseWindLightShadersOnObjects())
+	{
+		shader_level = 2;
+	}
+	else if (gPipeline.canUseVertexShaders())
+	{
+		shader_level = 1;
+	}
+
+
+	system["shader_level"] = shader_level;
 
 	LLSD &download = body["downloads"];
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index d844aeb12a407958b42abdff73780dcfd4d4c5be..7f638a24bf58aa1e93d790311c106c5c1ed09a20 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1398,10 +1398,10 @@ void LLViewerFetchedTexture::dump()
 // ONLY called from LLViewerFetchedTextureList
 void LLViewerFetchedTexture::destroyTexture() 
 {
-	if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes)//not ready to release unused memory.
-	{
-		return ;
-	}
+	//if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes)//not ready to release unused memory.
+	//{
+	//	return ;
+	//}
 	if (mNeedsCreateTexture)//return if in the process of generating a new texture.
 	{
 		return ;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 528e0080b78a61987fff9243925959432d885566..9a6c0569a996056846df55a8769e6263f7edfcd4 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -705,7 +705,7 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 			// Flush formatted images using a lazy flush
 			//
 			const F32 LAZY_FLUSH_TIMEOUT = 30.f; // stop decoding
-			const F32 MAX_INACTIVE_TIME  = 50.f; // actually delete
+			const F32 MAX_INACTIVE_TIME  = 20.f; // actually delete
 			S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference
 			
 			S32 num_refs = imagep->getNumRefs();
diff --git a/indra/newview/llviewervisualparam.h b/indra/newview/llviewervisualparam.h
index dd7751acd7bba704b4eca5111fa29a421ad8b293..3bc95cbfbfbf42d5963232cd744cfbc08807270f 100644
--- a/indra/newview/llviewervisualparam.h
+++ b/indra/newview/llviewervisualparam.h
@@ -83,11 +83,11 @@ class LLViewerVisualParam : public LLVisualParam
 
 	// New Virtual functions
 	virtual F32					getTotalDistortion() = 0;
-	virtual const LLVector3&	getAvgDistortion() = 0;
+	virtual const LLVector4a&	getAvgDistortion() = 0;
 	virtual F32					getMaxDistortion() = 0;
-	virtual LLVector3			getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0;
-	virtual const LLVector3*	getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0;
-	virtual const LLVector3*	getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0;
+	virtual LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *mesh) = 0;
+	virtual const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **mesh) = 0;
+	virtual const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0;
 	
 	// interface methods
 	F32					getDisplayOrder() const		{ return getInfo()->mEditGroupDisplayOrder; }
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 39e330ad666c727d874576d4457e88666b0b0b9a..862d53c6134948b3e5d6e182c0ea6e2f9445ee4e 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -175,6 +175,7 @@
 #include "llviewershadermgr.h"
 #include "llviewerstats.h"
 #include "llvoavatarself.h"
+#include "llvopartgroup.h"
 #include "llvovolume.h"
 #include "llworld.h"
 #include "llworldmapview.h"
@@ -4660,6 +4661,8 @@ void LLViewerWindow::stopGL(BOOL save_state)
 		LLVOAvatar::destroyGL();
 		stop_glerror();
 
+		LLVOPartGroup::destroyGL();
+
 		LLViewerDynamicTexture::destroyGL();
 		stop_glerror();
 
@@ -4713,7 +4716,8 @@ void LLViewerWindow::restoreGL(const std::string& progress_message)
 		gBumpImageList.restoreGL();
 		LLViewerDynamicTexture::restoreGL();
 		LLVOAvatar::restoreGL();
-		
+		LLVOPartGroup::restoreGL();
+
 		gResizeScreenTexture = TRUE;
 		gWindowResized = TRUE;
 
@@ -4759,8 +4763,11 @@ void LLViewerWindow::requestResolutionUpdate()
 	mResDirty = true;
 }
 
+static LLFastTimer::DeclareTimer FTM_WINDOW_CHECK_SETTINGS("Window Settings");
+
 void LLViewerWindow::checkSettings()
 {
+	LLFastTimer t(FTM_WINDOW_CHECK_SETTINGS);
 	if (mStatesDirty)
 	{
 		gGL.refreshState();
@@ -5196,8 +5203,10 @@ void LLPickInfo::getSurfaceInfo()
 			if (objectp->mDrawable.notNull() && mObjectFace > -1)
 			{
 				LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
-
-				mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal);
+				if (facep)
+				{
+					mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal);
+				}
 			}
 
 			// and XY coords:
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index eada77156e477aa9c4cc1640995537c8acaeeaa4..28a25f744b8fac674d8faf26295253e7a1db2624 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -817,6 +817,7 @@ LLVOAvatar::~LLVOAvatar()
 	lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
 
 	mRoot.removeAllChildren();
+	mJointMap.clear();
 
 	deleteAndClearArray(mSkeleton);
 	deleteAndClearArray(mCollisionVolumes);
@@ -961,7 +962,7 @@ void LLVOAvatar::deleteLayerSetCaches(bool clearAll)
 		}
 		if (mBakedTextureDatas[i].mMaskTexName)
 		{
-			glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName));
+			LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName));
 			mBakedTextureDatas[i].mMaskTexName = 0 ;
 		}
 	}
@@ -1459,8 +1460,6 @@ void LLVOAvatar::onShift(const LLVector4a& shift_vector)
 	const LLVector3& shift = reinterpret_cast<const LLVector3&>(shift_vector);
 	mLastAnimExtents[0] += shift;
 	mLastAnimExtents[1] += shift;
-	mNeedsImpostorUpdate = TRUE;
-	mNeedsAnimUpdate = TRUE;
 }
 
 void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
@@ -1934,6 +1933,7 @@ void LLVOAvatar::buildCharacter()
 	// remove all of mRoot's children
 	//-------------------------------------------------------------------------
 	mRoot.removeAllChildren();
+	mJointMap.clear();
 	mIsBuilt = FALSE;
 
 	//-------------------------------------------------------------------------
@@ -2094,11 +2094,17 @@ void LLVOAvatar::releaseMeshData()
 	if (mDrawable.notNull())
 	{
 		LLFace* facep = mDrawable->getFace(0);
-		facep->setSize(0, 0);
-		for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
+		if (facep)
 		{
-			facep = mDrawable->getFace(i);
 			facep->setSize(0, 0);
+			for(S32 i = mNumInitFaces ; i < mDrawable->getNumFaces(); i++)
+			{
+				facep = mDrawable->getFace(i);
+				if (facep)
+				{
+					facep->setSize(0, 0);
+				}
+			}
 		}
 	}
 	
@@ -2183,15 +2189,20 @@ void LLVOAvatar::updateMeshData()
 				part_index-- ;
 			}
 		
-			LLFace* facep ;
+			LLFace* facep = NULL;
 			if(f_num < mDrawable->getNumFaces()) 
 			{
 				facep = mDrawable->getFace(f_num);
 			}
 			else
 			{
-				facep = mDrawable->addFace(mDrawable->getFace(0)->getPool(), mDrawable->getFace(0)->getTexture()) ;
+				facep = mDrawable->getFace(0);
+				if (facep)
+				{
+					facep = mDrawable->addFace(facep->getPool(), facep->getTexture()) ;
+				}
 			}
+			if (!facep) continue;
 			
 			// resize immediately
 			facep->setSize(num_vertices, num_indices);
@@ -2379,7 +2390,7 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid)
 	}
 }
 
-static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar");
+static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Avatar Update");
 static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints");
 
 //------------------------------------------------------------------------
@@ -4236,10 +4247,14 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 			mNeedsSkin = FALSE;
 			mLastSkinTime = gFrameTimeSeconds;
 
-			LLVertexBuffer* vb = mDrawable->getFace(0)->getVertexBuffer();
-			if (vb)
+			LLFace * face = mDrawable->getFace(0);
+			if (face)
 			{
-				vb->flush();
+				LLVertexBuffer* vb = face->getVertexBuffer();
+				if (vb)
+				{
+					vb->flush();
+				}
 			}
 		}
 	}
@@ -5122,7 +5137,20 @@ const LLUUID& LLVOAvatar::getID() const
 // RN: avatar joints are multi-rooted to include screen-based attachments
 LLJoint *LLVOAvatar::getJoint( const std::string &name )
 {
-	LLJoint* jointp = mRoot.findJoint(name);
+	joint_map_t::iterator iter = mJointMap.find(name);
+
+	LLJoint* jointp = NULL;
+
+	if (iter == mJointMap.end() || iter->second == NULL)
+	{ //search for joint and cache found joint in lookup table
+		jointp = mRoot.findJoint(name);
+		mJointMap[name] = jointp;
+	}
+	else
+	{ //return cached pointer
+		jointp = iter->second;
+	}
+
 	return jointp;
 }
 
@@ -7492,7 +7520,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture
 			}
 
 			U32 gl_name;
-			LLImageGL::generateTextures(1, &gl_name );
+			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_ALPHA8, 1, &gl_name );
 			stop_glerror();
 
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name);
@@ -7529,7 +7557,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture
 						maskData->mLastDiscardLevel = discard_level;
 						if (self->mBakedTextureDatas[baked_index].mMaskTexName)
 						{
-							LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName));
+							LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, &(self->mBakedTextureDatas[baked_index].mMaskTexName));
 						}
 						self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name;
 						found_texture_id = true;
@@ -8395,7 +8423,7 @@ BOOL LLVOAvatar::updateLOD()
 	BOOL res = updateJointLODs();
 
 	LLFace* facep = mDrawable->getFace(0);
-	if (!facep->getVertexBuffer())
+	if (!facep || !facep->getVertexBuffer())
 	{
 		dirtyMesh(2);
 	}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 6fb56a4c0bb2bf70a0134746170612c59e665079..fab15c200defd1a1c0633a6beadc59d7c60e4635 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -356,6 +356,10 @@ class LLVOAvatar :
 
 	LLVector3			mHeadOffset; // current head position
 	LLViewerJoint		mRoot;
+
+	typedef std::map<std::string, LLJoint*> joint_map_t;
+	joint_map_t			mJointMap;
+
 protected:
 	static BOOL			parseSkeletonFile(const std::string& filename);
 	void				buildCharacter();
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index d2609e5587226a5103b08d3deefc4491e3951506..98f7245f8d1d4d79c078c6e9b4357caca3736c83 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -2751,7 +2751,7 @@ void LLVOAvatarSelf::deleteScratchTextures()
 		 namep; 
 		 namep = sScratchTexNames.getNextData() )
 	{
-		LLImageGL::deleteTextures(1, (U32 *)namep );
+		LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, 0, -1, 1, (U32 *)namep );
 		stop_glerror();
 	}
 
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 8a79d564d3a3dfd7dfdbe65958e0559c51713804..5ad9ccc9af3937c2c8256656acdd1401822c729e 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -34,6 +34,7 @@
 #include "llagentcamera.h"
 #include "llnotificationsutil.h"
 #include "lldrawable.h"
+#include "lldrawpoolalpha.h"
 #include "llface.h"
 #include "llsky.h"
 #include "llsurface.h"
@@ -380,8 +381,10 @@ BOOL LLVOGrass::updateLOD()
 		{
 			mNumBlades <<= 1;
 		}
-
-		face->setSize(mNumBlades*8, mNumBlades*12);
+		if (face)
+		{
+			face->setSize(mNumBlades*8, mNumBlades*12);
+		}
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 	}
 	else if (num_blades <= (mNumBlades >> 1))
@@ -391,7 +394,10 @@ BOOL LLVOGrass::updateLOD()
 			mNumBlades >>=1;
 		}
 
-		face->setSize(mNumBlades*8, mNumBlades*12);
+		if (face)
+		{
+			face->setSize(mNumBlades*8, mNumBlades*12);
+		}
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
 		return TRUE;
 	}
@@ -449,14 +455,16 @@ void LLVOGrass::plantBlades()
 	}
 		
 	LLFace *face = mDrawable->getFace(0);
+	if (face)
+	{
+		face->setTexture(getTEImage(0));
+		face->setState(LLFace::GLOBAL);
+		face->setSize(mNumBlades * 8, mNumBlades * 12);
+		face->setVertexBuffer(NULL);
+		face->setTEOffset(0);
+		face->mCenterLocal = mPosition + mRegionp->getOriginAgent();
+	}
 
-	face->setTexture(getTEImage(0));
-	face->setState(LLFace::GLOBAL);
-	face->setSize(mNumBlades * 8, mNumBlades * 12);
-	face->setVertexBuffer(NULL);
-	face->setTEOffset(0);
-	face->mCenterLocal = mPosition + mRegionp->getOriginAgent();
-	
 	mDepth = (face->mCenterLocal - LLViewerCamera::getInstance()->getOrigin())*LLViewerCamera::getInstance()->getAtAxis();
 	mDrawable->setPosition(face->mCenterLocal);
 	mDrawable->movePartition();
@@ -486,6 +494,8 @@ void LLVOGrass::getGeometry(S32 idx,
 	LLColor4U color(255,255,255,255);
 
 	LLFace *face = mDrawable->getFace(idx);
+	if (!face)
+		return;
 
 	F32 width  = sSpeciesTable[mSpecies]->mBladeSizeX;
 	F32 height = sSpeciesTable[mSpecies]->mBladeSizeY;
@@ -594,6 +604,7 @@ U32 LLVOGrass::getPartitionType() const
 }
 
 LLGrassPartition::LLGrassPartition()
+: LLSpatialPartition(LLDrawPoolAlpha::VERTEX_DATA_MASK | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, GL_STREAM_DRAW_ARB)
 {
 	mDrawableType = LLPipeline::RENDER_TYPE_GRASS;
 	mPartitionType = LLViewerRegion::PARTITION_GRASS;
@@ -604,6 +615,143 @@ LLGrassPartition::LLGrassPartition()
 	mBufferUsage = GL_DYNAMIC_DRAW_ARB;
 }
 
+void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
+{
+	group->mBufferUsage = mBufferUsage;
+
+	mFaceList.clear();
+
+	LLViewerCamera* camera = LLViewerCamera::getInstance();
+	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
+	{
+		LLDrawable* drawablep = *i;
+		
+		if (drawablep->isDead())
+		{
+			continue;
+		}
+
+		LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get();
+		obj->mDepth = 0.f;
+		
+		if (drawablep->isAnimating())
+		{
+			group->mBufferUsage = GL_STREAM_DRAW_ARB;
+		}
+
+		U32 count = 0;
+		for (S32 j = 0; j < drawablep->getNumFaces(); ++j)
+		{
+			drawablep->updateFaceSize(j);
+
+			LLFace* facep = drawablep->getFace(j);
+			if ( !facep || !facep->hasGeometry())
+			{
+				continue;
+			}
+			
+			if ((facep->getGeomCount() + vertex_count) <= 65536)
+			{
+				count++;
+				facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis();
+				obj->mDepth += facep->mDistance;
+			
+				mFaceList.push_back(facep);
+				vertex_count += facep->getGeomCount();
+				index_count += facep->getIndicesCount();
+				llassert(facep->getIndicesCount() < 65536);
+			}
+			else
+			{
+				facep->clearVertexBuffer();
+			}
+		}
+		
+		obj->mDepth /= count;
+	}
+}
+
+static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB");
+
+void LLGrassPartition::getGeometry(LLSpatialGroup* group)
+{
+	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
+	LLFastTimer ftm(FTM_REBUILD_GRASS_VB);
+
+	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
+
+	U32 index_count = 0;
+	U32 vertex_count = 0;
+
+	group->clearDrawMap();
+
+	LLVertexBuffer* buffer = group->mVertexBuffer;
+
+	LLStrider<U16> indicesp;
+	LLStrider<LLVector4a> verticesp;
+	LLStrider<LLVector3> normalsp;
+	LLStrider<LLVector2> texcoordsp;
+	LLStrider<LLColor4U> colorsp;
+
+	buffer->getVertexStrider(verticesp);
+	buffer->getNormalStrider(normalsp);
+	buffer->getColorStrider(colorsp);
+	buffer->getTexCoord0Strider(texcoordsp);
+	buffer->getIndexStrider(indicesp);
+
+	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];	
+
+	for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
+	{
+		LLFace* facep = *i;
+		LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject();
+		facep->setGeomIndex(vertex_count);
+		facep->setIndicesIndex(index_count);
+		facep->setVertexBuffer(buffer);
+		facep->setPoolType(LLDrawPool::POOL_ALPHA);
+		object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp);
+		
+		vertex_count += facep->getGeomCount();
+		index_count += facep->getIndicesCount();
+
+		S32 idx = draw_vec.size()-1;
+
+		BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
+		F32 vsize = facep->getVirtualSize();
+
+		if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
+			draw_vec[idx]->mTexture == facep->getTexture() &&
+			(U16) (draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount()) <= (U32) gGLManager.mGLMaxVertexRange &&
+			//draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
+			draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 &&
+			draw_vec[idx]->mFullbright == fullbright)
+		{
+			draw_vec[idx]->mCount += facep->getIndicesCount();
+			draw_vec[idx]->mEnd += facep->getGeomCount();
+			draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
+		}
+		else
+		{
+			U32 start = facep->getGeomIndex();
+			U32 end = start + facep->getGeomCount()-1;
+			U32 offset = facep->getIndicesStart();
+			U32 count = facep->getIndicesCount();
+			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), 
+				//facep->getTexture(),
+				buffer, fullbright); 
+			info->mExtents[0] = group->mObjectExtents[0];
+			info->mExtents[1] = group->mObjectExtents[1];
+			info->mVSize = vsize;
+			draw_vec.push_back(info);
+			//for alpha sorting
+			facep->setDrawInfo(info);
+		}
+	}
+
+	buffer->flush();
+	mFaceList.clear();
+}
+
 // virtual
 void LLVOGrass::updateDrawable(BOOL force_damped)
 {
diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp
index 0060f81ab5043f5235b6b1fd0ae03e868c9a515a..6da54435e3ca9904686f5d832d5527678c930ba0 100644
--- a/indra/newview/llvoground.cpp
+++ b/indra/newview/llvoground.cpp
@@ -82,6 +82,7 @@ LLDrawable *LLVOGround::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
+// TO DO - this always returns TRUE, 
 BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
 {
 	LLStrider<LLVector3> verticesp;
@@ -96,6 +97,8 @@ BOOL LLVOGround::updateGeometry(LLDrawable *drawable)
 	if (drawable->getNumFaces() < 1)
 		drawable->addFace(poolp, NULL);
 	face = drawable->getFace(0); 
+	if (!face)
+		return TRUE;
 		
 	if (!face->getVertexBuffer())
 	{
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 5c10a80b07380af65c80c7e7f57bd713261d0972..9cce68fff69796cfedec00e8539e66ff1970d3c2 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -48,6 +48,120 @@ const F32 MAX_PART_LIFETIME = 120.f;
 
 extern U64 gFrameTime;
 
+LLPointer<LLVertexBuffer> LLVOPartGroup::sVB = NULL;
+S32 LLVOPartGroup::sVBSlotFree[];
+S32* LLVOPartGroup::sVBSlotCursor = NULL;
+
+void LLVOPartGroup::initClass()
+{
+	for (S32 i = 0; i < LL_MAX_PARTICLE_COUNT; ++i)
+	{
+		sVBSlotFree[i] = i;
+	}
+
+	sVBSlotCursor = sVBSlotFree;
+}
+
+//static
+void LLVOPartGroup::restoreGL()
+{
+	sVB = new LLVertexBuffer(VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
+	U32 count = LL_MAX_PARTICLE_COUNT;
+	sVB->allocateBuffer(count*4, count*6, true);
+
+	//indices and texcoords are always the same, set once
+	LLStrider<U16> indicesp;
+
+	LLStrider<LLVector4a> verticesp;
+
+	sVB->getIndexStrider(indicesp);
+	sVB->getVertexStrider(verticesp);
+
+	LLVector4a v;
+	v.set(0,0,0,0);
+
+	
+	U16 vert_offset = 0;
+
+	for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++)
+	{
+		*indicesp++ = vert_offset + 0;
+		*indicesp++ = vert_offset + 1;
+		*indicesp++ = vert_offset + 2;
+
+		*indicesp++ = vert_offset + 1;
+		*indicesp++ = vert_offset + 3;
+		*indicesp++ = vert_offset + 2;
+
+		*verticesp++ = v;
+
+		vert_offset += 4;
+	}
+
+	LLStrider<LLVector2> texcoordsp;
+	sVB->getTexCoord0Strider(texcoordsp);
+
+	for (U32 i = 0; i < LL_MAX_PARTICLE_COUNT; i++)
+	{
+		*texcoordsp++ = LLVector2(0.f, 1.f);
+		*texcoordsp++ = LLVector2(0.f, 0.f);
+		*texcoordsp++ = LLVector2(1.f, 1.f);
+		*texcoordsp++ = LLVector2(1.f, 0.f);
+	}
+
+	sVB->flush();
+
+}
+
+//static
+void LLVOPartGroup::destroyGL()
+{
+	sVB = NULL;
+}
+
+//static
+S32 LLVOPartGroup::findAvailableVBSlot()
+{
+	if (sVBSlotCursor >= sVBSlotFree+LL_MAX_PARTICLE_COUNT)
+	{ //no more available slots
+		return -1;
+	}
+
+	S32 ret = *sVBSlotCursor;
+	sVBSlotCursor++;
+
+	return ret;
+}
+
+bool ll_is_part_idx_allocated(S32 idx, S32* start, S32* end)
+{
+	while (start < end)
+	{
+		if (*start == idx)
+		{ //not allocated (in free list)
+			return false;
+		}
+		++start;
+	}
+
+	//allocated (not in free list)
+	return true;
+}
+
+//static
+void LLVOPartGroup::freeVBSlot(S32 idx)
+{
+	llassert(idx < LL_MAX_PARTICLE_COUNT && idx >= 0);
+	llassert(sVBSlotCursor > sVBSlotFree);
+	llassert(ll_is_part_idx_allocated(idx, sVBSlotCursor, sVBSlotFree+LL_MAX_PARTICLE_COUNT));
+
+	if (sVBSlotCursor > sVBSlotFree)
+	{
+		sVBSlotCursor--;
+		*sVBSlotCursor = idx;
+	}
+}
+
 LLVOPartGroup::LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	:	LLAlphaObject(id, pcode, regionp),
 		mViewerPartGroupp(NULL)
@@ -62,7 +176,6 @@ LLVOPartGroup::~LLVOPartGroup()
 {
 }
 
-
 BOOL LLVOPartGroup::isActive() const
 {
 	return FALSE;
@@ -287,9 +400,6 @@ void LLVOPartGroup::getGeometry(S32 idx,
 
 	const LLViewerPart &part = *((LLViewerPart*) (mViewerPartGroupp->mParticles[idx]));
 
-	U32 vert_offset = mDrawable->getFace(idx)->getGeomIndex();
-
-	
 	LLVector4a part_pos_agent;
 	part_pos_agent.load3(part.mPosAgent.mV);
 	LLVector4a camera_agent;
@@ -361,33 +471,18 @@ void LLVOPartGroup::getGeometry(S32 idx,
 	verticesp->setAdd(ppamu, right);
 	(*verticesp++).getF32ptr()[3] = 0.f;
 
-	//*verticesp++ = part_pos_agent + up - right;
-	//*verticesp++ = part_pos_agent - up - right;
-	//*verticesp++ = part_pos_agent + up + right;
-	//*verticesp++ = part_pos_agent - up + right;
-
 	*colorsp++ = part.mColor;
 	*colorsp++ = part.mColor;
 	*colorsp++ = part.mColor;
 	*colorsp++ = part.mColor;
 
-	*texcoordsp++ = LLVector2(0.f, 1.f);
-	*texcoordsp++ = LLVector2(0.f, 0.f);
-	*texcoordsp++ = LLVector2(1.f, 1.f);
-	*texcoordsp++ = LLVector2(1.f, 0.f);
-
-	*normalsp++   = normal;
-	*normalsp++   = normal;
-	*normalsp++   = normal;
-	*normalsp++   = normal;
-
-	*indicesp++ = vert_offset + 0;
-	*indicesp++ = vert_offset + 1;
-	*indicesp++ = vert_offset + 2;
-
-	*indicesp++ = vert_offset + 1;
-	*indicesp++ = vert_offset + 3;
-	*indicesp++ = vert_offset + 2;
+	if (!(part.mFlags & LLPartData::LL_PART_EMISSIVE_MASK))
+	{ //not fullbright, needs normal
+		*normalsp++   = normal;
+		*normalsp++   = normal;
+		*normalsp++   = normal;
+		*normalsp++   = normal;
+	}
 }
 
 U32 LLVOPartGroup::getPartitionType() const
@@ -412,6 +507,49 @@ LLHUDParticlePartition::LLHUDParticlePartition() :
 	mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE;
 }
 
+static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VBO("Particle VBO");
+
+void LLParticlePartition::rebuildGeom(LLSpatialGroup* group)
+{
+	if (group->isDead() || !group->isState(LLSpatialGroup::GEOM_DIRTY))
+	{
+		return;
+	}
+
+	if (group->changeLOD())
+	{
+		group->mLastUpdateDistance = group->mDistance;
+		group->mLastUpdateViewAngle = group->mViewAngle;
+	}
+	
+	LLFastTimer ftm(FTM_REBUILD_PARTICLE_VBO);	
+
+	group->clearDrawMap();
+	
+	//get geometry count
+	U32 index_count = 0;
+	U32 vertex_count = 0;
+
+	addGeometryCount(group, vertex_count, index_count);
+	
+
+	if (vertex_count > 0 && index_count > 0)
+	{ 
+		group->mBuilt = 1.f;
+		//use one vertex buffer for all groups
+		group->mVertexBuffer = LLVOPartGroup::sVB;
+		getGeometry(group);
+	}
+	else
+	{
+		group->mVertexBuffer = NULL;
+		group->mBufferMap.clear();
+	}
+
+	group->mLastUpdateTime = gFrameTimeSeconds;
+	group->clearState(LLSpatialGroup::GEOM_DIRTY);
+}
+
 void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count)
 {
 	group->mBufferUsage = mBufferUsage;
@@ -419,7 +557,7 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 	mFaceList.clear();
 
 	LLViewerCamera* camera = LLViewerCamera::getInstance();
-	for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
 		LLDrawable* drawablep = *i;
 		
@@ -431,11 +569,6 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 		LLAlphaObject* obj = (LLAlphaObject*) drawablep->getVObj().get();
 		obj->mDepth = 0.f;
 		
-		if (drawablep->isAnimating())
-		{
-			group->mBufferUsage = GL_STREAM_DRAW_ARB;
-		}
-
 		U32 count = 0;
 		for (S32 j = 0; j < drawablep->getNumFaces(); ++j)
 		{
@@ -447,13 +580,14 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 				continue;
 			}
 			
+			vertex_count += facep->getGeomCount();
+			index_count += facep->getIndicesCount();
+
 			count++;
 			facep->mDistance = (facep->mCenterLocal - camera->getOrigin()) * camera->getAtAxis();
 			obj->mDepth += facep->mDistance;
 			
 			mFaceList.push_back(facep);
-			vertex_count += facep->getGeomCount();
-			index_count += facep->getIndicesCount();
 			llassert(facep->getIndicesCount() < 65536);
 		}
 		
@@ -461,15 +595,13 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co
 	}
 }
 
-static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB");
-static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VB("Particle VB");
+
+static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_GEOM("Particle Geom");
 
 void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	LLFastTimer ftm(mDrawableType == LLPipeline::RENDER_TYPE_GRASS ?
-					FTM_REBUILD_GRASS_VB :
-					FTM_REBUILD_PARTICLE_VB);
+	LLFastTimer ftm(FTM_REBUILD_PARTICLE_GEOM);
 
 	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());
 
@@ -489,21 +621,45 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 	buffer->getVertexStrider(verticesp);
 	buffer->getNormalStrider(normalsp);
 	buffer->getColorStrider(colorsp);
-	buffer->getTexCoord0Strider(texcoordsp);
-	buffer->getIndexStrider(indicesp);
-
+	
 	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];	
 
 	for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
 	{
 		LLFace* facep = *i;
 		LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject();
-		facep->setGeomIndex(vertex_count);
-		facep->setIndicesIndex(index_count);
-		facep->setVertexBuffer(buffer);
-		facep->setPoolType(LLDrawPool::POOL_ALPHA);
-		object->getGeometry(facep->getTEOffset(), verticesp, normalsp, texcoordsp, colorsp, indicesp);
+
+		if (!facep->isState(LLFace::PARTICLE))
+		{ //set the indices of this face
+			S32 idx = LLVOPartGroup::findAvailableVBSlot();
+			if (idx >= 0)
+			{
+				facep->setGeomIndex(idx*4);
+				facep->setIndicesIndex(idx*6);
+				facep->setVertexBuffer(LLVOPartGroup::sVB);
+				facep->setPoolType(LLDrawPool::POOL_ALPHA);
+				facep->setState(LLFace::PARTICLE);
+			}
+			else
+			{
+				continue; //out of space in particle buffer
+			}		
+		}
+
+		S32 geom_idx = (S32) facep->getGeomIndex();
+
+		LLStrider<U16> cur_idx = indicesp + facep->getIndicesStart();
+		LLStrider<LLVector4a> cur_vert = verticesp + geom_idx;
+		LLStrider<LLVector3> cur_norm = normalsp + geom_idx;
+		LLStrider<LLVector2> cur_tc = texcoordsp + geom_idx;
+		LLStrider<LLColor4U> cur_col = colorsp + geom_idx;
+
+		object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_idx);
 		
+		llassert(facep->getGeomCount() == 4);
+		llassert(facep->getIndicesCount() == 6);
+
+
 		vertex_count += facep->getGeomCount();
 		index_count += facep->getIndicesCount();
 
@@ -512,18 +668,31 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 		BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
 		F32 vsize = facep->getVirtualSize();
 
-		if (idx >= 0 && draw_vec[idx]->mEnd == facep->getGeomIndex()-1 &&
+		bool batched = false;
+	
+		if (idx >= 0 &&
 			draw_vec[idx]->mTexture == facep->getTexture() &&
-			(U16) (draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount()) <= (U32) gGLManager.mGLMaxVertexRange &&
-			//draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
-			draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() < 4096 &&
 			draw_vec[idx]->mFullbright == fullbright)
 		{
-			draw_vec[idx]->mCount += facep->getIndicesCount();
-			draw_vec[idx]->mEnd += facep->getGeomCount();
-			draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
+			if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1)
+			{
+				batched = true;
+				draw_vec[idx]->mCount += facep->getIndicesCount();
+				draw_vec[idx]->mEnd += facep->getGeomCount();
+				draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
+			}
+			else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1)
+			{
+				batched = true;
+				draw_vec[idx]->mCount += facep->getIndicesCount();
+				draw_vec[idx]->mStart -= facep->getGeomCount();
+				draw_vec[idx]->mOffset = facep->getIndicesStart();
+				draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
+			}
 		}
-		else
+
+
+		if (!batched)
 		{
 			U32 start = facep->getGeomIndex();
 			U32 end = start + facep->getGeomCount()-1;
@@ -541,7 +710,6 @@ void LLParticlePartition::getGeometry(LLSpatialGroup* group)
 		}
 	}
 
-	buffer->flush();
 	mFaceList.clear();
 }
 
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index e58fed86d969ff10d55bf800d3d3bdc1ee306ac4..43b2844f07b5e3409fec28e51afdae19366e3882 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -31,18 +31,33 @@
 #include "v3math.h"
 #include "v3color.h"
 #include "llframetimer.h"
+#include "llviewerpartsim.h"
+#include "llvertexbuffer.h"
 
 class LLViewerPartGroup;
 
 class LLVOPartGroup : public LLAlphaObject
 {
 public:
+
+	//vertex buffer for holding all particles
+	static LLPointer<LLVertexBuffer> sVB;
+	static S32 sVBSlotFree[LL_MAX_PARTICLE_COUNT];
+	static S32* sVBSlotCursor;
+
+	static void initClass();
+	static void restoreGL();
+	static void destroyGL();
+	static S32 findAvailableVBSlot();
+	static void freeVBSlot(S32 idx);
+
 	enum
 	{
-		VERTEX_DATA_MASK =	(1 << LLVertexBuffer::TYPE_VERTEX) |
-							(1 << LLVertexBuffer::TYPE_NORMAL) |
-							(1 << LLVertexBuffer::TYPE_TEXCOORD0) |
-							(1 << LLVertexBuffer::TYPE_COLOR)
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_NORMAL |
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR |
+							LLVertexBuffer::MAP_TEXTURE_INDEX
 	};
 
 	LLVOPartGroup(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp);
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index bf6158eeafff8ade246ff261820a1806bcfc62cd..94a3111f4cb6e06eefae11518f6a38265f0fd89b 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -296,18 +296,20 @@ void LLVOSurfacePatch::updateFaceSize(S32 idx)
 	}
 
 	LLFace* facep = mDrawable->getFace(idx);
-
-	S32 num_vertices = 0;
-	S32 num_indices = 0;
-	
-	if (mLastStride)
+	if (facep)
 	{
-		getGeomSizesMain(mLastStride, num_vertices, num_indices);
-		getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices);
-		getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices);
-	}
+		S32 num_vertices = 0;
+		S32 num_indices = 0;
+	
+		if (mLastStride)
+		{
+			getGeomSizesMain(mLastStride, num_vertices, num_indices);
+			getGeomSizesNorth(mLastStride, mLastNorthStride, num_vertices, num_indices);
+			getGeomSizesEast(mLastStride, mLastEastStride, num_vertices, num_indices);
+		}
 
-	facep->setSize(num_vertices, num_indices);	
+		facep->setSize(num_vertices, num_indices);	
+	}
 }
 
 BOOL LLVOSurfacePatch::updateLOD()
@@ -322,30 +324,32 @@ void LLVOSurfacePatch::getGeometry(LLStrider<LLVector3> &verticesp,
 								LLStrider<U16> &indicesp)
 {
 	LLFace* facep = mDrawable->getFace(0);
+	if (facep)
+	{
+		U32 index_offset = facep->getGeomIndex();
 
-	U32 index_offset = facep->getGeomIndex();
-
-	updateMainGeometry(facep, 
-					verticesp,
-					normalsp,
-					texCoords0p,
-					texCoords1p,
-					indicesp,
-					index_offset);
-	updateNorthGeometry(facep, 
-						verticesp,
-						normalsp,
-						texCoords0p,
-						texCoords1p,
-						indicesp,
-						index_offset);
-	updateEastGeometry(facep, 
+		updateMainGeometry(facep, 
 						verticesp,
 						normalsp,
 						texCoords0p,
 						texCoords1p,
 						indicesp,
 						index_offset);
+		updateNorthGeometry(facep, 
+							verticesp,
+							normalsp,
+							texCoords0p,
+							texCoords1p,
+							indicesp,
+							index_offset);
+		updateEastGeometry(facep, 
+							verticesp,
+							normalsp,
+							texCoords0p,
+							texCoords1p,
+							indicesp,
+							index_offset);
+	}
 }
 
 void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,
@@ -864,7 +868,11 @@ void LLVOSurfacePatch::dirtyGeom()
 	if (mDrawable)
 	{
 		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE);
-		mDrawable->getFace(0)->setVertexBuffer(NULL);
+		LLFace* facep = mDrawable->getFace(0);
+		if (facep)
+		{
+			facep->setVertexBuffer(NULL);
+		}
 		mDrawable->movePartition();
 	}
 }
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 4564207da4d4d2becc4b82aedb3e82e82a7acf47..337ddfb24d11ceecb24603c1f65f0c876b351319 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -374,7 +374,7 @@ BOOL LLVOTree::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 		// *TODO: I don't know what's so special about trees
 		// that they don't get REBUILD_POSITION automatically
 		// at a higher level.
-		const LLVector3 &this_position = getPositionAgent();
+		const LLVector3 &this_position = getPositionRegion();
 		if (this_position != mLastPosition)
 		{
 			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_POSITION);
@@ -490,11 +490,16 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 	if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree.
 	{
 		mReferenceBuffer = NULL ;
-		mDrawable->getFace(0)->setVertexBuffer(NULL);
+		LLFace * facep = drawable->getFace(0);
+		if (facep)
+		{
+			facep->setVertexBuffer(NULL);
+		}
 		return TRUE ;
 	}
 
-	if (mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer())
+	if (mDrawable->getFace(0) &&
+		(mReferenceBuffer.isNull() || !mDrawable->getFace(0)->getVertexBuffer()))
 	{
 		const F32 SRR3 = 0.577350269f; // sqrt(1/3)
 		const F32 SRR2 = 0.707106781f; // sqrt(1/2)
@@ -507,6 +512,7 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)
 		S32 lod;
 
 		LLFace *face = drawable->getFace(0);
+		if (!face) return TRUE;
 
 		face->mCenterAgent = getPositionAgent();
 		face->mCenterLocal = face->mCenterAgent;
@@ -837,10 +843,10 @@ void LLVOTree::updateMesh()
 	LLMatrix4 matrix;
 	
 	// Translate to tree base  HACK - adjustment in Z plants tree underground
-	const LLVector3 &pos_agent = getPositionAgent();
+	const LLVector3 &pos_region = getPositionRegion();
 	//gGL.translatef(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
 	LLMatrix4 trans_mat;
-	trans_mat.setTranslation(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ] - 0.1f);
+	trans_mat.setTranslation(pos_region.mV[VX], pos_region.mV[VY], pos_region.mV[VZ] - 0.1f);
 	trans_mat *= matrix;
 	
 	// Rotate to tree position and bend for current trunk/wind
@@ -879,6 +885,7 @@ void LLVOTree::updateMesh()
 	calcNumVerts(vert_count, index_count, mTrunkLOD, stop_depth, mDepth, mTrunkDepth, mBranches);
 
 	LLFace* facep = mDrawable->getFace(0);
+	if (!facep) return;
 	LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolTree::VERTEX_DATA_MASK, GL_STATIC_DRAW_ARB);
 	buff->allocateBuffer(vert_count, index_count, TRUE);
 	facep->setVertexBuffer(buff);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 080d1f774a0cb4417f4af93533066a0cecb54291..082818b112e4538dae1f3093466712fbf53cfa9d 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -520,6 +520,7 @@ void LLVOVolume::animateTextures()
 		for (S32 i = start; i <= end; i++)
 		{
 			LLFace* facep = mDrawable->getFace(i);
+			if (!facep) continue;
 			if(facep->getVirtualSize() <= MIN_TEX_ANIM_SIZE && facep->mTextureMatrix) continue;
 
 			const LLTextureEntry* te = facep->getTextureEntry();
@@ -638,8 +639,8 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 {
 	LLViewerObject::idleUpdate(agent, world, time);
 
-	static LLFastTimer::DeclareTimer ftm("Volume");
-	LLFastTimer t(ftm);
+	//static LLFastTimer::DeclareTimer ftm("Volume Idle");
+	//LLFastTimer t(ftm);
 
 	if (mDead || mDrawable.isNull())
 	{
@@ -682,7 +683,21 @@ void LLVOVolume::updateTextures()
 	const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
 	if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
 	{
-		updateTextureVirtualSize();		
+		updateTextureVirtualSize();
+
+		if (mDrawable.notNull() && !isVisible() && !mDrawable->isActive())
+		{ //delete vertex buffer to free up some VRAM
+			LLSpatialGroup* group  = mDrawable->getSpatialGroup();
+			if (group)
+			{
+				group->destroyGL(true);
+
+				//flag the group as having changed geometry so it gets a rebuild next time
+				//it becomes visible
+				group->setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
+			}
+		}
+
 	}
 }
 
@@ -715,7 +730,18 @@ void LLVOVolume::updateTextureVirtualSize(bool forced)
 	if(!forced)
 	{
 		if(!isVisible())
-		{
+		{ //don't load textures for non-visible faces
+			const S32 num_faces = mDrawable->getNumFaces();
+			for (S32 i = 0; i < num_faces; i++)
+			{
+				LLFace* face = mDrawable->getFace(i);
+				if (face)
+				{
+					face->setPixelArea(0.f); 
+					face->setVirtualSize(0.f);
+				}
+			}
+
 			return ;
 		}
 
@@ -743,6 +769,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced)
 	for (S32 i = 0; i < num_faces; i++)
 	{
 		LLFace* face = mDrawable->getFace(i);
+		if (!face) continue;
 		const LLTextureEntry *te = face->getTextureEntry();
 		LLViewerTexture *imagep = face->getTexture();
 		if (!imagep || !te ||			
@@ -1062,9 +1089,33 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 			}
 		}
 
+
+		static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback");
+
+		bool cache_in_vram = use_transform_feedback && gTransformPositionProgram.mProgramObject &&
+			(!mVolumeImpl || !mVolumeImpl->isVolumeUnique());
+
+		if (cache_in_vram)
+		{ //this volume might be used as source data for a transform object, put it in vram
+			LLVolume* volume = getVolume();
+			for (S32 i = 0; i < volume->getNumFaces(); ++i)
+			{
+				const LLVolumeFace& face = volume->getVolumeFace(i);
+				if (face.mVertexBuffer.notNull())
+				{ //already cached
+					break;
+				}
+				volume->genBinormals(i);
+				LLFace::cacheFaceInVRAM(face);
+			}
+		}
+		
+
 		return TRUE;
 	}
 
+
+
 	return FALSE;
 }
 
@@ -1246,7 +1297,8 @@ BOOL LLVOVolume::calcLOD()
 									llround(radius, 0.01f));
 
 
-	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO))
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_LOD_INFO) &&
+		mDrawable->getFace(0))
 	{
 		//setDebugText(llformat("%.2f:%.2f, %d", debug_distance, radius, cur_detail));
 
@@ -1325,25 +1377,23 @@ void LLVOVolume::updateFaceFlags()
 	for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
 	{
 		LLFace *face = mDrawable->getFace(i);
-		if (!face)
+		if (face)
 		{
-			return;
-		}
+			BOOL fullbright = getTE(i)->getFullbright();
+			face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
 
-		BOOL fullbright = getTE(i)->getFullbright();
-		face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
-
-		if (fullbright || (mMaterial == LL_MCODE_LIGHT))
-		{
-			face->setState(LLFace::FULLBRIGHT);
-		}
-		if (mDrawable->isLight())
-		{
-			face->setState(LLFace::LIGHT);
-		}
-		if (isHUDAttachment())
-		{
-			face->setState(LLFace::HUD_RENDER);
+			if (fullbright || (mMaterial == LL_MCODE_LIGHT))
+			{
+				face->setState(LLFace::FULLBRIGHT);
+			}
+			if (mDrawable->isLight())
+			{
+				face->setState(LLFace::LIGHT);
+			}
+			if (isHUDAttachment())
+			{
+				face->setState(LLFace::HUD_RENDER);
+			}
 		}
 	}
 }
@@ -1380,6 +1430,8 @@ void LLVOVolume::regenFaces()
 	for (S32 i = 0; i < mNumFaces; i++)
 	{
 		LLFace* facep = count_changed ? addFace(i) : mDrawable->getFace(i);
+		if (!facep) continue;
+
 		facep->setTEOffset(i);
 		facep->setTexture(getTEImage(i));
 		facep->setViewerObject(this);
@@ -1416,7 +1468,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 
 	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
 
-//	bool rigged = false;
+	//	bool rigged = false;
 	LLVolume* volume = mRiggedVolume;
 	if (!volume)
 	{
@@ -1471,11 +1523,11 @@ void LLVOVolume::preRebuild()
 	}
 }
 
-void LLVOVolume::updateRelativeXform()
+void LLVOVolume::updateRelativeXform(bool force_identity)
 {
 	if (mVolumeImpl)
 	{
-		mVolumeImpl->updateRelativeXform();
+		mVolumeImpl->updateRelativeXform(force_identity);
 		return;
 	}
 	
@@ -1495,15 +1547,16 @@ void LLVOVolume::updateRelativeXform()
 		mRelativeXform.invert();
 		mRelativeXformInvTrans.transpose();
 	}
-	else if (drawable->isActive())
+	else if (drawable->isActive() || force_identity)
 	{				
 		// setup relative transforms
 		LLQuaternion delta_rot;
 		LLVector3 delta_pos, delta_scale;
 		
 		//matrix from local space to parent relative/global space
-		delta_rot = drawable->isSpatialRoot() ? LLQuaternion() : mDrawable->getRotation();
-		delta_pos = drawable->isSpatialRoot() ? LLVector3(0,0,0) : mDrawable->getPosition();
+		bool use_identity = force_identity || drawable->isSpatialRoot();
+		delta_rot = use_identity ? LLQuaternion() : mDrawable->getRotation();
+		delta_pos = use_identity ? LLVector3(0,0,0) : mDrawable->getPosition();
 		delta_scale = mDrawable->getScale();
 
 		// Vertex transform (4x4)
@@ -1604,7 +1657,11 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 		return res;
 	}
 	
-	dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
+	LLSpatialGroup* group = drawable->getSpatialGroup();
+	if (group)
+	{
+		group->dirtyMesh();
+	}
 
 	BOOL compiled = FALSE;
 			
@@ -1617,6 +1674,8 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 
 	if (mVolumeChanged || mFaceMappingChanged )
 	{
+		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
+
 		compiled = TRUE;
 
 		if (mVolumeChanged)
@@ -1635,6 +1694,8 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	}
 	else if ((mLODChanged) || (mSculptChanged))
 	{
+		dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
+
 		LLVolume *old_volumep, *new_volumep;
 		F32 old_lod, new_lod;
 		S32 old_num_faces, new_num_faces ;
@@ -1716,16 +1777,19 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 void LLVOVolume::updateFaceSize(S32 idx)
 {
 	LLFace* facep = mDrawable->getFace(idx);
-	if (idx >= getVolume()->getNumVolumeFaces())
+	if (facep)
 	{
-		facep->setSize(0,0, true);
-	}
-	else
-	{
-		const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
-		facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, 
-						true); // <--- volume faces should be padded for 16-byte alignment
+		if (idx >= getVolume()->getNumVolumeFaces())
+		{
+			facep->setSize(0,0, true);
+		}
+		else
+		{
+			const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
+			facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, 
+							true); // <--- volume faces should be padded for 16-byte alignment
 		
+		}
 	}
 }
 
@@ -3098,6 +3162,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
 	for (S32 i = 0; i < num_faces; ++i)
 	{
 		const LLFace* face = drawablep->getFace(i);
+		if (!face) continue;
 		const LLTextureEntry* te = face->getTextureEntry();
 		const LLViewerTexture* img = face->getTexture();
 
@@ -3369,6 +3434,7 @@ F32 LLVOVolume::getBinRadius()
 		for (S32 i = 0; i < mDrawable->getNumFaces(); i++)
 		{
 			LLFace* face = mDrawable->getFace(i);
+			if (!face) continue;
 			if (face->getPoolType() == LLDrawPool::POOL_ALPHA &&
 			    !face->canRenderAsMask())
 			{
@@ -3450,9 +3516,12 @@ LLVector3 LLVOVolume::agentPositionToVolume(const LLVector3& pos) const
 {
 	LLVector3 ret = pos - getRenderPosition();
 	ret = ret * ~getRenderRotation();
-	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
-	LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
-	ret.scaleVec(invObjScale);
+	if (!isVolumeGlobal())
+	{
+		LLVector3 objScale = getScale();
+		LLVector3 invObjScale(1.f / objScale.mV[VX], 1.f / objScale.mV[VY], 1.f / objScale.mV[VZ]);
+		ret.scaleVec(invObjScale);
+	}
 	
 	return ret;
 }
@@ -3470,8 +3539,12 @@ LLVector3 LLVOVolume::agentDirectionToVolume(const LLVector3& dir) const
 LLVector3 LLVOVolume::volumePositionToAgent(const LLVector3& dir) const
 {
 	LLVector3 ret = dir;
-	LLVector3 objScale = isVolumeGlobal() ? LLVector3(1,1,1) : getScale();
-	ret.scaleVec(objScale);
+	if (!isVolumeGlobal())
+	{
+		LLVector3 objScale = getScale();
+		ret.scaleVec(objScale);
+	}
+
 	ret = ret * getRenderRotation();
 	ret += getRenderPosition();
 	
@@ -3592,7 +3665,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 			{
 				LLFace* face = mDrawable->getFace(face_hit);				
 
-				if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))
+				if (face &&
+					(pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))))
 				{
 					v_end = p;
 					if (face_hitp != NULL)
@@ -3902,8 +3976,11 @@ bool can_batch_texture(LLFace* facep)
 	return true;
 }
 
+static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face");
+
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
+	LLFastTimer t(FTM_REGISTER_FACE);
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 
 	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
@@ -3935,9 +4012,14 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	const LLMatrix4* model_mat = NULL;
 
 	LLDrawable* drawable = facep->getDrawable();
-	if (drawable->isActive())
+	
+	if (drawable->isState(LLDrawable::ANIMATED_CHILD))
 	{
-		model_mat = &(drawable->getRenderMatrix());
+		model_mat = &drawable->getWorldMatrix();
+	}
+	else if (drawable->isActive())
+	{
+		model_mat = &drawable->getRenderMatrix();
 	}
 	else
 	{
@@ -3948,6 +4030,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		}
 	}
 
+	//drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD)));
+
 	U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
 	
 	LLViewerTexture* tex = facep->getTexture();
@@ -4041,8 +4125,9 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 
 }
 
-static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
-static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
+static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume VB");
+static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_FACE_LIST("Build Face List");
+static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info");
 
 static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
 {
@@ -4073,6 +4158,8 @@ static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
+	
+
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -4084,19 +4171,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	{
 		if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate)
 		{
-			LLFastTimer ftm(FTM_REBUILD_VBO);	
-			LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
-		
 			rebuildMesh(group);
 		}
 		return;
 	}
 
-	group->mBuilt = 1.f;
-	LLFastTimer ftm(FTM_REBUILD_VBO);	
-
-	LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB);
+	LLFastTimer ftm(FTM_REBUILD_VOLUME_VB);
 
+	group->mBuilt = 1.f;
+	
 	LLVOAvatar* pAvatarVO = NULL;
 
 	LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
@@ -4145,359 +4228,375 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	bool emissive = false;
 
-	//get all the faces into a list
-	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 	{
-		LLDrawable* drawablep = *drawable_iter;
-		
-		if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
+		LLFastTimer t(FTM_REBUILD_VOLUME_FACE_LIST);
+
+		//get all the faces into a list
+		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 		{
-			continue;
-		}
+			LLDrawable* drawablep = *drawable_iter;
+		
+			if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
+			{
+				continue;
+			}
 	
-		if (drawablep->isAnimating())
-		{ //fall back to stream draw for animating verts
-			useage = GL_STREAM_DRAW_ARB;
-		}
+			if (drawablep->isAnimating())
+			{ //fall back to stream draw for animating verts
+				useage = GL_STREAM_DRAW_ARB;
+			}
 
-		LLVOVolume* vobj = drawablep->getVOVolume();
+			LLVOVolume* vobj = drawablep->getVOVolume();
 
-		if (!vobj)
-		{
-			continue;
-		}
+			if (!vobj)
+			{
+				continue;
+			}
 
-		if (vobj->isMesh() &&
-			(vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
-		{
-			continue;
-		}
+			if (vobj->isMesh() &&
+				(vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
+			{
+				continue;
+			}
 
-		LLVolume* volume = vobj->getVolume();
-		if (volume)
-		{
-			const LLVector3& scale = vobj->getScale();
-			group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
-		}
+			LLVolume* volume = vobj->getVolume();
+			if (volume)
+			{
+				const LLVector3& scale = vobj->getScale();
+				group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]);
+			}
 
-		llassert_always(vobj);
-		vobj->updateTextureVirtualSize(true);
-		vobj->preRebuild();
+			llassert_always(vobj);
+			vobj->updateTextureVirtualSize(true);
+			vobj->preRebuild();
 
-		drawablep->clearState(LLDrawable::HAS_ALPHA);
+			drawablep->clearState(LLDrawable::HAS_ALPHA);
 
-		bool rigged = vobj->isAttachment() && 
-					vobj->isMesh() && 
-					gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
+			bool rigged = vobj->isAttachment() && 
+						vobj->isMesh() && 
+						gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID(), vobj);
 
-		bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+			bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
 
-		bool is_rigged = false;
+			bool is_rigged = false;
 
-		//for each face
-		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
-		{
-			LLFace* facep = drawablep->getFace(i);
+			//for each face
+			for (S32 i = 0; i < drawablep->getNumFaces(); i++)
+			{
+				LLFace* facep = drawablep->getFace(i);
+				if (!facep)
+				{
+					continue;
+				}
 
-			//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
-			// batch, it will recover its vertex buffer reference from the spatial group
-			facep->setVertexBuffer(NULL);
+				//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
+				// batch, it will recover its vertex buffer reference from the spatial group
+				facep->setVertexBuffer(NULL);
 			
-			//sum up face verts and indices
-			drawablep->updateFaceSize(i);
+				//sum up face verts and indices
+				drawablep->updateFaceSize(i);
 			
 			
 
-			if (rigged) 
-			{
-				if (!facep->isState(LLFace::RIGGED))
-				{ //completely reset vertex buffer
-					facep->clearVertexBuffer();
-				}
+				if (rigged) 
+				{
+					if (!facep->isState(LLFace::RIGGED))
+					{ //completely reset vertex buffer
+						facep->clearVertexBuffer();
+					}
 		
-				facep->setState(LLFace::RIGGED);
-				is_rigged = true;
+					facep->setState(LLFace::RIGGED);
+					is_rigged = true;
 				
-				//get drawpool of avatar with rigged face
-				LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+					//get drawpool of avatar with rigged face
+					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
 				
-				//Determine if we've received skininfo that contains an
-				//alternate bind matrix - if it does then apply the translational component
-				//to the joints of the avatar.
-				bool pelvisGotSet = false;
+					//Determine if we've received skininfo that contains an
+					//alternate bind matrix - if it does then apply the translational component
+					//to the joints of the avatar.
+					bool pelvisGotSet = false;
 
-				if ( pAvatarVO )
-				{
-					LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
-					const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
-					
-					if ( pSkinData )
+					if ( pAvatarVO )
 					{
-						const int bindCnt = pSkinData->mAlternateBindMatrix.size();								
-						if ( bindCnt > 0 )
-						{					
-							const int jointCnt = pSkinData->mJointNames.size();
-							const F32 pelvisZOffset = pSkinData->mPelvisOffset;
-							bool fullRig = (jointCnt>=20) ? true : false;
-							if ( fullRig )
-							{
-								for ( int i=0; i<jointCnt; ++i )
+						LLUUID currentId = vobj->getVolume()->getParams().getSculptID();
+						const LLMeshSkinInfo*  pSkinData = gMeshRepo.getSkinInfo( currentId, vobj );
+					
+						if ( pSkinData )
+						{
+							const int bindCnt = pSkinData->mAlternateBindMatrix.size();								
+							if ( bindCnt > 0 )
+							{					
+								const int jointCnt = pSkinData->mJointNames.size();
+								const F32 pelvisZOffset = pSkinData->mPelvisOffset;
+								bool fullRig = (jointCnt>=20) ? true : false;
+								if ( fullRig )
 								{
-									std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
-									//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
-									LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
-									if ( pJoint && pJoint->getId() != currentId )
-									{   									
-										pJoint->setId( currentId );
-										const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									
-										//Set the joint position
-										pJoint->storeCurrentXform( jointPos );																																
-										//If joint is a pelvis then handle old/new pelvis to foot values
-										if ( lookingForJoint == "mPelvis" )
-										{	
+									for ( int i=0; i<jointCnt; ++i )
+									{
+										std::string lookingForJoint = pSkinData->mJointNames[i].c_str();
+										//llinfos<<"joint name "<<lookingForJoint.c_str()<<llendl;
+										LLJoint* pJoint = pAvatarVO->getJoint( lookingForJoint );
+										if ( pJoint && pJoint->getId() != currentId )
+										{   									
+											pJoint->setId( currentId );
+											const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation();									
+											//Set the joint position
 											pJoint->storeCurrentXform( jointPos );																																
-											if ( !pAvatarVO->hasPelvisOffset() )
-											{										
-												pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
-												//Trigger to rebuild viewer AV
-												pelvisGotSet = true;											
+											//If joint is a pelvis then handle old/new pelvis to foot values
+											if ( lookingForJoint == "mPelvis" )
+											{	
+												pJoint->storeCurrentXform( jointPos );																																
+												if ( !pAvatarVO->hasPelvisOffset() )
+												{										
+													pAvatarVO->setPelvisOffset( true, jointPos, pelvisZOffset );
+													//Trigger to rebuild viewer AV
+													pelvisGotSet = true;											
+												}										
 											}										
-										}										
+										}
 									}
-								}
-							}							
+								}							
+							}
 						}
 					}
-				}
-				//If we've set the pelvis to a new position we need to also rebuild some information that the
-				//viewer does at launch (e.g. body size etc.)
-				if ( pelvisGotSet )
-				{
-					pAvatarVO->postPelvisSetRecalc();
-				}
-
-				if (pool)
-				{
-					const LLTextureEntry* te = facep->getTextureEntry();
-
-					//remove face from old pool if it exists
-					LLDrawPool* old_pool = facep->getPool();
-					if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+					//If we've set the pelvis to a new position we need to also rebuild some information that the
+					//viewer does at launch (e.g. body size etc.)
+					if ( pelvisGotSet )
 					{
-						((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+						pAvatarVO->postPelvisSetRecalc();
 					}
 
-					//add face to new pool
-					LLViewerTexture* tex = facep->getTexture();
-					U32 type = gPipeline.getPoolTypeFromTE(te, tex);
-
-					if (type == LLDrawPool::POOL_ALPHA)
+					if (pool)
 					{
-						if (te->getColor().mV[3] > 0.f)
+						const LLTextureEntry* te = facep->getTextureEntry();
+
+						//remove face from old pool if it exists
+						LLDrawPool* old_pool = facep->getPool();
+						if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+						{
+							((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+						}
+
+						//add face to new pool
+						LLViewerTexture* tex = facep->getTexture();
+						U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+
+						if (type == LLDrawPool::POOL_ALPHA)
+						{
+							if (te->getColor().mV[3] > 0.f)
+							{
+								if (te->getFullbright())
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+								}
+							}
+						}
+						else if (te->getShiny())
 						{
 							if (te->getFullbright())
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
 							}
 							else
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+								if (LLPipeline::sRenderDeferred)
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+								}
 							}
 						}
-					}
-					else if (te->getShiny())
-					{
-						if (te->getFullbright())
-						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
-						}
 						else
 						{
-							if (LLPipeline::sRenderDeferred)
+							if (te->getFullbright())
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
 							}
 							else
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
 							}
 						}
-					}
-					else
-					{
-						if (te->getFullbright())
-						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
-						}
-						else
+
+						if (te->getGlow())
 						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
 						}
-					}
 
-					if (te->getGlow())
-					{
-						pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
-					}
-
-					if (LLPipeline::sRenderDeferred)
-					{
-						if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+						if (LLPipeline::sRenderDeferred)
 						{
-							if (te->getBumpmap())
+							if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
-							}
-							else
-							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+								if (te->getBumpmap())
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+								}
 							}
 						}
 					}
-				}
 
-				continue;
-			}
-			else
-			{
-				if (facep->isState(LLFace::RIGGED))
-				{ //face is not rigged but used to be, remove from rigged face pool
-					LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
-					if (pool)
-					{
-						pool->removeRiggedFace(facep);
+					continue;
+				}
+				else
+				{
+					if (facep->isState(LLFace::RIGGED))
+					{ //face is not rigged but used to be, remove from rigged face pool
+						LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+						if (pool)
+						{
+							pool->removeRiggedFace(facep);
+						}
+						facep->clearState(LLFace::RIGGED);
 					}
-					facep->clearState(LLFace::RIGGED);
 				}
-			}
-
-
-			if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
-			{
-				facep->clearVertexBuffer();
-				continue;
-			}
-
-			cur_total += facep->getGeomCount();
 
-			if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
-			{
-				const LLTextureEntry* te = facep->getTextureEntry();
-				LLViewerTexture* tex = facep->getTexture();
 
-				if (te->getGlow() >= 1.f/255.f)
+				if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
 				{
-					emissive = true;
+					facep->clearVertexBuffer();
+					continue;
 				}
 
-				if (facep->isState(LLFace::TEXTURE_ANIM))
-				{
-					if (!vobj->mTexAnimMode)
-					{
-						facep->clearState(LLFace::TEXTURE_ANIM);
-					}
-				}
+				cur_total += facep->getGeomCount();
 
-				BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
-				U32 type = gPipeline.getPoolTypeFromTE(te, tex);
-				if (type != LLDrawPool::POOL_ALPHA && force_simple)
+				if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
 				{
-					type = LLDrawPool::POOL_SIMPLE;
-				}
-				facep->setPoolType(type);
+					const LLTextureEntry* te = facep->getTextureEntry();
+					LLViewerTexture* tex = facep->getTexture();
 
-				if (vobj->isHUDAttachment())
-				{
-					facep->setState(LLFace::FULLBRIGHT);
-				}
+					if (te->getGlow() >= 1.f/255.f)
+					{
+						emissive = true;
+					}
 
-				if (vobj->mTextureAnimp && vobj->mTexAnimMode)
-				{
-					if (vobj->mTextureAnimp->mFace <= -1)
+					if (facep->isState(LLFace::TEXTURE_ANIM))
 					{
-						S32 face;
-						for (face = 0; face < vobj->getNumTEs(); face++)
+						if (!vobj->mTexAnimMode)
 						{
-							drawablep->getFace(face)->setState(LLFace::TEXTURE_ANIM);
+							facep->clearState(LLFace::TEXTURE_ANIM);
 						}
 					}
-					else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs())
+
+					BOOL force_simple = (facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA);
+					U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+					if (type != LLDrawPool::POOL_ALPHA && force_simple)
 					{
-						drawablep->getFace(vobj->mTextureAnimp->mFace)->setState(LLFace::TEXTURE_ANIM);
+						type = LLDrawPool::POOL_SIMPLE;
 					}
-				}
+					facep->setPoolType(type);
 
-				if (type == LLDrawPool::POOL_ALPHA)
-				{
-					if (facep->canRenderAsMask())
-					{ //can be treated as alpha mask
-						simple_faces.push_back(facep);
-					}
-					else
+					if (vobj->isHUDAttachment())
 					{
-						if (te->getColor().mV[3] > 0.f)
-						{ //only treat as alpha in the pipeline if < 100% transparent
-							drawablep->setState(LLDrawable::HAS_ALPHA);
-						}
-						alpha_faces.push_back(facep);
+						facep->setState(LLFace::FULLBRIGHT);
 					}
-				}
-				else
-				{
-					if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
+
+					if (vobj->mTextureAnimp && vobj->mTexAnimMode)
 					{
-						facep->mLastUpdateTime = gFrameTimeSeconds;
+						if (vobj->mTextureAnimp->mFace <= -1)
+						{
+							S32 face;
+							for (face = 0; face < vobj->getNumTEs(); face++)
+							{
+								LLFace * facep = drawablep->getFace(face);
+								if (facep)
+								{
+									facep->setState(LLFace::TEXTURE_ANIM);
+								}
+							}
+						}
+						else if (vobj->mTextureAnimp->mFace < vobj->getNumTEs())
+						{
+							LLFace * facep = drawablep->getFace(vobj->mTextureAnimp->mFace);
+							if (facep)
+							{
+								facep->setState(LLFace::TEXTURE_ANIM);
+							}
+						}
 					}
 
-					if (gPipeline.canUseWindLightShadersOnObjects()
-						&& LLPipeline::sRenderBump)
+					if (type == LLDrawPool::POOL_ALPHA)
 					{
-						if (te->getBumpmap())
-						{ //needs normal + binormal
-							bump_faces.push_back(facep);
-						}
-						else if (te->getShiny() || !te->getFullbright())
-						{ //needs normal
+						if (facep->canRenderAsMask())
+						{ //can be treated as alpha mask
 							simple_faces.push_back(facep);
 						}
-						else 
-						{ //doesn't need normal
-							facep->setState(LLFace::FULLBRIGHT);
-							fullbright_faces.push_back(facep);
+						else
+						{
+							if (te->getColor().mV[3] > 0.f)
+							{ //only treat as alpha in the pipeline if < 100% transparent
+								drawablep->setState(LLDrawable::HAS_ALPHA);
+							}
+							alpha_faces.push_back(facep);
 						}
 					}
 					else
 					{
-						if (te->getBumpmap() && LLPipeline::sRenderBump)
-						{ //needs normal + binormal
-							bump_faces.push_back(facep);
+						if (drawablep->isState(LLDrawable::REBUILD_VOLUME))
+						{
+							facep->mLastUpdateTime = gFrameTimeSeconds;
 						}
-						else if ((te->getShiny() && LLPipeline::sRenderBump) ||
-							!(te->getFullbright() || bake_sunlight))
-						{ //needs normal
-							simple_faces.push_back(facep);
+
+						if (gPipeline.canUseWindLightShadersOnObjects()
+							&& LLPipeline::sRenderBump)
+						{
+							if (te->getBumpmap())
+							{ //needs normal + binormal
+								bump_faces.push_back(facep);
+							}
+							else if (te->getShiny() || !te->getFullbright())
+							{ //needs normal
+								simple_faces.push_back(facep);
+							}
+							else 
+							{ //doesn't need normal
+								facep->setState(LLFace::FULLBRIGHT);
+								fullbright_faces.push_back(facep);
+							}
 						}
-						else 
-						{ //doesn't need normal
-							facep->setState(LLFace::FULLBRIGHT);
-							fullbright_faces.push_back(facep);
+						else
+						{
+							if (te->getBumpmap() && LLPipeline::sRenderBump)
+							{ //needs normal + binormal
+								bump_faces.push_back(facep);
+							}
+							else if ((te->getShiny() && LLPipeline::sRenderBump) ||
+								!(te->getFullbright() || bake_sunlight))
+							{ //needs normal
+								simple_faces.push_back(facep);
+							}
+							else 
+							{ //doesn't need normal
+								facep->setState(LLFace::FULLBRIGHT);
+								fullbright_faces.push_back(facep);
+							}
 						}
 					}
 				}
+				else
+				{	//face has no renderable geometry
+					facep->clearVertexBuffer();
+				}		
 			}
-			else
-			{	//face has no renderable geometry
-				facep->clearVertexBuffer();
-			}		
-		}
 
-		if (is_rigged)
-		{
-			drawablep->setState(LLDrawable::RIGGED);
-		}
-		else
-		{
-			drawablep->clearState(LLDrawable::RIGGED);
+			if (is_rigged)
+			{
+				drawablep->setState(LLDrawable::RIGGED);
+			}
+			else
+			{
+				drawablep->clearState(LLDrawable::RIGGED);
+			}
 		}
 	}
 
@@ -4539,7 +4638,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	if (!LLPipeline::sDelayVBUpdate)
 	{
 		//drawables have been rebuilt, clear rebuild status
-		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 		{
 			LLDrawable* drawablep = *drawable_iter;
 			drawablep->clearState(LLDrawable::REBUILD_ALL);
@@ -4564,31 +4663,35 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	}
 }
 
-static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
-static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild");
 
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
 	llassert(group);
 	if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY))
 	{
-		LLFastTimer tm(FTM_VOLUME_GEOM);
+		LLFastTimer ftm(FTM_REBUILD_VOLUME_VB);
+		LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers
+
 		S32 num_mapped_veretx_buffer = LLVertexBuffer::sMappedCount ;
 
 		group->mBuilt = 1.f;
 		
 		std::set<LLVertexBuffer*> mapped_buffers;
 
-		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+		for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 		{
-			LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
 			LLDrawable* drawablep = *drawable_iter;
 
-			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) )
+			if (!drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
 			{
 				LLVOVolume* vobj = drawablep->getVOVolume();
 				vobj->preRebuild();
 
+				if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+				{
+					vobj->updateRelativeXform(true);
+				}
+
 				LLVolume* volume = vobj->getVolume();
 				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 				{
@@ -4598,8 +4701,15 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 						LLVertexBuffer* buff = face->getVertexBuffer();
 						if (buff)
 						{
-							face->getGeometryVolume(*volume, face->getTEOffset(), 
-								vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
+							llassert(!face->isState(LLFace::RIGGED));
+
+							if (!face->getGeometryVolume(*volume, face->getTEOffset(), 
+								vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex()))
+							{ //something's gone wrong with the vertex buffer accounting, rebuild this group 
+								group->dirtyGeom();
+								gPipeline.markRebuild(group, TRUE);
+							}
+
 
 							if (buff->isLocked())
 							{
@@ -4608,6 +4718,12 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 						}
 					}
 				}
+
+				if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+				{
+					vobj->updateRelativeXform();
+				}
+
 				
 				drawablep->clearState(LLDrawable::REBUILD_ALL);
 			}
@@ -4630,16 +4746,19 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 		if(num_mapped_veretx_buffer != LLVertexBuffer::sMappedCount) 
 		{
 			llwarns << "Not all mapped vertex buffers are unmapped!" << llendl ; 
-			for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+			for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 			{
 				LLDrawable* drawablep = *drawable_iter;
 				for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
 				{
 					LLFace* face = drawablep->getFace(i);
-					LLVertexBuffer* buff = face->getVertexBuffer();
-					if (face && buff && buff->isLocked())
+					if (face)
 					{
-						buff->flush();
+						LLVertexBuffer* buff = face->getVertexBuffer();
+						if (buff && buff->isLocked())
+						{
+							buff->flush();
+						}
 					}
 				}
 			} 
@@ -4648,7 +4767,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 		group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO);
 	}
 
-	llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
+//	llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO));
 }
 
 struct CompareBatchBreakerModified
@@ -4674,8 +4793,20 @@ struct CompareBatchBreakerModified
 	}
 };
 
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_FIND_VB("Find VB");
+static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB");
+
+
+
+
+
 void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures)
 {
+	LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO);
+
 	U32 buffer_usage = group->mBufferUsage;
 	
 #if LL_DARWIN
@@ -4693,15 +4824,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcVertexSize(group->mSpatialPartition->mVertexDataMask);
 	max_vertices = llmin(max_vertices, (U32) 65535);
 
-	if (!distance_sort)
-	{
-		//sort faces by things that break batches
-		std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified());
-	}
-	else
 	{
-		//sort faces by distance
-		std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
+		LLFastTimer t(FTM_GEN_DRAW_INFO_SORT);
+		if (!distance_sort)
+		{
+			//sort faces by things that break batches
+			std::sort(faces.begin(), faces.end(), CompareBatchBreakerModified());
+		}
+		else
+		{
+			//sort faces by distance
+			std::sort(faces.begin(), faces.end(), LLFace::CompareDistanceGreater());
+		}
 	}
 				
 	bool hud_group = group->isHUDGroup() ;
@@ -4766,57 +4900,86 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 		
 		std::vector<LLViewerTexture*> texture_list;
 
-		if (batch_textures)
 		{
-			U8 cur_tex = 0;
-			facep->setTextureIndex(cur_tex);
-			texture_list.push_back(tex);
-
-			//if (can_batch_texture(facep))
+			LLFastTimer t(FTM_GEN_DRAW_INFO_FACE_SIZE);
+			if (batch_textures)
 			{
-				while (i != faces.end())
+				U8 cur_tex = 0;
+				facep->setTextureIndex(cur_tex);
+				texture_list.push_back(tex);
+
+				//if (can_batch_texture(facep))
 				{
-					facep = *i;
-					if (facep->getTexture() != tex)
+					while (i != faces.end())
 					{
-						if (distance_sort)
-						{ //textures might be out of order, see if texture exists in current batch
-							bool found = false;
-							for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
-							{
-								if (facep->getTexture() == texture_list[tex_idx])
+						facep = *i;
+						if (facep->getTexture() != tex)
+						{
+							if (distance_sort)
+							{ //textures might be out of order, see if texture exists in current batch
+								bool found = false;
+								for (U32 tex_idx = 0; tex_idx < texture_list.size(); ++tex_idx)
 								{
-									cur_tex = tex_idx;
-									found = true;
-									break;
+									if (facep->getTexture() == texture_list[tex_idx])
+									{
+										cur_tex = tex_idx;
+										found = true;
+										break;
+									}
 								}
-							}
 
-							if (!found)
+								if (!found)
+								{
+									cur_tex = texture_list.size();
+								}
+							}
+							else
 							{
-								cur_tex = texture_list.size();
+								cur_tex++;
 							}
-						}
-						else
-						{
-							cur_tex++;
-						}
 
-						if (!can_batch_texture(facep))
-						{ //face is bump mapped or has an animated texture matrix -- can't 
-							//batch more than 1 texture at a time
-							break;
+							if (!can_batch_texture(facep))
+							{ //face is bump mapped or has an animated texture matrix -- can't 
+								//batch more than 1 texture at a time
+								break;
+							}
+
+							if (cur_tex >= texture_index_channels)
+							{ //cut batches when index channels are depleted
+								break;
+							}
+
+							tex = facep->getTexture();
+
+							texture_list.push_back(tex);
 						}
 
-						if (cur_tex >= texture_index_channels)
-						{ //cut batches when index channels are depleted
+						if (geom_count + facep->getGeomCount() > max_vertices)
+						{ //cut batches on geom count too big
 							break;
 						}
 
-						tex = facep->getTexture();
+						++i;
+						index_count += facep->getIndicesCount();
+						geom_count += facep->getGeomCount();
 
-						texture_list.push_back(tex);
+						facep->setTextureIndex(cur_tex);
 					}
+				}
+
+				tex = texture_list[0];
+			}
+			else
+			{
+				while (i != faces.end() && 
+					(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+				{
+					facep = *i;
+			
+
+					//face has no texture index
+					facep->mDrawInfo = NULL;
+					facep->setTextureIndex(255);
 
 					if (geom_count + facep->getGeomCount() > max_vertices)
 					{ //cut batches on geom count too big
@@ -4826,69 +4989,18 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 					++i;
 					index_count += facep->getIndicesCount();
 					geom_count += facep->getGeomCount();
-
-					facep->setTextureIndex(cur_tex);
 				}
 			}
-
-			tex = texture_list[0];
 		}
-		else
-		{
-			while (i != faces.end() && 
-				(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
-			{
-				facep = *i;
-			
-
-				//face has no texture index
-				facep->mDrawInfo = NULL;
-				facep->setTextureIndex(255);
 
-				if (geom_count + facep->getGeomCount() > max_vertices)
-				{ //cut batches on geom count too big
-					break;
-				}
-
-				++i;
-				index_count += facep->getIndicesCount();
-				geom_count += facep->getGeomCount();
-			}
-		}
-	
-		//create/delete/resize vertex buffer if needed
+		//create vertex buffer
 		LLVertexBuffer* buffer = NULL;
 
-		{ //try to find a buffer to reuse
-			LLSpatialGroup::buffer_texture_map_t::iterator found_iter = group->mBufferMap[mask].find(*face_iter);
-		
-			if (found_iter != group->mBufferMap[mask].end())
-			{
-				if ((U32) buffer_index < found_iter->second.size())
-				{
-					buffer = found_iter->second[buffer_index];
-				}
-			}
-		}
-						
-		if (!buffer || !buffer->isWriteable())
-		{ //create new buffer if needed
+		{
+			LLFastTimer t(FTM_GEN_DRAW_INFO_ALLOCATE);
 			buffer = createVertexBuffer(mask, buffer_usage);
 			buffer->allocateBuffer(geom_count, index_count, TRUE);
 		}
-		else 
-		{ //resize pre-existing buffer
-			if (LLVertexBuffer::sEnableVBOs && buffer->getUsage() != buffer_usage ||
-				buffer->getTypeMask() != mask)
-			{
-				buffer = createVertexBuffer(mask, buffer_usage);
-				buffer->allocateBuffer(geom_count, index_count, TRUE);
-			}
-			else
-			{
-				buffer->resizeBuffer(geom_count, index_count);
-			}
-		}
 
 		group->mGeometryBytes += buffer->getSize() + buffer->getIndicesSize();
 
@@ -4922,10 +5034,25 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 					LLVOVolume* vobj = drawablep->getVOVolume();
 					LLVolume* volume = vobj->getVolume();
 
+					if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+					{
+						vobj->updateRelativeXform(true);
+					}
+
 					U32 te_idx = facep->getTEOffset();
 
-					facep->getGeometryVolume(*volume, te_idx, 
-						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset);
+					llassert(!facep->isState(LLFace::RIGGED));
+
+					if (!facep->getGeometryVolume(*volume, te_idx, 
+						vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true))
+					{
+						llwarns << "Failed to get geometry for face!" << llendl;
+					}
+
+					if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+					{
+						vobj->updateRelativeXform(false);
+					}
 				}
 			}
 
@@ -5089,7 +5216,8 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 	mFaceList.clear();
 
 	//for each drawable
-	for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
+
+	for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter)
 	{
 		LLDrawable* drawablep = *drawable_iter;
 		
@@ -5109,17 +5237,21 @@ void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_coun
 			//sum up face verts and indices
 			drawablep->updateFaceSize(i);
 			LLFace* facep = drawablep->getFace(i);
-			if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA)
+			if (facep)
 			{
-				vertex_count += facep->getGeomCount();
-				index_count += facep->getIndicesCount();
-				llassert(facep->getIndicesCount() < 65536);
-				//remember face (for sorting)
-				mFaceList.push_back(facep);
-			}
-			else
-			{
-				facep->clearVertexBuffer();
+				if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA && 
+					facep->getGeomCount() + vertex_count <= 65536)
+				{
+					vertex_count += facep->getGeomCount();
+					index_count += facep->getIndicesCount();
+				
+					//remember face (for sorting)
+					mFaceList.push_back(facep);
+				}
+				else
+				{
+					facep->clearVertexBuffer();
+				}
 			}
 		}
 	}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 3cf434dc260a917e7a1db1f7225a4ab86157331d..5a0960204cac9a78d20794d9ba5d994eaff02a8e 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -68,7 +68,7 @@ class LLVolumeInterface
 public:
 	virtual ~LLVolumeInterface() { }
 	virtual LLVolumeInterfaceType getInterfaceType() const = 0;
-	virtual BOOL doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) = 0;
+	virtual void doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) = 0;
 	virtual BOOL doUpdateGeometry(LLDrawable *drawable) = 0;
 	virtual LLVector3 getPivotPosition() const = 0;
 	virtual void onSetVolume(const LLVolumeParams &volume_params, const S32 detail) = 0;
@@ -79,7 +79,7 @@ class LLVolumeInterface
 	virtual bool isVolumeGlobal() const = 0; // Are we in global space?
 	virtual bool isActive() const = 0; // Is this object currently active?
 	virtual const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const = 0;
-	virtual void updateRelativeXform() = 0;
+	virtual void updateRelativeXform(bool force_identity = false) = 0;
 	virtual U32 getID() const = 0;
 	virtual void preRebuild() = 0;
 };
@@ -203,7 +203,7 @@ class LLVOVolume : public LLViewerObject
 														  LLAssetType::EType type,
 														  void* user_data, S32 status, LLExtStat ext_status);
 					
-				void	updateRelativeXform();
+				void	updateRelativeXform(bool force_identity = false);
 	/*virtual*/ BOOL	updateGeometry(LLDrawable *drawable);
 	/*virtual*/ void	updateFaceSize(S32 idx);
 	/*virtual*/ BOOL	updateLOD();
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index cd7815794444869bfa417251a8605f30ef7276a4..942eff61718caab626837ba0c8b64fc5206bd575 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -146,6 +146,10 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable)
 		drawable->addFace(poolp, NULL);
 	}
 	face = drawable->getFace(0);
+	if (!face)
+	{
+		return TRUE;
+	}
 
 //	LLVector2 uvs[4];
 //	LLVector3 vtx[4];
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index b061c90d98c6d8b126e63dd04f3676956ed48c6b..78ee3e4fd98d8da4c7834c5cf1a8ac46d4556eb5 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -657,7 +657,10 @@ void LLWorld::updateRegions(F32 max_update_time)
 		if (did_one && max_time <= 0.f)
 			break;
 		max_time = llmin(max_time, max_update_time*.1f);
-		did_one |= regionp->idleUpdate(max_update_time);
+		if (regionp->idleUpdate(max_update_time))
+		{
+			did_one = TRUE;
+		}
 	}
 }
 
@@ -837,6 +840,9 @@ void LLWorld::updateWaterObjects()
 	}
 	mHoleWaterObjects.clear();
 
+	// Use the water height of the region we're on for areas where there is no region
+	F32 water_height = gAgent.getRegion()->getWaterHeight();
+
 	// Now, get a list of the holes
 	S32 x, y;
 	for (x = min_x; x <= max_x; x += rwidth)
@@ -845,12 +851,12 @@ void LLWorld::updateWaterObjects()
 		{
 			U64 region_handle = to_region_handle(x, y);
 			if (!getRegionFromHandle(region_handle))
-			{
+			{	// No region at that area, so make water
 				LLVOWater* waterp = (LLVOWater *)gObjectList.createObjectViewer(LLViewerObject::LL_VO_WATER, gAgent.getRegion());
 				waterp->setUseTexture(FALSE);
 				waterp->setPositionGlobal(LLVector3d(x + rwidth/2,
 													 y + rwidth/2,
-													 256.f+DEFAULT_WATER_HEIGHT));
+													 256.f + water_height));
 				waterp->setScale(LLVector3((F32)rwidth, (F32)rwidth, 512.f));
 				gPipeline.createObject(waterp);
 				mHoleWaterObjects.push_back(waterp);
@@ -907,7 +913,7 @@ void LLWorld::updateWaterObjects()
 		}
 
 		waterp->setRegion(gAgent.getRegion());
-		LLVector3d water_pos(water_center_x, water_center_y, 256.f+DEFAULT_WATER_HEIGHT) ;
+		LLVector3d water_pos(water_center_x, water_center_y, 256.f + water_height) ;
 		LLVector3 water_scale((F32) dim[0], (F32) dim[1], 512.f);
 
 		//stretch out to horizon
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index ed636a40b290ae73045d8fb8b981a05d8e6e5cf7..cfa47b3ba3f2f522835ac518fb1cb648ac486ca1 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -51,6 +51,10 @@
 // newview includes
 #include "llagent.h"
 #include "llagentcamera.h"
+#include "llappviewer.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "llimageworker.h"
 #include "lldrawable.h"
 #include "lldrawpoolalpha.h"
 #include "lldrawpoolavatar.h"
@@ -113,6 +117,8 @@
 //#define DEBUG_INDICES
 #endif
 
+bool gShiftFrame = false;
+
 //cached settings
 BOOL LLPipeline::RenderAvatarVP;
 BOOL LLPipeline::VertexShaderEnable;
@@ -210,7 +216,7 @@ BOOL	gDebugPipeline = FALSE;
 LLPipeline gPipeline;
 const LLMatrix4* gGLLastMatrix = NULL;
 
-LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry");
+LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Render Geometry");
 LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass");
 LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible");
 LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion");
@@ -227,8 +233,13 @@ LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
 LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
 LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
 LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
+LLFastTimer::DeclareTimer FTM_PIPELINE_CREATE("Pipeline Create");
 LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool");
 LLFastTimer::DeclareTimer FTM_POOLS("Pools");
+LLFastTimer::DeclareTimer FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)");
+LLFastTimer::DeclareTimer FTM_DEFERRED_POOLS("Pools (Deferred)");
+LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)");
+LLFastTimer::DeclareTimer FTM_POST_DEFERRED_POOLS("Pools (Post)");
 LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
 LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
 LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
@@ -264,6 +275,7 @@ std::string gPoolNames[] =
 void drawBox(const LLVector3& c, const LLVector3& r);
 void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
 U32 nhpo2(U32 v);
+LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage);
 
 glh::matrix4f glh_copy_matrix(F32* src)
 {
@@ -403,9 +415,11 @@ LLPipeline::LLPipeline() :
 	mInitialized(FALSE),
 	mVertexShadersEnabled(FALSE),
 	mVertexShadersLoaded(0),
+	mTransformFeedbackPrimitives(0),
 	mRenderDebugFeatureMask(0),
 	mRenderDebugMask(0),
 	mOldRenderDebugMask(0),
+	mMeshDirtyQueryObject(0),
 	mGroupQ1Locked(false),
 	mGroupQ2Locked(false),
 	mResetVertexBuffers(false),
@@ -504,6 +518,11 @@ void LLPipeline::init()
 		mSpotLightFade[i] = 1.f;
 	}
 
+	if (mCubeVB.isNull())
+	{
+		mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB);
+	}
+
 	mDeferredVB = new LLVertexBuffer(DEFERRED_VB_MASK, 0);
 	mDeferredVB->allocateBuffer(8, 0, true);
 	setLightingDetail(-1);
@@ -693,6 +712,12 @@ void LLPipeline::destroyGL()
 	{
 		LLVertexBuffer::sEnableVBOs = FALSE;
 	}
+
+	if (mMeshDirtyQueryObject)
+	{
+		glDeleteQueriesARB(1, &mMeshDirtyQueryObject);
+		mMeshDirtyQueryObject = 0;
+	}
 }
 
 static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
@@ -942,6 +967,7 @@ void LLPipeline::refreshCachedSettings()
 
 	LLPipeline::sUseOcclusion = 
 			(!gUseWireframe
+			&& LLGLSLShader::sNoFixedFunction
 			&& LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") 
 			&& gSavedSettings.getBOOL("UseOcclusion") 
 			&& gGLManager.mHasOcclusionQuery) ? 2 : 0;
@@ -1030,13 +1056,13 @@ void LLPipeline::releaseGLBuffers()
 	
 	if (mNoiseMap)
 	{
-		LLImageGL::deleteTextures(1, &mNoiseMap);
+		LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mNoiseMap);
 		mNoiseMap = 0;
 	}
 
 	if (mTrueNoiseMap)
 	{
-		LLImageGL::deleteTextures(1, &mTrueNoiseMap);
+		LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 0, 1, &mTrueNoiseMap);
 		mTrueNoiseMap = 0;
 	}
 
@@ -1060,7 +1086,7 @@ void LLPipeline::releaseLUTBuffers()
 {
 	if (mLightFunc)
 	{
-		LLImageGL::deleteTextures(1, &mLightFunc);
+		LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_R8, 0, 1, &mLightFunc);
 		mLightFunc = 0;
 	}
 }
@@ -1138,7 +1164,7 @@ void LLPipeline::createGLBuffers()
 				noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
 			}
 
-			LLImageGL::generateTextures(1, &mNoiseMap);
+			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mNoiseMap);
 			
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
 			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise, false);
@@ -1154,7 +1180,7 @@ void LLPipeline::createGLBuffers()
 				noise[i] = ll_frand()*2.0-1.0;
 			}
 
-			LLImageGL::generateTextures(1, &mTrueNoiseMap);
+			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_RGB16F_ARB, 1, &mTrueNoiseMap);
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
 			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise, false);
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
@@ -1210,7 +1236,7 @@ void LLPipeline::createLUTBuffers()
 				}
 			}
 			
-			LLImageGL::generateTextures(1, &mLightFunc);
+			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_R8, 1, &mLightFunc);
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
 			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls, false);
 			gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
@@ -1349,7 +1375,7 @@ class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
 
-		if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
+		if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->isEmpty())
 		{
 			for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
 			{
@@ -1658,7 +1684,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj)
 
 void LLPipeline::createObjects(F32 max_dtime)
 {
-	LLFastTimer ftm(FTM_GEO_UPDATE);
+	LLFastTimer ftm(FTM_PIPELINE_CREATE);
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS);
 
 	LLTimer update_timer;
@@ -1820,6 +1846,16 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
 		if (done)
 		{
 			drawablep->clearState(LLDrawable::ON_MOVE_LIST);
+			if (drawablep->isState(LLDrawable::ANIMATED_CHILD))
+			{ //will likely not receive any future world matrix updates
+				// -- this keeps attachments from getting stuck in space and falling off your avatar
+				drawablep->clearState(LLDrawable::ANIMATED_CHILD);
+				markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, TRUE);
+				if (drawablep->getVObj())
+				{
+					drawablep->getVObj()->dirtySpatialGroup(TRUE);
+				}
+			}
 			iter = moved_list.erase(curiter);
 		}
 	}
@@ -1944,7 +1980,7 @@ void LLPipeline::clearReferences()
 
 void check_references(LLSpatialGroup* group, LLDrawable* drawable)
 {
-	for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
 		if (drawable == *i)
 		{
@@ -1966,7 +2002,7 @@ void check_references(LLDrawable* drawable, LLFace* face)
 
 void check_references(LLSpatialGroup* group, LLFace* face)
 {
-	for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+	for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 	{
 		LLDrawable* drawable = *i;
 		check_references(drawable, face);
@@ -1978,25 +2014,25 @@ void LLPipeline::checkReferences(LLFace* face)
 #if 0
 	if (sCull)
 	{
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, face);
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, face);
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, face);
 		}
 
-		for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+		for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
 		{
 			LLDrawable* drawable = *iter;
 			check_references(drawable, face);	
@@ -2010,25 +2046,25 @@ void LLPipeline::checkReferences(LLDrawable* drawable)
 #if 0
 	if (sCull)
 	{
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, drawable);
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, drawable);
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, drawable);
 		}
 
-		for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+		for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
 		{
 			if (drawable == *iter)
 			{
@@ -2061,19 +2097,19 @@ void LLPipeline::checkReferences(LLDrawInfo* draw_info)
 #if 0
 	if (sCull)
 	{
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, draw_info);
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, draw_info);
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			check_references(group, draw_info);
@@ -2087,7 +2123,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group)
 #if 0
 	if (sCull)
 	{
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
 		{
 			if (group == *iter)
 			{
@@ -2095,7 +2131,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group)
 			}
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
 		{
 			if (group == *iter)
 			{
@@ -2103,7 +2139,7 @@ void LLPipeline::checkReferences(LLSpatialGroup* group)
 			}
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
 		{
 			if (group == *iter)
 			{
@@ -2214,8 +2250,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	gGLLastMatrix = NULL;
 	gGL.loadMatrix(gGLLastModelView);
 
-
-	LLVertexBuffer::unbind();
 	LLGLDisable blend(GL_BLEND);
 	LLGLDisable test(GL_ALPHA_TEST);
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
@@ -2259,7 +2293,16 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 	{ //if no shader is currently bound, use the occlusion shader instead of fixed function if we can
 		// (shadow render uses a special shader that clamps to clip planes)
 		bound_shader = true;
-		gOcclusionProgram.bind();
+		gOcclusionCubeProgram.bind();
+	}
+
+	if (sUseOcclusion > 1)
+	{
+		if (mCubeVB.isNull())
+		{ //cube VB will be used for issuing occlusion queries
+			mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB);
+		}
+		mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 	}
 	
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
@@ -2291,7 +2334,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	if (bound_shader)
 	{
-		gOcclusionProgram.unbind();
+		gOcclusionCubeProgram.unbind();
 	}
 
 	camera.disableUserClipPlane();
@@ -2335,7 +2378,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 {
-	if (group->getData().empty())
+	if (group->isEmpty())
 	{ 
 		return;
 	}
@@ -2424,15 +2467,21 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 		{
 			if (LLPipeline::sShadowRender)
 			{
-				gDeferredShadowProgram.bind();
+				gDeferredShadowCubeProgram.bind();
 			}
 			else
 			{
-				gOcclusionProgram.bind();
+				gOcclusionCubeProgram.bind();
 			}
 		}
 
-		for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
+		if (mCubeVB.isNull())
+		{ //cube VB will be used for issuing occlusion queries
+			mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB);
+		}
+		mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+		for (LLCullResult::sg_iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
 		{
 			LLSpatialGroup* group = *iter;
 			group->doOcclusion(&camera);
@@ -2443,11 +2492,11 @@ void LLPipeline::doOcclusion(LLCamera& camera)
 		{
 			if (LLPipeline::sShadowRender)
 			{
-				gDeferredShadowProgram.unbind();
+				gDeferredShadowCubeProgram.unbind();
 			}
 			else
 			{
-				gOcclusionProgram.unbind();
+				gOcclusionCubeProgram.unbind();
 			}
 		}
 
@@ -2466,22 +2515,36 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
 	return update_complete;
 }
 
+static LLFastTimer::DeclareTimer FTM_SEED_VBO_POOLS("Seed VBO Pool");
+
+static LLFastTimer::DeclareTimer FTM_UPDATE_GL("Update GL");
+
 void LLPipeline::updateGL()
 {
-	while (!LLGLUpdate::sGLQ.empty())
 	{
-		LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
-		glu->updateGL();
-		glu->mInQ = FALSE;
-		LLGLUpdate::sGLQ.pop_front();
+		LLFastTimer t(FTM_UPDATE_GL);
+		while (!LLGLUpdate::sGLQ.empty())
+		{
+			LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
+			glu->updateGL();
+			glu->mInQ = FALSE;
+			LLGLUpdate::sGLQ.pop_front();
+		}
+	}
+
+	{ //seed VBO Pools
+		LLFastTimer t(FTM_SEED_VBO_POOLS);
+		LLVertexBuffer::seedPools();
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups");
+
 void LLPipeline::rebuildPriorityGroups()
 {
+	LLFastTimer t(FTM_REBUILD_PRIORITY_GROUPS);
 	LLTimer update_timer;
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
-	
 	assertInitialized();
 
 	gMeshRepo.notifyLoadedMeshes();
@@ -2500,7 +2563,9 @@ void LLPipeline::rebuildPriorityGroups()
 	mGroupQ1Locked = false;
 
 }
-		
+
+static LLFastTimer::DeclareTimer FTM_REBUILD_GROUPS("Rebuild Groups");
+
 void LLPipeline::rebuildGroups()
 {
 	if (mGroupQ2.empty())
@@ -2508,6 +2573,7 @@ void LLPipeline::rebuildGroups()
 		return;
 	}
 
+	LLFastTimer t(FTM_REBUILD_GROUPS);
 	mGroupQ2Locked = true;
 	// Iterate through some drawables on the non-priority build queue
 	S32 size = (S32) mGroupQ2.size();
@@ -2749,6 +2815,10 @@ void LLPipeline::markShift(LLDrawable *drawablep)
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_SHIFT_DRAWABLE("Shift Drawable");
+static LLFastTimer::DeclareTimer FTM_SHIFT_OCTREE("Shift Octree");
+static LLFastTimer::DeclareTimer FTM_SHIFT_HUD("Shift HUD");
+
 void LLPipeline::shiftObjects(const LLVector3 &offset)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS);
@@ -2761,35 +2831,46 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 	LLVector4a offseta;
 	offseta.load3(offset.mV);
 
-	for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
-		 iter != mShiftList.end(); iter++)
 	{
-		LLDrawable *drawablep = *iter;
-		if (drawablep->isDead())
+		LLFastTimer t(FTM_SHIFT_DRAWABLE);
+
+		for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
+			 iter != mShiftList.end(); iter++)
 		{
-			continue;
-		}	
-		drawablep->shiftPos(offseta);	
-		drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
+			LLDrawable *drawablep = *iter;
+			if (drawablep->isDead())
+			{
+				continue;
+			}	
+			drawablep->shiftPos(offseta);	
+			drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
+		}
+		mShiftList.resize(0);
 	}
-	mShiftList.resize(0);
 
-	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
-			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+	
 	{
-		LLViewerRegion* region = *iter;
-		for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+		LLFastTimer t(FTM_SHIFT_OCTREE);
+		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
+				iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 		{
-			LLSpatialPartition* part = region->getSpatialPartition(i);
-			if (part)
+			LLViewerRegion* region = *iter;
+			for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
 			{
-				part->shift(offseta);
+				LLSpatialPartition* part = region->getSpatialPartition(i);
+				if (part)
+				{
+					part->shift(offseta);
+				}
 			}
 		}
 	}
 
-	LLHUDText::shiftAll(offset);
-	LLHUDNameTag::shiftAll(offset);
+	{
+		LLFastTimer t(FTM_SHIFT_HUD);
+		LLHUDText::shiftAll(offset);
+		LLHUDNameTag::shiftAll(offset);
+	}
 	display_update_camera();
 }
 
@@ -2822,8 +2903,10 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable)
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_PROCESS_PARTITIONQ("PartitionQ");
 void LLPipeline::processPartitionQ()
 {
+	LLFastTimer t(FTM_PROCESS_PARTITIONQ);
 	for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter)
 	{
 		LLDrawable* drawable = *iter;
@@ -2838,6 +2921,11 @@ void LLPipeline::processPartitionQ()
 	mPartitionQ.clear();
 }
 
+void LLPipeline::markMeshDirty(LLSpatialGroup* group)
+{
+	mMeshDirtyGroup.push_back(group);
+}
+
 void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
@@ -2934,7 +3022,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 	//LLVertexBuffer::unbind();
 
 	grabReferences(result);
-	for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+	for (LLCullResult::sg_iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
 	{
 		LLSpatialGroup* group = *iter;
 		group->checkOcclusion();
@@ -2945,7 +3033,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 		else
 		{
 			group->setVisible();
-			for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+			for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 			{
 				markVisible(*i, camera);
 			}
@@ -2960,9 +3048,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 	if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
 	{
 		LLSpatialGroup* last_group = NULL;
-		for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+		for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 		{
-			LLCullResult::bridge_list_t::iterator cur_iter = i;
+			LLCullResult::bridge_iterator cur_iter = i;
 			LLSpatialBridge* bridge = *cur_iter;
 			LLSpatialGroup* group = bridge->getSpatialGroup();
 
@@ -2992,7 +3080,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 		}
 	}
 
-	for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+	for (LLCullResult::sg_iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
 	{
 		LLSpatialGroup* group = *iter;
 		group->checkOcclusion();
@@ -3014,7 +3102,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 	
 	{
 		LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
-		for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
+		for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList();
 			 iter != sCull->endVisibleList(); ++iter)
 		{
 			LLDrawable *drawablep = *iter;
@@ -3033,7 +3121,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
 	if (group->changeLOD())
 	{
-		for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+		for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i)
 		{
 			LLDrawable* drawablep = *i;
 			stateSort(drawablep, camera);
@@ -3150,13 +3238,13 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
 }
 
 
-void forAllDrawables(LLCullResult::sg_list_t::iterator begin, 
-					 LLCullResult::sg_list_t::iterator end,
+void forAllDrawables(LLCullResult::sg_iterator begin, 
+					 LLCullResult::sg_iterator end,
 					 void (*func)(LLDrawable*))
 {
-	for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
+	for (LLCullResult::sg_iterator i = begin; i != end; ++i)
 	{
-		for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
+		for (LLSpatialGroup::element_iter j = (*i)->getDataBegin(); j != (*i)->getDataEnd(); ++j)
 		{
 			func(*j);	
 		}
@@ -3189,7 +3277,11 @@ void renderScriptedBeacons(LLDrawable* drawablep)
 			S32 count = drawablep->getNumFaces();
 			for (face_id = 0; face_id < count; face_id++)
 			{
-				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+				LLFace * facep = drawablep->getFace(face_id);
+				if (facep) 
+				{
+					gPipeline.mHighlightFaces.push_back(facep);
+				}
 			}
 		}
 	}
@@ -3215,7 +3307,11 @@ void renderScriptedTouchBeacons(LLDrawable* drawablep)
 			S32 count = drawablep->getNumFaces();
 			for (face_id = 0; face_id < count; face_id++)
 			{
-				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+				LLFace * facep = drawablep->getFace(face_id);
+				if (facep)
+				{
+					gPipeline.mHighlightFaces.push_back(facep);
+				}
 			}
 		}
 	}
@@ -3240,7 +3336,11 @@ void renderPhysicalBeacons(LLDrawable* drawablep)
 			S32 count = drawablep->getNumFaces();
 			for (face_id = 0; face_id < count; face_id++)
 			{
-				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+				LLFace * facep = drawablep->getFace(face_id);
+				if (facep)
+				{
+					gPipeline.mHighlightFaces.push_back(facep);
+				}
 			}
 		}
 	}
@@ -3276,7 +3376,11 @@ void renderMOAPBeacons(LLDrawable* drawablep)
 			S32 count = drawablep->getNumFaces();
 			for (face_id = 0; face_id < count; face_id++)
 			{
-				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+				LLFace * facep = drawablep->getFace(face_id);
+				if (facep)
+				{
+					gPipeline.mHighlightFaces.push_back(facep);
+				}
 			}
 		}
 	}
@@ -3301,7 +3405,11 @@ void renderParticleBeacons(LLDrawable* drawablep)
 			S32 count = drawablep->getNumFaces();
 			for (face_id = 0; face_id < count; face_id++)
 			{
-				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+				LLFace * facep = drawablep->getFace(face_id);
+				if (facep)
+				{
+					gPipeline.mHighlightFaces.push_back(facep);
+				}
 			}
 		}
 	}
@@ -3319,7 +3427,11 @@ void renderSoundHighlights(LLDrawable* drawablep)
 			S32 count = drawablep->getNumFaces();
 			for (face_id = 0; face_id < count; face_id++)
 			{
-				gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+				LLFace * facep = drawablep->getFace(face_id);
+				if (facep)
+				{
+					gPipeline.mHighlightFaces.push_back(facep);
+				}
 			}
 		}
 	}
@@ -3334,7 +3446,7 @@ void LLPipeline::postSort(LLCamera& camera)
 
 	llpushcallstacks ;
 	//rebuild drawable geometry
-	for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
+	for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
 		if (!sUseOcclusion || 
@@ -3350,23 +3462,9 @@ void LLPipeline::postSort(LLCamera& camera)
 	rebuildPriorityGroups();
 	llpushcallstacks ;
 
-	const S32 bin_count = 1024*8;
-		
-	static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
-	static U32 bin_size[bin_count];
-
-	//clear one bin per frame to avoid memory bloat
-	static S32 clear_idx = 0;
-	clear_idx = (1+clear_idx)%bin_count;
-	alpha_bins[clear_idx].clear();
-
-	for (U32 j = 0; j < bin_count; j++)
-	{
-		bin_size[j] = 0;
-	}
-
+	
 	//build render map
-	for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+	for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
 		if (sUseOcclusion && 
@@ -3436,11 +3534,43 @@ void LLPipeline::postSort(LLCamera& camera)
 			}
 		}
 	}
+	
+	//flush particle VB
+	LLVOPartGroup::sVB->flush();
+
+	/*bool use_transform_feedback = gTransformPositionProgram.mProgramObject && !mMeshDirtyGroup.empty();
+
+	if (use_transform_feedback)
+	{ //place a query around potential transform feedback code for synchronization
+		mTransformFeedbackPrimitives = 0;
+
+		if (!mMeshDirtyQueryObject)
+		{
+			glGenQueriesARB(1, &mMeshDirtyQueryObject);
+		}
+
 		
+		glBeginQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, mMeshDirtyQueryObject);
+	}*/
+
+	//pack vertex buffers for groups that chose to delay their updates
+	for (LLSpatialGroup::sg_vector_t::iterator iter = mMeshDirtyGroup.begin(); iter != mMeshDirtyGroup.end(); ++iter)
+	{
+		(*iter)->rebuildMesh();
+	}
+
+	/*if (use_transform_feedback)
+	{
+		glEndQueryARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
+	}*/
+	
+	mMeshDirtyGroup.clear();
+
 	if (!sShadowRender)
 	{
 		std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
 	}
+
 	llpushcallstacks ;
 	// only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
 	if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender)
@@ -3514,7 +3644,11 @@ void LLPipeline::postSort(LLCamera& camera)
 				{
 					if (object->mDrawable)
 					{
-						gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
+						LLFace * facep = object->mDrawable->getFace(te);
+						if (facep)
+						{
+							gPipeline.mSelectedFaces.push_back(facep);
+						}
 					}
 					return true;
 				}
@@ -3523,6 +3657,33 @@ void LLPipeline::postSort(LLCamera& camera)
 		}
 	}
 
+	/*static LLFastTimer::DeclareTimer FTM_TRANSFORM_WAIT("Transform Fence");
+	static LLFastTimer::DeclareTimer FTM_TRANSFORM_DO_WORK("Transform Work");
+	if (use_transform_feedback)
+	{ //using transform feedback, wait for transform feedback to complete
+		LLFastTimer t(FTM_TRANSFORM_WAIT);
+
+		S32 done = 0;
+		//glGetQueryivARB(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, GL_CURRENT_QUERY, &count);
+		
+		glGetQueryObjectivARB(mMeshDirtyQueryObject, GL_QUERY_RESULT_AVAILABLE, &done);
+		
+		while (!done)
+		{ 
+			{
+				LLFastTimer t(FTM_TRANSFORM_DO_WORK);
+				F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f);
+				//do some useful work while we wait
+				LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread
+				LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread
+				LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread
+			}
+			glGetQueryObjectivARB(mMeshDirtyQueryObject, GL_QUERY_RESULT_AVAILABLE, &done);
+		}
+
+		mTransformFeedbackPrimitives = 0;
+	}*/
+						
 	//LLSpatialGroup::sNoDelete = FALSE;
 	llpushcallstacks ;
 }
@@ -4005,7 +4166,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 	LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED);
 	LLFastTimer t(FTM_RENDER_GEOMETRY);
 
-	LLFastTimer t2(FTM_POOLS);
+	LLFastTimer t2(FTM_DEFERRED_POOLS);
 
 	LLGLEnable cull(GL_CULL_FACE);
 
@@ -4047,7 +4208,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 		pool_set_t::iterator iter2 = iter1;
 		if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
 		{
-			LLFastTimer t(FTM_POOLRENDER);
+			LLFastTimer t(FTM_DEFERRED_POOLRENDER);
 
 			gGLLastMatrix = NULL;
 			gGL.loadMatrix(gGLModelView);
@@ -4100,7 +4261,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 {
 	LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF);
-	LLFastTimer t(FTM_POOLS);
+	LLFastTimer t(FTM_POST_DEFERRED_POOLS);
 	U32 cur_type = 0;
 
 	LLGLEnable cull(GL_CULL_FACE);
@@ -4134,7 +4295,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 		pool_set_t::iterator iter2 = iter1;
 		if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
 		{
-			LLFastTimer t(FTM_POOLRENDER);
+			LLFastTimer t(FTM_POST_DEFERRED_POOLRENDER);
 
 			gGLLastMatrix = NULL;
 			gGL.loadMatrix(gGLModelView);
@@ -4324,7 +4485,7 @@ void LLPipeline::renderPhysicsDisplay()
 		}
 	}
 
-	for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+	for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 	{
 		LLSpatialBridge* bridge = *i;
 		if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
@@ -4419,7 +4580,7 @@ void LLPipeline::renderDebug()
 		}
 	}
 
-	for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+	for (LLCullResult::bridge_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 	{
 		LLSpatialBridge* bridge = *i;
 		if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
@@ -4671,8 +4832,11 @@ void LLPipeline::renderDebug()
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_REBUILD_POOLS("Rebuild Pools");
+
 void LLPipeline::rebuildPools()
 {
+	LLFastTimer t(FTM_REBUILD_POOLS);
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS);
 
 	assertInitialized();
@@ -6219,7 +6383,10 @@ void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
 	for (S32 i = 0; i < drawable->getNumFaces(); i++)
 	{
 		LLFace* facep = drawable->getFace(i);
-		facep->clearVertexBuffer();
+		if (facep)
+		{
+			facep->clearVertexBuffer();
+		}
 	}
 }
 
@@ -6228,15 +6395,20 @@ void LLPipeline::resetVertexBuffers()
 	mResetVertexBuffers = true;
 }
 
+static LLFastTimer::DeclareTimer FTM_RESET_VB("Reset VB");
+
 void LLPipeline::doResetVertexBuffers()
 {
 	if (!mResetVertexBuffers)
 	{
 		return;
 	}
-	
+
+	LLFastTimer t(FTM_RESET_VB);
 	mResetVertexBuffers = false;
 
+	mCubeVB = NULL;
+
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
 	{
@@ -6255,11 +6427,15 @@ void LLPipeline::doResetVertexBuffers()
 
 	gSky.resetVertexBuffers();
 
+	LLVOPartGroup::destroyGL();
+
 	LLVertexBuffer::cleanupClass();
 	
 	//delete all name pool caches
 	LLGLNamePool::cleanupPools();
 
+	
+
 	if (LLVertexBuffer::sGLCount > 0)
 	{
 		llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl;
@@ -6279,6 +6455,8 @@ void LLPipeline::doResetVertexBuffers()
 	LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
 
 	LLVertexBuffer::initClass(LLVertexBuffer::sEnableVBOs, LLVertexBuffer::sDisableVBOMapping);
+
+	LLVOPartGroup::restoreGL();
 }
 
 void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture)
@@ -7466,12 +7644,17 @@ void LLPipeline::renderDeferredLighting()
 			std::list<LLVector4> light_colors;
 
 			LLVertexBuffer::unbind();
-			LLVector4a* v = (LLVector4a*) vert.get();
 
 			{
 				bindDeferredShader(gDeferredLightProgram);
-				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				
+				if (mCubeVB.isNull())
+				{
+					mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB);
+				}
 
+				mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				
 				LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 				for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
 				{
@@ -7517,25 +7700,7 @@ void LLPipeline::renderDeferredLighting()
 					}
 
 					sVisibleLightCount++;
-
-					glh::vec3f tc(c);
-					mat.mult_matrix_vec(tc);
-					
-					//vertex positions are encoded so the 3 bits of their vertex index 
-					//correspond to their axis facing, with bit position 3,2,1 matching
-					//axis facing x,y,z, bit set meaning positive facing, bit clear 
-					//meaning negative facing
-					mDeferredVB->getVertexStrider(vert);
-					v[0].set(c[0]-s,c[1]-s,c[2]-s);  // 0 - 0000 
-					v[1].set(c[0]-s,c[1]-s,c[2]+s);  // 1 - 0001
-					v[2].set(c[0]-s,c[1]+s,c[2]-s);  // 2 - 0010
-					v[3].set(c[0]-s,c[1]+s,c[2]+s);  // 3 - 0011
-																									   
-					v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100
-					v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101
-					v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110
-					v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111
-
+										
 					if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
 						camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
 						camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
@@ -7553,16 +7718,13 @@ void LLPipeline::renderDeferredLighting()
 							}
 							
 							LLFastTimer ftm(FTM_LOCAL_LIGHTS);
-							//glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
-							gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
+							gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
 							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
 							gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
 							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
-							//gGL.diffuseColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
 							gGL.syncMatrices();
-							mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-							glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
-								GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center));
+							
+							mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center));
 							stop_glerror();
 						}
 					}
@@ -7575,6 +7737,9 @@ void LLPipeline::renderDeferredLighting()
 							continue;
 						}
 
+						glh::vec3f tc(c);
+						mat.mult_matrix_vec(tc);
+					
 						fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
 						light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
 					}
@@ -7587,7 +7752,7 @@ void LLPipeline::renderDeferredLighting()
 				LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 				bindDeferredShader(gDeferredSpotLightProgram);
 
-				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 
 				gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
 
@@ -7605,36 +7770,17 @@ void LLPipeline::renderDeferredLighting()
 
 					sVisibleLightCount++;
 
-					glh::vec3f tc(c);
-					mat.mult_matrix_vec(tc);
-					
 					setupSpotLight(gDeferredSpotLightProgram, drawablep);
 					
 					LLColor3 col = volume->getLightColor();
 					
-					//vertex positions are encoded so the 3 bits of their vertex index 
-					//correspond to their axis facing, with bit position 3,2,1 matching
-					//axis facing x,y,z, bit set meaning positive facing, bit clear 
-					//meaning negative facing
-					mDeferredVB->getVertexStrider(vert);
-					v[0].set(c[0]-s,c[1]-s,c[2]-s);  // 0 - 0000 
-					v[1].set(c[0]-s,c[1]-s,c[2]+s);  // 1 - 0001
-					v[2].set(c[0]-s,c[1]+s,c[2]-s);  // 2 - 0010
-					v[3].set(c[0]-s,c[1]+s,c[2]+s);  // 3 - 0011
-																									   
-					v[4].set(c[0]+s,c[1]-s,c[2]-s); // 4 - 0100
-					v[5].set(c[0]+s,c[1]-s,c[2]+s); // 5 - 0101
-					v[6].set(c[0]+s,c[1]+s,c[2]-s); // 6 - 0110
-					v[7].set(c[0]+s,c[1]+s,c[2]+s); // 7 - 0111
-					
-					gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
+					gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
 					gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s*s);
 					gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
 					gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
 					gGL.syncMatrices();
-					mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
-							GL_UNSIGNED_SHORT, get_box_fan_indices_ptr(camera, center));
+										
+					mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center));
 				}
 				gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
 				unbindDeferredShader(gDeferredSpotLightProgram);
@@ -7666,8 +7812,6 @@ void LLPipeline::renderDeferredLighting()
 				LLVector4 light[max_count];
 				LLVector4 col[max_count];
 
-//				glVertexPointer(2, GL_FLOAT, 0, vert);
-
 				F32 far_z = 0.f;
 
 				while (!fullscreen_lights.empty())
@@ -8324,7 +8468,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
 	if (use_shader)
 	{
-		gDeferredShadowProgram.bind();
+		gDeferredShadowCubeProgram.bind();
 	}
 
 	updateCull(shadow_cam, result);
@@ -8341,17 +8485,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 	stop_glerror();
 	gGLLastMatrix = NULL;
 
-	{
-		//LLGLDepthTest depth(GL_TRUE);
-		//glClear(GL_DEPTH_BUFFER_BIT);
-	}
-
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	
 	stop_glerror();
 	
-	//glCullFace(GL_FRONT);
-
 	LLVertexBuffer::unbind();
 
 	{
@@ -8359,6 +8496,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 		{ //occlusion program is general purpose depth-only no-textures
 			gOcclusionProgram.bind();
 		}
+		else
+		{
+			gDeferredShadowProgram.bind();
+		}
 
 		gGL.diffuseColor4f(1,1,1,1);
 		gGL.setColorMask(false, false);
@@ -8408,7 +8549,7 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 
 	//glCullFace(GL_BACK);
 
-	gDeferredShadowProgram.bind();
+	gDeferredShadowCubeProgram.bind();
 	gGLLastMatrix = NULL;
 	gGL.loadMatrix(gGLModelView);
 	doOcclusion(shadow_cam);
@@ -8683,6 +8824,8 @@ void LLPipeline::generateHighlight(LLCamera& camera)
 }
 
 
+static LLFastTimer::DeclareTimer FTM_GEN_SUN_SHADOW("Gen Sun Shadow");
+
 void LLPipeline::generateSunShadow(LLCamera& camera)
 {
 	if (!sRenderDeferred || RenderShadowDetail <= 0)
@@ -8690,6 +8833,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		return;
 	}
 
+	LLFastTimer t(FTM_GEN_SUN_SHADOW);
+
 	BOOL skip_avatar_update = FALSE;
 	if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson)
 	{
@@ -9439,7 +9584,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
 void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
 {
-	for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+	for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
 		if (!group->isDead() &&
@@ -9452,6 +9597,12 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible");
+static LLFastTimer::DeclareTimer FTM_IMPOSTOR_SETUP("Impostor Setup");
+static LLFastTimer::DeclareTimer FTM_IMPOSTOR_BACKGROUND("Impostor Background");
+static LLFastTimer::DeclareTimer FTM_IMPOSTOR_ALLOCATE("Impostor Allocate");
+static LLFastTimer::DeclareTimer FTM_IMPOSTOR_RESIZE("Impostor Resize");
+
 void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 {
 	LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR);
@@ -9507,101 +9658,114 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	sImpostorRender = TRUE;
 
 	LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
-	markVisible(avatar->mDrawable, *viewer_camera);
-	LLVOAvatar::sUseImpostors = FALSE;
 
-	LLVOAvatar::attachment_map_t::iterator iter;
-	for (iter = avatar->mAttachmentPoints.begin();
-		iter != avatar->mAttachmentPoints.end();
-		++iter)
 	{
-		LLViewerJointAttachment *attachment = iter->second;
-		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
-			 attachment_iter != attachment->mAttachedObjects.end();
-			 ++attachment_iter)
+		LLFastTimer t(FTM_IMPOSTOR_MARK_VISIBLE);
+		markVisible(avatar->mDrawable, *viewer_camera);
+		LLVOAvatar::sUseImpostors = FALSE;
+
+		LLVOAvatar::attachment_map_t::iterator iter;
+		for (iter = avatar->mAttachmentPoints.begin();
+			iter != avatar->mAttachmentPoints.end();
+			++iter)
 		{
-			if (LLViewerObject* attached_object = (*attachment_iter))
+			LLViewerJointAttachment *attachment = iter->second;
+			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+				 attachment_iter != attachment->mAttachedObjects.end();
+				 ++attachment_iter)
 			{
-				markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+				if (LLViewerObject* attached_object = (*attachment_iter))
+				{
+					markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+				}
 			}
 		}
 	}
 
 	stateSort(*LLViewerCamera::getInstance(), result);
 	
-	const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
-	LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
-
 	LLCamera camera = *viewer_camera;
-
-	camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
-	
 	LLVector2 tdim;
+	U32 resY = 0;
+	U32 resX = 0;
 
+	{
+		LLFastTimer t(FTM_IMPOSTOR_SETUP);
+		const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
+		LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
 
-	LLVector4a half_height;
-	half_height.setSub(ext[1], ext[0]);
-	half_height.mul(0.5f);
+		camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
+	
+		LLVector4a half_height;
+		half_height.setSub(ext[1], ext[0]);
+		half_height.mul(0.5f);
 
-	LLVector4a left;
-	left.load3(camera.getLeftAxis().mV);
-	left.mul(left);
-	left.normalize3fast();
+		LLVector4a left;
+		left.load3(camera.getLeftAxis().mV);
+		left.mul(left);
+		left.normalize3fast();
 
-	LLVector4a up;
-	up.load3(camera.getUpAxis().mV);
-	up.mul(up);
-	up.normalize3fast();
+		LLVector4a up;
+		up.load3(camera.getUpAxis().mV);
+		up.mul(up);
+		up.normalize3fast();
 
-	tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
-	tdim.mV[1] = fabsf(half_height.dot3(up).getF32());
+		tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
+		tdim.mV[1] = fabsf(half_height.dot3(up).getF32());
 
-	gGL.matrixMode(LLRender::MM_PROJECTION);
-	gGL.pushMatrix();
+		gGL.matrixMode(LLRender::MM_PROJECTION);
+		gGL.pushMatrix();
 	
-	F32 distance = (pos-camera.getOrigin()).length();
-	F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
-	F32 aspect = tdim.mV[0]/tdim.mV[1];
-	glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
-	glh_set_current_projection(persp);
-	gGL.loadMatrix(persp.m);
+		F32 distance = (pos-camera.getOrigin()).length();
+		F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
+		F32 aspect = tdim.mV[0]/tdim.mV[1];
+		glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
+		glh_set_current_projection(persp);
+		gGL.loadMatrix(persp.m);
 
-	gGL.matrixMode(LLRender::MM_MODELVIEW);
-	gGL.pushMatrix();
-	glh::matrix4f mat;
-	camera.getOpenGLTransform(mat.m);
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		gGL.pushMatrix();
+		glh::matrix4f mat;
+		camera.getOpenGLTransform(mat.m);
 
-	mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
+		mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
 
-	gGL.loadMatrix(mat.m);
-	glh_set_current_modelview(mat);
+		gGL.loadMatrix(mat.m);
+		glh_set_current_modelview(mat);
 
-	glClearColor(0.0f,0.0f,0.0f,0.0f);
-	gGL.setColorMask(true, true);
+		glClearColor(0.0f,0.0f,0.0f,0.0f);
+		gGL.setColorMask(true, true);
 	
-	// get the number of pixels per angle
-	F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
+		// get the number of pixels per angle
+		F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
 
-	//get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
-	U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
-	U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
+		//get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
+		resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
+		resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
 
-	if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
-		resY != avatar->mImpostor.getHeight())
-	{
-		avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+		if (!avatar->mImpostor.isComplete())
+		{
+			LLFastTimer t(FTM_IMPOSTOR_ALLOCATE);
+			avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+
+			if (LLPipeline::sRenderDeferred)
+			{
+				addDeferredAttachments(avatar->mImpostor);
+			}
 		
-		if (LLPipeline::sRenderDeferred)
+			gGL.getTexUnit(0)->bind(&avatar->mImpostor);
+			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+		}
+		else if(resX != avatar->mImpostor.getWidth() ||
+			resY != avatar->mImpostor.getHeight())
 		{
-			addDeferredAttachments(avatar->mImpostor);
+			LLFastTimer t(FTM_IMPOSTOR_RESIZE);
+			avatar->mImpostor.resize(resX,resY,GL_RGBA);
 		}
-		
-		gGL.getTexUnit(0)->bind(&avatar->mImpostor);
-		gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	}
 
-	avatar->mImpostor.bindTarget();
+		avatar->mImpostor.bindTarget();
+	}
 
 	if (LLPipeline::sRenderDeferred)
 	{
@@ -9618,6 +9782,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	}
 	
 	{ //create alpha mask based on depth buffer (grey out if muted)
+		LLFastTimer t(FTM_IMPOSTOR_BACKGROUND);
 		if (LLPipeline::sRenderDeferred)
 		{
 			GLuint buff = GL_COLOR_ATTACHMENT0;
@@ -9703,22 +9868,22 @@ BOOL LLPipeline::hasRenderBatches(const U32 type) const
 	return sCull->getRenderMapSize(type) > 0;
 }
 
-LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
+LLCullResult::drawinfo_iterator LLPipeline::beginRenderMap(U32 type)
 {
 	return sCull->beginRenderMap(type);
 }
 
-LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
+LLCullResult::drawinfo_iterator LLPipeline::endRenderMap(U32 type)
 {
 	return sCull->endRenderMap(type);
 }
 
-LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
+LLCullResult::sg_iterator LLPipeline::beginAlphaGroups()
 {
 	return sCull->beginAlphaGroups();
 }
 
-LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
+LLCullResult::sg_iterator LLPipeline::endAlphaGroups()
 {
 	return sCull->endAlphaGroups();
 }
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 5c623fc9f2dce8a634333893851be7ae6bf18db6..efc94315d76bc11455d0cdc9da544f3b30672af1 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -163,6 +163,7 @@ class LLPipeline
 	void		markRebuild(LLSpatialGroup* group, BOOL priority = FALSE);
 	void        markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag = LLDrawable::REBUILD_ALL, BOOL priority = FALSE);
 	void		markPartitionMove(LLDrawable* drawablep);
+	void		markMeshDirty(LLSpatialGroup* group);
 
 	//get the object between start and end that's closest to start.
 	LLViewerObject* lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
@@ -293,10 +294,10 @@ class LLPipeline
 	void setLight(LLDrawable *drawablep, BOOL is_light);
 	
 	BOOL hasRenderBatches(const U32 type) const;
-	LLCullResult::drawinfo_list_t::iterator beginRenderMap(U32 type);
-	LLCullResult::drawinfo_list_t::iterator endRenderMap(U32 type);
-	LLCullResult::sg_list_t::iterator beginAlphaGroups();
-	LLCullResult::sg_list_t::iterator endAlphaGroups();
+	LLCullResult::drawinfo_iterator beginRenderMap(U32 type);
+	LLCullResult::drawinfo_iterator endRenderMap(U32 type);
+	LLCullResult::sg_iterator beginAlphaGroups();
+	LLCullResult::sg_iterator endAlphaGroups();
 	
 
 	void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES);
@@ -544,6 +545,9 @@ class LLPipeline
 	//utility buffer for rendering post effects, gets abused by renderDeferredLighting
 	LLPointer<LLVertexBuffer> mDeferredVB;
 
+	//utility buffer for rendering cubes, 8 vertices are corners of a cube [-1, 1]
+	LLPointer<LLVertexBuffer> mCubeVB;
+
 	//sun shadow map
 	LLRenderTarget			mShadow[6];
 	std::vector<LLVector3>	mShadowFrustPoints[4];
@@ -595,6 +599,7 @@ class LLPipeline
 	BOOL					mVertexShadersEnabled;
 	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed
 
+	U32						mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback
 protected:
 	BOOL					mRenderTypeEnabled[NUM_RENDER_TYPES];
 	std::stack<std::string> mRenderTypeEnableStack;
@@ -652,6 +657,9 @@ class LLPipeline
 	LLSpatialGroup::sg_vector_t		mGroupQ1; //priority
 	LLSpatialGroup::sg_vector_t		mGroupQ2; // non-priority
 
+	LLSpatialGroup::sg_vector_t		mMeshDirtyGroup; //groups that need rebuildMesh called
+	U32 mMeshDirtyQueryObject;
+
 	LLDrawable::drawable_list_t		mPartitionQ; //drawables that need to update their spatial partition radius 
 
 	bool mGroupQ2Locked;
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index d011c7295cb7169d8b42bc6985b9e1f4238e2d69..c875b8c6529bee68dda6ad9148a5b9d33fa48bb7 100644
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -21,7 +21,6 @@
 			<menu_item_call label="Beschäftigt" name="Set Busy"/>
 		</menu>
 		<menu_item_call label="L$ kaufen..." name="Buy and Sell L$"/>
-		<menu_item_call label="Händler-Outbox..." name="MerchantOutbox"/>
 		<menu_item_call label="Kontoübersicht..." name="Manage My Account">
 			<menu_item_call.on_click name="ManageMyAccount_url" parameter="WebLaunchJoinNow,http://secondlife.com/account/index.php?lang=de"/>
 		</menu_item_call>
diff --git a/indra/newview/skins/default/xui/en/floater_my_inventory.xml b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
index 184f29625595a485568d60304ff98e526df51ba0..ea44fd493ec01de3a596bbc1615712aaf0d61981 100644
--- a/indra/newview/skins/default/xui/en/floater_my_inventory.xml
+++ b/indra/newview/skins/default/xui/en/floater_my_inventory.xml
@@ -6,7 +6,7 @@
  height="570"
  help_topic="sidebar_inventory"
  min_width="333"
- min_height="440"
+ min_height="560"
  name="floater_my_inventory"
  save_rect="true"
  save_visibility="true"
diff --git a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
index ffb8b842f0cbb3920eb1507d22de4fa25d5fc1cf..2e29c61cb28456fc75cc401082ba6de07dad57b2 100644
--- a/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
+++ b/indra/newview/skins/default/xui/en/floater_texture_ctrl.xml
@@ -134,6 +134,26 @@
      top_delta="-25"
      name="Pipette"
      width="28" />
+   <check_box
+     follows="left|bottom"
+     height="20"
+     initial_value="true"
+     label="Live Preview"
+     layout="topleft"
+     left="4"
+     name="apply_immediate_check"
+     top="262"
+     width="120" />
+   <text
+     follows="left|bottom"
+     height="20"
+     layout="topleft"
+     left="8"
+     name="preview_disabled"
+     top="266"
+     value="Preview Disabled"
+     visible="false"
+     width="120" />
     <filter_editor
      follows="left|top|right"
      height="23"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index a26c5bb3449969e023b538cf835966dcb7f49593..e806a40951da3c6068633083b93f86d8b2353075 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -7195,6 +7195,18 @@ You uploaded a [RESOLUTION] baked texture for '[BODYREGION]' after [TIME] second
 You locally updated a [RESOLUTION] baked texture for '[BODYREGION]' after [TIME] seconds.
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="LivePreviewUnavailable"
+   type="alert">
+   
+We cannot display a preview of this texture because it is no-copy and/or no-transfer.
+  <usetemplate
+    ignoretext="Warn me that Live Preview mode is not available for no-copy and/or no-transfer textures"
+    name="okignore"
+    yestext="OK"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="ConfirmLeaveCall"
diff --git a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
index 54a312bd59247e66d0ba34dc0170f4f2b7dae06f..c5dfb703e50ccbabcc2ab455bc3c995581da0ac0 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_item_info.xml
@@ -11,6 +11,10 @@
 		 name="unknown">
         (unknown)
 	</panel.string>
+    <panel.string
+         name="unknown_multiple">
+        (unknown / multiple)
+    </panel.string>
 	<panel.string
 		 name="public">
         (public)