diff --git a/indra/fix-incredibuild.py b/indra/fix-incredibuild.py
new file mode 100644
index 0000000000000000000000000000000000000000..b96b00dc850cddca4329fb5c80bb5eecedaf9e3f
--- /dev/null
+++ b/indra/fix-incredibuild.py
@@ -0,0 +1,38 @@
+import sys
+import os
+import glob
+
+def delete_file_types(path, filetypes):
+    if os.path.exists(path):
+        print 'Cleaning: ' + path
+        orig_dir = os.getcwd();
+        os.chdir(path)
+        filelist = []
+        for type in filetypes:
+            filelist.extend(glob.glob(type))
+        for file in filelist:
+            os.remove(file)
+        os.chdir(orig_dir)
+
+def main():
+    build_types = ['*.exp','*.exe','*.pdb','*.idb',
+                 '*.ilk','*.lib','*.obj','*.ib_pdb_index']
+    pch_types = ['*.pch']
+    delete_file_types("build-vc80/newview/Release", build_types)
+    delete_file_types("build-vc80/newview/secondlife-bin.dir/Release/", 
+                      pch_types)
+    delete_file_types("build-vc80/newview/RelWithDebInfo", build_types)
+    delete_file_types("build-vc80/newview/secondlife-bin.dir/RelWithDebInfo/", 
+                      pch_types)
+    delete_file_types("build-vc80/newview/Debug", build_types)
+    delete_file_types("build-vc80/newview/secondlife-bin.dir/Debug/", 
+                      pch_types)
+
+
+    delete_file_types("build-vc80/test/RelWithDebInfo", build_types)
+    delete_file_types("build-vc80/test/test.dir/RelWithDebInfo/", 
+                      pch_types)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index be0ab9fcb7e82941562ea176cd5ae2b9f3720d0c..5c33b675ca3a64221ee46f48cb5869f14615e5e7 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -147,7 +147,7 @@ U8* LLImageBase::allocateData(S32 size)
 		size = mWidth * mHeight * mComponents;
 		if (size <= 0)
 		{
-			llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl;
+			llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << llendl;
 		}
 	}
 	
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 90fcf6ab3f180917a57bf95950d1e70800813dc9..9d037f2565db8fba6ce2c29ed27afc7500960906 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1055,7 +1055,8 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 		{
 			llinfos << "Calling glCopyTexSubImage2D(...)" << llendl ;
 			checkTexSize(true) ;
-			llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height << llcallstacksendl ;
+			llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height <<
+				" : " << (S32)mComponents << llcallstacksendl ;
 		}
 
 		glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index d6622f164e68e62aaac18b67eb3efb9ba9b14019..592f7725497b1efcaceeaf2541c5772c152d9010 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -82,6 +82,7 @@ set(viewer_SOURCE_FILES
     llappviewerlistener.cpp
     llassetuploadqueue.cpp
     llassetuploadresponders.cpp
+    llattachmentsmgr.cpp
     llaudiosourcevo.cpp
     llavataractions.cpp
     llavatariconctrl.cpp
@@ -605,6 +606,7 @@ set(viewer_HEADER_FILES
     llappviewerlistener.h
     llassetuploadqueue.h
     llassetuploadresponders.h
+    llattachmentsmgr.h
     llaudiosourcevo.h
     llavataractions.h
     llavatariconctrl.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6285df31c0e03ae0cce05279e3b8fb9681be7051..b3f6f0c9f8a8824bdd5c19c79bf6c4378edb31ee 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1147,6 +1147,17 @@
       <key>Value</key>
       <string />
     </map>	
+    <key>CacheNumberOfRegionsForObjects</key>
+    <map>
+      <key>Comment</key>
+      <string>Controls number of regions to be cached for objects, ranges from 16 to 128.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>128</integer>
+    </map>
     <key>CacheSize</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 9440e877dfac4435dcac52e6c2c12cb40a5fd9e2..e3fc9d4949a536c3016db05c3269fc4f8d708224 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 22
+version 23
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -81,7 +81,7 @@ RenderTerrainDetail			1	0
 RenderTerrainLODFactor		1	1
 RenderTreeLODFactor			1	0
 RenderUseImpostors			1	1
-RenderVolumeLODFactor		1	0
+RenderVolumeLODFactor		1	0.5
 VertexShaderEnable			1	0
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index 85b8564138f58f3ccfc3f2afd3b0c1d1d74b27a9..1bad7e5260ba4f486f5038c891577de75515aa4a 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -1,4 +1,4 @@
-version 21
+version 22
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -80,7 +80,7 @@ RenderTerrainDetail			1	0
 RenderTerrainLODFactor		1	1
 RenderTreeLODFactor			1	0
 RenderUseImpostors			1	1
-RenderVolumeLODFactor		1	0
+RenderVolumeLODFactor		1	0.5
 VertexShaderEnable			1	0
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 2095f3a81d83739c6fd7499424a144ec20ad64e8..4fba47e3df7e527a494f110705048c067938d24a 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 21
+version 22
 
 // NOTE: This is mostly identical to featuretable_mac.txt with a few differences
 // Should be combined into one table
@@ -81,7 +81,7 @@ RenderTerrainDetail			1	0
 RenderTerrainLODFactor		1	1
 RenderTreeLODFactor			1	0
 RenderUseImpostors			1	1
-RenderVolumeLODFactor		1	0
+RenderVolumeLODFactor		1	0.5
 RenderWaterReflections		1	0
 VertexShaderEnable			1	0
 WindLightUseAtmosShaders	1	0
diff --git a/indra/newview/featuretable_xp.txt b/indra/newview/featuretable_xp.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9b901022c412142d744d461930fe54dc537977cb
--- /dev/null
+++ b/indra/newview/featuretable_xp.txt
@@ -0,0 +1,554 @@
+version 23
+
+// NOTE: This is mostly identical to featuretable_mac.txt with a few differences
+// Should be combined into one table
+
+//
+// Generates lists of feature mask that can be applied on top of each other.
+//
+//		//		Begin comments
+//		list <name>
+//		Starts a feature list named <name>
+//		<name> <available> <recommended>
+//		<name> is the name of a feature
+//		<available> is 0 or 1, whether the feature is available
+//		<recommended> is an F32 which is the recommended value
+//
+// For now, the first list read sets up all of the default values
+//
+
+
+//
+// All contains everything at their default settings for high end machines
+// NOTE: All settings are set to the MIN of applied values, including 'all'!
+//
+list all
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	1
+RenderAvatarLODFactor		1	1.0
+RenderAvatarMaxVisible      1   12
+RenderAvatarVP				1	1
+RenderCubeMap				1	1
+RenderDelayVBUpdate			1	0
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderFogRatio				1	4.0
+RenderGamma					1	0
+RenderGlowResolutionPow		1	9
+RenderGround				1	1
+RenderMaxPartCount			1	8192
+RenderNightBrightness		1	1.0
+RenderObjectBump			1	1
+RenderReflectionDetail		1	4
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVBOEnable				1	1
+RenderVolumeLODFactor		1	2.0
+UseStartScreen				1	1
+UseOcclusion				1	1
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+Disregard128DefaultDrawDistance	1	1
+Disregard96DefaultDrawDistance	1	1
+RenderTextureMemoryMultiple		1	1.0
+RenderShaderLightingMaxLevel	1	3
+SkyUseClassicClouds			1	1
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+WatchdogDisabled				1	1
+RenderUseStreamVBO			1	1
+
+//
+// Low Graphics Settings
+//
+list Low
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0
+RenderAvatarMaxVisible      1   3
+RenderAvatarVP				1	0
+RenderFarClip				1	64
+RenderFlexTimeFactor		1	0
+RenderGlowResolutionPow		1	8
+RenderMaxPartCount			1	0
+RenderObjectBump			1	0
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	0
+RenderTerrainLODFactor		1	1
+RenderTreeLODFactor			1	0
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	0.5
+VertexShaderEnable			1	0
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+SkyUseClassicClouds			1	0
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
+
+//
+// Mid Graphics Settings
+//
+list Mid
+RenderAnisotropic			1	0
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	0.5
+RenderAvatarVP				1	1
+RenderFarClip				1	96
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	8
+RenderMaxPartCount			1	2048
+RenderObjectBump			1	1
+RenderReflectionDetail		1	0
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	1.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	0
+WLSkyDetail					1	48
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
+
+//
+// High Graphics Settings (purty)
+//
+list High
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	0
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	128
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderMaxPartCount			1	4096
+RenderObjectBump			1	1
+RenderReflectionDetail		1	2
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	0.5
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	1.125
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	48
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
+
+//
+// Ultra graphics (REALLY PURTY!)
+//
+list Ultra
+RenderAnisotropic			1	1
+RenderAvatarCloth			1	1
+RenderAvatarLODFactor		1	1.0
+RenderAvatarVP				1	1
+RenderFarClip				1	256
+RenderFlexTimeFactor		1	1.0
+RenderGlowResolutionPow		1	9
+RenderMaxPartCount			1	8192
+RenderObjectBump			1	1
+RenderReflectionDetail		1	4
+RenderTerrainDetail			1	1
+RenderTerrainLODFactor		1	2.0
+RenderTreeLODFactor			1	1.0
+RenderUseImpostors			1	1
+RenderVolumeLODFactor		1	2.0
+VertexShaderEnable			1	1
+WindLightUseAtmosShaders	1	1
+WLSkyDetail					1	128
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
+//
+// Class Unknown Hardware (unknown)
+//
+list Unknown
+RenderVBOEnable				1	0
+
+//
+// Class 0 Hardware (just old)
+//
+list Class0
+RenderVBOEnable				1	1
+
+//
+// Class 1 Hardware
+//
+list Class1
+RenderVBOEnable				1	1
+
+//
+// Class 2 Hardware (make it purty)
+//
+list Class2
+RenderVBOEnable				1	1
+
+//
+// Class 3 Hardware (make it purty)
+//
+list Class3
+RenderVBOEnable				1	1
+
+//
+// No Pixel Shaders available
+//
+list NoPixelShaders
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderReflectionDetail		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
+
+//
+// No Vertex Shaders available
+//
+list NoVertexShaders
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+RenderReflectionDetail		0	0
+VertexShaderEnable			0	0
+WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
+
+//
+// "Default" setups for safe, low, medium, high
+//
+list safe
+RenderAnisotropic			1	0
+RenderAvatarCloth			0	0
+RenderAvatarVP				0	0
+RenderObjectBump			0	0
+RenderMaxPartCount			1	1024
+RenderTerrainDetail 		1	0
+RenderUseImpostors			0	0
+RenderVBOEnable				1	0
+RenderReflectionDetail		0	0
+WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
+
+//
+// CPU based feature masks
+//
+
+// 1Ghz or less (equiv)
+list CPUSlow
+RenderMaxPartCount			1	1024
+
+//
+// RAM based feature masks
+//
+list RAM256MB
+RenderObjectBump			0	0
+
+//
+// Graphics card based feature masks
+//
+list OpenGLPre15
+RenderVBOEnable				1	0
+
+list Intel
+RenderAnisotropic			1	0
+
+list GeForce2
+RenderAnisotropic			1	0
+RenderMaxPartCount			1	2048
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	1
+
+list SiS
+UseOcclusion				0	0
+
+
+list Intel_830M
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			0	0
+
+list Intel_845G					
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			0	0
+
+list Intel_855GM				
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			0	0
+
+list Intel_865G			
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			0	0
+
+list Intel_900		
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			0	0
+
+list Intel_915GM	
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			0	0
+
+list Intel_915G					
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			0	0
+
+list Intel_945GM			
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_945G
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_950
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_965
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+RenderUseImpostors			1	0
+UseOcclusion				0	0
+
+list Intel_G33
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_G45
+WindLightUseAtmosShaders		0	0
+
+list Intel_Bear_Lake	
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_Broadwater 
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_Brookdale	
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_Eaglelake
+WindLightUseAtmosShaders	0	0
+
+list Intel_Montara
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+list Intel_Springdale
+RenderTerrainDetail			1	0
+RenderVBOEnable				1	0
+
+
+list ATI_FireGL_5200
+RenderVBOEnable				1	0
+WindLightUseAtmosShaders	0	0
+
+
+list ATI_Mobility_Radeon_7xxx
+RenderVBOEnable				0	0
+
+list ATI_Radeon_7xxx
+RenderVBOEnable				0	0
+
+list ATI_All-in-Wonder_Radeon
+RenderVBOEnable				0	0
+
+list ATI_All-in-Wonder_7500
+RenderVBOEnable				0	0
+
+list ATI_Mobility_Radeon_9600
+Disregard96DefaultDrawDistance	1	0
+
+
+/// tweaked ATI to 96 Draw distance
+
+list ATI_Radeon_9000
+Disregard96DefaultDrawDistance	1	0
+list ATI_Radeon_9200
+Disregard96DefaultDrawDistance	1	0
+list ATI_Radeon_9500
+Disregard96DefaultDrawDistance	1	0
+list ATI_Radeon_9600
+Disregard96DefaultDrawDistance	1	0
+
+/// tweaked ATI to 128 draw distance
+
+list ATI_Radeon_X300 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Radeon_X400 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Radeon_X500 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Radeon_X600 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Radeon_X700 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Radeon_X1300 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+UseStartScreen					0	0
+list ATI_Radeon_X1400 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Radeon_X1500 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+UseStartScreen					0	0
+list ATI_Radeon_X1600 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Radeon_X1700 
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+list ATI_Mobility_Radeon_X1xxx
+Disregard128DefaultDrawDistance	1	0
+RenderVBOEnable				1	0
+
+list ATI_Radeon_HD_2300
+Disregard128DefaultDrawDistance	1	0
+list ATI_Radeon_HD_2400
+Disregard128DefaultDrawDistance	1	0
+list ATI_ASUS_AH24xx
+Disregard128DefaultDrawDistance	1	0
+
+
+// Avatar hardware skinning causes invisible avatars
+// on various ATI chipsets on drivers before 8.2
+
+list ATIOldDriver
+RenderAvatarVP				0	0
+RenderAvatarCloth			0	0
+
+// ATI cards generally perform better when not using VBOs for streaming data
+
+list ATI
+RenderUseStreamVBO			1	0
+
+/// Tweaked NVIDIA
+
+list NVIDIA_GeForce_FX_5100
+Disregard96DefaultDrawDistance	1	0
+list NVIDIA_GeForce_FX_5200
+Disregard96DefaultDrawDistance	1	0
+list NVIDIA_GeForce_FX_5500
+Disregard96DefaultDrawDistance	1	0
+list NVIDIA_GeForce_FX_5600
+Disregard96DefaultDrawDistance	1	0
+
+list NVIDIA_GeForce_FX_Go5100
+Disregard96DefaultDrawDistance	1	0
+list NVIDIA_GeForce_FX_Go5200
+Disregard96DefaultDrawDistance	1	0
+list NVIDIA_GeForce_FX_Go5300
+Disregard96DefaultDrawDistance	1	0
+list NVIDIA_GeForce_FX_Go5500
+Disregard96DefaultDrawDistance	1	0
+list NVIDIA_GeForce_FX_Go5600
+Disregard96DefaultDrawDistance	1	0
+
+list NVIDIA_GeForce_6100
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_6200
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_6500
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_6600
+Disregard128DefaultDrawDistance	1	0
+
+list NVIDIA_G73
+Disregard128DefaultDrawDistance	1	0
+
+list NVIDIA_GeForce_Go_6100
+RenderVBOEnable				1	0
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_Go_6200
+RenderVBOEnable				1	0
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_Go_6500
+RenderVBOEnable				1	0
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_Go_6600
+RenderVBOEnable				1	0
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_Go_6700
+RenderVBOEnable				1	0
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_Go_6800
+RenderVBOEnable				1	0
+Disregard128DefaultDrawDistance	1	0
+list NVIDIA_GeForce_Go_6
+RenderVBOEnable				1	0
+Disregard128DefaultDrawDistance	1	0
+
+list NVIDIA_GeForce_7000
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7100
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7200
+Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7300
+Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7400
+Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7500
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7600
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7700
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7800
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7900
+RenderShaderLightingMaxLevel	1	2
+
+list NVIDIA_GeForce_Go_7200
+Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7300
+Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7300_LE
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7400
+Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7600
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7700
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7800
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7900
+RenderShaderLightingMaxLevel	1	2
+
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index dd08e6c49a53e4ad47807bd77c9169b8e27f1887..055be4cae28a0a75e03a6e2cad1bde6c028bf308 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -1882,7 +1882,7 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra
 		msg->nextBlockFast(_PREHASH_ObjectData );
 		msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
 		msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
-		msg->addU8Fast(_PREHASH_AttachmentPt, 0 );	// Wear at the previous or default attachment point
+		msg->addU8Fast(_PREHASH_AttachmentPt, 0 | ATTACHMENT_ADD);	// Wear at the previous or default attachment point
 		pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
 		msg->addStringFast(_PREHASH_Name, item->getName());
 		msg->addStringFast(_PREHASH_Description, item->getDescription());
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 7159d89d21d09b201e214794a6e4d9928977e5f2..ed5e8ceee33af72f99e9b82aef171bfb919d730b 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -31,6 +31,7 @@
 #include "llagentcamera.h"
 #include "llagentwearables.h"
 #include "llappearancemgr.h"
+#include "llattachmentsmgr.h"
 #include "llcommandhandler.h"
 #include "lleventtimer.h"
 #include "llgesturemgr.h"
@@ -2644,6 +2645,8 @@ LLAppearanceMgr::LLAppearanceMgr():
 
 	mUnlockOutfitTimer.reset(new LLOutfitUnLockTimer(gSavedSettings.getS32(
 			"OutfitOperationsTimeout")));
+
+	gIdleCallbacks.addFunction(&LLAttachmentsMgr::onIdle,NULL);
 }
 
 LLAppearanceMgr::~LLAppearanceMgr()
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index bfe3e52657019fbb34f4f832005bf51a5706d821..fd6b8b739dc669c94af2ae70e18f1f6e7d5eaf5d 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3025,14 +3025,6 @@ void LLAppViewer::migrateCacheDirectory()
 #endif // LL_WINDOWS || LL_DARWIN
 }
 
-//static
-S32 LLAppViewer::getCacheVersion() 
-{
-	static const S32 cache_version = 7;
-
-	return cache_version ;
-}
-
 void dumpVFSCaches()
 {
 	llinfos << "======= Static VFS ========" << llendl;
@@ -3071,23 +3063,40 @@ void dumpVFSCaches()
 	SetCurrentDirectory(w_str);
 #endif
 }
+
+//static
+U32 LLAppViewer::getTextureCacheVersion() 
+{
+	//viewer texture cache version, change if the texture cache format changes.
+	const U32 TEXTURE_CACHE_VERSION = 7;
+
+	return TEXTURE_CACHE_VERSION ;
+}
+
+//static
+U32 LLAppViewer::getObjectCacheVersion() 
+{
+	// Viewer object cache version, change if object update
+	// format changes. JC
+	const U32 INDRA_OBJECT_CACHE_VERSION = 14;
+
+	return INDRA_OBJECT_CACHE_VERSION;
+}
+
 bool LLAppViewer::initCache()
 {
 	mPurgeCache = false;
-	BOOL disable_texture_cache = FALSE ;
 	BOOL read_only = mSecondInstance ? TRUE : FALSE;
 	LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
+	LLVOCache::getInstance()->setReadOnly(read_only);
 
-	if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getCacheVersion()) 
+	BOOL texture_cache_mismatch = FALSE ;
+	if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) 
 	{
-		if(read_only) 
+		texture_cache_mismatch = TRUE ;
+		if(!read_only) 
 		{
-			disable_texture_cache = TRUE ; //if the cache version of this viewer is different from the running one, this viewer can not use the texture cache.
-		}
-		else
-		{
-			mPurgeCache = true; // Purge cache if the version number is different.
-			gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getCacheVersion());
+			gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion());
 		}
 	}
 
@@ -3138,9 +3147,11 @@ bool LLAppViewer::initCache()
 	const S64 MAX_CACHE_SIZE = 1024*MB;
 	cache_size = llmin(cache_size, MAX_CACHE_SIZE);
 	S64 texture_cache_size = ((cache_size * 8)/10);
-	S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, disable_texture_cache);
+	S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
 	texture_cache_size -= extra;
 
+	LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()) ;
+
 	LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS"));
 	
 	// Init the VFS
@@ -3303,6 +3314,7 @@ void LLAppViewer::purgeCache()
 {
 	LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl;
 	LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
+	LLVOCache::getInstance()->removeCache(LL_PATH_CACHE);
 	std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
 	gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
 }
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 1fcf38d18ad8ffd41a43a4e378ff113ffc73acaf..c5cac6827c8a1f1a6d6400f615446bc8fb1463c9 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -94,7 +94,8 @@ class LLAppViewer : public LLApp
 	static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }
 	static LLTextureFetch* getTextureFetch() { return sTextureFetch; }
 
-	static S32 getCacheVersion() ;
+	static U32 getTextureCacheVersion() ;
+	static U32 getObjectCacheVersion() ;
 
 	const std::string& getSerialNumber() { return mSerialNumber; }
 	
diff --git a/indra/newview/llattachmentsmgr.cpp b/indra/newview/llattachmentsmgr.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c9543988a68b212751730df554946ac92bf3074b
--- /dev/null
+++ b/indra/newview/llattachmentsmgr.cpp
@@ -0,0 +1,131 @@
+/** 
+ * @file llattachmentsmgr.cpp
+ * @brief Manager for initiating attachments changes on the viewer
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llattachmentsmgr.h"
+
+#include "llagent.h"
+#include "llinventorymodel.h"
+#include "lltooldraganddrop.h" // pack_permissions_slam
+#include "llviewerinventory.h"
+#include "llviewerregion.h"
+#include "message.h"
+
+
+LLAttachmentsMgr::LLAttachmentsMgr()
+{
+}
+
+LLAttachmentsMgr::~LLAttachmentsMgr()
+{
+}
+
+void LLAttachmentsMgr::addAttachment(const LLUUID& item_id,
+									 const U8 attachment_pt,
+									 const BOOL add)
+{
+	AttachmentsInfo attachment;
+	attachment.mItemID = item_id;
+	attachment.mAttachmentPt = attachment_pt;
+	attachment.mAdd = add;
+	mPendingAttachments.push_back(attachment);
+}
+
+// static
+void LLAttachmentsMgr::onIdle(void *)
+{
+	LLAttachmentsMgr::instance().onIdle();
+}
+
+void LLAttachmentsMgr::onIdle()
+{
+	S32 obj_count = mPendingAttachments.size();
+	if (obj_count == 0)
+	{
+		return;
+	}
+	
+	// Limit number of packets to send
+	const S32 MAX_PACKETS_TO_SEND = 10;
+	const S32 OBJECTS_PER_PACKET = 4;
+	const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
+	if( obj_count > MAX_OBJECTS_TO_SEND )
+	{
+		obj_count = MAX_OBJECTS_TO_SEND;
+	}
+
+	LLUUID compound_msg_id;
+	compound_msg_id.generate();
+	LLMessageSystem* msg = gMessageSystem;
+
+	
+	S32 i = 0;
+	for (attachments_vec_t::const_iterator iter = mPendingAttachments.begin();
+		 iter != mPendingAttachments.end();
+		 ++iter)
+	{
+		if( 0 == (i % OBJECTS_PER_PACKET) )
+		{
+			// Start a new message chunk
+			msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv);
+			msg->nextBlockFast(_PREHASH_AgentData);
+			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+			msg->nextBlockFast(_PREHASH_HeaderData);
+			msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id );
+			msg->addU8Fast(_PREHASH_TotalObjects, obj_count );
+			msg->addBOOLFast(_PREHASH_FirstDetachAll, false );
+		}
+
+		const AttachmentsInfo &attachment = (*iter);
+		LLViewerInventoryItem* item = gInventory.getItem(attachment.mItemID);
+		if (!item)
+		{
+			llinfos << "Attempted to add non-existant item ID:" << attachment.mItemID << llendl;
+			continue;
+		}
+		S32 attachment_pt = attachment.mAttachmentPt;
+		if (attachment.mAdd) 
+			attachment_pt |= ATTACHMENT_ADD;
+
+		msg->nextBlockFast(_PREHASH_ObjectData );
+		msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
+		msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
+		msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
+		pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
+		msg->addStringFast(_PREHASH_Name, item->getName());
+		msg->addStringFast(_PREHASH_Description, item->getDescription());
+
+		if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
+		{
+			// End of message chunk
+			msg->sendReliable( gAgent.getRegion()->getHost() );
+		}
+		i++;
+	}
+
+	mPendingAttachments.clear();
+}
diff --git a/indra/newview/llattachmentsmgr.h b/indra/newview/llattachmentsmgr.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d8ab74dfd9b6caa739f60b9bcb7d2ece67947d8
--- /dev/null
+++ b/indra/newview/llattachmentsmgr.h
@@ -0,0 +1,73 @@
+/** 
+ * @file llattachmentsmgr.h
+ * @brief Batches up attachment requests and sends them all
+ * in one message.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLATTACHMENTSMGR_H
+#define LL_LLATTACHMENTSMGR_H
+
+#include "llsingleton.h"
+
+class LLViewerInventoryItem;
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// LLAttachmentsMgr
+// 
+// The sole purpose of this class is to take attachment
+// requests, queue them up, and send them all at once.
+// This handles situations where the viewer may request
+// a bunch of attachments at once in a short period of
+// time, where each of the requests would normally be
+// sent as a separate message versus being batched into
+// one single message.
+// 
+// The intent of this batching is to reduce viewer->server
+// traffic.
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLAttachmentsMgr: public LLSingleton<LLAttachmentsMgr>
+{
+public:
+	LLAttachmentsMgr();
+	virtual ~LLAttachmentsMgr();
+
+	void addAttachment(const LLUUID& item_id,
+					   const U8 attachment_pt,
+					   const BOOL add);
+	static void onIdle(void *);
+protected:
+	void onIdle();
+private:
+	struct AttachmentsInfo
+	{
+		LLUUID mItemID;
+		U8 mAttachmentPt;
+		BOOL mAdd;
+	};
+
+	typedef std::vector<AttachmentsInfo> attachments_vec_t;
+	attachments_vec_t mPendingAttachments;
+};
+
+#endif
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index ed35546ca31e911165b685818dda4a5114a699fb..a3d2941114f39d4124e0cc9b550202676debb977 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -54,6 +54,13 @@ LLViewerDynamicTexture::LLViewerDynamicTexture(S32 width, S32 height, S32 compon
 {
 	llassert((1 <= components) && (components <= 4));
 
+	if(gGLManager.mDebugGPU)
+	{
+		if(components == 3)
+		{
+			mComponents = 4 ; //convert to 32bits.
+		}
+	}
 	generateGLTexture();
 
 	llassert( 0 <= order && order < ORDER_COUNT );
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 03cfc6764a8479f2bd20a16f3609a5fc4bcfd90f..ca2ef5f5b8e1bdafcf462cccf502359253947c76 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -67,8 +67,8 @@ const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_linux.%s.txt";
 const char FEATURE_TABLE_FILENAME[] = "featuretable_solaris.txt";
 const char FEATURE_TABLE_VER_FILENAME[] = "featuretable_solaris.%s.txt";
 #else
-const char FEATURE_TABLE_FILENAME[] = "featuretable.txt";
-const char FEATURE_TABLE_VER_FILENAME[] = "featuretable.%s.txt";
+const char FEATURE_TABLE_FILENAME[] = "featuretable%s.txt";
+const char FEATURE_TABLE_VER_FILENAME[] = "featuretable%s.%s.txt";
 #endif
 
 const char GPU_TABLE_FILENAME[] = "gpu_table.txt";
@@ -220,10 +220,30 @@ BOOL LLFeatureManager::loadFeatureTables()
 	// first table is install with app
 	std::string app_path = gDirUtilp->getAppRODataDir();
 	app_path += gDirUtilp->getDirDelimiter();
-	app_path += FEATURE_TABLE_FILENAME;
 
+	std::string filename;
+	std::string http_filename; 
+#if LL_WINDOWS
+	std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
+	if (os_string.find("Microsoft Windows XP") == 0)
+	{
+		filename = llformat(FEATURE_TABLE_FILENAME, "_xp");
+		http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "_xp", LLVersionInfo::getVersion().c_str());
+	}
+	else
+	{
+		filename = llformat(FEATURE_TABLE_FILENAME, "");
+		http_filename = llformat(FEATURE_TABLE_VER_FILENAME, "", LLVersionInfo::getVersion().c_str());
+	}
+#else
+	filename = FEATURE_TABLE_FILENAME;
+	http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
+#endif
+
+	app_path += filename;
+
+	
 	// second table is downloaded with HTTP
-	std::string http_filename = llformat(FEATURE_TABLE_VER_FILENAME, LLVersionInfo::getVersion().c_str());
 	std::string http_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, http_filename);
 
 	// use HTTP table if it exists
@@ -488,7 +508,35 @@ class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder
 	std::string mFilename;
 };
 
-void fetch_table(std::string table)
+void fetch_feature_table(std::string table)
+{
+	const std::string base       = gSavedSettings.getString("FeatureManagerHTTPTable");
+
+#if LL_WINDOWS
+	std::string os_string = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
+	std::string filename;
+	if (os_string.find("Microsoft Windows XP") == 0)
+	{
+		filename = llformat(table.c_str(), "_xp", LLVersionInfo::getVersion().c_str());
+	}
+	else
+	{
+		filename = llformat(table.c_str(), "", LLVersionInfo::getVersion().c_str());
+	}
+#else
+	const std::string filename   = llformat(table.c_str(), LLVersionInfo::getVersion().c_str());
+#endif
+
+	const std::string url        = base + "/" + filename;
+
+	const std::string path       = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, filename);
+
+	llinfos << "LLFeatureManager fetching " << url << " into " << path << llendl;
+	
+	LLHTTPClient::get(url, new LLHTTPFeatureTableResponder(path));
+}
+
+void fetch_gpu_table(std::string table)
 {
 	const std::string base       = gSavedSettings.getString("FeatureManagerHTTPTable");
 
@@ -506,8 +554,8 @@ void fetch_table(std::string table)
 // fetch table(s) from a website (S3)
 void LLFeatureManager::fetchHTTPTables()
 {
-	fetch_table(FEATURE_TABLE_VER_FILENAME);
-	fetch_table(GPU_TABLE_VER_FILENAME);
+	fetch_feature_table(FEATURE_TABLE_VER_FILENAME);
+	fetch_gpu_table(GPU_TABLE_VER_FILENAME);
 }
 
 
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index aff0bc409976dc0b8f3dc47dac7e48a6b300d7a1..02e7f0b9e2b65d3d47ba64b77a2b8d3b1b4200cf 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -28,19 +28,20 @@
 #include "llinventorybridge.h"
 
 // external projects
-#include "lltransfersourceasset.h"
+#include "lltransfersourceasset.h" 
 
 #include "llagent.h"
 #include "llagentcamera.h"
 #include "llagentwearables.h"
 #include "llappearancemgr.h"
-#include "llavataractions.h"
+#include "llattachmentsmgr.h"
+#include "llavataractions.h" 
 #include "llfloateropenobject.h"
 #include "llfloaterreg.h"
 #include "llfloaterworldmap.h"
 #include "llfriendcard.h"
 #include "llgesturemgr.h"
-#include "llgiveinventory.h"
+#include "llgiveinventory.h" 
 #include "llimfloater.h"
 #include "llimview.h"
 #include "llinventoryclipboard.h"
@@ -100,7 +101,7 @@ void dec_busy_count()
 void remove_inventory_category_from_avatar(LLInventoryCategory* category);
 void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id);
 bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*);
-bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response);
+bool confirm_attachment_rez(const LLSD& notification, const LLSD& response);
 void teleport_via_landmark(const LLUUID& asset_id);
 
 // +=================================================+
@@ -3978,22 +3979,22 @@ std::string LLObjectBridge::getLabelSuffix() const
 {
 	if (get_is_item_worn(mUUID))
 	{
-		if (!isAgentAvatarValid())
+		if (!isAgentAvatarValid()) // Error condition, can't figure out attach point
 		{
 			return LLItemBridge::getLabelSuffix() + LLTrans::getString("worn");
 		}
-
 		std::string attachment_point_name = gAgentAvatarp->getAttachedPointName(mUUID);
-
+		if (attachment_point_name == LLStringUtil::null) // Error condition, invalid attach point
+		{
+			attachment_point_name = "Invalid Attachment";
+		}
 		// e.g. "(worn on ...)" / "(attached to ...)"
 		LLStringUtil::format_map_t args;
 		args["[ATTACHMENT_POINT]"] =  LLTrans::getString(attachment_point_name);
+
 		return LLItemBridge::getLabelSuffix() + LLTrans::getString("WornOnAttachmentPoint", args);
 	}
-	else
-	{
-		return LLItemBridge::getLabelSuffix();
-	}
+	return LLItemBridge::getLabelSuffix();
 }
 
 void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment, bool replace)
@@ -4024,19 +4025,15 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach
 		}
 	}
 
-	if (!replace)
-	{
-		attach_pt |= ATTACHMENT_ADD;
-	}
-
 	LLSD payload;
 	payload["item_id"] = item_id; // Wear the base object in case this is a link.
 	payload["attachment_point"] = attach_pt;
+	payload["is_add"] = !replace;
 
 	if (replace &&
 		(attachment && attachment->getNumObjects() > 0))
 	{
-		LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_replace_attachment_rez);
+		LLNotificationsUtil::add("ReplaceAttachment", LLSD(), payload, confirm_attachment_rez);
 	}
 	else
 	{
@@ -4044,7 +4041,7 @@ void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attach
 	}
 }
 
-bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response)
+bool confirm_attachment_rez(const LLSD& notification, const LLSD& response)
 {
 	if (!gAgentAvatarp->canAttachMoreObjects())
 	{
@@ -4062,27 +4059,41 @@ bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& respon
 
 		if (itemp)
 		{
+			/*
+			{
+				U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
+				
+				LLMessageSystem* msg = gMessageSystem;
+				msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
+				msg->nextBlockFast(_PREHASH_AgentData);
+				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+				msg->nextBlockFast(_PREHASH_ObjectData);
+				msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());
+				msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner());
+				msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
+				pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());
+				msg->addStringFast(_PREHASH_Name, itemp->getName());
+				msg->addStringFast(_PREHASH_Description, itemp->getDescription());
+				msg->sendReliable(gAgent.getRegion()->getHost());
+				return false;
+			}
+			*/
+
+			// Queue up attachments to be sent in next idle tick, this way the
+			// attachments are batched up all into one message versus each attachment
+			// being sent in its own separate attachments message.
 			U8 attachment_pt = notification["payload"]["attachment_point"].asInteger();
-			
+			BOOL is_add = notification["payload"]["is_add"].asBoolean();
 
-			LLMessageSystem* msg = gMessageSystem;
-			msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
-			msg->nextBlockFast(_PREHASH_AgentData);
-			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-			msg->nextBlockFast(_PREHASH_ObjectData);
-			msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());
-			msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner());
-			msg->addU8Fast(_PREHASH_AttachmentPt, attachment_pt);
-			pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());
-			msg->addStringFast(_PREHASH_Name, itemp->getName());
-			msg->addStringFast(_PREHASH_Description, itemp->getDescription());
-			msg->sendReliable(gAgent.getRegion()->getHost());
+			LLAttachmentsMgr::instance().addAttachment(item_id,
+													   attachment_pt,
+													   is_add);
 		}
 	}
 	return false;
 }
-static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_replace_attachment_rez);
+static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("ReplaceAttachment", confirm_attachment_rez);
 
 void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 {
diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp
index 021790648d634abbe318c9f8a8c6ec01b07e2bcb..7216d61e7fc3197255b5be8d849aa5c53cfc68da 100644
--- a/indra/newview/llinventoryicon.cpp
+++ b/indra/newview/llinventoryicon.cpp
@@ -85,6 +85,8 @@ LLIconDictionary::LLIconDictionary()
 	addEntry(LLInventoryIcon::ICONNAME_LINKITEM, 				new IconEntry("Inv_LinkItem"));
 	addEntry(LLInventoryIcon::ICONNAME_LINKFOLDER, 				new IconEntry("Inv_LinkItem"));
 
+	addEntry(LLInventoryIcon::ICONNAME_INVALID, 				new IconEntry("Inv_Invalid"));
+
 	addEntry(LLInventoryIcon::ICONNAME_NONE, 					new IconEntry("NONE"));
 }
 
diff --git a/indra/newview/llinventoryicon.h b/indra/newview/llinventoryicon.h
index 3c7ac7f6093652b1b73d9a187424bcade2969e0e..9a2cc080955577616c3c7f8b30f191a894a43e8c 100644
--- a/indra/newview/llinventoryicon.h
+++ b/indra/newview/llinventoryicon.h
@@ -73,8 +73,8 @@ class LLInventoryIcon
 		ICONNAME_LINKITEM,
 		ICONNAME_LINKFOLDER,
 
+		ICONNAME_INVALID,
 		ICONNAME_COUNT,
-
 		ICONNAME_NONE = -1
 	};
 
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 2fd0a22f809d056d3a261bc3e1af031b2f688255..6a213309a0bff583ceb3b205df5fd4189ee01b40 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -927,7 +927,7 @@ void LLTextureCache::setReadOnly(BOOL read_only)
 }
 
 //called in the main thread.
-S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_texture_cache)
+S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache_mismatch)
 {
 	llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
 
@@ -942,20 +942,23 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_textu
 		sCacheMaxTexturesSize = max_size;
 	max_size -= sCacheMaxTexturesSize;
 	
-	if(disable_texture_cache) //the texture cache is disabled
-	{
-		llinfos << "The texture cache is disabled!" << llendl ;
-		setReadOnly(TRUE) ;
-		purgeAllTextures(true); 
-
-		return max_size ;
-	}
-
 	LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries
 			<< " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL;
 
 	setDirNames(location);
 	
+	if(texture_cache_mismatch) 
+	{
+		//if readonly, disable the texture cache,
+		//otherwise wipe out the texture cache.
+		purgeAllTextures(true); 
+
+		if(mReadOnly)
+		{
+			return max_size ;
+		}
+	}
+	
 	if (!mReadOnly)
 	{
 		LLFile::mkdir(mTexturesDirName);
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 7f1bba56fb9335ffaf140441443f9acacffc5b44..64e3a2658c38565f1b8f32253fdb50621ed90773 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -105,7 +105,7 @@ class LLTextureCache : public LLWorkerThread
 	
 	void purgeCache(ELLPath location);
 	void setReadOnly(BOOL read_only) ;
-	S64 initCache(ELLPath location, S64 maxsize, BOOL disable_texture_cache);
+	S64 initCache(ELLPath location, S64 maxsize, BOOL texture_cache_mismatch);
 
 	handle_t readFromCache(const std::string& local_filename, const LLUUID& id, U32 priority, S32 offset, S32 size,
 						   ReadResponder* responder);
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 6a75e4b00998fd696f17dc0eb29c241158b6aad4..c87aff022fcee4d572818b5aa9d8b7b92009033d 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -48,6 +48,7 @@
 #include "llviewertexture.h"
 #include "llviewertexturelist.h"
 #include "llvovolume.h"
+#include "llviewerstats.h"
 
 // For avatar texture view
 #include "llvoavatarself.h"
@@ -513,6 +514,7 @@ void LLGLTexMemBar::draw()
 	F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ;
 	S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
 	S32 v_offset = (S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f);
+	S32 total_downloaded = BYTES_TO_MEGA_BYTES(gTotalTextureBytes);
 	//----------------------------------------------------------------------------
 	LLGLSUIDefault gls_ui;
 	LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
@@ -523,13 +525,13 @@ void LLGLTexMemBar::draw()
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6,
 											 text_color, LLFontGL::LEFT, LLFontGL::TOP);
 
-	text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
+	text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot: %d MB",
 					total_mem,
 					max_total_mem,
 					bound_mem,
 					max_bound_mem,
-					LLImageRaw::sGlobalRawMemory >> 20,					discard_bias,
-					cache_usage, cache_max_usage);
+					LLImageRaw::sGlobalRawMemory >> 20,	discard_bias,
+					cache_usage, cache_max_usage, total_downloaded);
 	//, cache_entries, cache_max_entries
 
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3,
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index a86efa215b1c9a6ae29c4840d253190af2f6d344..98f16757b2b49a4c6d2819398b634ce62a9340cb 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -69,13 +69,6 @@
 	#pragma warning(disable:4355)
 #endif
 
-// Viewer object cache version, change if object update
-// format changes. JC
-const U32 INDRA_OBJECT_CACHE_VERSION = 14;
-
-// Format string used to construct filename for the object cache
-static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
-
 extern BOOL gNoRender;
 
 const F32 WATER_TEXTURE_SCALE = 8.f;			//  Number of times to repeat the water texture across a region
@@ -214,7 +207,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	mProductName("unknown"),
 	mHttpUrl(""),
 	mCacheLoaded(FALSE),
-	mCacheEntriesCount(0),
+	mCacheDirty(FALSE),
 	mCacheID(),
 	mEventPoll(NULL),
 	mReleaseNotesRequested(FALSE),
@@ -264,8 +257,6 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,
 	// Create the object lists
 	initStats();
 
-	mCacheStart.append(mCacheEnd);
-	
 	//create object partitions
 	//MUST MATCH declaration of eObjectPartitions
 	mObjectPartition.push_back(new LLHUDPartition());		//PARTITION_HUD
@@ -324,19 +315,6 @@ LLViewerRegion::~LLViewerRegion()
 	std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer());
 }
 
-
-const std::string LLViewerRegion::getObjectCacheFilename(U64 mHandle) const
-{
-	std::string filename;
-	U32 region_x, region_y;
-
-	grid_from_region_handle(mHandle, &region_x, &region_y);
-	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,
-			   llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
-
-	return filename;
-}
-
 void LLViewerRegion::loadObjectCache()
 {
 	if (mCacheLoaded)
@@ -347,77 +325,10 @@ void LLViewerRegion::loadObjectCache()
 	// Presume success.  If it fails, we don't want to try again.
 	mCacheLoaded = TRUE;
 
-	LLVOCacheEntry *entry;
-
-	std::string filename = getObjectCacheFilename(mHandle);
-	LL_DEBUGS("ObjectCache") << filename << LL_ENDL;
-
-	LLFILE* fp = LLFile::fopen(filename, "rb");		/* Flawfinder: ignore */
-	if (!fp)
-	{
-		// might not have a file, which is normal
-		return;
-	}
-
-	U32 zero;
-	size_t nread;
-	nread = fread(&zero, sizeof(U32), 1, fp);
-	if (nread != 1 || zero)
-	{
-		// a non-zero value here means bad things!
-		// skip reading the cached values
-		llinfos << "Cache file invalid" << llendl;
-		fclose(fp);
-		return;
-	}
-
-	U32 version;
-	nread = fread(&version, sizeof(U32), 1, fp);
-	if (nread != 1 || version != INDRA_OBJECT_CACHE_VERSION)
+	if(LLVOCache::hasInstance())
 	{
-		// a version mismatch here means we've changed the binary format!
-		// skip reading the cached values
-		llinfos << "Cache version changed, discarding" << llendl;
-		fclose(fp);
-		return;
-	}
-
-	LLUUID cache_id;
-	nread = fread(&cache_id.mData, 1, UUID_BYTES, fp);
-	if (nread != (size_t)UUID_BYTES || mCacheID != cache_id)
-	{
-		llinfos << "Cache ID doesn't match for this region, discarding"
-			<< llendl;
-		fclose(fp);
-		return;
-	}
-
-	S32 num_entries;
-	nread = fread(&num_entries, sizeof(S32), 1, fp);
-	if (nread != 1)
-	{
-		llinfos << "Short read, discarding" << llendl;
-		fclose(fp);
-		return;
+		LLVOCache::getInstance()->readFromCache(mHandle, mCacheID, mCacheMap) ;
 	}
-	
-	S32 i;
-	for (i = 0; i < num_entries; i++)
-	{
-		entry = new LLVOCacheEntry(fp);
-		if (!entry->getLocalID())
-		{
-			llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
-			delete entry;
-			entry = NULL;
-			break;
-		}
-		mCacheEnd.insert(*entry);
-		mCacheMap[entry->getLocalID()] = entry;
-		mCacheEntriesCount++;
-	}
-
-	fclose(fp);
 }
 
 
@@ -428,61 +339,22 @@ void LLViewerRegion::saveObjectCache()
 		return;
 	}
 
-	S32 num_entries = mCacheEntriesCount;
-	if (0 == num_entries)
+	if (mCacheMap.empty())
 	{
 		return;
 	}
 
-	std::string filename = getObjectCacheFilename(mHandle);
-	LL_DEBUGS("ObjectCache") << filename << LL_ENDL;
-
-	LLFILE* fp = LLFile::fopen(filename, "wb");		/* Flawfinder: ignore */
-	if (!fp)
+	if(LLVOCache::hasInstance())
 	{
-		llwarns << "Unable to write cache file " << filename << llendl;
-		return;
+		LLVOCache::getInstance()->writeToCache(mHandle, mCacheID, mCacheMap, mCacheDirty) ;
+		mCacheDirty = FALSE;
 	}
 
-	// write out zero to indicate a version cache file
-	U32 zero = 0;
-	if (fwrite(&zero, sizeof(U32), 1, fp) != 1)
+	for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter)
 	{
-		llwarns << "Short write" << llendl;
+		delete iter->second;
 	}
-
-	// write out version number
-	U32 version = INDRA_OBJECT_CACHE_VERSION;
-	if (fwrite(&version, sizeof(U32), 1, fp) != 1)
-	{
-		llwarns << "Short write" << llendl;
-	}
-
-	// write the cache id for this sim
-	if (fwrite(&mCacheID.mData, 1, UUID_BYTES, fp) != (size_t)UUID_BYTES)
-	{
-		llwarns << "Short write" << llendl;
-	}
-
-	if (fwrite(&num_entries, sizeof(S32), 1, fp) != 1)
-	{
-		llwarns << "Short write" << llendl;
-	}
-
-	LLVOCacheEntry *entry;
-
-	for (entry = mCacheStart.getNext(); entry && (entry != &mCacheEnd); entry = entry->getNext())
-	{
-		entry->writeToFile(fp);
-	}
-
 	mCacheMap.clear();
-	mCacheEnd.unlink();
-	mCacheEnd.init();
-	mCacheStart.deleteAll();
-	mCacheStart.init();
-
-	fclose(fp);
 }
 
 void LLViewerRegion::sendMessage()
@@ -1175,7 +1047,6 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary
 			mCacheMap.erase(local_id);
 			delete entry;
 			entry = new LLVOCacheEntry(local_id, crc, dp);
-			mCacheEnd.insert(*entry);
 			mCacheMap[local_id] = entry;
 		}
 	}
@@ -1184,18 +1055,13 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary
 		// we haven't seen this object before
 
 		// Create new entry and add to map
-		if (mCacheEntriesCount > MAX_OBJECT_CACHE_ENTRIES)
+		if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)
 		{
-			entry = mCacheStart.getNext();
-			mCacheMap.erase(entry->getLocalID());
-			delete entry;
-			mCacheEntriesCount--;
+			mCacheMap.erase(mCacheMap.begin());
 		}
 		entry = new LLVOCacheEntry(local_id, crc, dp);
 
-		mCacheEnd.insert(*entry);
 		mCacheMap[local_id] = entry;
-		mCacheEntriesCount++;
 	}
 	return ;
 }
@@ -1310,6 +1176,7 @@ void LLViewerRegion::requestCacheMisses()
 	mCacheMissFull.reset();
 	mCacheMissCRC.reset();
 
+	mCacheDirty = TRUE ;
 	// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;
 }
 
@@ -1327,9 +1194,10 @@ void LLViewerRegion::dumpCache()
 	}
 
 	LLVOCacheEntry *entry;
-
-	for (entry = mCacheStart.getNext(); entry && (entry != &mCacheEnd); entry = entry->getNext())
+	for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter)
 	{
+		entry = iter->second ;
+
 		S32 hits = entry->getHitCount();
 		S32 changes = entry->getCRCChangeCount();
 
@@ -1340,7 +1208,7 @@ void LLViewerRegion::dumpCache()
 		change_bin[changes]++;
 	}
 
-	llinfos << "Count " << mCacheEntriesCount << llendl;
+	llinfos << "Count " << mCacheMap.size() << llendl;
 	for (i = 0; i < BINS; i++)
 	{
 		llinfos << "Hits " << i << " " << hit_bin[i] << llendl;
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 361ae87e1b9b087d96ba2f9ddcd4764fe53470d1..038c831e59dd1b9b6cfa9091573f4d02f5d8591f 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -323,9 +323,6 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	LLDynamicArray<LLUUID> mMapAvatarIDs;
 
 private:
-	// determine the cache filename for the region from the region handle
-	const std::string getObjectCacheFilename(U64 mHandle) const;
-
 	// The surfaces and other layers
 	LLSurface*	mLandp;
 
@@ -387,11 +384,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	// Regions can have order 10,000 objects, so assume
 	// a structure of size 2^14 = 16,000
 	BOOL									mCacheLoaded;
-	typedef std::map<U32, LLVOCacheEntry *>	cache_map_t;
-	cache_map_t			  				 	mCacheMap;
-	LLVOCacheEntry							mCacheStart;
-	LLVOCacheEntry							mCacheEnd;
-	U32										mCacheEntriesCount;
+	BOOL                                    mCacheDirty;
+	LLVOCacheEntry::vocache_entry_map_t		mCacheMap;
 	LLDynamicArray<U32>						mCacheMissFull;
 	LLDynamicArray<U32>						mCacheMissCRC;
 	// time?
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index 5d8f58d5e9a42054ab74689325b6c69b23a02748..ca977d45999ea73dc391ce20c9dd4771a397edeb 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -263,5 +263,5 @@ void send_stats();
 
 extern std::map<S32,LLFrameTimer> gDebugTimers;
 extern std::map<S32,std::string> gDebugTimerLabel;
-
+extern U32	gTotalTextureBytes;
 #endif // LL_LLVIEWERSTATS_H
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 556451e3906a036decf70aad23559dd818bb59b5..43d18c6d838e91faa3e4c638fe40898ecd39c5d8 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3911,7 +3911,14 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei
 		image_buffer_x = llfloor(snapshot_width*scale_factor) ;
 		image_buffer_y = llfloor(snapshot_height *scale_factor) ;
 	}
-	raw->resize(image_buffer_x, image_buffer_y, 3);
+	if(image_buffer_x > 0 && image_buffer_y > 0)
+	{
+		raw->resize(image_buffer_x, image_buffer_y, 3);
+	}
+	else
+	{
+		return FALSE ;
+	}
 	if(raw->isBufferInvalid())
 	{
 		return FALSE ;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f985ee0c157329ed1d4232549e96d6f1e72c045f..cab6fbdc935323ac85b29dd9c350e90432c6e974 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -6835,12 +6835,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 			llinfos << "AvatarAppearance msg received without any parameters, object: " << getID() << llendl;
 		}
 
+		const F32 LOADING_TIMEOUT_SECONDS = 60.f;
 		// this isn't really a problem if we already have a non-default shape
-		if (visualParamWeightsAreDefault())
+		if (visualParamWeightsAreDefault() && mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT_SECONDS)
 		{
 			// re-request appearance, hoping that it comes back with a shape next time
 			llinfos << "Re-requesting AvatarAppearance for object: "  << getID() << llendl;
 			LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID());
+			mRuthTimer.reset();
 		}
 		else
 		{
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index a231afad3fdae41d0dd35479907d97ff7d431ff8..ec5c95469e76f0266a7f51ad0ff0c24231a528a9 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1163,12 +1163,24 @@ BOOL LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id)
 		gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);
 		gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
 		
-		// this object might have been selected, so let the selection manager know it's gone now
+		// This object might have been selected, so let the selection manager know it's gone now
 		LLViewerObject *found_obj = gObjectList.findObject(item_id);
 		if (found_obj)
 		{
 			LLSelectMgr::getInstance()->remove(found_obj);
 		}
+
+		// Error checking in case this object was attached to an invalid point
+		// In that case, just remove the item from COF preemptively since detach 
+		// will fail.
+		if (isAgentAvatarValid())
+		{
+			const LLViewerObject *attached_obj = gAgentAvatarp->getWornAttachment(item_id);
+			if (!attached_obj)
+			{
+				LLAppearanceMgr::instance().removeCOFItemLinks(item_id, false);
+			}
+		}
 		return TRUE;
 	}
 	return FALSE;
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index eb2475f666022181efc42456a912c95e15b03a54..23a799ea3ac8b60633710fd292c265374a0a5848 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -33,6 +33,7 @@
 
 struct LocalTextureData;
 
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // LLVOAvatarSelf
 //
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 4e6d630ed88b29088baf52dcfcbaeb4a18396d67..ee32bd562e2c3de1b85b518d050ad747f4b65b86 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -25,10 +25,19 @@
  */
 
 #include "llviewerprecompiledheaders.h"
-
 #include "llvocache.h"
-
 #include "llerror.h"
+#include "llregionhandle.h"
+
+BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes) 
+{
+	return apr_file->read(src, n_bytes) == n_bytes ;
+}
+
+BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) 
+{
+	return apr_file->write(src, n_bytes) == n_bytes ;
+}
 
 //---------------------------------------------------------------------------
 // LLVOCacheEntry
@@ -57,26 +66,31 @@ LLVOCacheEntry::LLVOCacheEntry()
 	mDP.assignBuffer(mBuffer, 0);
 }
 
+LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file)
+{
+	S32 size = -1;
+	BOOL success;
 
-static inline void checkedRead(LLFILE *fp, void *data, size_t nbytes)
+	success = check_read(apr_file, &mLocalID, sizeof(U32));
+	if(success)
 {
-	if (fread(data, 1, nbytes, fp) != nbytes)
+		success = check_read(apr_file, &mCRC, sizeof(U32));
+	}
+	if(success)
 	{
-		llwarns << "Short read" << llendl;
-		memset(data, 0, nbytes);
+		success = check_read(apr_file, &mHitCount, sizeof(S32));
 	}
+	if(success)
+	{
+		success = check_read(apr_file, &mDupeCount, sizeof(S32));
 }
-
-LLVOCacheEntry::LLVOCacheEntry(LLFILE *fp)
+	if(success)
 {
-	S32 size;
-	checkedRead(fp, &mLocalID, sizeof(U32));
-	checkedRead(fp, &mCRC, sizeof(U32));
-	checkedRead(fp, &mHitCount, sizeof(S32));
-	checkedRead(fp, &mDupeCount, sizeof(S32));
-	checkedRead(fp, &mCRCChangeCount, sizeof(S32));
-
-	checkedRead(fp, &size, sizeof(S32));
+		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32));
+	}
+	if(success)
+	{
+		success = check_read(apr_file, &size, sizeof(S32));
 
 	// Corruption in the cache entries
 	if ((size > 10000) || (size < 1))
@@ -90,11 +104,30 @@ LLVOCacheEntry::LLVOCacheEntry(LLFILE *fp)
 		mBuffer = NULL;
 		return;
 	}
+	}
+	if(success && size > 0)
+	{
+		mBuffer = new U8[size];
+		success = check_read(apr_file, mBuffer, size);
 
-	mBuffer = new U8[size];
-	checkedRead(fp, mBuffer, size);
+		if(success)
+		{
 	mDP.assignBuffer(mBuffer, size);
 }
+		else
+		{
+			delete[] mBuffer ;
+			mBuffer = NULL ;
+		}
+	}
+
+	if(!success)
+	{
+		mLocalID = 0;
+		mCRC = 0;
+		mBuffer = NULL;
+	}
+}
 
 LLVOCacheEntry::~LLVOCacheEntry()
 {
@@ -148,22 +181,466 @@ void LLVOCacheEntry::dump() const
 		<< llendl;
 }
 
-static inline void checkedWrite(LLFILE *fp, const void *data, size_t nbytes)
+BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
+{
+	BOOL success;
+	success = check_write(apr_file, (void*)&mLocalID, sizeof(U32));
+	if(success)
+	{
+		success = check_write(apr_file, (void*)&mCRC, sizeof(U32));
+	}
+	if(success)
+	{
+		success = check_write(apr_file, (void*)&mHitCount, sizeof(S32));
+	}
+	if(success)
+	{
+		success = check_write(apr_file, (void*)&mDupeCount, sizeof(S32));
+	}
+	if(success)
+	{
+		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32));
+	}
+	if(success)
+	{
+		S32 size = mDP.getBufferSize();
+		success = check_write(apr_file, (void*)&size, sizeof(S32));
+	
+		if(success)
+		{
+			success = check_write(apr_file, (void*)mBuffer, size);
+	}
+}
+
+	return success ;
+}
+
+//-------------------------------------------------------------------
+//LLVOCache
+//-------------------------------------------------------------------
+// Format string used to construct filename for the object cache
+static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
+
+const U32 MAX_NUM_OBJECT_ENTRIES = 128 ;
+const U32 NUM_ENTRIES_TO_PURGE = 16 ;
+const char* object_cache_dirname = "objectcache";
+const char* header_filename = "object.cache";
+
+LLVOCache* LLVOCache::sInstance = NULL;
+
+//static 
+LLVOCache* LLVOCache::getInstance() 
+{
+	if(!sInstance)
+	{
+		sInstance = new LLVOCache() ;
+}
+	return sInstance ;
+}
+
+//static 
+BOOL LLVOCache::hasInstance() 
+{
+	return sInstance != NULL ;
+}
+
+//static 
+void LLVOCache::destroyClass() 
+{
+	if(sInstance)
+	{
+		delete sInstance ;
+		sInstance = NULL ;
+	}
+}
+
+LLVOCache::LLVOCache():
+	mInitialized(FALSE),
+	mReadOnly(TRUE),
+	mNumEntries(0)
+{
+	mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
+}
+
+LLVOCache::~LLVOCache()
+{
+	writeCacheHeader();
+	clearCacheInMemory();
+	delete mLocalAPRFilePoolp;
+}
+
+void LLVOCache::setDirNames(ELLPath location)
+{
+	std::string delem = gDirUtilp->getDirDelimiter();
+
+	mHeaderFileName = gDirUtilp->getExpandedFilename(location, object_cache_dirname, header_filename);
+	mObjectCacheDirName = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
+}
+
+void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
+{
+	if(mInitialized)
+	{
+		return ;
+	}
+
+	setDirNames(location);
+	if (!mReadOnly)
+	{
+		LLFile::mkdir(mObjectCacheDirName);
+	}	
+	mCacheSize = llmin(size, MAX_NUM_OBJECT_ENTRIES) ;
+	mCacheSize = llmax(mCacheSize, NUM_ENTRIES_TO_PURGE);
+
+	mMetaInfo.mVersion = cache_version;
+	readCacheHeader();
+	mInitialized = TRUE ;
+
+	if(mMetaInfo.mVersion != cache_version) 
+	{
+		mMetaInfo.mVersion = cache_version ;
+		if(mReadOnly) //disable cache
+		{
+			clearCacheInMemory();
+		}
+		else //delete the current cache if the format does not match.
+		{			
+			removeCache();
+		}
+	}	
+}
+	
+void LLVOCache::removeCache(ELLPath location) 
+{
+	if(mReadOnly)
+	{
+		return ;
+	}
+
+	std::string delem = gDirUtilp->getDirDelimiter();
+	std::string mask = delem + "*";
+	std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
+	gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files
+	LLFile::rmdir(cache_dir);
+
+	clearCacheInMemory();
+	mInitialized = FALSE ;
+}
+
+void LLVOCache::removeCache() 
+{
+	llassert_always(mInitialized) ;
+	if(mReadOnly)
+	{
+		return ;
+	}
+
+	std::string delem = gDirUtilp->getDirDelimiter();
+	std::string mask = delem + "*";
+	gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); 
+
+	clearCacheInMemory() ;
+	writeCacheHeader();
+}
+
+void LLVOCache::clearCacheInMemory()
+{
+	if(!mHeaderEntryQueue.empty()) 
+	{
+		for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter)
+		{
+			delete *iter ;
+		}
+		mHeaderEntryQueue.clear();
+		mHandleEntryMap.clear();
+		mNumEntries = 0 ;
+	}
+}
+
+void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename) 
 {
-	if (fwrite(data, 1, nbytes, fp) != nbytes)
+	U32 region_x, region_y;
+
+	grid_from_region_handle(handle, &region_x, &region_y);
+	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname,
+			   llformat(OBJECT_CACHE_FILENAME, region_x, region_y));
+
+	return ;
+}
+
+void LLVOCache::removeFromCache(U64 handle)
+{
+	if(mReadOnly)
+	{
+		return ;
+	}
+
+	std::string filename;
+	getObjectCacheFilename(handle, filename);
+	LLAPRFile::remove(filename, mLocalAPRFilePoolp);	
+}
+
+BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) 
+{
+	if(!check_read(apr_file, src, n_bytes))
+	{
+		delete apr_file ;
+		removeCache() ;
+		return FALSE ;
+	}
+
+	return TRUE ;
+}
+
+BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) 
+{
+	if(!check_write(apr_file, src, n_bytes))
 	{
-		llwarns << "Short write" << llendl;
+		delete apr_file ;
+		removeCache() ;
+		return FALSE ;
 	}
+
+	return TRUE ;
+}
+
+void LLVOCache::readCacheHeader()
+{
+	//clear stale info.
+	clearCacheInMemory();	
+
+	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
+	{
+		LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		
+		
+		//read the meta element
+		if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
+		{
+			return ;
+		}
+
+		HeaderEntryInfo* entry ;
+		mNumEntries = 0 ;
+		while(mNumEntries < MAX_NUM_OBJECT_ENTRIES)
+		{
+			entry = new HeaderEntryInfo() ;
+			if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo)))
+			{
+				delete entry ;			
+				return ;
+			}
+			else if(!entry->mTime) //end of the cache.
+			{
+				delete entry ;
+				return ;
+			}
+
+			entry->mIndex = mNumEntries++ ;
+			mHeaderEntryQueue.insert(entry) ;
+			mHandleEntryMap[entry->mHandle] = entry ;
+		}
+
+		delete apr_file ;
+	}
+	else
+	{
+		writeCacheHeader() ;
+	}
+}
+
+void LLVOCache::writeCacheHeader()
+{
+	if(mReadOnly)
+	{
+		return ;
+	}	
+
+	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+
+	//write the meta element
+	if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
+	{
+		return ;
+	}
+
+	mNumEntries = 0 ;
+	for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter)
+	{
+		(*iter)->mIndex = mNumEntries++ ;
+		if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo)))
+		{
+			return ;
+		}
+	}
+
+	mNumEntries = mHeaderEntryQueue.size() ;
+	if(mNumEntries < MAX_NUM_OBJECT_ENTRIES)
+	{
+		HeaderEntryInfo* entry = new HeaderEntryInfo() ;
+		for(S32 i = mNumEntries ; i < MAX_NUM_OBJECT_ENTRIES ; i++)
+		{
+			//fill the cache with the default entry.
+			if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo)))
+			{
+				mReadOnly = TRUE ; //disable the cache.
+				return ;
+			}
+		}
+		delete entry ;
+	}
+	delete apr_file ;
+}
+
+BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
+{
+	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
+
+	return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
 }
 
-void LLVOCacheEntry::writeToFile(LLFILE *fp) const
+void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) 
 {
-	checkedWrite(fp, &mLocalID, sizeof(U32));
-	checkedWrite(fp, &mCRC, sizeof(U32));
-	checkedWrite(fp, &mHitCount, sizeof(S32));
-	checkedWrite(fp, &mDupeCount, sizeof(S32));
-	checkedWrite(fp, &mCRCChangeCount, sizeof(S32));
-	S32 size = mDP.getBufferSize();
-	checkedWrite(fp, &size, sizeof(S32));
-	checkedWrite(fp, mBuffer, size);
+	llassert_always(mInitialized);
+
+	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
+	if(iter == mHandleEntryMap.end()) //no cache
+	{
+		return ;
+	}
+
+	std::string filename;
+	getObjectCacheFilename(handle, filename);
+	LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+
+	LLUUID cache_id ;
+	if(!checkRead(apr_file, cache_id.mData, UUID_BYTES))
+	{
+		return ;
+	}
+	if(cache_id != id)
+	{
+		llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
+
+		delete apr_file ;
+		return ;
+	}
+
+	S32 num_entries;
+	if(!checkRead(apr_file, &num_entries, sizeof(S32)))
+	{
+		return ;
+	}
+	
+	for (S32 i = 0; i < num_entries; i++)
+	{
+		LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file);
+		if (!entry->getLocalID())
+		{
+			llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
+			delete entry ;
+			break;
+		}
+		cache_entry_map[entry->getLocalID()] = entry;
+	}
+	num_entries = cache_entry_map.size() ;
+
+	delete apr_file ;
+	return ;
+}
+	
+void LLVOCache::purgeEntries()
+{
+	U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ;
+	while(mHeaderEntryQueue.size() > limit)
+	{
+		header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
+		HeaderEntryInfo* entry = *iter ;
+		
+		removeFromCache(entry->mHandle) ;
+		mHandleEntryMap.erase(entry->mHandle) ;		
+		mHeaderEntryQueue.erase(iter) ;
+		delete entry ;
+	}
+
+	writeCacheHeader() ;
+	readCacheHeader() ;
+	mNumEntries = mHandleEntryMap.size() ;
 }
+
+void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) 
+{
+	llassert_always(mInitialized);
+
+	if(mReadOnly)
+	{
+		return ;
+	}
+
+	HeaderEntryInfo* entry;
+	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
+	if(iter == mHandleEntryMap.end()) //new entry
+	{		
+		if(mNumEntries >= mCacheSize)
+		{
+			purgeEntries() ;
+		}
+		
+		entry = new HeaderEntryInfo();
+		entry->mHandle = handle ;
+		entry->mTime = time(NULL) ;
+		entry->mIndex = mNumEntries++ ;
+		mHeaderEntryQueue.insert(entry) ;
+		mHandleEntryMap[handle] = entry ;
+	}
+	else
+	{
+		entry = iter->second ;
+		entry->mTime = time(NULL) ;
+
+		//resort
+		mHeaderEntryQueue.erase(entry) ;
+		mHeaderEntryQueue.insert(entry) ;
+	}
+
+	//update cache header
+	if(!updateEntry(entry))
+	{
+		return ; //update failed.
+	}
+
+	if(!dirty_cache)
+	{
+		return ; //nothing changed, no need to update.
+	}
+
+	//write to cache file
+	std::string filename;
+	getObjectCacheFilename(handle, filename);
+	LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	
+	if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES))
+	{
+		return ;
+	}
+
+	S32 num_entries = cache_entry_map.size() ;
+	if(!checkWrite(apr_file, &num_entries, sizeof(S32)))
+	{
+		return ;
+	}
+
+	for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter)
+	{
+		if(!iter->second->writeToFile(apr_file))
+		{
+			//failed
+			delete apr_file ;
+			removeCache() ;
+			return ;
+		}
+	}
+
+	delete apr_file ;
+	return ;
+}
\ No newline at end of file
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 7a4572b399c1c4735933c609592fa21728ebecaf..56b48ef705d44263cd09c64ee0d47a91afd01613 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -36,11 +36,11 @@
 // Cache entries
 class LLVOCacheEntry;
 
-class LLVOCacheEntry : public LLDLinked<LLVOCacheEntry>
+class LLVOCacheEntry
 {
 public:
 	LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp);
-	LLVOCacheEntry(LLFILE *fp);
+	LLVOCacheEntry(LLAPRFile* apr_file);
 	LLVOCacheEntry();
 	~LLVOCacheEntry();
 
@@ -50,12 +50,15 @@ class LLVOCacheEntry : public LLDLinked<LLVOCacheEntry>
 	S32 getCRCChangeCount() const	{ return mCRCChangeCount; }
 
 	void dump() const;
-	void writeToFile(LLFILE *fp) const;
+	BOOL writeToFile(LLAPRFile* apr_file) const;
 	void assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp);
 	LLDataPackerBinaryBuffer *getDP(U32 crc);
 	void recordHit();
 	void recordDupe() { mDupeCount++; }
 
+public:
+	typedef std::map<U32, LLVOCacheEntry*>	vocache_entry_map_t;
+
 protected:
 	U32							mLocalID;
 	U32							mCRC;
@@ -66,4 +69,81 @@ class LLVOCacheEntry : public LLDLinked<LLVOCacheEntry>
 	U8							*mBuffer;
 };
 
+//
+//Note: LLVOCache is not thread-safe
+//
+class LLVOCache
+{
+private:
+	struct HeaderEntryInfo
+	{
+		HeaderEntryInfo() : mIndex(0), mHandle(0), mTime(0) {}
+		S32 mIndex;
+		U64 mHandle ;
+		U32 mTime ;
+	};
+
+	struct HeaderMetaInfo
+	{
+		HeaderMetaInfo() : mVersion(0){}
+
+		U32 mVersion;
+	};
+
+	struct header_entry_less
+	{
+		bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const
+		{
+			return lhs->mTime < rhs->mTime; // older entry in front of queue (set)
+		}
+	};
+	typedef std::set<HeaderEntryInfo*, header_entry_less> header_entry_queue_t;
+	typedef std::map<U64, HeaderEntryInfo*> handle_entry_map_t;
+private:
+	LLVOCache() ;
+
+public:
+	~LLVOCache() ;
+
+	void initCache(ELLPath location, U32 size, U32 cache_version) ;
+	void removeCache(ELLPath location) ;
+
+	void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ;
+	void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) ;
+
+	void setReadOnly(BOOL read_only) {mReadOnly = read_only;} 
+
+private:
+	void setDirNames(ELLPath location);	
+	// determine the cache filename for the region from the region handle	
+	void getObjectCacheFilename(U64 handle, std::string& filename);
+	void removeFromCache(U64 handle);
+	void readCacheHeader();
+	void writeCacheHeader();
+	void clearCacheInMemory();
+	void removeCache() ;
+	void purgeEntries();
+	BOOL updateEntry(const HeaderEntryInfo* entry);
+	BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
+	BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
+	
+private:
+	BOOL                 mInitialized ;
+	BOOL                 mReadOnly ;
+	HeaderMetaInfo       mMetaInfo;
+	U32                  mCacheSize;
+	U32                  mNumEntries;
+	std::string          mHeaderFileName ;
+	std::string          mObjectCacheDirName;
+	LLVolatileAPRPool*   mLocalAPRFilePoolp ; 	
+	header_entry_queue_t mHeaderEntryQueue;
+	handle_entry_map_t   mHandleEntryMap;	
+
+	static LLVOCache* sInstance ;
+public:
+	static LLVOCache* getInstance() ;
+	static BOOL       hasInstance() ;
+	static void       destroyClass() ;
+};
+
 #endif
diff --git a/indra/newview/llwearabletype.cpp b/indra/newview/llwearabletype.cpp
index d2e62c86ab788aee5b6b9a9adf0dc584959db6a7..0d707d65bf8d52f3762ef33ba81a1aa599f6fe97 100644
--- a/indra/newview/llwearabletype.cpp
+++ b/indra/newview/llwearabletype.cpp
@@ -77,8 +77,8 @@ LLWearableDictionary::LLWearableDictionary()
 	addEntry(LLWearableType::WT_SKIRT,        new WearableEntry("skirt",       "New Skirt",			LLAssetType::AT_CLOTHING, 	LLInventoryIcon::ICONNAME_CLOTHING_SKIRT));
 	addEntry(LLWearableType::WT_ALPHA,        new WearableEntry("alpha",       "New Alpha",			LLAssetType::AT_CLOTHING, 	LLInventoryIcon::ICONNAME_CLOTHING_ALPHA));
 	addEntry(LLWearableType::WT_TATTOO,       new WearableEntry("tattoo",      "New Tattoo",		LLAssetType::AT_CLOTHING, 	LLInventoryIcon::ICONNAME_CLOTHING_TATTOO));
-	addEntry(LLWearableType::WT_INVALID,      new WearableEntry("invalid",     "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryIcon::ICONNAME_NONE));
-	addEntry(LLWearableType::WT_NONE,      	  new WearableEntry("none",        "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryIcon::ICONNAME_NONE));
+	addEntry(LLWearableType::WT_INVALID,      new WearableEntry("invalid",     "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryIcon::ICONNAME_INVALID));
+	addEntry(LLWearableType::WT_NONE,      	  new WearableEntry("none",        "Invalid Wearable", 	LLAssetType::AT_NONE, 		LLInventoryIcon::ICONNAME_INVALID));
 }
 
 // static
@@ -94,6 +94,7 @@ const std::string& LLWearableType::getTypeName(LLWearableType::EType type)
 { 
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+	if (!entry) return getTypeName(WT_INVALID);
 	return entry->mName;
 }
 
@@ -102,6 +103,7 @@ const std::string& LLWearableType::getTypeDefaultNewName(LLWearableType::EType t
 { 
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+	if (!entry) return getTypeDefaultNewName(WT_INVALID);
 	return entry->mDefaultNewName;
 }
 
@@ -110,6 +112,7 @@ const std::string& LLWearableType::getTypeLabel(LLWearableType::EType type)
 { 
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+	if (!entry) return getTypeLabel(WT_INVALID);
 	return entry->mLabel;
 }
 
@@ -118,6 +121,7 @@ LLAssetType::EType LLWearableType::getAssetType(LLWearableType::EType type)
 {
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+	if (!entry) return getAssetType(WT_INVALID);
 	return entry->mAssetType;
 }
 
@@ -126,6 +130,7 @@ LLInventoryIcon::EIconName LLWearableType::getIconName(LLWearableType::EType typ
 {
 	const LLWearableDictionary *dict = LLWearableDictionary::getInstance();
 	const WearableEntry *entry = dict->lookup(type);
+	if (!entry) return getIconName(WT_INVALID);
 	return entry->mIconName;
-}
+} 
 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 2ad43ff3942d5e8bc9bb3b43738e788fafe3fbd3..5760d04a084aff147368f0b11782df586570ced0 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -121,6 +121,7 @@ void LLWorld::destroyClass()
 		LLViewerRegion* region_to_delete = *region_it++;
 		removeRegion(region_to_delete->getHost());
 	}
+	LLVOCache::getInstance()->destroyClass() ;
 	LLViewerPartSim::getInstance()->destroyClass();
 }
 
@@ -256,6 +257,8 @@ void LLWorld::removeRegion(const LLHost &host)
 
 		llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl;
 		LLAppViewer::instance()->forceDisconnect(LLTrans::getString("YouHaveBeenDisconnected"));
+
+		regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed.
 		return;
 	}
 
diff --git a/indra/newview/noise.cpp b/indra/newview/noise.cpp
index 00d04f7be459bf730ab78177890fdee63a272aaf..5f2c718b49be57cbba159822e3c1f25ed624e4aa 100644
--- a/indra/newview/noise.cpp
+++ b/indra/newview/noise.cpp
@@ -30,6 +30,7 @@
 
 #include "llrand.h"
 
+
 // static
 #define B 0x100
 S32 p[B + B + 2];
diff --git a/indra/newview/skins/default/textures/icons/Inv_Invalid.png b/indra/newview/skins/default/textures/icons/Inv_Invalid.png
new file mode 100644
index 0000000000000000000000000000000000000000..328be104eedbb2a8e0a1ed4968fba980927df415
Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Inv_Invalid.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index ce67cf008324ae7082dababce2fdeb5aeaa73fdd..2e282d813e29c834ccc612641574fae0153d567b 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -229,7 +229,8 @@ with the same filename but different name
   <texture name="Inv_Underpants" file_name="icons/Inv_Underpants.png" preload="false" />
   <texture name="Inv_Undershirt" file_name="icons/Inv_Undershirt.png" preload="false" />
   <texture name="Inv_Link" file_name="icons/Inv_Link.png" preload="false" />
-
+  <texture name="Inv_Invalid" file_name="icons/Inv_Invalid.png" preload="false" />
+  
   <texture name="Linden_Dollar_Alert" file_name="widgets/Linden_Dollar_Alert.png"/>
   <texture name="Linden_Dollar_Background" file_name="widgets/Linden_Dollar_Background.png"/>
 
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index cf040b10c7a5add2a8bfc9759c51e6a53d5a6da1..72639f08ee958d3e058984c66cd8ebf64048c5ca 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -2019,6 +2019,7 @@ Clears (deletes) the media and all params from the given face.
 	<string name="Stomach">Stomach</string>
 	<string name="Left Pec">Left Pec</string>
 	<string name="Right Pec">Right Pec</string>
+	<string name="Invalid Attachment">Invalid Attachment Point</string>
 
   <!-- Avatar age computation, see LLDateUtil::ageFromDate -->
   <string name="YearsMonthsOld">[AGEYEARS] [AGEMONTHS] old</string>
@@ -2182,7 +2183,6 @@ Clears (deletes) the media and all params from the given face.
 	<string name="ATTACH_HUD_BOTTOM_LEFT">HUD Bottom Left</string>
 	<string name="ATTACH_HUD_BOTTOM">HUD Bottom</string>
 	<string name="ATTACH_HUD_BOTTOM_RIGHT">HUD Bottom Right</string>
-	<string name="Bad attachment point">Invalid Attachment Point</string>
 			
 	<!-- script editor -->
 	<string name="CursorPos">Line [LINE], Column [COLUMN]</string>