diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 7348904c6165d8f987aa34a116cfb24c8843c4d3..f7d5f14ba35c8ae19a2f66d0cec8ffa2b0c66a51 100755
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -36,6 +36,8 @@
 
 
 extern U32 gOctreeMaxCapacity;
+extern float gOctreeMinSize;
+
 /*#define LL_OCTREE_PARANOIA_CHECK 0
 #if LL_DARWIN
 #define LL_OCTREE_MAX_CAPACITY 32
@@ -106,6 +108,7 @@ class LLOctreeNode : public LLTreeNode<T>
 	:	mParent((oct_node*)parent), 
 		mOctant(octant) 
 	{ 
+		llassert(size[0] >= gOctreeMinSize*0.5f);
 		//always keep a NULL terminated list to avoid out of bounds exceptions in debug builds
 		mData.push_back(NULL);
 		mDataEnd = &mData[0];
@@ -213,7 +216,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		F32 size = mSize[0];
 		F32 p_size = size * 2.f;
 
-		return (radius <= 0.001f && size <= 0.001f) ||
+		return (radius <= gOctreeMinSize && size <= gOctreeMinSize) ||
 				(radius <= p_size && radius > size);
 	}
 
@@ -319,7 +322,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		//is it here?
 		if (isInside(data->getPositionGroup()))
 		{
-			if ((getElementCount() < gOctreeMaxCapacity && contains(data->getBinRadius()) ||
+			if (((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius()) ||
 				(data->getBinRadius() > getSize()[0] &&	parent && parent->getElementCount() >= gOctreeMaxCapacity))) 
 			{ //it belongs here
 				mData.push_back(NULL);
@@ -356,8 +359,9 @@ class LLOctreeNode : public LLTreeNode<T>
 				LLVector4a val;
 				val.setSub(center, getCenter());
 				val.setAbs(val);
-								
-				S32 lt = val.lessThan(LLVector4a::getEpsilon()).getGatheredBits() & 0x7;
+				LLVector4a min_diff(gOctreeMinSize);
+
+				S32 lt = val.lessThan(min_diff).getGatheredBits() & 0x7;
 
 				if( lt == 0x7 )
 				{
@@ -389,6 +393,7 @@ class LLOctreeNode : public LLTreeNode<T>
 				}
 #endif
 
+				llassert(size[0] >= gOctreeMinSize*0.5f);
 				//make the new kid
 				child = new LLOctreeNode<T>(center, size, this);
 				addChild(child);
@@ -796,6 +801,8 @@ class LLOctreeRoot : public LLOctreeNode<T>
 				this->setSize(size2);
 				this->updateMinMax();
 
+				llassert(size[0] >= gOctreeMinSize);
+
 				//copy our children to a new branch
 				LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, this);
 				
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index e45a511e6d88f885d2486ccccfd13bb4f193cba0..5106da09b271bb081cb4b519168a85d90443f091 100755
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -85,6 +85,18 @@ void show_window_creation_error(const std::string& title)
 	LL_WARNS("Window") << title << LL_ENDL;
 }
 
+HGLRC SafeCreateContext(HDC hdc)
+{
+	__try 
+	{
+		return wglCreateContext(hdc);
+	}
+	__except(EXCEPTION_EXECUTE_HANDLER)
+	{ 
+		return NULL;
+	}
+}
+
 //static
 BOOL LLWindowWin32::sIsClassRegistered = FALSE;
 
@@ -1166,14 +1178,15 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
 		return FALSE;
 	}
 
-	if (!(mhRC = wglCreateContext(mhDC)))
+
+	if (!(mhRC = SafeCreateContext(mhDC)))
 	{
 		close();
 		OSMessageBox(mCallbacks->translateString("MBGLContextErr"),
 			mCallbacks->translateString("MBError"), OSMB_OK);
 		return FALSE;
 	}
-
+		
 	if (!wglMakeCurrent(mhDC, mhRC))
 	{
 		close();
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6ebda3ff6a647c5b067bfd0b930980f5c1c95afb..dfbf6b0156085322cdc517b9e9e3c87b01d57961 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7982,6 +7982,18 @@
     <integer>128</integer>
   </map>
 
+  <key>OctreeMinimumNodeSize</key>
+  <map>
+    <key>Comment</key>
+    <string>Minimum size of any octree node</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.01</real>
+  </map>
+
   <key>OctreeStaticObjectSizeFactor</key>
   <map>
     <key>Comment</key>
diff --git a/indra/newview/llfloaterhardwaresettings.cpp b/indra/newview/llfloaterhardwaresettings.cpp
index 792a2a5d2559a84bda1fe1acb866b572e303d820..6923308ce943526a7149a3448e25ea57a5295715 100755
--- a/indra/newview/llfloaterhardwaresettings.cpp
+++ b/indra/newview/llfloaterhardwaresettings.cpp
@@ -87,15 +87,30 @@ void LLFloaterHardwareSettings::refresh()
 	refreshEnabledState();
 }
 
+void LLFloaterHardwareSettings::onSetVRAM()
+{
+	S32 vram = childGetValue("GraphicsCardTextureMemory").asInteger();
+
+	//give the texture system plenty of leeway to avoid swapping
+	vram /= 3;
+
+	gSavedSettings.setS32("TextureMemory", vram);
+}
+
 void LLFloaterHardwareSettings::refreshEnabledState()
 {
     F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple");
     
 	S32 min_tex_mem = LLViewerTextureList::getMinVideoRamSetting();
-	S32 max_tex_mem = LLViewerTextureList::getMaxVideoRamSetting(false, mem_multiplier);
+	S32 max_tex_mem = LLViewerTextureList::getMaxVideoRamSetting(true, mem_multiplier);
 	getChild<LLSliderCtrl>("GraphicsCardTextureMemory")->setMinValue(min_tex_mem);
 	getChild<LLSliderCtrl>("GraphicsCardTextureMemory")->setMaxValue(max_tex_mem);
 
+	S32 vram = gSavedSettings.getS32("TextureMemory");
+	vram = vram*3;
+
+	getChild<LLSliderCtrl>("GraphicsCardTextureMemory")->setValue(vram);
+	getChild<LLSliderCtrl>("GraphicsCardTextureMemory")->setCommitCallback(boost::bind(&LLFloaterHardwareSettings::onSetVRAM, this));
 	if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") ||
 		!gGLManager.mHasVertexBufferObject)
 	{
diff --git a/indra/newview/llfloaterhardwaresettings.h b/indra/newview/llfloaterhardwaresettings.h
index 626771b1d2a6a75c9a18944489d9aeafcb9e04fd..63d86d5667e88f622ae83ef35e5105160a754fbf 100755
--- a/indra/newview/llfloaterhardwaresettings.h
+++ b/indra/newview/llfloaterhardwaresettings.h
@@ -64,6 +64,8 @@ class LLFloaterHardwareSettings : public LLFloater
 	/// don't apply the changed values
 	void cancel();
 
+	void onSetVRAM();
+
 	/// refresh the enabled values
 	void refreshEnabledState();
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 2c83f6d0b707f1f0ecd5f9e455cfb89d1adc54cd..69ba51b10a767b4b3087d8c6b77405102356474a 100755
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -78,6 +78,7 @@ U32 LLSpatialGroup::sNodeCount = 0;
 std::set<GLuint> LLSpatialGroup::sPendingQueries;
 
 U32 gOctreeMaxCapacity;
+F32 gOctreeMinSize;
 
 BOOL LLSpatialGroup::sNoDelete = FALSE;
 
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 744ec4de2b02705f5605ff792df317d58dee2a03..002a337e04e6db8a2e1544d3435c38fdca1111e8 100755
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -368,6 +368,7 @@ static bool handleRepartition(const LLSD&)
 	if (gPipeline.isInit())
 	{
 		gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity");
+		gOctreeMinSize = gSavedSettings.getF32("OctreeMinimumNodeSize");
 		gObjectList.repartitionObjects();
 	}
 	return true;
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 10101a4b9b7ce70cd61ca834f869892ecdf9e22b..78db136427274111ecb465e68c8ce530f6821fe8 100755
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -40,7 +40,7 @@
 #include <list>
 
 #define MIN_VIDEO_RAM_IN_MEGA_BYTES    32
-#define MAX_VIDEO_RAM_IN_MEGA_BYTES    512 // 512MB max for performance reasons.
+#define MAX_VIDEO_RAM_IN_MEGA_BYTES    4096
 
 class LLImageGL ;
 class LLImageRaw;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 783d1f220226e005091ffcbb96fb694f57214775..26f32941bfc7e95865816de679629d51a13bf3a4 100755
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1270,7 +1270,7 @@ S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_m
 		//  - it's going to be swapping constantly regardless
 		S32 max_vram = gGLManager.mVRAM;
 
-		if(gGLManager.mIsATI)
+		if(!get_recommended && gGLManager.mIsATI)
 		{
 			//shrink the availabe vram for ATI cards because some of them do not handel texture swapping well.
 			max_vram = (S32)(max_vram * 0.75f);  
@@ -1285,15 +1285,15 @@ S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_m
 	{
 		if (!get_recommended)
 		{
-			max_texmem = 512;
+			max_texmem = 2048;
 		}
 		else if (gSavedSettings.getBOOL("NoHardwareProbe")) //did not do hardware detection at startup
 		{
-			max_texmem = 512;
+			max_texmem = 2048;
 		}
 		else
 		{
-			max_texmem = 128;
+			max_texmem = 512;
 		}
 
 		llwarns << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << llendl;
@@ -1301,10 +1301,7 @@ S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_m
 
 	S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); // In MB
 	//llinfos << "*** DETECTED " << system_ram << " MB of system memory." << llendl;
-	if (get_recommended)
-		max_texmem = llmin(max_texmem, (S32)(system_ram/2));
-	else
-		max_texmem = llmin(max_texmem, (S32)(system_ram));
+	max_texmem = llmin(max_texmem, (S32)(system_ram));
     
     // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise
 	max_texmem = llmin(max_texmem, (S32) (mem_multiplier * (F32) max_texmem));
@@ -1334,7 +1331,7 @@ void LLViewerTextureList::updateMaxResidentTexMem(S32 mem)
 	mem = llclamp(mem, getMinVideoRamSetting(), getMaxVideoRamSetting(false, mem_multiplier));
 	if (mem != cur_mem)
 	{
-		gSavedSettings.setS32("TextureMemory", mem);
+		gSavedSettings.setS32("TextureMemory", mem/3);
 		return; //listener will re-enter this function
 	}
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 5da8a78b1b423ed43a30dc6e4007364297a4d64e..ab6e5cc353503dab84eac5814572e63b60b5828f 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -498,6 +498,7 @@ void LLPipeline::init()
 	refreshCachedSettings();
 
 	gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity");
+	gOctreeMinSize = gSavedSettings.getF32("OctreeMinimumNodeSize");
 	sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
diff --git a/indra/newview/skins/default/xui/en/floater_hardware_settings.xml b/indra/newview/skins/default/xui/en/floater_hardware_settings.xml
index 9deb0d20300d09978617ee1070d91eff0ed2360d..05594c2d861860ccba2dff59d3a9a92cfac56fd6 100755
--- a/indra/newview/skins/default/xui/en/floater_hardware_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_hardware_settings.xml
@@ -155,13 +155,12 @@
      tool_tip="Compresses textures in video memory, allowing for higher resolution textures to be loaded at the cost of some color quality."
      width="315" />
     <slider
-     control_name="TextureMemory"
      decimal_digits="0"
      follows="left|top"
      height="20"
      increment="16"
      initial_value="32"
-     label="Texture Memory (MB):"
+     label="Video Memory (MB):"
      label_width="195"
      layout="topleft"
      left="10"