diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp
index b1fc20bf327a158a613dd9bba0ec5e29f064eea1..71bbdfb9327db8e05a0bf4c45bea8abaf95d3652 100644
--- a/indra/llcharacter/llmotioncontroller.cpp
+++ b/indra/llcharacter/llmotioncontroller.cpp
@@ -790,6 +790,7 @@ BOOL LLMotionController::activateMotion(LLMotion *motion, F32 time)
 		motion->mSendStopTimestamp = F32_MAX;
 	}
 
+	mActiveMotions.remove(motion); // in case it is already in the active list
 	mActiveMotions.push_front(motion);
 
 	motion->activate();
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 2a58db659e11582b2929461087399a93b3c075ab..1253d34a7dd228740759321e03aaff1599246556 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -174,6 +174,14 @@ template <class Type> class LLPointer
 		}
 		return *this; 
 	}
+	
+	// Just exchange the pointers, which will not change the reference counts.
+	static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
+	{
+		Type* temp = a.mPointer;
+		a.mPointer = b.mPointer;
+		b.mPointer = temp;
+	}
 
 protected:
 	void ref()                             
diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h
index aaecbf3ddca8767bfe515c10cdd77215230ae854..08824722425e69963ca49f44bfa69a41eb31113c 100644
--- a/indra/llcommon/llpreprocessor.h
+++ b/indra/llcommon/llpreprocessor.h
@@ -22,6 +22,13 @@
 #define LL_BIG_ENDIAN 1
 #endif
 
+// Per-compiler switches
+#ifdef __GNUC__
+#define LL_FORCE_INLINE inline __attribute__((always_inline))
+#else
+#define LL_FORCE_INLINE __forceinline
+#endif
+
 // Per-OS feature switches.
 
 #if LL_DARWIN
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index a941941fa8054d221bdfa74ec57c2213bc5b1f01..0e469e63412952d78001526d30a814f8fc788021 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -84,6 +84,7 @@ static	void	_Delay(unsigned int ms)
 CProcessor::CProcessor()
 {
 	uqwFrequency = 0;
+	strCPUName[0] = 0;
 	memset(&CPUInfo, 0, sizeof(CPUInfo));
 }
 
@@ -226,77 +227,44 @@ bool CProcessor::AnalyzeIntelProcessor()
 	CPUInfo.uiType     = (eaxreg >> 12) & 0x3;
 	CPUInfo.uiBrandID  = ebxreg & 0xF;
 
-	// Now we can translate the type number to a more understandable string format
-    switch (CPUInfo.uiType)
+	static const char* INTEL_BRAND[] =
 	{
-		case 0:			// Type = 0:  Original OEM processor
-			strcpy(CPUInfo.strType, "Original OEM"); /* Flawfinder: ignore */
-			strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */
-			strcat(strCPUName, " "); /* Flawfinder: ignore */
-			break;
-		case 1:			// Type = 1:  Overdrive processor
-			strcpy(CPUInfo.strType, "Overdrive"); /* Flawfinder: ignore */
-			strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */
-			strcat(strCPUName, " "); /* Flawfinder: ignore */
-			break;
-		case 2:			// Type = 2:  Dual-capable processor
-			strcpy(CPUInfo.strType, "Dual-capable"); /* Flawfinder: ignore */
-			strcpy(strCPUName, CPUInfo.strType); /* Flawfinder: ignore */
-			strcat(strCPUName, " "); /* Flawfinder: ignore */
-			break;
-		case 3:			// Type = 3:  Reserved for future use
-			strcpy(CPUInfo.strType, "Reserved");	/* Flawfinder: ignore */	
-			break;
-		default:		// This should be never called, cause we just mask 2 bits --> [0..3]
-			strcpy(CPUInfo.strType, "Unknown");	/* Flawfinder: ignore */	
-			break;
-    }
-
-	// Then we translate the brand id:
-	switch (CPUInfo.uiBrandID)
+		/* 0x00 */ "",
+		/* 0x01 */ "0.18 micron Intel Celeron",
+		/* 0x02 */ "0.18 micron Intel Pentium III",
+		/* 0x03 */ "0.13 micron Intel Celeron",
+		/* 0x04 */ "0.13 micron Intel Pentium III",
+		/* 0x05 */ "",
+		/* 0x06 */ "0.13 micron Intel Pentium III mobile",
+		/* 0x07 */ "0.13 micron Intel Celeron mobile",
+		/* 0x08 */ "0.18 micron Intel Pentium 4",
+		/* 0x09 */ "0.13 micron Intel Pentium 4",
+		/* 0x0A */ "0.13 micron Intel Pentium 4",
+		/* 0x0B */ "0.13 micron Intel Pentium 4 Xeon",
+		/* 0x0C */ "",
+		/* 0x0D */ "",
+		/* 0x0E */ "0.18 micron Intel Pentium 4 Xeon",
+		/* 0x0F */ "",
+		/* 0x10 */ "",
+		/* 0x11 */ "",
+		/* 0x12 */ "Intel Celeron M",
+		/* 0x13 */ "mobile Intel Celeron",
+		/* 0x14 */ "Intel Celeron",
+		/* 0x15 */ "mobile Intel",
+		/* 0x16 */ "Intel Pentium M",
+		/* 0x17 */ "mobile Intel Celeron",
+	};
+
+	// Only override the brand if we have it in the lookup table.  We should
+	// already have a string here from GetCPUInfo().  JC
+	if (CPUInfo.uiBrandID < sizeof(INTEL_BRAND))
 	{
-		case 0:			// Brand id = 0:  Brand id not supported on this processor
-			strcpy(CPUInfo.strBrandID, "Not supported");	/* Flawfinder: ignore */	
-			break;
-		case 1:			// Brand id = 1:  Intel Celeron (0.18 micron) processor
-			strcpy(CPUInfo.strBrandID, "0.18 micron Intel Celeron");	/* Flawfinder: ignore */	
-			break;
-		case 2:			// Brand id = 2:  Intel Pentium III (0.18 micron) processor
-			strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III");	/* Flawfinder: ignore */	
-			break;
-		case 3:			// Brand id = 3:  Model dependent
-			if (CPUInfo.uiModel == 6)	// If the cpu model is Celeron (well, I'm NOT SURE!!!)
-				strcpy(CPUInfo.strBrandID, "0.13 micron Intel Celeron");	/* Flawfinder: ignore */	
-			else
-				strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III Xeon");	/* Flawfinder: ignore */	
-			break;
-		case 4:			// Brand id = 4:  Intel Pentium III Tualatin (0.13 micron) processor
-			strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium III");	/* Flawfinder: ignore */	
-			break;
-		case 6:			// Brand id = 6:  Intel Pentium III mobile (0.13 micron) processor
-			strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium III mobile");		/* Flawfinder: ignore */	
-			break;
-		case 7:			// Brand id = 7:  Intel Celeron mobile (0.13 micron) processor
-			strcpy(CPUInfo.strBrandID, "0.13 micron Intel Celeron mobile");	/* Flawfinder: ignore */	
-			break;
-		case 8:			// Brand id = 8:  Intel Pentium 4 Willamette (0.18 micron) processor
-			strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium 4");	/* Flawfinder: ignore */	
-			break;
-		case 9:			// Brand id = 9:  Intel Pentium 4 Northwood (0.13 micron) processor
-			strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium 4");	/* Flawfinder: ignore */	
-			break;
-		case 0xA:		// Brand id = 0xA:  Intel Pentium 4 Northwood (0.13 micron processor) 
-			strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium 4");	/* Flawfinder: ignore */	
-			break;		// No idea, where the difference to id=9 is
-		case 0xB:		// Brand id = 0xB:  Intel Pentium 4 Northwood Xeon (0.13 micron processor)
-			strcpy(CPUInfo.strBrandID, "0.13 micron Intel Pentium 4 Xeon");	/* Flawfinder: ignore */	
-			break;
-		case 0xE:		// Brand id = 0xE:  Intel Pentium 4 Willamette Xeon (0.18 micron processor)
-			strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium 4 Xeon");	/* Flawfinder: ignore */	
-			break;
-		default:		// Should be never called, but sure is sure
-			strcpy(CPUInfo.strBrandID, "Unknown");	/* Flawfinder: ignore */	
-			break;
+		strcpy(CPUInfo.strBrandID, INTEL_BRAND[CPUInfo.uiBrandID]);
+
+		if (CPUInfo.uiBrandID == 3 && CPUInfo.uiModel == 6)
+		{
+			strcpy(CPUInfo.strBrandID, "0.18 micron Intel Pentium III Xeon");
+		}
 	}
 
 	// Then we translate the cpu family
@@ -648,33 +616,6 @@ bool CProcessor::AnalyzeAMDProcessor()
 	CPUInfo.uiFamily   = (eaxreg >> 8) & 0xF;
 	CPUInfo.uiType     = (eaxreg >> 12) & 0x3;
 
-	// After that, we translate the processor type (see CProcessor::AnalyzeIntelProcessor()
-	// for further comments on this)
-    switch (CPUInfo.uiType)
-	{
-		case 0:
-			strcpy(CPUInfo.strType, "Original OEM");		/* Flawfinder: ignore */
-			strcpy(strCPUName, CPUInfo.strType);	/* Flawfinder: ignore */	
-			strcat(strCPUName, " "); /*Flawfinder: ignore*/
-			break;
-		case 1:
-			strcpy(CPUInfo.strType, "Overdrive");		/* Flawfinder: ignore */
-			strcpy(strCPUName, CPUInfo.strType);	/* Flawfinder: ignore */	
-			strcat(strCPUName, " "); /*Flawfinder: ignore*/
-			break;
-		case 2:
-			strcpy(CPUInfo.strType, "Dual-capable");		/* Flawfinder: ignore */
-			strcpy(strCPUName, CPUInfo.strType);	/* Flawfinder: ignore */	
-			strcat(strCPUName, " "); /*Flawfinder: ignore*/
-			break;
-		case 3:
-			strcpy(CPUInfo.strType, "Reserved");		/* Flawfinder: ignore */
-			break;
-		default:
-			strcpy(CPUInfo.strType, "Unknown");		/* Flawfinder: ignore */
-			break;
-    }
-
 	// Now we check if the processor supports the brand id string extended CPUID level
 	if (CPUInfo.MaxSupportedExtendedLevel >= 0x80000004)
 	{
@@ -709,7 +650,7 @@ bool CProcessor::AnalyzeAMDProcessor()
 	else
 	{
 		// Or just tell there is no brand id string support
-		strcpy(CPUInfo.strBrandID, "Not supported");		/* Flawfinder: ignore */
+		strcpy(CPUInfo.strBrandID, "");		/* Flawfinder: ignore */
 	}
 
 	// After that we translate the processor family
@@ -1103,26 +1044,6 @@ bool CProcessor::AnalyzeUnknownProcessor()
 	snprintf(CPUInfo.strFamily, sizeof(CPUInfo.strFamily), "Family number %d", CPUInfo.uiFamily);		/* Flawfinder: ignore */
 	snprintf(CPUInfo.strModel, sizeof(CPUInfo.strModel), "Model number %d", CPUInfo.uiModel);		/* Flawfinder: ignore */
 
-	// Nevertheless we can determine the processor type
-    switch (CPUInfo.uiType)
-	{
-		case 0:
-			strcpy(CPUInfo.strType, "Original OEM");	/*Flawfinder: ignore*/
-			break;
-		case 1:
-			strcpy(CPUInfo.strType, "Overdrive");	/*Flawfinder: ignore*/
-			break;
-		case 2:
-			strcpy(CPUInfo.strType, "Dual-capable");	/*Flawfinder: ignore*/
-			break;
-		case 3:
-			strcpy(CPUInfo.strType, "Reserved");		/*Flawfinder: ignore*/
-			break;
-		default:
-			strcpy(CPUInfo.strType, "Unknown");	/*Flawfinder: ignore*/
-			break;
-    }
-
 	// And thats it
 	return true;
 #else
@@ -1634,6 +1555,8 @@ const ProcessorInfo *CProcessor::GetCPUInfo()
 	*((unsigned long *) CPUInfo.strVendor) = ebxreg;
 	*((unsigned long *) (CPUInfo.strVendor+4)) = edxreg;
 	*((unsigned long *) (CPUInfo.strVendor+8)) = ecxreg;
+	// Null terminate for string comparisons below.
+	CPUInfo.strVendor[12] = 0;
 
 	// We can also read the max. supported standard CPUID level
 	CPUInfo.MaxSupportedLevel = eaxreg & 0xFFFF;
@@ -1649,22 +1572,52 @@ const ProcessorInfo *CProcessor::GetCPUInfo()
 	CPUInfo.MaxSupportedExtendedLevel = eaxreg;
 
 	// Then we switch to the specific processor vendors
-	switch (ebxreg)
+	// See http://www.sandpile.org/ia32/cpuid.htm
+	if (!strcmp(CPUInfo.strVendor, "GenuineIntel"))
 	{
-		case 0x756E6547:	// GenuineIntel
-			AnalyzeIntelProcessor();
-			break;
-		case 0x68747541:	// AuthenticAMD
-			AnalyzeAMDProcessor();
-			break;
-		case 0x69727943:	// CyrixInstead
-			// I really do not know anyone owning such a piece of crab
-			// So we analyze it as an unknown processor *ggggg*
-		default:
-			AnalyzeUnknownProcessor();
-			break;
+		AnalyzeIntelProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "AuthenticAMD"))
+	{
+		AnalyzeAMDProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "UMC UMC UMC"))
+	{
+		AnalyzeUnknownProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "CyrixInstead"))
+	{
+		AnalyzeUnknownProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "NexGenDriven"))
+	{
+		AnalyzeUnknownProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "CentaurHauls"))
+	{
+		AnalyzeUnknownProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "RiseRiseRise"))
+	{
+		AnalyzeUnknownProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "SiS SiS SiS"))
+	{
+		AnalyzeUnknownProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "GenuineTMx86"))
+	{
+		// Transmeta
+		AnalyzeUnknownProcessor();
+	}
+	else if (!strcmp(CPUInfo.strVendor, "Geode by NSC"))
+	{
+		AnalyzeUnknownProcessor();
+	}
+	else
+	{
+		AnalyzeUnknownProcessor();
 	}
-
 #endif
 	// After all we return the class CPUInfo member var
 	return (&CPUInfo);
@@ -1748,6 +1701,7 @@ void CProcessor::TranslateProcessorConfiguration()
 CProcessor::CProcessor()
 {
 	uqwFrequency = 0;
+	strCPUName[0] = 0;
 	memset(&CPUInfo, 0, sizeof(CPUInfo));
 }
 
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 54276f9f2f4d54915c9262192c79e9dfdcda63d3..6f0bda4b7106977349e0ca92e27e5b5899932f7f 100644
--- a/indra/llcommon/llsys.cpp
+++ b/indra/llcommon/llsys.cpp
@@ -12,6 +12,7 @@
 
 #include <iostream>
 #include <zlib/zlib.h>
+
 #include "processor.h"
 
 #if LL_WINDOWS
@@ -289,50 +290,28 @@ LLCPUInfo::LLCPUInfo()
 	mFamily.assign( info->strFamily );
 }
 
+
 std::string LLCPUInfo::getCPUString() const
 {
-	std::string cpu_string;
-
 #if LL_WINDOWS || LL_DARWIN
-	// gather machine information.
-	char proc_buf[CPUINFO_BUFFER_SIZE];		/* Flawfinder: ignore */
-	CProcessor proc;
-	if(proc.CPUInfoToText(proc_buf, CPUINFO_BUFFER_SIZE))
-	{
-		cpu_string.append(proc_buf);
-	}
-#else
-	cpu_string.append("Can't get CPU information");
-#endif
-
-	return cpu_string;
-}
-
-std::string LLCPUInfo::getCPUStringTerse() const
-{
-	std::string cpu_string;
+	std::ostringstream out;
 
-#if LL_WINDOWS || LL_DARWIN
 	CProcessor proc;
-	const ProcessorInfo *info = proc.GetCPUInfo();
-
-	cpu_string.append(info->strBrandID);
+	(void) proc.GetCPUInfo();
+	out << proc.strCPUName << " ";
 	
-	F64 freq = (F64)(S64)proc.GetCPUFrequency(50) / 1000000.f;
+	F32 freq = (F32)(proc.GetCPUFrequency(50) / 1000000.0);
 
 	// cpu speed is often way wrong, do a sanity check
-	if (freq < 10000.f && freq > 200.f )
+	if (200.f < freq && freq < 10000.f)
 	{
-		char tmp[MAX_STRING];		/* Flawfinder: ignore */
-		snprintf(tmp, sizeof(tmp), " (%.0f Mhz)", freq);	/* Flawfinder: ignore */
-
-		cpu_string.append(tmp);
+		out << "(" << (S32)(freq) << " MHz)";
 	}
+
+	return out.str();
 #else
-	cpu_string.append("Can't get terse CPU information");
+	return "Can't get terse CPU information";
 #endif
-
-	return cpu_string;
 }
 
 void LLCPUInfo::stream(std::ostream& s) const
diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h
index 05c975a5fa318f9421cc21a8adc1aad87e81300f..7808a97b80731c2108343c04d32fdb049ea0002f 100644
--- a/indra/llcommon/llsys.h
+++ b/indra/llcommon/llsys.h
@@ -51,7 +51,6 @@ class LLCPUInfo
 	void stream(std::ostream& s) const;
 
 	std::string getCPUString() const;
-	std::string getCPUStringTerse() const;
 
 	BOOL  hasSSE() const	{ return mHasSSE; }
 	BOOL  hasSSE2()	const	{ return mHasSSE2; }
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index 969c3663e6fd46facaaecb7243871004fa9a310d..8d5fc277762575f22db60c597931404db9993361 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -654,31 +654,55 @@ LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b)
 }
 */
 
+// Operates "to the left" on row-vector a
+//
+// This used to be in the header file but was not actually inlined in practice.
+// When avatar vertex programs are off, this function is a hot spot in profiles
+// due to software skinning in LLViewerJointMesh::updateGeometry().  JC
+LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b)
+{
+	// This is better than making a temporary LLVector3.  This eliminates an
+	// unnecessary LLVector3() constructor and also helps the compiler to
+	// realize that the output floats do not alias the input floats, hence
+	// eliminating redundant loads of a.mV[0], etc.  JC
+	return LLVector3(a.mV[VX] * b.mMatrix[VX][VX] + 
+					 a.mV[VY] * b.mMatrix[VY][VX] + 
+					 a.mV[VZ] * b.mMatrix[VZ][VX] +
+					 b.mMatrix[VW][VX],
+					 
+					 a.mV[VX] * b.mMatrix[VX][VY] + 
+					 a.mV[VY] * b.mMatrix[VY][VY] + 
+					 a.mV[VZ] * b.mMatrix[VZ][VY] +
+					 b.mMatrix[VW][VY],
+					 
+					 a.mV[VX] * b.mMatrix[VX][VZ] + 
+					 a.mV[VY] * b.mMatrix[VY][VZ] + 
+					 a.mV[VZ] * b.mMatrix[VZ][VZ] +
+					 b.mMatrix[VW][VZ]);
+}
 
 LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b)
 {
 	// Operate "to the left" on row-vector a
-	LLVector4	vec;
-	vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] + 
-				 a.mV[VY] * b.mMatrix[VY][VX] + 
-				 a.mV[VZ] * b.mMatrix[VZ][VX] +
-				 a.mV[VW] * b.mMatrix[VW][VX];
-
-	vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] + 
-				 a.mV[VY] * b.mMatrix[VY][VY] + 
-				 a.mV[VZ] * b.mMatrix[VZ][VY] +
-				 a.mV[VW] * b.mMatrix[VW][VY];
-
-	vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] + 
-				 a.mV[VY] * b.mMatrix[VY][VZ] + 
-				 a.mV[VZ] * b.mMatrix[VZ][VZ] +
-				 a.mV[VW] * b.mMatrix[VW][VZ];
-
-	vec.mV[VW] = a.mV[VX] * b.mMatrix[VX][VW] + 
-				 a.mV[VY] * b.mMatrix[VY][VW] + 
-				 a.mV[VZ] * b.mMatrix[VZ][VW] +
-				 a.mV[VW] * b.mMatrix[VW][VW];
-	return vec;
+	return LLVector4(a.mV[VX] * b.mMatrix[VX][VX] + 
+					 a.mV[VY] * b.mMatrix[VY][VX] + 
+					 a.mV[VZ] * b.mMatrix[VZ][VX] +
+					 a.mV[VW] * b.mMatrix[VW][VX],
+
+					 a.mV[VX] * b.mMatrix[VX][VY] + 
+					 a.mV[VY] * b.mMatrix[VY][VY] + 
+					 a.mV[VZ] * b.mMatrix[VZ][VY] +
+					 a.mV[VW] * b.mMatrix[VW][VY],
+
+					 a.mV[VX] * b.mMatrix[VX][VZ] + 
+					 a.mV[VY] * b.mMatrix[VY][VZ] + 
+					 a.mV[VZ] * b.mMatrix[VZ][VZ] +
+					 a.mV[VW] * b.mMatrix[VW][VZ],
+
+					 a.mV[VX] * b.mMatrix[VX][VW] + 
+					 a.mV[VY] * b.mMatrix[VY][VW] + 
+					 a.mV[VZ] * b.mMatrix[VZ][VW] +
+					 a.mV[VW] * b.mMatrix[VW][VW]);
 }
 
 LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b)
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index 69463d7718acc686e143eccf6b6a60c67b1ccf66..e95a40af1621b9a8c634ea4f53353956056c1204 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -247,27 +247,6 @@ inline const LLMatrix4&	LLMatrix4::identity()
 	return (*this);
 }
 
-inline LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b)
-{
-	// Converts a to LLVector4 and applies full transformation
-	// Operates "to the left" on row-vector a
-	LLVector3	vec;
-	vec.mV[VX] = a.mV[VX] * b.mMatrix[VX][VX] + 
-				 a.mV[VY] * b.mMatrix[VY][VX] + 
-				 a.mV[VZ] * b.mMatrix[VZ][VX] +
-				 b.mMatrix[VW][VX];
-
-	vec.mV[VY] = a.mV[VX] * b.mMatrix[VX][VY] + 
-				 a.mV[VY] * b.mMatrix[VY][VY] + 
-				 a.mV[VZ] * b.mMatrix[VZ][VY] +
-				 b.mMatrix[VW][VY];
-
-	vec.mV[VZ] = a.mV[VX] * b.mMatrix[VX][VZ] + 
-				 a.mV[VY] * b.mMatrix[VY][VZ] + 
-				 a.mV[VZ] * b.mMatrix[VZ][VZ] +
-				 b.mMatrix[VW][VZ];
-	return vec;
-}
 
 /*
 inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b)
diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h
index e9b8d5b71f71f64270fe556db47a9486ae4201e9..ced7ef131a1b6a4affd84f84d065541a38538861 100644
--- a/indra/llmath/v4math.h
+++ b/indra/llmath/v4math.h
@@ -26,7 +26,8 @@ class LLVector4
 	public:
 		F32 mV[LENGTHOFVECTOR4];
 		LLVector4();						// Initializes LLVector4 to (0, 0, 0, 1)
-		explicit LLVector4(const F32 *vec);			// Initializes LLVector4 to (vec[0]. vec[1], vec[2], 1)
+		explicit LLVector4(const F32 *vec);			// Initializes LLVector4 to (vec[0]. vec[1], vec[2], vec[3])
+		explicit LLVector4(const F64 *vec);			// Initialized LLVector4 to ((F32) vec[0], (F32) vec[1], (F32) vec[3], (F32) vec[4]);
 		explicit LLVector4(const LLVector3 &vec);			// Initializes LLVector4 to (vec, 1)
 		explicit LLVector4(const LLVector3 &vec, F32 w);	// Initializes LLVector4 to (vec, w)
 		LLVector4(F32 x, F32 y, F32 z);		// Initializes LLVector4 to (x. y, z, 1)
@@ -136,6 +137,14 @@ inline LLVector4::LLVector4(const F32 *vec)
 	mV[VW] = vec[VW];
 }
 
+inline LLVector4::LLVector4(const F64 *vec)
+{
+	mV[VX] = (F32) vec[VX];
+	mV[VY] = (F32) vec[VY];
+	mV[VZ] = (F32) vec[VZ];
+	mV[VW] = (F32) vec[VW];
+}
+
 inline LLVector4::LLVector4(const LLVector3 &vec)
 {
 	mV[VX] = vec.mV[VX];
diff --git a/indra/llmessage/llclassifiedflags.h b/indra/llmessage/llclassifiedflags.h
index 1949eb54d0c9ce8bade949a24c2e6592219c5650..610ad35c4a909bef54204052050a0620a8d71943 100644
--- a/indra/llmessage/llclassifiedflags.h
+++ b/indra/llmessage/llclassifiedflags.h
@@ -22,6 +22,8 @@ const U8 CLASSIFIED_QUERY_FILTER_MATURE		= 1 << 1;
 const U8 CLASSIFIED_QUERY_FILTER_ENABLED	= 1 << 2;
 const U8 CLASSIFIED_QUERY_FILTER_PRICE		= 1 << 3;
 
+const S32 MAX_CLASSIFIEDS = 100;
+
 ClassifiedFlags pack_classified_flags(BOOL is_mature, BOOL auto_renew);
 bool is_cf_mature(ClassifiedFlags flags);
 //bool is_cf_enabled(ClassifiedFlags flags);
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index 099b6a0a5b13768039c571fea3de8c22c89d6e1f..6fb319326b015b695c9a36849541348dba6d5baa 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -33,6 +33,7 @@
 
 // linden library headers
 #include "indra_constants.h"
+#include "lldarray.h"
 #include "lldir.h"
 #include "llerror.h"
 #include "llfasttimer.h"
@@ -447,7 +448,6 @@ class LLMessageTemplate
 };
 
 
-
 // static
 BOOL LLMessageSystem::mTimeDecodes = FALSE;
 
@@ -827,6 +827,9 @@ void LLMessageSystem::init()
 
 	mMessageFileChecksum = 0;
 	mMessageFileVersionNumber = 0.f;
+
+	mTimingCallback = NULL;
+	mTimingCallbackData = NULL;
 }
 
 LLMessageSystem::LLMessageSystem()
@@ -3480,7 +3483,7 @@ BOOL LLMessageSystem::decodeData(const U8* buffer, const LLHost& sender )
 	{
 		static LLTimer decode_timer;
 
-		if( mTimeDecodes )
+		if( mTimeDecodes || mTimingCallback )
 		{
 			decode_timer.reset();
 		}
@@ -3503,25 +3506,36 @@ BOOL LLMessageSystem::decodeData(const U8* buffer, const LLHost& sender )
 		//		VTPause();	// VTune
 		//	}
 
-		if( mTimeDecodes )
+		if( mTimeDecodes || mTimingCallback )
 		{
 			F32 decode_time = decode_timer.getElapsedTimeF32();
-			mCurrentRMessageTemplate->mDecodeTimeThisFrame += decode_time;
-
-			mCurrentRMessageTemplate->mTotalDecoded++;
-			mCurrentRMessageTemplate->mTotalDecodeTime += decode_time;
 
-			if( mCurrentRMessageTemplate->mMaxDecodeTimePerMsg < decode_time )
+			if (mTimingCallback)
 			{
-				mCurrentRMessageTemplate->mMaxDecodeTimePerMsg = decode_time;
+				mTimingCallback(mCurrentRMessageTemplate->mName,
+								decode_time,
+								mTimingCallbackData);
 			}
 
-
-			if( decode_time > mTimeDecodesSpamThreshold )
+			if (mTimeDecodes)
 			{
-				lldebugs << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" <<
-					mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " <<
-					(mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << llendl;
+				mCurrentRMessageTemplate->mDecodeTimeThisFrame += decode_time;
+
+				mCurrentRMessageTemplate->mTotalDecoded++;
+				mCurrentRMessageTemplate->mTotalDecodeTime += decode_time;
+
+				if( mCurrentRMessageTemplate->mMaxDecodeTimePerMsg < decode_time )
+				{
+					mCurrentRMessageTemplate->mMaxDecodeTimePerMsg = decode_time;
+				}
+
+
+				if( decode_time > mTimeDecodesSpamThreshold )
+				{
+					lldebugs << "--------- Message " << mCurrentRMessageTemplate->mName << " decode took " << decode_time << " seconds. (" <<
+						mCurrentRMessageTemplate->mMaxDecodeTimePerMsg << " max, " <<
+						(mCurrentRMessageTemplate->mTotalDecodeTime / mCurrentRMessageTemplate->mTotalDecoded) << " avg)" << llendl;
+				}
 			}
 		}
 	}
@@ -4516,76 +4530,6 @@ void process_deny_trusted_circuit(LLMessageSystem *msg, void **)
 	msg->sendCreateTrustedCircuit(msg->getSender(), local_id, remote_id);
 }
 
-#define LL_ENCRYPT_BUF_LENGTH	16384
-
-void encrypt_template(const char *src_name, const char *dest_name)
-{
-	// encrypt and decrypt are symmetric
-	decrypt_template(src_name, dest_name);
-}
-
-BOOL decrypt_template(const char *src_name, const char *dest_name)
-{
-	S32 buf_length = LL_ENCRYPT_BUF_LENGTH;
-	char buf[LL_ENCRYPT_BUF_LENGTH];	/* Flawfinder: ignore */
-	
-	FILE* infp = NULL;
-	FILE* outfp = NULL;
-	BOOL success = FALSE;
-	char* bufp = NULL;
-	U32 key = 0;
-	S32 more_data = 0;
-
-	if(src_name==NULL)
-	{
-		 llwarns << "Input src_name is NULL!!" << llendl;
-		 goto exit;
-	}
-
-	infp = LLFile::fopen(src_name,"rb");	/* Flawfinder: ignore */
-	if (!infp)
-	{
-		llwarns << "could not open " << src_name << " for reading" << llendl;
-		goto exit;
-	}
-
-	if(dest_name==NULL)
-	{
-		 llwarns << "Output dest_name is NULL!!" << llendl;
-		 goto exit;
-	}
-
-	outfp = LLFile::fopen(dest_name,"w+b");	/* Flawfinder: ignore */
-	if (!outfp)
-	{
-		llwarns << "could not open " << src_name << " for writing" << llendl;
-		goto exit;
-	}
-
-	while ((buf_length = (S32)fread(buf,1,LL_ENCRYPT_BUF_LENGTH,infp)))
-	{
-		// unscrozzle bits here
-		bufp = buf;
-		more_data = buf_length;
-		while (more_data--)
-		{
-			*bufp = *bufp ^ ((key * 43) % 256);
-			key++;
-			bufp++;
-		}
-
-		if(buf_length != (S32)fwrite(buf,1,buf_length,outfp))
-		{
-			goto exit;
-		}
-	}
-	success = TRUE;
-
- exit:
-	if(infp) fclose(infp);
-	if(outfp) fclose(outfp);
-	return success;
-}
 
 void dump_prehash_files()
 {
@@ -5278,6 +5222,12 @@ BOOL LLMessageSystem::callExceptionFunc(EMessageException exception)
 	return FALSE;
 }
 
+void LLMessageSystem::setTimingFunc(msg_timing_callback func, void* data)
+{
+	mTimingCallback = func;
+	mTimingCallbackData = data;
+}
+
 BOOL LLMessageSystem::isCircuitCodeKnown(U32 code) const
 {
 	if(mCircuitCodes.find(code) == mCircuitCodes.end())
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index 3f9dfa08d6e0f6f3296c5b6a736807c67a49d6b6..3ffafcc1b8549f3924253c75a618f8237536a5c3 100644
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -26,16 +26,13 @@
 #include "llerror.h"
 #include "net.h"
 #include "string_table.h"
-#include "llptrskipmap.h"
 #include "llcircuit.h"
 #include "lltimer.h"
 #include "llpacketring.h"
 #include "llhost.h"
 #include "llpacketack.h"
-#include "doublelinkedlist.h"
 #include "message_prehash.h"
 #include "llstl.h"
-#include "lldarray.h"
 
 const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
 const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
@@ -178,7 +175,6 @@ enum EMessageException
 typedef void (*msg_exception_callback)(LLMessageSystem*,void*,EMessageException);
 
 
-
 class LLMsgData;
 class LLMsgBlkData;
 class LLMessageTemplate;
@@ -307,6 +303,12 @@ class LLMessageSystem
 	// function was found and called. Otherwise return FALSE.
 	BOOL callExceptionFunc(EMessageException exception);
 
+	// Set a function that will be called once per packet processed with the 
+	// hashed message name and the time spent in the processing handler function
+	// measured in seconds.  JC
+	typedef void (*msg_timing_callback)(const char* hashed_name, F32 time, void* data);
+	void setTimingFunc(msg_timing_callback func, void* data = NULL);
+
 	// This method returns true if the code is in the circuit codes map.
 	BOOL isCircuitCodeKnown(U32 code) const;
 
@@ -734,16 +736,15 @@ class LLMessageSystem
 	static F32 mTimeDecodesSpamThreshold;  // If mTimeDecodes is on, all this many seconds for each msg decode before spamming
 	static BOOL mTimeDecodes;  // Measure time for all message decodes if TRUE;
 
+	msg_timing_callback mTimingCallback;
+	void* mTimingCallbackData;
+
 	void init(); // ctor shared initialisation.
 };
 
 
 // external hook into messaging system
 extern LLMessageSystem	*gMessageSystem;
-//extern const char* MESSAGE_LOG_FILENAME;
-
-void encrypt_template(const char *src_name, const char *dest_name);
-BOOL decrypt_template(const char *src_name, const char *dest_name);
 
 // Must specific overall system version, which is used to determine
 // if a patch is available in the message template checksum verification.
@@ -1232,22 +1233,9 @@ inline void LLMessageSystem::getString(const char *block, const char *var, S32 b
 	s[buffer_size - 1] = '\0';
 }
 
-//-----------------------------------------------------------------------------
-// Transmission aliases
-//-----------------------------------------------------------------------------
-//inline S32 LLMessageSystem::sendMessage(U32 ip, U32 port, BOOL zero_code)
-//{
-//	return sendMessage(LLHost(ip, port), zero_code);
-//}
-
-//inline S32 LLMessageSystem::sendMessage(const char *ip_str, U32 port, BOOL zero_code)
-//{
-//	return sendMessage(LLHost(ip_str, port), zero_code);
-//}
-
-inline S32 LLMessageSystem::sendMessage(const U32 circuit)//, BOOL zero_code)
+inline S32 LLMessageSystem::sendMessage(const U32 circuit)
 {
-	return sendMessage(findHost(circuit));//, zero_code);
+	return sendMessage(findHost(circuit));
 }
 
 #endif
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 1196db18fac6ea22fa57810c2461f7f0cac09179..a36dfd2269578050e4b1a560daacaae429bbcf0a 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -157,7 +157,7 @@ void LLImageGL::destroyGL(BOOL save_state)
 			if (save_state)
 			{
 				glimage->mSaveData = new LLImageRaw;
-				glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData);
+				glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false);
 			}
 			glimage->destroyGLTexture();
 			stop_glerror();
@@ -920,7 +920,7 @@ BOOL LLImageGL::setDiscardLevel(S32 discard_level)
 		LLPointer<LLImageRaw> imageraw = new LLImageRaw;
 		while(discard_level > mCurrentDiscardLevel)
 		{
-			if (readBackRaw(discard_level, imageraw))
+			if (readBackRaw(discard_level, imageraw, false))
 			{
 				break;
 			}
@@ -942,7 +942,7 @@ BOOL LLImageGL::setDiscardLevel(S32 discard_level)
 	}
 }
 
-BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw)
+BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok)
 {
 	if (discard_level < 0)
 	{
@@ -980,7 +980,10 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw)
 	}
 	
 	LLGLint is_compressed = 0;
-	glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
+	if (compressed_ok)
+	{
+		glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
+	}
 	if (is_compressed)
 	{
 		LLGLint glbytes;
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 1586a837b414db65665c12c41d47024cd992fa80..d66c286184df81cf6df5d2a710bf7008f12cc98a 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -72,7 +72,8 @@ class LLImageGL : public LLRefCount
 	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height);
 	BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
 	BOOL setDiscardLevel(S32 discard_level);
-	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw); // Read back a raw image for this discard level, if it exists
+	// Read back a raw image for this discard level, if it exists
+	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok); 
 	void destroyGLTexture();
 	
 	void setClamp(BOOL clamps, BOOL clampt);
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 8e81fec33bdc652bfcc5ecea5bd447d7f7b8a666..9f66daf8907b09a69ea4320b25b35b10ee7c57ed 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -933,6 +933,19 @@ LLXMLNodePtr LLButton::getXML(bool save_children) const
 	return node;
 }
 
+void clicked_help(void* data)
+{
+	LLButton* self = (LLButton*)data;
+	if (!self) return;
+	
+	if (!LLUI::sHtmlHelp)
+	{
+		return;
+	}
+	
+	LLUI::sHtmlHelp->show(self->getHelpURL());
+}
+
 // static
 LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
 {
@@ -1009,9 +1022,21 @@ LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *fa
 	{
 		button->setLabelSelected(node->getTextContents());
 	}
+		
+	if (node->hasAttribute("help_url")) 
+	{
+		LLString	help_url;
+		node->getAttributeString("help_url",help_url);
+		button->setHelpURLCallback(help_url);
+	}
 
 	button->initFromXML(node, parent);
 	
 	return button;
 }
 
+void LLButton::setHelpURLCallback(std::string help_url)
+{
+	mHelpURL = help_url;
+	setClickedCallback(clicked_help,this);
+}
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index 3dea4434a9e9b40aec605cecf9859305342d5ce2..9048358bd8cd584c183b0a044da117d6c557a481 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -163,6 +163,8 @@ class LLButton
 	void			setCommitOnReturn(BOOL commit) { mCommitOnReturn = commit; }
 	BOOL			getCommitOnReturn() { return mCommitOnReturn; }
 
+	void			setHelpURLCallback(std::string help_url);
+	LLString		getHelpURL() { return mHelpURL; }
 protected:
 	virtual void	drawBorder(const LLColor4& color, S32 size);
 
@@ -243,6 +245,8 @@ class LLButton
 	BOOL			mNeedsHighlight;
 	BOOL			mCommitOnReturn;
 
+	LLString		mHelpURL;
+
 	LLPointer<LLImageGL> mImagep;
 
 	static LLFrameTimer	sFlashingTimer;
diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp
index c412d779224a5c62e40ce0a1ab5ca96578f8004b..a3353d2028e5c6184a8dcbbd5892d2dedf490e0c 100644
--- a/indra/llui/lltabcontainer.cpp
+++ b/indra/llui/lltabcontainer.cpp
@@ -457,6 +457,24 @@ void LLTabContainerCommon::onPrevBtn( void* userdata )
 	self->mScrolled = FALSE;
 }
 
+
+void LLTabContainerCommon::onJumpFirstBtn( void* userdata )
+{
+	LLTabContainer* self = (LLTabContainer*) userdata;
+	
+	self->mScrollPos = 0;
+
+}
+
+
+void LLTabContainerCommon::onJumpLastBtn( void* userdata )
+{
+	LLTabContainer* self = (LLTabContainer*) userdata;
+
+	self->mScrollPos = self->mMaxScrollPos;
+}
+
+
 // static 
 void LLTabContainerCommon::onPrevBtnHeld( void* userdata )
 {
@@ -673,6 +691,8 @@ LLTabContainer::LLTabContainer(
 	LLTabContainerCommon(name, rect, pos, close_callback, callback_userdata, bordered),
 	mLeftArrowBtn(NULL),
 	mRightArrowBtn(NULL),
+	mJumpLeftArrowBtn(NULL),
+	mJumpRightArrowBtn(NULL),
 	mRightTabBtnOffset(0),
 	mMinTabWidth(TABCNTR_TAB_MIN_WIDTH),
 	mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH),
@@ -689,6 +709,8 @@ LLTabContainer::LLTabContainer(
 	LLTabContainerCommon(name, rect_control, pos, close_callback, callback_userdata, bordered),
 	mLeftArrowBtn(NULL),
 	mRightArrowBtn(NULL),
+	mJumpLeftArrowBtn(NULL),
+	mJumpRightArrowBtn(NULL),
 	mRightTabBtnOffset(0),
 	mMinTabWidth(TABCNTR_TAB_MIN_WIDTH),
 	mMaxTabWidth(TABCNTR_TAB_MAX_WIDTH),
@@ -720,14 +742,35 @@ void LLTabContainer::initButtons()
 	S32 btn_top = (mTabPosition == TOP ) ? mRect.getHeight() - mTopBorderHeight : TABCNTR_ARROW_BTN_SIZE + 1;
 
 	LLRect left_arrow_btn_rect;
-	left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
+	left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1+TABCNTR_ARROW_BTN_SIZE, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
+
+	LLRect jump_left_arrow_btn_rect;
+	jump_left_arrow_btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH+1, btn_top + arrow_fudge, TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
 
 	S32 right_pad = TABCNTR_ARROW_BTN_SIZE + LLPANEL_BORDER_WIDTH + 1;
+
 	LLRect right_arrow_btn_rect;
-	right_arrow_btn_rect.setLeftTopAndSize( mRect.getWidth() - mRightTabBtnOffset - right_pad,
+	right_arrow_btn_rect.setLeftTopAndSize( mRect.getWidth() - mRightTabBtnOffset - right_pad - TABCNTR_ARROW_BTN_SIZE,
 											btn_top + arrow_fudge,
 											TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
 
+
+	LLRect jump_right_arrow_btn_rect;
+	jump_right_arrow_btn_rect.setLeftTopAndSize( mRect.getWidth() - mRightTabBtnOffset - right_pad,
+											btn_top + arrow_fudge,
+											TABCNTR_ARROW_BTN_SIZE, TABCNTR_ARROW_BTN_SIZE );
+
+	out_id = "UIImgBtnJumpLeftOutUUID";
+	in_id = "UIImgBtnJumpLeftInUUID";
+	mJumpLeftArrowBtn = new LLButton(
+		"Jump Left Arrow", jump_left_arrow_btn_rect,
+		out_id, in_id, "",
+		&LLTabContainer::onJumpFirstBtn, this, LLFontGL::sSansSerif );
+	mJumpLeftArrowBtn->setFollowsLeft();
+	mJumpLeftArrowBtn->setSaveToXML(false);
+	mJumpLeftArrowBtn->setTabStop(FALSE);
+	addChild(mJumpLeftArrowBtn);
+
 	out_id = "UIImgBtnScrollLeftOutUUID";
 	in_id = "UIImgBtnScrollLeftInUUID";
 	mLeftArrowBtn = new LLButton(
@@ -739,6 +782,18 @@ void LLTabContainer::initButtons()
 	mLeftArrowBtn->setSaveToXML(false);
 	mLeftArrowBtn->setTabStop(FALSE);
 	addChild(mLeftArrowBtn);
+	
+	out_id = "UIImgBtnJumpRightOutUUID";
+	in_id = "UIImgBtnJumpRightInUUID";
+	mJumpRightArrowBtn = new LLButton(
+		"Jump Right Arrow", jump_right_arrow_btn_rect,
+		out_id, in_id, "",
+		&LLTabContainer::onJumpLastBtn, this,
+		LLFontGL::sSansSerif);
+	mJumpRightArrowBtn->setFollowsRight();
+	mJumpRightArrowBtn->setSaveToXML(false);
+	mJumpRightArrowBtn->setTabStop(FALSE);
+	addChild(mJumpRightArrowBtn);
 
 	out_id = "UIImgBtnScrollRightOutUUID";
 	in_id = "UIImgBtnScrollRightInUUID";
@@ -753,15 +808,20 @@ void LLTabContainer::initButtons()
 	mRightArrowBtn->setTabStop(FALSE);
 	addChild(mRightArrowBtn);
 
+
 	if( mTabPosition == TOP )
 	{
 		mRightArrowBtn->setFollowsTop();
 		mLeftArrowBtn->setFollowsTop();
+		mJumpLeftArrowBtn->setFollowsTop();
+		mJumpRightArrowBtn->setFollowsTop();
 	}
 	else
 	{
 		mRightArrowBtn->setFollowsBottom();
 		mLeftArrowBtn->setFollowsBottom();
+		mJumpLeftArrowBtn->setFollowsBottom();
+		mJumpRightArrowBtn->setFollowsBottom();
 	}
 
 	// set default tab group to be panel contents
@@ -952,7 +1012,7 @@ void LLTabContainer::updateMaxScrollPos()
 
 	if( tab_space > available_space )
 	{
-		S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + 1);
+		S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
 		// subtract off reserved portion on left
 		available_width_with_arrows -= TABCNTR_TAB_PARTIAL_WIDTH;
 
@@ -1059,7 +1119,7 @@ BOOL LLTabContainer::selectTab(S32 which)
 				}
 				else
 				{
-					S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + 1);
+					S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
 					S32 running_tab_width = tuple->mButton->getRect().getWidth();
 					S32 j = i - 1;
 					S32 min_scroll_pos = i;
@@ -1101,7 +1161,7 @@ void LLTabContainer::draw()
 	S32 cur_scroll_pos = mScrollPos;
 	if (cur_scroll_pos > 0)
 	{
-		S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE + 1);
+		S32 available_width_with_arrows = mRect.getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + TABCNTR_ARROW_BTN_SIZE  + TABCNTR_ARROW_BTN_SIZE + 1);
 		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter)
 		{
 			if (cur_scroll_pos == 0)
@@ -1122,11 +1182,13 @@ void LLTabContainer::draw()
 	if( getVisible() )
 	{
 		BOOL has_scroll_arrows = (mMaxScrollPos > 0) || (mScrollPosPixels > 0);
+		mJumpLeftArrowBtn->setVisible( has_scroll_arrows );
+		mJumpRightArrowBtn->setVisible( has_scroll_arrows );
 		mLeftArrowBtn->setVisible( has_scroll_arrows );
 		mRightArrowBtn->setVisible( has_scroll_arrows );
 
 		// Set the leftmost position of the tab buttons.
-		S32 left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? TABCNTR_ARROW_BTN_SIZE : TABCNTR_TAB_H_PAD);
+		S32 left = LLPANEL_BORDER_WIDTH + (has_scroll_arrows ? (TABCNTR_ARROW_BTN_SIZE * 2) : TABCNTR_TAB_H_PAD);
 		left -= mScrollPosPixels;
 
 		// Hide all the buttons
@@ -1215,7 +1277,19 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
 	BOOL has_scroll_arrows = (mMaxScrollPos > 0);
 
 	if (has_scroll_arrows)
-	{
+	{		
+		if (mJumpLeftArrowBtn->getRect().pointInRect(x, y))
+		{
+			S32 local_x = x - mJumpLeftArrowBtn->getRect().mLeft;
+			S32 local_y = y - mJumpLeftArrowBtn->getRect().mBottom;
+			handled = mJumpLeftArrowBtn->handleMouseDown(local_x, local_y, mask);
+		}
+		if (mJumpRightArrowBtn->getRect().pointInRect(x, y))
+		{
+			S32 local_x = x - mJumpRightArrowBtn->getRect().mLeft;
+			S32 local_y = y - mJumpRightArrowBtn->getRect().mBottom;
+			handled = mJumpRightArrowBtn->handleMouseDown(local_x, local_y, mask);
+		}
 		if (mLeftArrowBtn->getRect().pointInRect(x, y))
 		{
 			S32 local_x = x - mLeftArrowBtn->getRect().mLeft;
@@ -1237,9 +1311,9 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask )
 	if (mTabList.size() > 0)
 	{
 		LLTabTuple* firsttuple = mTabList[0];
-		LLRect tab_rect(has_scroll_arrows ? mLeftArrowBtn->getRect().mRight : mLeftArrowBtn->getRect().mLeft,
+		LLRect tab_rect(has_scroll_arrows ? mLeftArrowBtn->getRect().mRight : mJumpLeftArrowBtn->getRect().mLeft,
 						firsttuple->mButton->getRect().mTop,
-						has_scroll_arrows ? mRightArrowBtn->getRect().mLeft : mRightArrowBtn->getRect().mRight,
+						has_scroll_arrows ? mRightArrowBtn->getRect().mLeft : mJumpRightArrowBtn->getRect().mRight,
 						firsttuple->mButton->getRect().mBottom );
 		if( tab_rect.pointInRect( x, y ) )
 		{
@@ -1257,7 +1331,19 @@ BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask )
 	BOOL has_scroll_arrows = (mMaxScrollPos > 0);
 
 	if (has_scroll_arrows)
-	{
+	{		
+		if (mJumpLeftArrowBtn->getRect().pointInRect(x, y))
+		{
+			S32 local_x = x - mJumpLeftArrowBtn->getRect().mLeft;
+			S32 local_y = y - mJumpLeftArrowBtn->getRect().mBottom;
+			handled = mJumpLeftArrowBtn->handleHover(local_x, local_y, mask);
+		}
+		if (mJumpRightArrowBtn->getRect().pointInRect(x, y))
+		{
+			S32 local_x = x - mJumpRightArrowBtn->getRect().mLeft;
+			S32 local_y = y - mJumpRightArrowBtn->getRect().mBottom;
+			handled = mJumpRightArrowBtn->handleHover(local_x, local_y, mask);
+		}
 		if (mLeftArrowBtn->getRect().pointInRect(x, y))
 		{
 			S32 local_x = x - mLeftArrowBtn->getRect().mLeft;
@@ -1287,6 +1373,18 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask )
 
 	if (has_scroll_arrows)
 	{
+		if (mJumpLeftArrowBtn->getRect().pointInRect(x, y))
+		{
+			S32 local_x = x - mJumpLeftArrowBtn->getRect().mLeft;
+			S32 local_y = y - mJumpLeftArrowBtn->getRect().mBottom;
+			handled = mJumpLeftArrowBtn->handleMouseUp(local_x, local_y, mask);
+		}		
+		if (mJumpRightArrowBtn->getRect().pointInRect(x,	y))
+		{
+			S32	local_x	= x	- mJumpRightArrowBtn->getRect().mLeft;
+			S32	local_y	= y	- mJumpRightArrowBtn->getRect().mBottom;
+			handled = mJumpRightArrowBtn->handleMouseUp(local_x,	local_y, mask);
+		}
 		if (mLeftArrowBtn->getRect().pointInRect(x, y))
 		{
 			S32 local_x = x - mLeftArrowBtn->getRect().mLeft;
@@ -1332,7 +1430,7 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_
 
 		BOOL has_scroll_arrows = (mMaxScrollPos > 0);
 		LLRect clip(
-			has_scroll_arrows ? mLeftArrowBtn->getRect().mRight : mLeftArrowBtn->getRect().mLeft,
+			has_scroll_arrows ? mJumpLeftArrowBtn->getRect().mRight : mJumpLeftArrowBtn->getRect().mLeft,
 			firsttuple->mButton->getRect().mTop,
 			has_scroll_arrows ? mRightArrowBtn->getRect().mLeft : mRightArrowBtn->getRect().mRight,
 			0 );
@@ -1438,6 +1536,18 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask,	BOOL drop,	EDrag
 
 	if (has_scroll_arrows)
 	{
+		if (mJumpLeftArrowBtn->getRect().pointInRect(x,	y))
+		{
+			S32	local_x	= x	- mJumpLeftArrowBtn->getRect().mLeft;
+			S32	local_y	= y	- mJumpLeftArrowBtn->getRect().mBottom;
+			mJumpLeftArrowBtn->handleHover(local_x,	local_y, mask);
+		}
+		if (mJumpRightArrowBtn->getRect().pointInRect(x,	y))
+		{
+			S32	local_x	= x	- mJumpRightArrowBtn->getRect().mLeft;
+			S32	local_y	= y	- mJumpRightArrowBtn->getRect().mBottom;
+			mJumpRightArrowBtn->handleHover(local_x,	local_y, mask);
+		}
 		if (mLeftArrowBtn->getRect().pointInRect(x,	y))
 		{
 			S32	local_x	= x	- mLeftArrowBtn->getRect().mLeft;
diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h
index 41e602eaea4032cfcd435e53309bc1fab4993a5c..aa4c1c608a3312f30b98fd9252aa0326fe0a73b0 100644
--- a/indra/llui/lltabcontainer.h
+++ b/indra/llui/lltabcontainer.h
@@ -109,6 +109,8 @@ class LLTabContainerCommon : public LLPanel
 	static void	onNextBtnHeld(void* userdata);
 	static void	onPrevBtn(void* userdata);
 	static void	onPrevBtnHeld(void* userdata);
+	static void onJumpFirstBtn( void* userdata );
+	static void onJumpLastBtn( void* userdata );
 
 	virtual void		setRightTabBtnOffset( S32 offset ) { }
 	virtual void		setPanelTitle(S32 index, const LLString& title) { }
@@ -223,7 +225,9 @@ class LLTabContainer : public LLTabContainerCommon
 protected:
 
 	LLButton*						mLeftArrowBtn;
+	LLButton*						mJumpLeftArrowBtn;
 	LLButton*						mRightArrowBtn;
+	LLButton*						mJumpRightArrowBtn;
 
 	S32								mRightTabBtnOffset; // Extra room to the right of the tab buttons.
 
diff --git a/indra/llui/lltextbox.cpp b/indra/llui/lltextbox.cpp
index f6f706754033f2289ec3884bd430c5abdfe6c6e5..2afa32eccd8e8266acbab43be123cd9ceaf0eb5f 100644
--- a/indra/llui/lltextbox.cpp
+++ b/indra/llui/lltextbox.cpp
@@ -328,7 +328,7 @@ void LLTextBox::draw()
 void LLTextBox::reshape(S32 width, S32 height, BOOL called_from_parent)
 {
 	// reparse line lengths
-	setText(mText);
+	setLineLengths();
 	LLView::reshape(width, height, called_from_parent);
 }
 
diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp
index f32266faa864266b68291a19591a1bfff09094ec..c9a506756a08bd9f11a220e6a7d0cc42b809623c 100644
--- a/indra/llui/llui.cpp
+++ b/indra/llui/llui.cpp
@@ -55,6 +55,7 @@ LLImageProviderInterface* LLUI::sImageProvider = NULL;
 LLUIAudioCallback LLUI::sAudioCallback = NULL;
 LLVector2		LLUI::sGLScaleFactor(1.f, 1.f);
 LLWindow*		LLUI::sWindow = NULL;
+LLHtmlHelp*		LLUI::sHtmlHelp = NULL;
 BOOL            LLUI::sShowXUINames = FALSE;
 //
 // Functions
@@ -387,7 +388,7 @@ void gl_corners_2d(S32 left, S32 top, S32 right, S32 bottom, S32 length, F32 max
 
 void gl_draw_image( S32 x, S32 y, LLImageGL* image, const LLColor4& color )
 {
-	gl_draw_scaled_rotated_image( x, y, image->getWidth(), image->getHeight(), 0.f, image, color );
+	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), 0.f, image, color );
 }
 
 void gl_draw_scaled_image(S32 x, S32 y, S32 width, S32 height, LLImageGL* image, const LLColor4& color)
@@ -439,8 +440,8 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
 
 		glColor4fv(color.mV);
 		
-		F32 border_width_fraction = (F32)border_width / (F32)image->getWidth();
-		F32 border_height_fraction = (F32)border_height / (F32)image->getHeight();
+		F32 border_width_fraction = (F32)border_width / (F32)image->getWidth(0);
+		F32 border_height_fraction = (F32)border_height / (F32)image->getHeight(0);
 
 		glBegin(GL_QUADS);
 		{
@@ -573,7 +574,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 border_width, S32 border
 
 void gl_draw_rotated_image(S32 x, S32 y, F32 degrees, LLImageGL* image, const LLColor4& color)
 {
-	gl_draw_scaled_rotated_image( x, y, image->getWidth(), image->getHeight(), degrees, image, color );
+	gl_draw_scaled_rotated_image( x, y, image->getWidth(0), image->getHeight(0), degrees, image, color );
 }
 
 void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degrees, LLImageGL* image, const LLColor4& color)
@@ -1766,3 +1767,9 @@ LLUUID			LLUI::findAssetUUIDByName(const LLString	&asset_name)
 	}
 	return LLUUID( foundValue );
 }
+
+// static 
+void LLUI::setHtmlHelp(LLHtmlHelp* html_help)
+{
+	LLUI::sHtmlHelp = html_help;
+}
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 282e41a113bafb7f7a82176998f5bb1f8f151c8a..c8c244072ef0b7e15d2f51b4aff07d007c81af31 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -15,6 +15,7 @@
 #include "llcontrol.h"
 #include "llrect.h"
 #include "llcoord.h"
+#include "llhtmlhelp.h"
 
 class LLColor4;
 class LLVector3;
@@ -151,6 +152,7 @@ class LLUI
 	static void setLineWidth(F32 width);
 	static LLUUID findAssetUUIDByName(const LLString&	name);
 	static LLVector2 getWindowSize();
+	static void setHtmlHelp(LLHtmlHelp* html_help);
 public:
 	static LLControlGroup* sConfigGroup;
 	static LLControlGroup* sColorsGroup;
@@ -160,6 +162,7 @@ class LLUI
 	static LLVector2		sGLScaleFactor;
 	static LLWindow*		sWindow;
 	static BOOL             sShowXUINames;
+	static LLHtmlHelp*		sHtmlHelp;
 };
 
 // UI widgets
diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp
index 8b6ec2ad0cc0396888194b7a0ab5a6e3ca7551ac..ae2a0c8afe82968bb99aa68481ccceae99671554 100644
--- a/indra/lscript/lscript_compile/lscript_tree.cpp
+++ b/indra/lscript/lscript_compile/lscript_tree.cpp
@@ -251,7 +251,6 @@ void LLScriptConstantString::recurse(FILE *fp, S32 tabs, S32 tabsize, LSCRIPTCom
 		break;
 	case LSCP_EMIT_ASSEMBLY:
 		fprintf(fp, "PUSHARGS \"%s\"\n", mValue);
-		fprintf(fp, "STACKTOS %lu\n", strlen(mValue) + 1);	/*Flawfinder: ignore*/
 		break;
 	case LSCP_TYPE:
 		type = mType;
diff --git a/indra/lscript/lscript_execute/lscript_execute.cpp b/indra/lscript/lscript_execute/lscript_execute.cpp
index 4521c7b43c3877cd9960745a033104d79e0a2bc3..9f123025ff861541722d834e20e1bb836b300a27 100644
--- a/indra/lscript/lscript_execute/lscript_execute.cpp
+++ b/indra/lscript/lscript_execute/lscript_execute.cpp
@@ -3337,6 +3337,7 @@ BOOL run_cast(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
 
 BOOL run_stacktos(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
 {
+	offset++;
 	S32 length = lscript_pop_int(buffer);
 	S32 i;
 	char *arg = new char[length];
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 17e24277f0394c5c57f93d9d9b804cdcb1426228..28b1ddc131ec7eab9b0b469fd127e2f74948181f 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -153,21 +153,8 @@ RenderLighting		1	0
 RenderParticleCount	1	2048
 RenderTerrainDetail	1	0
 
-list GeForce3
-
-list ATI
-
-list Radeon8500
-RenderLighting		1	0
-RenderParticleCount	1	4096
-
-// Hacked to be paranoid "safe"
-list Radeon9700
-RenderParticleCount	1	4096
-
-// Hacked to be paranoid "safe"
-list MobilityRadeon9000
-RenderLighting		1	0
-RenderParticleCount	1	4096
+list ATI_Mobility_Radeon_X3xx
+VertexShaderEnable	1	0
 
-list GeForceFX
+list ATI_Mobility_Radeon_X6xx
+VertexShaderEnable	1	0
diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt
index 92f9b446f87936084d4912b9e94fd8823814064c..49b199c0a489e40c9ad451028f7b17da92f091e8 100644
--- a/indra/newview/gpu_table.txt
+++ b/indra/newview/gpu_table.txt
@@ -22,6 +22,8 @@ ATI All-in-Wonder X1800			.*ATI.*All-in-Wonder X18.*				3
 ATI All-in-Wonder X1900			.*ATI.*All-in-Wonder X19.*				3
 ATI ASUS X1xxx					.*ASUS X1.*			 					3
 ATI Mobility Radeon X1xxx		.*ATI.*Mobility.*X1.*					2
+ATI Mobility Radeon X3xx		.*ATI.*Mobility.*X3.*					1
+ATI Mobility Radeon X6xx		.*ATI.*Mobility.*X6.*					1
 ATI Radeon OpenGL				.*ATI.*Radeon OpenGL.* 					3
 ATI Diamond X1xxx				.*ATI.*Diamond.*X1.*					3
 ATI FireGL 5xxx					.*ATI.*FireGL V5.*						3
diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt
index 7c972bb8d11fd698c63018a9b1a90260d3309b32..cabb0345db450d9ec486481e552ad24bf985c93f 100644
--- a/indra/newview/linux_tools/client-readme.txt
+++ b/indra/newview/linux_tools/client-readme.txt
@@ -10,8 +10,16 @@ Life itself - please see <http://www.secondlife.com/whatis/>.
 3. Installing & Running
 4. Known Issues
 5. Troubleshooting
+   5.1. 'Error creating window.'
+   5.2. System hangs
+   5.3. 'Shiny' and client performance
+   5.4. Audio
+   5.5. 'Alt' key for camera controls doesn't work
 6. Advanced Troubleshooting
-7. Getting more help, and reporting problems
+   6.1. Audio
+   6.2. OpenGL
+7. Obtaining and working with the client source code
+8. Getting more help, and reporting problems
 
 
 1. INTRODUCTION
@@ -28,6 +36,11 @@ with your system.  Be aware that although the client itself is provided
 for testing purposes, any changes you make within the Second Life world
 are permanent.
 
+You will have either obtained this client from secondlife.com (the official
+site) or from a third-party packager; if you encounter any problems then
+we recommend trying the latest official builds from secondlife.com which are
+updated often.
+
 Please enjoy!
 
 
@@ -37,10 +50,10 @@ Please enjoy!
 Minimum requirements:
     * Internet Connection: Cable or DSL
     * Computer Processor: 800MHz Pentium III or Athlon, or better
-    * Computer Memory: 256MB or better
+    * Computer Memory: 256MB or better (strongly recommend more!)
     * Linux Operating System: A reasonably modern 32-bit Linux environment
-          is required.  If you are running a 64-bit Linux distribution, you
-          may need a set of 32-bit compatibility libraries.
+          is required.  If you are running a 64-bit Linux distribution then
+          you will need its 32-bit compatibility environment installed.
     * Video/Graphics Card:
           o nVidia GeForce 2, GeForce 4mx, or better
           o OR ATI Radeon 8500, 9250, or better
@@ -125,7 +138,7 @@ SOLUTION:- Usually this indicates that your graphics card does not meet
 PROBLEM 2:- My whole system seems to hang when running Second Life.
 SOLUTION:- This is typically a hardware/driver issue.  The first thing to
    do is to check that you have the most recent official drivers for your
-   graphics card.
+   graphics card (see PROBLEM 1).
 SOLUTION:- Some residents with ATI cards have reported that running
    'sudo aticonfig --locked-userpages=off' before running Second Life solves
    their stability issues.
@@ -147,6 +160,9 @@ SOLUTION:- Some graphics performance features in Second Life are disabled
      automatically used, and some new options in Preferences will now be
      available to you; there is no guarantee, however, that they will
      positively affect performance!
+SOLUTION:- If you are not running an official Second Life client obtained from
+     secondlife.com, you should consider doing so as you may find its
+     performance to be superior to third-party versions.
 
 PROBLEM 4:- Sound effects seem to 'lag' a fraction of a second behind
    actions.
@@ -154,6 +170,13 @@ SOLUTION:- You may uncomment the 'LL_BAD_ESD' line in the 'secondlife' script
    to get more responsive audio.  However, if you do this then you may
    encounter audio issues or a hang during login, so beware.
 
+PROBLEM 5:- Using the 'Alt' key to control the camera doesn't work or just
+   moves the Second Life window.
+SOLUTION:- Some window managers eat the Alt key for their own purposes; you
+   can configure your window manager to use a different key instead (for
+   example, the 'Windows' key!) which will allow the Alt key to function
+   properly with mouse actions in Second Life and other applications.
+
 
 6. ADVANCED TROUBLESHOOTING
 -=-=-=-=-=-=-=-=-=-=-=-=-=-
@@ -178,15 +201,28 @@ configuration options for advanced troubleshooters.
   LL_GL_BASICEXT and LL_GL_NOEXT should be commented-out for this to be useful.
 
 
-7. GETTING MORE HELP AND REPORTING PROBLEMS
+7. OBTAINING AND WORKING WITH THE CLIENT SOURCE CODE
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+We're pleased to have released the Second Life client's source code under
+an Open Source license compatible with the 'GPL'.  To get involved with client
+development, please see:
+<http://wiki.secondlife.com/wiki/Open_Source_Portal>
+
+
+8. GETTING MORE HELP AND REPORTING PROBLEMS
 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
 For general help and support with Second Life:
 <http://secondlife.com/community/support.php>
 
+For problems and discussion concerning unofficial (not secondlife.com)
+releases, please contact your packager or the SLDev mailing list:
+<https://lists.secondlife.com/cgi-bin/mailman/listinfo/sldev>
+
 In-world help: Please use the 'Help' menu in the client for general
 non-Linux-specific Second Life help including live support from the fabulous
-Live Help team.
+'Help Request' team.
 
 In-world discussion: There is a 'Linux Client Users' group
 inside Second Life which is free to join.  You can find it by pressing
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 77bbc1ca81c2890ba700f81bbc687feb083280a9..5af5353c1b161923328012e684f23e769ca2295a 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -82,7 +82,6 @@ void LLDrawable::init()
 	mVObjp   = NULL;
 	// mFaces
 	mSpatialGroupp = NULL;
-	mSpatialGroupOffset = -1;
 	mVisible = 0;
 	mRadius = 0.f;
 	mSunShadowFactor = 1.f;
@@ -1026,18 +1025,13 @@ void LLDrawable::updateUVMinMax()
 {
 }
 
-void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp, const S32 offset)
+void LLDrawable::setSpatialGroup(LLSpatialGroup *groupp)
 {
-	mSpatialGroupp = groupp;
-	
-	if (mSpatialGroupp)
+	if (mSpatialGroupp && (groupp != mSpatialGroupp))
 	{
-		mSpatialGroupOffset = offset;
+		mSpatialGroupp->setState(LLSpatialGroup::GEOM_DIRTY);
 	}
-	else
-	{
-		mSpatialGroupOffset = -1;
-	}	
+	mSpatialGroupp = groupp;
 }
 
 LLSpatialPartition* LLDrawable::getSpatialPartition()
@@ -1411,13 +1405,13 @@ void LLSpatialBridge::cleanupReferences()
 	LLDrawable::cleanupReferences();
 	if (mDrawable)
 	{
-		mDrawable->setSpatialGroup(NULL, -1);
+		mDrawable->setSpatialGroup(NULL);
 		for (U32 i = 0; i < mDrawable->getChildCount(); i++)
 		{
 			LLDrawable* drawable = mDrawable->getChild(i);
-			if (drawable && drawable->getVOVolume())
+			if (drawable)
 			{
-				drawable->setSpatialGroup(NULL, -1);
+				drawable->setSpatialGroup(NULL);
 			}
 		}
 
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index fef8b02ad5e7ad7a88a141ee7b57395deeb0ac61..e95437f4ec3036e5158ecb0fd11fa12a8d715f78 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -170,7 +170,7 @@ class LLDrawable : public LLRefCount
 	// Debugging methods
 	S32 findReferences(LLDrawable *drawablep); // Not const because of @#$! iterators...
 
-	void setSpatialGroup(LLSpatialGroup *groupp, const S32 offset);
+	void setSpatialGroup(LLSpatialGroup *groupp);
 	LLSpatialGroup *getSpatialGroup() const			{ return mSpatialGroupp; }
 	LLSpatialPartition* getSpatialPartition();
 	
@@ -287,7 +287,6 @@ class LLDrawable : public LLRefCount
 	face_list_t     mFaces;
 	LLSpatialGroup* mSpatialGroupp;
 	LLPointer<LLDrawable> mSpatialBridge;
-	S32				mSpatialGroupOffset;
 	
 	mutable U32		mVisible;
 	F32				mRadius;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index a0cc189c4658a893e1f50c762ba95e65d84cde72..d8b923c2711febbce414c00ba8d8251a5501ba11 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -79,7 +79,6 @@ LLDrawPool *LLDrawPoolAvatar::instancePool()
 }
 
 BOOL gRenderAvatar = TRUE;
-static LLMatrix4 sModelViewMatrix = LLMatrix4();
 
 S32 LLDrawPoolAvatar::getVertexShaderLevel() const
 {
@@ -103,7 +102,14 @@ void LLDrawPoolAvatar::prerender()
 
 LLMatrix4& LLDrawPoolAvatar::getModelView()
 {
-	return sModelViewMatrix;
+	static LLMatrix4 ret;
+
+	ret.initRows(LLVector4(gGLModelView+0),
+				 LLVector4(gGLModelView+4),
+				 LLVector4(gGLModelView+8),
+				 LLVector4(gGLModelView+12));
+
+	return ret;
 }
 
 //-----------------------------------------------------------------------------
@@ -132,7 +138,6 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 		beginFootShadow();
 		break;
 	case 1:
-		glGetFloatv(GL_MODELVIEW_MATRIX, (F32*) sModelViewMatrix.mMatrix);
 		beginRigid();
 		break;
 	case 2:
@@ -507,7 +512,6 @@ void LLDrawPoolAvatar::renderForSelect()
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_NORMAL_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-	glGetFloatv(GL_MODELVIEW_MATRIX, (F32*) sModelViewMatrix.mMatrix);
 	sVertexProgram = &gAvatarPickProgram;
 	if (sShaderLevel > 0)
 	{
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index f0f7130e0b387f19d91e392cad93c350f3287f9c..67f60ffdfa2a0069dd821b68f38452a20258b017 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -16,6 +16,7 @@
 #include "llimagegl.h"
 #include "m3math.h"
 #include "m4math.h"
+#include "v4math.h"
 
 #include "llagent.h"
 #include "llcubemap.h"
@@ -182,6 +183,11 @@ void LLDrawPoolBump::render(S32 pass)
 {
 	LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP);
 	
+	if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE))
+	{
+		return;
+	}
+	
 	switch( pass )
 	{
 	  case 0:
@@ -237,7 +243,10 @@ void LLDrawPoolBump::beginShiny()
 		if (LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_OBJECT) > 0)
 		{
 			LLMatrix4 mat;
-			glGetFloatv(GL_MODELVIEW_MATRIX, (F32*) mat.mMatrix);
+			mat.initRows(LLVector4(gGLModelView+0),
+						 LLVector4(gGLModelView+4),
+						 LLVector4(gGLModelView+8),
+						 LLVector4(gGLModelView+12));
 			gObjectShinyProgram.bind();
 			LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 			LLVector4 vec4(vec, gShinyOrigin.mV[3]);
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index e3b5a2bb685cb4b2879fc3254374ea91eeb4621d..7d7c2017aa62d070f3bce4c5fdc202f3070ac0e7 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -173,7 +173,7 @@ BOOL LLFeatureManager::maskFeatures(const char *name)
 	LLFeatureList *maskp = findMask(name);
 	if (!maskp)
 	{
-		llwarns << "Unknown feature mask " << name << llendl;
+// 		llwarns << "Unknown feature mask " << name << llendl;
 		return FALSE;
 	}
 	llinfos << "Applying Feature Mask: " << name << llendl;
@@ -431,14 +431,6 @@ void LLFeatureManager::initGraphicsFeatureMasks()
 	{
 		maskFeatures("ATI");
 	}
-	if (gGLManager.mIsRadeon8500)
-	{
-		maskFeatures("Radeon8500");
-	}
-	if (gGLManager.mIsRadeon9700)
-	{
-		maskFeatures("Radeon9700");
-	}
 	if (gGLManager.mIsGFFX)
 	{
 		maskFeatures("GeForceFX");
@@ -451,11 +443,18 @@ void LLFeatureManager::initGraphicsFeatureMasks()
 	{
 		maskFeatures("OpenGLPre15");
 	}
-
-	if (gGLManager.mIsMobilityRadeon9000)
+	// Replaces ' ' with '_' in mGPUString to deal with inability for parser to handle spaces
+	std::string gpustr = mGPUString;
+	for (std::string::iterator iter = gpustr.begin(); iter != gpustr.end(); ++iter)
 	{
-		maskFeatures("MobilityRadeon9000");
+		if (*iter == ' ')
+		{
+			*iter = '_';
+		}
 	}
+// 	llinfos << "Masking features from gpu table match: " << gpustr << llendl;
+	maskFeatures(gpustr.c_str());
+
 	if (isSafe())
 	{
 		maskFeatures("safe");
diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp
index 5ced5eafb7f0fc2bd88f4877374e11e0021bfb1f..63b5262ced02503bda89ef218afce1ae3e6ac02e 100644
--- a/indra/newview/llfloaterabout.cpp
+++ b/indra/newview/llfloaterabout.cpp
@@ -93,7 +93,7 @@ LLFloaterAbout::LLFloaterAbout()
 
 	// CPU
 	support.append("CPU: ");
-	support.append( gSysCPU.getCPUStringTerse() );
+	support.append( gSysCPU.getCPUString() );
 	support.append("\n");
 
 	U32 memory = gSysMemory.getPhysicalMemory() / 1024 / 1024;
diff --git a/indra/newview/llfloateravatartextures.cpp b/indra/newview/llfloateravatartextures.cpp
index 293bf61a0d7c3d39c8349f263ad8bcbb9fa444b8..59df3bc2e2d7fe999ba484f4c599d91374b1be2e 100644
--- a/indra/newview/llfloateravatartextures.cpp
+++ b/indra/newview/llfloateravatartextures.cpp
@@ -78,6 +78,7 @@ void LLFloaterAvatarTextures::draw()
 	LLFloater::draw();
 }
 
+#if !LL_RELEASE_FOR_DOWNLOAD
 static void update_texture_ctrl(LLVOAvatar* avatarp,
 								 LLTextureCtrl* ctrl,
 								 LLVOAvatar::ETextureIndex te)
@@ -115,7 +116,6 @@ static LLVOAvatar* find_avatar(const LLUUID& id)
 
 void LLFloaterAvatarTextures::refresh()
 {
-#if !LL_RELEASE_FOR_DOWNLOAD
 	LLVOAvatar *avatarp = find_avatar(mID);
 	if (avatarp)
 	{
@@ -158,9 +158,16 @@ void LLFloaterAvatarTextures::refresh()
 	{
 		setTitle(mTitle + ": INVALID AVATAR (" + mID.asString() + ")");
 	}
-#endif
 }
 
+#else
+
+void LLFloaterAvatarTextures::refresh()
+{
+}
+
+#endif
+
 // static
 void LLFloaterAvatarTextures::onClickDump(void* data)
 {
diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp
index 6f31cbb3a054396459120070967a3cfc7c745c95..534aac077f62eba635627505e10500c76c829744 100644
--- a/indra/newview/llfloaterfriends.cpp
+++ b/indra/newview/llfloaterfriends.cpp
@@ -526,38 +526,51 @@ void LLFloaterFriends::requestFriendship(const LLUUID& target_id, const LLString
 					 IM_FRIENDSHIP_OFFERED);
 }
 
+struct LLAddFriendData
+{
+	LLUUID mID;
+	std::string mName;
+};
+
 // static
-void LLFloaterFriends::callbackAddFriend(S32 option, void* user_data)
+void LLFloaterFriends::callbackAddFriend(S32 option, void* data)
 {
+	LLAddFriendData* add = (LLAddFriendData*)data;
 	if (option == 0)
 	{
-		LLFloaterFriends* self = (LLFloaterFriends*)user_data;
-		requestFriendship(self->mAddFriendID, self->mAddFriendName);
+		requestFriendship(add->mID, add->mName);
 	}
+	delete add;
 }
 
 // static
 void LLFloaterFriends::onPickAvatar(const std::vector<std::string>& names,
 									const std::vector<LLUUID>& ids,
-									void* user_data)
+									void* )
 {
 	if (names.empty()) return;
 	if (ids.empty()) return;
+	requestFriendshipDialog(ids[0], names[0]);
+}
 
-	LLFloaterFriends* self = (LLFloaterFriends*)user_data;
-	self->mAddFriendID = ids[0];
-	self->mAddFriendName = names[0];
-
-	if(ids[0] == gAgentID)
+// static
+void LLFloaterFriends::requestFriendshipDialog(const LLUUID& id,
+											   const std::string& name)
+{
+	if(id == gAgentID)
 	{
 		LLNotifyBox::showXml("AddSelfFriend");
 		return;
 	}
 
+	LLAddFriendData* data = new LLAddFriendData();
+	data->mID = id;
+	data->mName = name;
+	
 	// TODO: accept a line of text with this dialog
 	LLString::format_map_t args;
-	args["[NAME]"] = names[0];
-	gViewerWindow->alertXml("AddFriend", args, callbackAddFriend, user_data);
+	args["[NAME]"] = name;
+	gViewerWindow->alertXml("AddFriend", args, callbackAddFriend, data);
 }
 
 // static
diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h
index a71b53f2067a0eae270c4d239a673f0e1a1b4ec6..c6ef365517c4ff3b15cccc759dea6c51367beddd 100644
--- a/indra/newview/llfloaterfriends.h
+++ b/indra/newview/llfloaterfriends.h
@@ -53,7 +53,14 @@ class LLFloaterFriends : public LLFloater, public LLEventTimer
 	// Toggles visibility of floater
 	static void toggle(void* unused = NULL);
 
-	static void requestFriendship(const LLUUID& target_id, const LLString& target_name);
+	// Show a dialog explaining what friendship entails, then request
+	// friendship. JC
+	static void requestFriendshipDialog(const LLUUID& target_id, 
+										const std::string& target_name);
+
+	// Just request friendship, no dialog.
+	static void requestFriendship(const LLUUID& target_id,
+								  const LLString& target_name);
 
 private:
 
diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp
index 9b74b3963bbed685c30038f935e50faf0b486649..72c114d96677daa4ce7e21b307bb01d245184b51 100644
--- a/indra/newview/llhudrender.cpp
+++ b/indra/newview/llhudrender.cpp
@@ -77,12 +77,9 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
 	LLVector3 render_pos = pos_agent + (floorf(x_offset) * right_axis) + (floorf(y_offset) * up_axis);
 
 	//get the render_pos in screen space
-	F64 modelview[16];
-	F64 projection[16];
-	GLint viewport[4];
-	glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
-	glGetDoublev(GL_PROJECTION_MATRIX, projection);
-	glGetIntegerv(GL_VIEWPORT, viewport);
+	F64* modelview = gGLModelView;
+	F64* projection = gGLProjection;
+	GLint* viewport = (GLint*) gGLViewport;
 
 	F64 winX, winY, winZ;
 	gluProject(render_pos.mV[0], render_pos.mV[1], render_pos.mV[2],
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 1050070f810dbba830a8053b71d1d886b7343510..5c32f8d90a26422f2ce432d8eae3d432f448791c 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -219,8 +219,6 @@ void LLNetMap::draw()
 	mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
 
 	// Prepare a scissor region
-	// GLint params[4];
-	// glGetIntegerv( GL_SCISSOR_BOX, params );
 	F32 rotation = 0;
 
 	{
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 05bd59593de2515276754785e0e040221529b89f..1b0c731ea9fb568ebe81de4ca66f734ed62f6bbe 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -10,6 +10,7 @@
 
 #include "llpanelavatar.h"
 
+#include "llclassifiedflags.h"
 #include "llfontgl.h"
 #include "llcachename.h"
 
@@ -24,6 +25,8 @@
 #include "llcallingcard.h"
 #include "llcheckboxctrl.h"
 #include "llfloater.h"
+
+#include "llfloaterfriends.h"
 #include "llfloatergroupinfo.h"
 #include "llfloaterworldmap.h"
 #include "llfloatermute.h"
@@ -446,7 +449,8 @@ BOOL LLPanelAvatarSecondLife::postBuild(void)
 
 	childSetAction("Show on Map", LLPanelAvatar::onClickTrack, getPanelAvatar());
 	childSetAction("Instant Message...", LLPanelAvatar::onClickIM, getPanelAvatar());
-	childSetAction("Rate...", LLPanelAvatar::onClickRate, getPanelAvatar());
+	//childSetAction("Rate...", LLPanelAvatar::onClickRate, getPanelAvatar());
+	childSetAction("Add Friend...", LLPanelAvatar::onClickAddFriend, getPanelAvatar());
 	childSetAction("Pay...", LLPanelAvatar::onClickPay, getPanelAvatar());
 	childSetAction("Mute", LLPanelAvatar::onClickMute, getPanelAvatar() );	
 
@@ -839,9 +843,9 @@ void LLPanelAvatarClassified::refresh()
 	
 	S32 tab_count = tabs ? tabs->getTabCount() : 0;
 
-	BOOL allow_new = TRUE; //tab_count < MAX_CLASSIFIEDS;
-	BOOL allow_delete = (tab_count > 0);
-	BOOL show_help = (tab_count == 0);
+	bool allow_new = tab_count < MAX_CLASSIFIEDS;
+	bool allow_delete = (tab_count > 0);
+	bool show_help = (tab_count == 0);
 
 	childSetEnabled("New...",self && allow_new);
 	childSetEnabled("Delete...",self && allow_delete);
@@ -904,9 +908,8 @@ void LLPanelAvatarClassified::processAvatarClassifiedReply(LLMessageSystem* msg,
 
 	LLTabContainerCommon* tabs = LLViewerUICtrlFactory::getTabContainerByName(this,"classified tab");
 
-	// Clear out all the old panels.
-	// We'll replace them with the correct number of new panels.
-	deleteClassifiedPanels();
+	// Don't remove old panels.  We need to be able to process multiple
+	// packets for people who have lots of classifieds. JC
 
 	block_count = msg->getNumberOfBlocksFast(_PREHASH_Data);
 	for (block = 0; block < block_count; block++)
@@ -1434,6 +1437,8 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const LLString &name,
 			childSetEnabled("Show on Map",FALSE);
 			childSetVisible("Rate...",FALSE);
 			childSetEnabled("Rate...",FALSE);
+			childSetVisible("Add Friend...",FALSE);
+			childSetEnabled("Add Friend...",FALSE);
 			childSetVisible("Pay...",FALSE);
 			childSetEnabled("Pay...",FALSE);
 		}
@@ -1472,6 +1477,8 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const LLString &name,
 			}
 			childSetVisible("Rate...",TRUE);
 			childSetEnabled("Rate...",FALSE);
+			childSetVisible("Add Friend...", true);
+			childSetEnabled("Add Friend...", true);
 			childSetVisible("Pay...",TRUE);
 			childSetEnabled("Pay...",FALSE);
 		}
@@ -1580,6 +1587,18 @@ void LLPanelAvatar::onClickRate(void *userdata)
 	LLFloaterRate::show(self->mAvatarID);
 }
 
+// static
+void LLPanelAvatar::onClickAddFriend(void* userdata)
+{
+	LLPanelAvatar* self = (LLPanelAvatar*) userdata;
+	LLNameEditor* name_edit = LLViewerUICtrlFactory::getNameEditorByName(self->mPanelSecondLife, "name");	
+	if (name_edit)
+	{
+		LLFloaterFriends::requestFriendshipDialog(self->getAvatarID(),
+												  name_edit->getText());
+	}
+}
+
 //-----------------------------------------------------------------------------
 // onClickMute()
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index be6feebc30650bf85b0da1901f91d28cedc7e827..994d23b7d33c7a83dbc7afaa534ef199490ba152 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -289,6 +289,7 @@ class LLPanelAvatar : public LLPanel
 	static void onClickOfferTeleport(	void *userdata);
 	static void onClickPay(	void *userdata);
 	static void onClickRate(	void *userdata);
+	static void onClickAddFriend(void* userdata);
 	static void onClickOK(		void *userdata);
 	static void onClickCancel(	void *userdata);
 	static void onClickKick(	void *userdata);
@@ -296,7 +297,6 @@ class LLPanelAvatar : public LLPanel
 	static void onClickUnfreeze(void *userdata);
 	static void onClickCSR(		void *userdata);
 	static void onClickMute(	void *userdata);
-	static void onClickAddFriend(void* data);
 
 	static void finishKick(S32 option, const LLString& text, void* userdata);
 	static void finishFreeze(S32 option, const LLString& text, void* userdata);
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 94773e21ba53c20469eeb5d8f0c5e7b160652d80..58a596979292d4c06fab3825b379c835dd7435a3 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -382,7 +382,7 @@ BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
 		if ( KEY_F1 == key )
 		{
 			llinfos << "Spawning HTML help window" << llendl;
-			LLHtmlHelp::show();
+			gViewerHtmlHelp.show();
 			return TRUE;
 		};
 			#if ! LL_RELEASE_FOR_DOWNLOAD
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 4b7be3701bd25171feb53bfcab06b89a5e01ed9b..b8f1e51e9e84589147c0ca87d63d2cae5b56b7b6 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -457,7 +457,7 @@ void LLPreviewTexture::updateAspectRatio()
 
 void LLPreviewTexture::loadAsset()
 {
-	mImage = gImageList.getImage(mImageID, MIPMAP_FALSE, FALSE);
+	mImage = gImageList.getImage(mImageID, MIPMAP_TRUE, FALSE);
 	mImage->setBoostLevel(LLViewerImage::BOOST_PREVIEW);
 	mAssetStatus = PREVIEW_ASSET_LOADING;
 }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index d8d9f1c5d6f006caa2239b61b376e13a1a8568dd..333ed91e4a0752bcaa719665863df4d5dfd21ef9 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -126,7 +126,7 @@ LLSpatialGroup::~LLSpatialGroup()
 	{
 		sZombieGroups--;
 	}
-
+	
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	clearDrawMap();
 }
@@ -197,10 +197,34 @@ void LLSpatialGroup::validate()
 #if LL_OCTREE_PARANOIA_CHECK
 
 	sg_assert(!isState(DIRTY));
+	sg_assert(!isDead());
 
 	LLVector3 myMin = mBounds[0] - mBounds[1];
 	LLVector3 myMax = mBounds[0] + mBounds[1];
 
+	validateDrawMap();
+
+	for (element_iter i = getData().begin(); i != getData().end(); ++i)
+	{
+		LLDrawable* drawable = *i;
+		sg_assert(drawable->getSpatialGroup() == this);
+		if (drawable->getSpatialBridge())
+		{
+			sg_assert(drawable->getSpatialBridge() == mSpatialPartition->asBridge());
+		}
+
+		if (drawable->isSpatialBridge())
+		{
+			LLSpatialPartition* part = drawable->asPartition();
+			if (!part)
+			{
+				llerrs << "Drawable reports it is a spatial bridge but not a partition." << llendl;
+			}
+			LLSpatialGroup* group = (LLSpatialGroup*) part->mOctree->getListener(0);
+			group->validate();
+		}
+	}
+
 	for (U32 i = 0; i < mOctreeNode->getChildCount(); ++i)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
@@ -226,8 +250,8 @@ void LLSpatialGroup::validate()
 
 void validate_draw_info(LLDrawInfo& params)
 {
-#if LL_DEBUG
-/*	if (params.mVertexBuffer.isNull())
+#if LL_OCTREE_PARANOIA_CHECK
+	if (params.mVertexBuffer.isNull())
 	{
 		llerrs << "Draw batch has no vertex buffer." << llendl;
 	}
@@ -238,12 +262,12 @@ void validate_draw_info(LLDrawInfo& params)
 		llerrs << "Draw batch has invalid range." << llendl;
 	}
 	
-	if (params.mEnd >= params.mVertexBuffer->getNumVerts())
+	if (params.mEnd >= (U32) params.mVertexBuffer->getNumVerts())
 	{
 		llerrs << "Draw batch has buffer overrun error." << llendl;
 	}
 	
-	if (params.mOffset + params.mCount > params.mVertexBuffer->getNumIndices())
+	if (params.mOffset + params.mCount > (U32) params.mVertexBuffer->getNumIndices())
 	{
 		llerrs << "Draw batch has index buffer ovverrun error." << llendl;
 	}
@@ -264,13 +288,14 @@ void validate_draw_info(LLDrawInfo& params)
 				llerrs << "Draw batch has vertex buffer index out of range error (index too high)." << llendl;
 			}
 		}
-	}*/
+	}
 #endif
 }
 
 void LLSpatialGroup::validateDrawMap()
 {
-/*	for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
+#if LL_OCTREE_PARANOIA_CHECK
+	for (draw_map_t::iterator i = mDrawMap.begin(); i != mDrawMap.end(); ++i)
 	{
 		std::vector<LLDrawInfo*>& draw_vec = i->second;
 		for (std::vector<LLDrawInfo*>::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
@@ -279,7 +304,8 @@ void LLSpatialGroup::validateDrawMap()
 			
 			validate_draw_info(params);
 		}
-	}*/
+	}
+#endif
 }
 
 void LLSpatialGroup::makeStatic()
@@ -342,7 +368,7 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc
 	}
 	else
 	{
-		drawablep->setSpatialGroup(this, 0);
+		drawablep->setSpatialGroup(this);
 		validate_drawable(drawablep);
 		setState(OBJECT_DIRTY | GEOM_DIRTY);
 		mLastAddTime = gFrameTimeSeconds;
@@ -554,7 +580,7 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 	}
 	else
 	{
-		drawablep->setSpatialGroup(NULL, -1);
+		drawablep->setSpatialGroup(NULL);
 		setState(GEOM_DIRTY);
 		if (drawablep->isSpatialBridge())
 		{
@@ -867,6 +893,16 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	setState(DEAD);
+	
+	for (element_iter i = getData().begin(); i != getData().end(); ++i)
+	{
+		LLDrawable* drawable = *i;
+		if (drawable->getSpatialGroup() == this)
+		{
+			drawable->setSpatialGroup(NULL);
+		}
+	}
+	
 	clearDrawMap();
 	mOcclusionVerts = NULL;
 	mVertexBuffer = NULL;
@@ -1108,7 +1144,7 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	
-	drawablep->setSpatialGroup(NULL, -1);
+	drawablep->setSpatialGroup(NULL);
 
 	if (!curp->removeObject(drawablep))
 	{
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index f3a2c629fdaab438d0979760b16de0fbb1c34436..baf6abda11e1f28d856a2afd62ef200bfe5578f7 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -328,13 +328,16 @@ BOOL idle_startup()
 		{
 			gViewerWindow->alertXml("DisplaySetToSafe");
 		}
-		else if (gSavedSettings.getS32("LastFeatureVersion") < gFeatureManagerp->getVersion())
+		else if ((gSavedSettings.getS32("LastFeatureVersion") < gFeatureManagerp->getVersion()) &&
+				 (gSavedSettings.getS32("LastFeatureVersion") != 0))
 		{
-			if (gSavedSettings.getS32("LastFeatureVersion") != 0)
-			{
-				gViewerWindow->alertXml("DisplaySetToRecommended");
-			}
+			gViewerWindow->alertXml("DisplaySetToRecommended");
 		}
+		else if (!gViewerWindow->getInitAlert().empty())
+		{
+			gViewerWindow->alertXml(gViewerWindow->getInitAlert());
+		}
+			
 		gSavedSettings.setS32("LastFeatureVersion", gFeatureManagerp->getVersion());
 
 		LLString xml_file = LLUI::locateSkin("xui_version.xml");
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 4be7cf41e77380618b1fcee36ae30b1068293af1..8d30ebbcdaedddab31bb3f8a8295d521d086d80d 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -183,6 +183,11 @@ LLVector2 LLSurfacePatch::getTexCoords(const U32 x, const U32 y) const
 void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal,
 						  LLVector2 *tex0, LLVector2 *tex1)
 {
+	if (!mSurfacep || !mSurfacep->getRegion())
+	{
+		return; // failsafe
+	}
+	
 	U32 surface_stride = mSurfacep->getGridsPerEdge();
 	U32 point_offset = x + y*surface_stride;
 
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 2c7c89280769630a4c430d14dc44a50d3a402566..a155a7aeec610f5721147b39d9a38442725d1e06 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -77,6 +77,7 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
 
 // Handy copies of last good GL matrices
 F64	gGLModelView[16];
+F64 gGLProjection[16];
 S32	gGLViewport[4];
 
 const LLMatrix4 &LLViewerCamera::getProjection() const
@@ -231,6 +232,7 @@ void LLViewerCamera::setPerspective(BOOL for_selection,
 				   aspect,
 				   z_near,
 				   z_far);
+	glGetDoublev(GL_PROJECTION_MATRIX, gGLProjection);
 	glGetFloatv(GL_PROJECTION_MATRIX, (float*)&gProjectionMat);
 	
 	glMatrixMode( GL_MODELVIEW );
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index 6ce1dcc0467f1ff2a01bfaf418722ee1cfd9ae00..b28aac269b68a0dfb2bad212ddd6c1cb4ca7cb51 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -90,6 +90,7 @@ class LLViewerCamera : public LLCamera
 
 extern LLViewerCamera *gCamera;
 extern F64 gGLModelView[16];
+extern F64 gGLProjection[16];
 extern S32 gGLViewport[4];
 
 #endif // LL_LLVIEWERCAMERA_H
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index df5b0f1182860d86861ab315dd7fb6f2c59edaaf..ee878c1dc0fb1b6e6f8831e1d334efc1ed5bd59d 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -577,11 +577,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield)
 			gPipeline.stateSort(hud_cam);
 		}
 		
-		if (LLVertexBuffer::sEnableVBOs)
-		{
-			LLImageGL::sBoundTextureMemory += LLVertexBuffer::sAllocatedBytes;
-		}
-		
 		gPipeline.renderGeom(hud_cam);
 
 		//restore type mask
@@ -800,8 +795,10 @@ void render_ui_2d()
 		glPushMatrix();
 		S32 half_width = (gViewerWindow->getWindowWidth() / 2);
 		S32 half_height = (gViewerWindow->getWindowHeight() / 2);
+		glScalef(LLUI::sGLScaleFactor.mV[0], LLUI::sGLScaleFactor.mV[1], 1.f);
 		glTranslatef((F32)half_width, (F32)half_height, 0.f);
-		glScalef(gAgent.getAvatarObject()->mHUDCurZoom, gAgent.getAvatarObject()->mHUDCurZoom, gAgent.getAvatarObject()->mHUDCurZoom);
+		F32 zoom = gAgent.getAvatarObject()->mHUDCurZoom;
+		glScalef(zoom,zoom,1.f);
 		glColor4fv(LLColor4::white.mV);
 		gl_rect_2d(-half_width, half_height, half_width, -half_height, FALSE);
 		glPopMatrix();
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 123dcc8eb416868dccaddfe089cce9ffe1acb6dc..9bb4aa4cf92ac9e14b44b6100d2cb3e758e7f889 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -47,7 +47,6 @@ static LLPointer<LLVertexBuffer> sRenderBuffer = NULL;
 static const U32 sRenderMask = LLVertexBuffer::MAP_VERTEX |
 							   LLVertexBuffer::MAP_NORMAL |
 							   LLVertexBuffer::MAP_TEXCOORD;
-LLMatrix4 gBlendMat;
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -884,89 +883,108 @@ BOOL LLViewerJointMesh::updateLOD(F32 pixel_area, BOOL activate)
 	return (valid != activate);
 }
 
+
 void LLViewerJointMesh::updateGeometry()
 {
-	if (mValid && mMesh && mFace &&
-		mMesh->hasWeights() &&
-		mFace->mVertexBuffer.notNull() &&
-		LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) == 0)
+	if (!(mValid
+		  && mMesh
+		  && mFace
+		  && mMesh->hasWeights()
+		  && mFace->mVertexBuffer.notNull()
+		  && LLShaderMgr::getVertexShaderLevel(LLShaderMgr::SHADER_AVATAR) == 0))
 	{
-		uploadJointMatrices();
-		LLStrider<LLVector3> o_vertices;
-		LLStrider<LLVector3> o_normals;
+		return;
+	}
+	
+	uploadJointMatrices();
 
-		//get vertex and normal striders
-		LLVertexBuffer *buffer = mFace->mVertexBuffer;
-		buffer->getVertexStrider(o_vertices,  0);
-		buffer->getNormalStrider(o_normals,   0);
+	LLStrider<LLVector3> o_vertices;
+	LLStrider<LLVector3> o_normals;
 
+	//get vertex and normal striders
+	LLVertexBuffer *buffer = mFace->mVertexBuffer;
+	buffer->getVertexStrider(o_vertices,  0);
+	buffer->getNormalStrider(o_normals,   0);
+
+	F32 last_weight = F32_MAX;
+	LLMatrix4 gBlendMat;
+	LLMatrix3 gBlendRotMat;
+
+	const F32* weights = mMesh->getWeights();
+	const LLVector3* coords = mMesh->getCoords();
+	const LLVector3* normals = mMesh->getNormals();
+	for (U32 index = 0; index < mMesh->getNumVertices(); index++)
+	{
+		U32 bidx = index + mMesh->mFaceVertexOffset;
+		
+		// blend by first matrix
+		F32 w = weights[index]; 
+		
+		// Maybe we don't have to change gBlendMat.
+		// Profiles of a single-avatar scene on a Mac show this to be a very
+		// common case.  JC
+		if (w == last_weight)
 		{
-			LLVector4 tpos0, tnorm0, tpos1, tnorm1, tbinorm0, tbinorm1;
-			F32 last_weight = F32_MAX;
-			LLMatrix3 gBlendRotMat;
+			o_vertices[bidx] = coords[index] * gBlendMat;
+			o_normals[bidx] = normals[index] * gBlendRotMat;
+			continue;
+		}
+		
+		last_weight = w;
 
+		S32 joint = llfloor(w);
+		w -= joint;
 		
-			for (U32 index= 0; index < mMesh->getNumVertices(); index++)
-			{
-				// blend by first matrix
-				F32 w = mMesh->getWeights()[index]; 
-				
-				if (w != last_weight)
-				{
-					last_weight = w;
-
-					S32 joint = llfloor(w);
-					w -= joint;
-
-					LLMatrix4 &m0 = gJointMat[joint+1];
-					LLMatrix4 &m1 = gJointMat[joint+0];
-					LLMatrix3 &n0 = gJointRot[joint+1];
-					LLMatrix3 &n1 = gJointRot[joint+0];
-
-					if (w == 1.0f)
-					{
-						gBlendMat = m0;
-						gBlendRotMat = n0;
-					}	
-					else
-					{
-						gBlendMat.mMatrix[VX][VX] = lerp(m1.mMatrix[VX][VX], m0.mMatrix[VX][VX], w);
-						gBlendMat.mMatrix[VX][VY] = lerp(m1.mMatrix[VX][VY], m0.mMatrix[VX][VY], w);
-						gBlendMat.mMatrix[VX][VZ] = lerp(m1.mMatrix[VX][VZ], m0.mMatrix[VX][VZ], w);
-
-						gBlendMat.mMatrix[VY][VX] = lerp(m1.mMatrix[VY][VX], m0.mMatrix[VY][VX], w);
-						gBlendMat.mMatrix[VY][VY] = lerp(m1.mMatrix[VY][VY], m0.mMatrix[VY][VY], w);
-						gBlendMat.mMatrix[VY][VZ] = lerp(m1.mMatrix[VY][VZ], m0.mMatrix[VY][VZ], w);
-
-						gBlendMat.mMatrix[VZ][VX] = lerp(m1.mMatrix[VZ][VX], m0.mMatrix[VZ][VX], w);
-						gBlendMat.mMatrix[VZ][VY] = lerp(m1.mMatrix[VZ][VY], m0.mMatrix[VZ][VY], w);
-						gBlendMat.mMatrix[VZ][VZ] = lerp(m1.mMatrix[VZ][VZ], m0.mMatrix[VZ][VZ], w);
-
-						gBlendMat.mMatrix[VW][VX] = lerp(m1.mMatrix[VW][VX], m0.mMatrix[VW][VX], w);
-						gBlendMat.mMatrix[VW][VY] = lerp(m1.mMatrix[VW][VY], m0.mMatrix[VW][VY], w);
-						gBlendMat.mMatrix[VW][VZ] = lerp(m1.mMatrix[VW][VZ], m0.mMatrix[VW][VZ], w);
-
-						gBlendRotMat.mMatrix[VX][VX] = lerp(n1.mMatrix[VX][VX], n0.mMatrix[VX][VX], w);
-						gBlendRotMat.mMatrix[VX][VY] = lerp(n1.mMatrix[VX][VY], n0.mMatrix[VX][VY], w);
-						gBlendRotMat.mMatrix[VX][VZ] = lerp(n1.mMatrix[VX][VZ], n0.mMatrix[VX][VZ], w);
-
-						gBlendRotMat.mMatrix[VY][VX] = lerp(n1.mMatrix[VY][VX], n0.mMatrix[VY][VX], w);
-						gBlendRotMat.mMatrix[VY][VY] = lerp(n1.mMatrix[VY][VY], n0.mMatrix[VY][VY], w);
-						gBlendRotMat.mMatrix[VY][VZ] = lerp(n1.mMatrix[VY][VZ], n0.mMatrix[VY][VZ], w);
-
-						gBlendRotMat.mMatrix[VZ][VX] = lerp(n1.mMatrix[VZ][VX], n0.mMatrix[VZ][VX], w);
-						gBlendRotMat.mMatrix[VZ][VY] = lerp(n1.mMatrix[VZ][VY], n0.mMatrix[VZ][VY], w);
-						gBlendRotMat.mMatrix[VZ][VZ] = lerp(n1.mMatrix[VZ][VZ], n0.mMatrix[VZ][VZ], w);
-					}
-				}
+		// No lerp required in this case.
+		if (w == 1.0f)
+		{
+			gBlendMat = gJointMat[joint+1];
+			o_vertices[bidx] = coords[index] * gBlendMat;
+			gBlendRotMat = gJointRot[joint+1];
+			o_normals[bidx] = normals[index] * gBlendRotMat;
+			continue;
+		}
+		
+		// Try to keep all the accesses to the matrix data as close
+		// together as possible.  This function is a hot spot on the
+		// Mac. JC
+		LLMatrix4 &m0 = gJointMat[joint+1];
+		LLMatrix4 &m1 = gJointMat[joint+0];
+		
+		gBlendMat.mMatrix[VX][VX] = lerp(m1.mMatrix[VX][VX], m0.mMatrix[VX][VX], w);
+		gBlendMat.mMatrix[VX][VY] = lerp(m1.mMatrix[VX][VY], m0.mMatrix[VX][VY], w);
+		gBlendMat.mMatrix[VX][VZ] = lerp(m1.mMatrix[VX][VZ], m0.mMatrix[VX][VZ], w);
 
-				// write result
-				U32 bidx = index + mMesh->mFaceVertexOffset;
+		gBlendMat.mMatrix[VY][VX] = lerp(m1.mMatrix[VY][VX], m0.mMatrix[VY][VX], w);
+		gBlendMat.mMatrix[VY][VY] = lerp(m1.mMatrix[VY][VY], m0.mMatrix[VY][VY], w);
+		gBlendMat.mMatrix[VY][VZ] = lerp(m1.mMatrix[VY][VZ], m0.mMatrix[VY][VZ], w);
 
-				o_vertices[bidx] = mMesh->getCoords()[index] * gBlendMat;
-				o_normals[bidx] = mMesh->getNormals()[index] * gBlendRotMat;
-			}
-		}
+		gBlendMat.mMatrix[VZ][VX] = lerp(m1.mMatrix[VZ][VX], m0.mMatrix[VZ][VX], w);
+		gBlendMat.mMatrix[VZ][VY] = lerp(m1.mMatrix[VZ][VY], m0.mMatrix[VZ][VY], w);
+		gBlendMat.mMatrix[VZ][VZ] = lerp(m1.mMatrix[VZ][VZ], m0.mMatrix[VZ][VZ], w);
+
+		gBlendMat.mMatrix[VW][VX] = lerp(m1.mMatrix[VW][VX], m0.mMatrix[VW][VX], w);
+		gBlendMat.mMatrix[VW][VY] = lerp(m1.mMatrix[VW][VY], m0.mMatrix[VW][VY], w);
+		gBlendMat.mMatrix[VW][VZ] = lerp(m1.mMatrix[VW][VZ], m0.mMatrix[VW][VZ], w);
+
+		o_vertices[bidx] = coords[index] * gBlendMat;
+		
+		LLMatrix3 &n0 = gJointRot[joint+1];
+		LLMatrix3 &n1 = gJointRot[joint+0];
+		
+		gBlendRotMat.mMatrix[VX][VX] = lerp(n1.mMatrix[VX][VX], n0.mMatrix[VX][VX], w);
+		gBlendRotMat.mMatrix[VX][VY] = lerp(n1.mMatrix[VX][VY], n0.mMatrix[VX][VY], w);
+		gBlendRotMat.mMatrix[VX][VZ] = lerp(n1.mMatrix[VX][VZ], n0.mMatrix[VX][VZ], w);
+
+		gBlendRotMat.mMatrix[VY][VX] = lerp(n1.mMatrix[VY][VX], n0.mMatrix[VY][VX], w);
+		gBlendRotMat.mMatrix[VY][VY] = lerp(n1.mMatrix[VY][VY], n0.mMatrix[VY][VY], w);
+		gBlendRotMat.mMatrix[VY][VZ] = lerp(n1.mMatrix[VY][VZ], n0.mMatrix[VY][VZ], w);
+
+		gBlendRotMat.mMatrix[VZ][VX] = lerp(n1.mMatrix[VZ][VX], n0.mMatrix[VZ][VX], w);
+		gBlendRotMat.mMatrix[VZ][VY] = lerp(n1.mMatrix[VZ][VY], n0.mMatrix[VZ][VY], w);
+		gBlendRotMat.mMatrix[VZ][VZ] = lerp(n1.mMatrix[VZ][VZ], n0.mMatrix[VZ][VZ], w);
+		
+		o_normals[bidx] = normals[index] * gBlendRotMat;
 	}
 }
 
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 114c90a4d818dc965619e49ac21aeaa5f4a4b180..e9d2218d5546024ef9e7aa5317475f8fc2d2a7c7 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1237,11 +1237,6 @@ void init_debug_rendering_menu(LLMenuGL* menu)
 	item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, NULL, menu_check_control, (void*)"CheesyBeacon");
 	menu->append(item);
 	
-#if 0 // 1.9.2
-	item = new LLMenuItemCheckGL("Vertex Shaders", toggle_vertex_shaders, NULL, check_vertex_shaders, (void*)"VertexShaderEnable", 'V', MASK_CONTROL|MASK_ALT);
-	item->setEnabled(gGLManager.mHasVertexShader);
-	menu->append(item);
-#endif
 	menu->createJumpKeys();
 }
 
@@ -6481,7 +6476,7 @@ class LLShowFloater : public view_listener_t
 		else if (floater_name == "help f1")
 		{
 #if LL_LIBXUL_ENABLED
-			LLHtmlHelp::show();
+			gViewerHtmlHelp.show();
 #endif
 		}
 		else if (floater_name == "help in-world")
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 55256a6f2326214b59632bc9ff897e26ebd37ffd..cc1beefec5f944c3056663673303e0acbb01df89 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1560,7 +1560,17 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 			{
 				return;
 			}
-			
+
+			// System messages, specifically "Foo Bar has left this session"
+			// are not shown unless you actually have that session open.
+			// Band-aid.  JC
+			if (offline == IM_ONLINE
+				&& chat.mFromName == SYSTEM_FROM
+				&& !gIMView->hasSession(session_id))
+			{
+				return;
+			}
+
 			// standard message, not from system
 			char saved[MAX_STRING];		/* Flawfinder: ignore */
 			saved[0] = '\0';
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index bd8ac806f58b2395db44a96f45d6e43fc001e278..7ae166849b8bc4ac57e3031835e84516a8a04097 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4612,6 +4612,13 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp)
 	llassert(regionp);
 	mLatestRecvPacketID = 0;
 	mRegionp = regionp;
+
+	for (child_list_t::iterator i = getChildren().begin(); i != getChildren().end(); ++i)
+	{
+		LLViewerObject* child = *i;
+		child->setRegion(regionp);
+	}
+
 	setChanged(MOVED | SILHOUETTE);
 	updateDrawable(FALSE);
 }
diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index bf09c54100ee1a26be63983d426556b61da9a8f3..cb0df9238648ddfeeca9e8be1642d7e21d409f5d 100644
--- a/indra/newview/llviewerpartsim.cpp
+++ b/indra/newview/llviewerpartsim.cpp
@@ -230,13 +230,13 @@ void LLViewerPartGroup::removePart(const S32 part_num)
 void LLViewerPartGroup::updateParticles(const F32 dt)
 {
 	LLMemType mt(LLMemType::MTYPE_PARTICLES);
-	S32 i, count;
+	S32 i;
 	
 	LLVector3 gravity(0.f, 0.f, -9.8f);
 
 	LLViewerRegion *regionp = getRegion();
-	count = (S32) mParticles.size();
-	for (i = 0; i < count; i++)
+	S32 end = (S32) mParticles.size();
+	for (i = 0; i < end; i++)
 	{
 		LLVector3 a(0.f, 0.f, 0.f);
 		LLViewerPart& part = *((LLViewerPart*) mParticles[i]);
@@ -345,9 +345,8 @@ void LLViewerPartGroup::updateParticles(const F32 dt)
 		// Kill dead particles (either flagged dead, or too old)
 		if ((part.mLastUpdateTime > part.mMaxAge) || (LLViewerPart::LL_PART_DEAD_MASK == part.mFlags))
 		{
-			removePart(i);
-			i--;
-			count--;
+			end--;
+			LLPointer<LLViewerPart>::swap(mParticles[i], mParticles[end]);
 		}
 		else 
 		{
@@ -356,13 +355,24 @@ void LLViewerPartGroup::updateParticles(const F32 dt)
 			{
 				// Transfer particles between groups
 				gWorldPointer->mPartSim.put(&part);
-				removePart(i);
-				i--;
-				count--;
+				end--;
+				LLPointer<LLViewerPart>::swap(mParticles[i], mParticles[end]);
 			}
 		}
 	}
 
+	S32 removed = (S32)mParticles.size() - end;
+	if (removed > 0)
+	{
+		// we removed one or more particles, so flag this group for update
+		mParticles.erase(mParticles.begin() + end, mParticles.end());
+		if (mVOPartGroupp.notNull())
+		{
+			gPipeline.markRebuild(mVOPartGroupp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+		}
+		LLViewerPartSim::decPartCount(removed);
+	}
+	
 	// Kill the viewer object if this particle group is empty
 	if (mParticles.empty())
 	{
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index 4ebfef3a9bc8dd856b93580b1c72f0821eca93e7..d81454fa8d5b9305077e0185cf6ed67dc85bce31 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -1433,12 +1433,14 @@ BOOL LLViewerTextEditor::exportBuffer( LLString& buffer )
 {
 	LLNotecard nc(LLNotecard::MAX_SIZE);
 
-	std::vector<LLPointer<LLInventoryItem> > embedded_items;
-	mEmbeddedItemList->getEmbeddedItemList(embedded_items);
-	
-	nc.setItems(embedded_items);
+	// Get the embedded text and update the item list to just be the used items
 	nc.setText(getEmbeddedText());
 
+	// Now get the used items and copy the list to the notecard
+	std::vector<LLPointer<LLInventoryItem> > embedded_items;
+	mEmbeddedItemList->getEmbeddedItemList(embedded_items);	
+	nc.setItems(embedded_items);
+	
 	std::stringstream out_stream;
 	nc.exportStream(out_stream);
 	
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 732568f652a6d8d7621378c60b77fea70b175093..f11f9fb1be6f9d7d4cca901fbb931d6f6ee40874 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1450,6 +1450,8 @@ LLViewerWindow::LLViewerWindow(
 	
 	LLFontManager::initClass();
 
+	// Initialize OpenGL Renderer
+
 	if (!gFeatureManagerp->isFeatureAvailable("RenderVBO") ||
 		!gGLManager.mHasVertexBufferObject)
 	{
@@ -1475,16 +1477,30 @@ LLViewerWindow::LLViewerWindow(
 		idx = LLViewerImageList::getMaxVideoRamSetting(-2); // get max recommended setting
 		gSavedSettings.setS32("GraphicsCardMemorySetting", idx);
 	}
-	
+
+	// If we crashed while initializng GL stuff last time, disable certain features
+	if (gSavedSettings.getBOOL("RenderInitError"))
+	{
+		mInitAlert = "DisplaySettingsNoShaders";
+		gSavedSettings.setBOOL("VertexShaderEnable", FALSE);
+	}
+		
 	if (!gNoRender)
 	{
 		//
 		// Initialize GL stuff
 		//
 
+		// Set this flag in case we crash while initializing GL
+		gSavedSettings.setBOOL("RenderInitError", TRUE);
+		gSavedSettings.saveToFile( gSettingsFileName, TRUE );
+	
 		gPipeline.init();
 		stop_glerror();
 		initGLDefaults();
+
+		gSavedSettings.setBOOL("RenderInitError", FALSE);
+		gSavedSettings.saveToFile( gSettingsFileName, TRUE );
 	}
 
 	//
@@ -1531,6 +1547,7 @@ LLViewerWindow::LLViewerWindow(
 	gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
 
 	mDebugText = new LLDebugText(this);
+
 }
 
 void LLViewerWindow::initGLDefaults()
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 8f3642ffd37d5811d4791cd5edd0a1303009cce6..af5ffd79144370dbf03e1a63bd607bf26ca423d9 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -125,7 +125,9 @@ class LLViewerWindow : public LLWindowCallbacks
 	void			getTargetWindow(BOOL& fullscreen, S32& width, S32& height) const;
 		// The 'target' is where the user wants the window to be. It may not be
 		// there yet, because we may be supressing fullscreen prior to login.
-		
+
+	const LLString&	getInitAlert() { return mInitAlert; }
+	
 	//
 	// MANIPULATORS
 	//
@@ -319,6 +321,8 @@ class LLViewerWindow : public LLWindowCallbacks
 	BOOL			mIgnoreActivate;
 	U8*				mPickBuffer;
 
+	LLString		mInitAlert;			// Window / GL initialization requires an alert
+	
 	class LLDebugText* mDebugText; // Internal class for debug text
 
 protected:
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index 7dd7f2674bc2057e4ff761955f5d0c4673f48465..de67506e3faa08c196981129439e77e4ca3a7ca7 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -265,7 +265,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
 				ddiscard++;
 				min_dim /= 2;
 			}
-			if (!mDetailTextures[i]->readBackRaw(ddiscard, mRawImages[i]))
+			if (!mDetailTextures[i]->readBackRaw(ddiscard, mRawImages[i], false))
 			{
 				llwarns << "Unable to read raw data for terrain detail texture: " << mDetailTextures[i]->getID() << llendl;
 				mRawImages[i] = NULL;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f0e797b6e94dbd78f451da1491951272bda9ecb7..e74c286e439318a0080c31df20a327a6b81f3229 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -6329,7 +6329,7 @@ BOOL LLVOAvatar::getLocalTextureRaw(S32 index, LLImageRaw* image_raw)
 		}
 		else
 		{
-			if( mLocalTexture[ index ]->readBackRaw(-1, image_raw) )
+			if( mLocalTexture[ index ]->readBackRaw(-1, image_raw, false) )
 			{
 				success = TRUE;
 			}
@@ -9184,7 +9184,7 @@ void LLVOAvatar::writeCAL3D(std::string& path, std::string& file_base)
 			continue;
 		}
 		LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-		viewer_imagep->readBackRaw(-1, raw_image);
+		viewer_imagep->readBackRaw(-1, raw_image, false);
 		BOOL success = tga_image->encode(raw_image);
 		success = tga_image->save(filename);
 	}
@@ -9199,7 +9199,7 @@ void LLVOAvatar::writeCAL3D(std::string& path, std::string& file_base)
 	else
 	{
 		LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-		viewer_imagep->readBackRaw(-1, raw_image);
+		viewer_imagep->readBackRaw(-1, raw_image, false);
 		BOOL success = tga_image->encode(raw_image);
 		success = tga_image->save(filename);
 	}
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 94f9f0b21f707afe4a5974799edf9f297071b7cf..9da6027ab562a4f99f40d31db7b1a6bea18b8b10 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -169,7 +169,7 @@ inline F32 color_intens ( const LLColor4 &col )
 
 inline F32 color_avg ( const LLColor3 &col )
 {
-	return color_intens(col) / 3;
+	return color_intens(col) / 3.f;
 }
 
 inline void color_gamma_correct(LLColor3 &col)
@@ -756,7 +756,7 @@ LLColor3 LLVOSky::calcSkyColorInDir(const LLVector3 &dir)
 {
 	LLColor3 col, transp;
 
-	if (dir.mV[VZ] < -0.02)
+	if (dir.mV[VZ] < -0.02f)
 	{
 		col = LLColor3(llmax(mFogColor[0],0.2f), llmax(mFogColor[1],0.2f), llmax(mFogColor[2],0.27f));
 		float x = 1.0f-fabsf(-0.1f-dir.mV[VZ]);
@@ -806,15 +806,18 @@ void LLVOSky::calcSkyColorInDir(LLColor3& res, LLColor3& transp, const LLVector3
 	const F32 e_pow_k = (F32)LL_FAST_EXP(K);
 	F32 step = FIRST_STEP * (1 - 1 / e_pow_k);
 
+	// Initialize outside the loop because we write into them every iteration. JC
+	LLColor3 air_sca_opt_depth;
+	LLColor3 haze_sca_opt_depth;
+	LLColor3 air_transp;
+
 	for (S32 s = 0; s < NO_STEPS; ++s)
 	{
 		h = calcHeight(cur_pos);
 		step *= e_pow_k;
-		LLColor3 air_sca_opt_depth;
 		LLHaze::calcAirSca(h, air_sca_opt_depth);
 		air_sca_opt_depth *= step;
 
-		LLColor3 haze_sca_opt_depth;
 		mHaze.calcSigSca(h, haze_sca_opt_depth);
 		haze_sca_opt_depth *= step;
 
@@ -824,7 +827,6 @@ void LLVOSky::calcSkyColorInDir(LLColor3& res, LLColor3& transp, const LLVector3
 		if (calcHitsEarth(cur_pos, tosun) < 0) // calculates amount of in-scattered light from the sun
 		{
 			//visibility check is too expensive
-			LLColor3 air_transp;
 			mTransp.calcTransp(calcUpVec(cur_pos) * tosun, h, air_transp);
 			air_transp *= transp;
 			res += air_sca_opt_depth * air_transp;
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 0ded91bb809e96cc30c3bf4efbea464885bad850..5697e721ff161030d75e1c3c7b7dae45cf54b7f7 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -42,19 +42,12 @@ const F32 INV_NO_STEPS = 1.f/NO_STEPS;
 
 // constants used in calculation of scattering coeff of clear air
 const F32 sigma		= 0.035f;
-const F32 fsigma	= (6+3*sigma)/(6.f-7.f*sigma);
+const F32 fsigma	= (6.f + 3.f * sigma) / (6.f-7.f*sigma);
 const F64 Ndens		= 2.55e25;
 const F64 Ndens2	= Ndens*Ndens;
 
-// !!! *FIX: This #define should be in llcommon somewhere...
-// We should not be #defining anything with leading underscores and
-// much less double leading underscores since that is always vendor
-// specific. Change this to something like LL_FORCE_INLINE.
-#ifdef __GNUC__
-#define __forceinline inline __attribute__((always_inline))
-#endif
 
-__forceinline LLColor3 color_div(const LLColor3 &col1, const LLColor3 &col2)
+LL_FORCE_INLINE LLColor3 color_div(const LLColor3 &col1, const LLColor3 &col2)
 {
 	return LLColor3( 
 		col1.mV[0] / col2.mV[0],
@@ -121,7 +114,7 @@ class LLSkyTex
 public:
 	static F32 getInterpVal()					{ return sInterpVal; }
 	static void setInterpVal(const F32 v)		{ sInterpVal = v; }
-	static BOOL doInterpolate()					{ return sInterpVal > 0.001; }
+	static BOOL doInterpolate()					{ return sInterpVal > 0.001f; }
 
 	void bindTexture(BOOL curr = TRUE);
 	
@@ -292,7 +285,7 @@ class LLHeavenBody
 };
 
 
-__forceinline LLColor3 refr_ind_calc(const LLColor3 &wave_length)
+LL_FORCE_INLINE LLColor3 refr_ind_calc(const LLColor3 &wave_length)
 {
 	LLColor3 refr_ind;
 	for (S32 i = 0; i < 3; ++i)
@@ -306,7 +299,7 @@ __forceinline LLColor3 refr_ind_calc(const LLColor3 &wave_length)
 }
 
 
-__forceinline LLColor3 calc_air_sca_sea_level()
+LL_FORCE_INLINE LLColor3 calc_air_sca_sea_level()
 {
 	const static LLColor3 WAVE_LEN(675, 520, 445);
 	const static LLColor3 refr_ind = refr_ind_calc(WAVE_LEN);
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 759493504eefc35f80bc6062e921162c2694af9c..e524cc32fc806f91106b9ffb2a8746859270e436 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -69,21 +69,21 @@ class LLVertexBufferTerrain : public LLVertexBuffer
 //============================================================================
 
 LLVOSurfacePatch::LLVOSurfacePatch(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
-:	LLStaticViewerObject(id, LL_VO_SURFACE_PATCH, regionp)
+	:	LLStaticViewerObject(id, LL_VO_SURFACE_PATCH, regionp),
+		mDirtiedPatch(FALSE),
+		mPool(NULL),
+		mBaseComp(0),
+		mPatchp(NULL),
+		mDirtyTexture(FALSE),
+		mDirtyTerrain(FALSE),
+		mLastNorthStride(0),
+		mLastEastStride(0),
+		mLastStride(0),
+		mLastLength(0)
 {
 	// Terrain must draw during selection passes so it can block objects behind it.
 	mbCanSelect = TRUE;
-
-	mBaseComp = 0;
 	setScale(LLVector3(16.f, 16.f, 16.f)); // Hack for setting scale for bounding boxes/visibility.
-	mPool = NULL;
-	mDirtiedPatch = FALSE;
-	mLastStride = 0;
-	mLastNorthStride = 0;
-	mLastEastStride = 0;
-	mLastLength = 0;
-
-	mDirtyTerrain = TRUE;
 }
 
 
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index a42d447d5f3031bf66b3a07b3b6c6b8a9e8b6cb6..1090bf4210ba115de0fbeaa0b33b1a22dbb623fb 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -257,60 +257,41 @@ void LLVOVolume::animateTextures()
 		
 		for (S32 i = start; i <= end; i++)
 		{
-			LLQuaternion quat;
-			LLVector3 scale(1,1,1);
-			
 			LLFace* facep = mDrawable->getFace(i);
 			const LLTextureEntry* te = facep->getTextureEntry();
-			LLMatrix4& tex_mat = facep->mTextureMatrix;
 			
 			if (!te)
 			{
 				continue;
 			}
+		
 			if (!(result & LLViewerTextureAnim::ROTATE))
 			{
 				te->getRotation(&rot);
 			}
-
-			{
-				F32 axis = -1;
-				F32 s,t;	
-				te->getScale(&s,&t);
-				if (s < 0)
-				{
-					axis = -axis;
-				}
-				if (t < 0)
-				{
-					axis = -axis;
-				}
-				quat.setQuat(rot, 0, 0, axis);
-			}
-			
 			if (!(result & LLViewerTextureAnim::TRANSLATE))
 			{
 				te->getOffset(&off_s,&off_t);
 			}			
+			if (!(result & LLViewerTextureAnim::SCALE))
+			{
+				te->getScale(&scale_s, &scale_t);
+			}
 
+			LLVector3 scale(scale_s, scale_t, 1.f);
 			LLVector3 trans(off_s+0.5f, off_t+0.5f, 0.f);
-
+			LLQuaternion quat;
+			quat.setQuat(rot, 0, 0, -1.f);
+		
+			LLMatrix4& tex_mat = facep->mTextureMatrix;
 			tex_mat.identity();
 			tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
 			tex_mat.rotate(quat);				
 
-			if (!(result & LLViewerTextureAnim::SCALE))
-			{
-				te->getScale(&scale_s, &scale_t);
-			}
-	
-			{
-				scale.setVec(scale_s, scale_t, 1.f);
-				LLMatrix4 mat;
-				mat.initAll(scale, LLQuaternion(), LLVector3());
-				tex_mat *= mat;
-			}
-
+			LLMatrix4 mat;
+			mat.initAll(scale, LLQuaternion(), LLVector3());
+			tex_mat *= mat;
+		
 			tex_mat.translate(trans);
 		}
 	}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 44ebb2503b2c0539c374715d934edcf04ffeb3bf..43c587ed922576a132b590f27d68c30937f706ba 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -181,6 +181,8 @@ LLPipeline::LLPipeline() :
 void LLPipeline::init()
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+	mInitialized = TRUE;
 	
 	stop_glerror();
 
@@ -1466,7 +1468,7 @@ void renderScriptedBeacons(LLDrawable* drawablep)
 		&& !vobj->getParent()
 		&& vobj->flagScripted())
 	{
-		gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f));
+		gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
 	}
 }
 
@@ -1478,7 +1480,7 @@ void renderPhysicalBeacons(LLDrawable* drawablep)
 		&& !vobj->getParent()
 		&& vobj->usePhysics())
 	{
-		gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f));
+		gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
 	}
 }
 
@@ -1490,7 +1492,7 @@ void renderParticleBeacons(LLDrawable* drawablep)
 		&& vobj->isParticleSource())
 	{
 		LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f);
-		gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f));
+		gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
 	}
 }
 
@@ -1711,7 +1713,7 @@ void LLPipeline::postSort(LLCamera& camera)
 			LLVector3d pos_global = sourcep->getPositionGlobal();
 			LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global);
 			//pos += LLVector3(0.f, 0.f, 0.2f);
-			gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f));
+			gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
 		}
 	}
 
@@ -1976,6 +1978,7 @@ void LLPipeline::renderGeom(LLCamera& camera)
 					}
 					poolp->endRenderPass(i);
 #ifndef LL_RELEASE_FOR_DOWNLOAD
+#if LL_DEBUG_GL
 					GLint depth;
 					glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
 					if (depth > 3)
@@ -1985,6 +1988,7 @@ void LLPipeline::renderGeom(LLCamera& camera)
 					LLGLState::checkStates();
 					LLGLState::checkTextureChannels();
 					LLGLState::checkClientArrays();
+#endif
 #endif
 				}
 			}
@@ -3874,14 +3878,14 @@ void LLPipeline::bindScreenToTexture()
 {
 	LLGLEnable gl_texture_2d(GL_TEXTURE_2D);
 
+	GLint* viewport = (GLint*) gGLViewport;
+	GLuint resX = nhpo2(viewport[2]);
+	GLuint resY = nhpo2(viewport[3]);
+
 	if (mScreenTex == 0)
 	{
 		glGenTextures(1, &mScreenTex);
 		glBindTexture(GL_TEXTURE_2D, mScreenTex);
-		GLint viewport[4];
-		glGetIntegerv(GL_VIEWPORT, viewport);
-		GLuint resX = nhpo2(viewport[2]);
-		GLuint resY = nhpo2(viewport[3]);
 		
 		gImageList.updateMaxResidentTexMem(-1, resX*resY*3);
 		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, resX, resY, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@@ -3892,11 +3896,6 @@ void LLPipeline::bindScreenToTexture()
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 	}
 
-	GLint viewport[4];
-	glGetIntegerv(GL_VIEWPORT, viewport);
-	GLuint resX = nhpo2(viewport[2]);
-	GLuint resY = nhpo2(viewport[3]);
-
 	glBindTexture(GL_TEXTURE_2D, mScreenTex);
 	GLint cResX;
 	GLint cResY;
@@ -4026,5 +4025,4 @@ void LLPipeline::renderBloom(GLuint source, GLuint dest, GLuint buffer, U32 res,
 	glPopMatrix();
 	glMatrixMode(GL_MODELVIEW);
 	glPopMatrix();
-}
-
+}
\ No newline at end of file
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 5baf01de517c8ffbd32f067bcb3e1d25bc36a6d5..f20731c749875e121fdbb226319ab273f875157b 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -364,6 +364,7 @@ class LLPipeline
 
 	void clearRenderMap();
 
+	BOOL					mInitialized;
 	BOOL					mVertexShadersEnabled;
 	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed