diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 35bd9a2254c2e813f57df8849e9bbe1211e491df..9bbeb00efe4326d589c8940fc62fc8c395ded651 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -1051,6 +1051,19 @@ LLColor3 LLSettingsSky::getAmbientColor() const
     return getColor(SETTING_AMBIENT, LLColor3(0.25f, 0.25f, 0.25f));
 }
 
+LLColor3 LLSettingsSky::getAmbientColorClamped() const
+{
+    LLColor3 ambient = getAmbientColor();
+
+    F32 max_color = llmax(ambient.mV[0], ambient.mV[1], ambient.mV[2]);
+    if (max_color > 1.0f)
+    {
+        ambient *= 1.0f/max_color;
+    }
+
+    return ambient;
+}
+
 LLColor3 LLSettingsSky::getBlueDensity() const
 {
     return getColor(SETTING_BLUE_DENSITY, LLColor3(0.2447f, 0.4487f, 0.7599f));
@@ -1313,10 +1326,23 @@ void LLSettingsSky::calculateLightSettings() const
     componentMultBy(sunlight, componentExp((light_atten * -1.f) * lighty));
     componentMultBy(sunlight, light_transmittance);
 
+    //F32 max_color = llmax(sunlight.mV[0], sunlight.mV[1], sunlight.mV[2]);
+    //if (max_color > 1.0f)
+    //{
+    //    sunlight *= 1.0f/max_color;
+    //}
+
     //increase ambient when there are more clouds
     LLColor3 tmpAmbient = ambient + (smear(1.f) - ambient) * cloud_shadow * 0.5;
     componentMultBy(tmpAmbient, light_transmittance);
 
+    //tmpAmbient = LLColor3::clamp(tmpAmbient, getGamma(), 1.0f);
+    //max_color = llmax(tmpAmbient.mV[0], tmpAmbient.mV[1], tmpAmbient.mV[2]);
+    //if (max_color > 1.0f)
+    //{
+    //    tmpAmbient *= 1.0f/max_color;
+    //}
+
     //brightness of surface both sunlight and ambient
     mSunDiffuse = sunlight;
     mSunAmbient = tmpAmbient;
@@ -1334,6 +1360,7 @@ void LLSettingsSky::calculateLightSettings() const
     LLColor3 moonlight_b(0.66, 0.66, 1.2); // scotopic ambient value
 
     componentMultBy(moonlight, componentExp((light_atten * -1.f) * lighty));
+    //clampColor(moonlight, getGamma(), 1.0f);
 
     mMoonDiffuse  = componentMult(moonlight, light_transmittance) * moon_brightness;
     mMoonAmbient  = componentMult(moonlight_b, light_transmittance) * 0.0125f;
@@ -1676,6 +1703,20 @@ LLColor3 LLSettingsSky::getSunlightColor() const
     return LLColor3(mSettings[SETTING_SUNLIGHT_COLOR]);
 }
 
+LLColor3 LLSettingsSky::getSunlightColorClamped() const
+{
+    LLColor3 sunlight = getSunlightColor();
+    //clampColor(sunlight, getGamma(), 3.0f);
+
+    F32 max_color = llmax(sunlight.mV[0], sunlight.mV[1], sunlight.mV[2]);
+    if (max_color > 1.0f)
+    {
+        sunlight *= 1.0f/max_color;
+    }
+
+    return sunlight;
+}
+
 void LLSettingsSky::setSunlightColor(const LLColor3 &val)
 {
     setValue(SETTING_SUNLIGHT_COLOR, val);
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
index e562fe38ff3e79716f50b6b1f3b28c81b4f87723..412791164327d9e7c3dcebfa5fca437f9a069b6a 100644
--- a/indra/llinventory/llsettingssky.h
+++ b/indra/llinventory/llsettingssky.h
@@ -292,6 +292,9 @@ class LLSettingsSky: public LLSettingsBase
     LLColor4  getTotalAmbient() const;
     LLColor4  getHazeColor() const;
 
+    LLColor3 getSunlightColorClamped() const;
+    LLColor3 getAmbientColorClamped() const;
+
     virtual LLSettingsBase::ptr_t buildDerivedClone() const SETTINGS_OVERRIDE { return buildClone(); }
 
     static LLUUID GetDefaultAssetId();
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index a13c8de43ef86b3d9c02eb1365d7d43abb5fe3e7..023172c84446f13f4ebc9fdcf466027d13cae392 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -276,6 +276,10 @@ void main()
 #endif
     final_color.a = max(final_color.a, emissive_brightness);
 
+#if !defined(HAS_NORMAL_MAP)
+    final_color.a = 0.0f;
+#endif
+
     vec4 final_specular = spec;
     final_specular.a = specular_color.a;
 #ifdef HAS_SPECULAR_MAP
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 269b76a19fb00451b4a667f31fc1ad8a2aea0997..09b1813ebe599d234f419d10ea01925f160d87ec 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -158,7 +158,9 @@ vec3 post_diffuse = color.rgb;
        
  vec3 post_spec = color.rgb;
  
-#ifndef WATER_FOG
+#ifdef WATER_FOG
+        color.rgb += diffuse_srgb.rgb * diffuse_srgb.a * 0.25;
+#else
         color.rgb = mix(color.rgb, diffuse_srgb.rgb, diffuse_srgb.a);
 #endif
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl
index 641c6fbd363d73dd25fdd837f244585c9678b4a3..9a5debb3c125729cacd1f0d4ef47eed7efc3e908 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl
@@ -58,45 +58,8 @@ VARYING vec4 refCoord;
 VARYING vec4 littleWave;
 VARYING vec4 view;
 
-vec3 srgb_to_linear(vec3 c);
 vec2 encode_normal(vec3 n);
 
-vec4 applyWaterFog(vec4 color, vec3 viewVec)
-{
-	//normalize view vector
-	vec3 view = normalize(viewVec);
-	float es = -view.z;
-
-	//find intersection point with water plane and eye vector
-	
-	//get eye depth
-	float e0 = max(-waterPlane.w, 0.0);
-	
-	//get object depth
-	float depth = length(viewVec);
-		
-	//get "thickness" of water
-	float l = max(depth, 0.1);
-
-	float kd = waterFogDensity;
-	float ks = waterFogKS;
-	vec4 kc = waterFogColor;
-	
-	float F = 0.98;
-	
-	float t1 = -kd * pow(F, ks * e0);
-	float t2 = kd + ks * es;
-	float t3 = pow(F, t2*l) - 1.0;
-	
-	float L = min(t1/t2*t3, 1.0);
-	
-	float D = pow(0.98, l*kd);
-	//return vec4(1.0, 0.0, 1.0, 1.0);
-	return color * D + kc * L;
-	//depth /= 10.0;
-	//return vec4(depth,depth,depth,0.0);
-}
-
 void main() 
 {
 	vec4 color;
@@ -113,9 +76,7 @@ void main()
 		
 	vec4 fb = texture2D(screenTex, distort);
 
-    fb.rgb = srgb_to_linear(fb.rgb);
-
 	frag_data[0] = vec4(fb.rgb, 1.0); // diffuse
 	frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec
-	frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, displace
+	frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, env intens, atmo kill
 }
diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp
index 720c7e238854bdf7be6c6c3111d40ba686dbde92..a1093df7e1e958dda721219f25c5a788753041af 100644
--- a/indra/newview/lllegacyatmospherics.cpp
+++ b/indra/newview/lllegacyatmospherics.cpp
@@ -242,8 +242,10 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(AtmosphericsVars& vars, const LLVecto
 
 	calcSkyColorWLVert(Pn, vars);
 
+    bool low_end = !gPipeline.canUseWindLightShaders();
+
 	LLColor3 sky_color =  isShiny ? vars.hazeColor : 
-                          !gPipeline.canUseWindLightShaders() ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f);
+                          low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f);
 
 	if (isShiny)
 	{
@@ -443,8 +445,8 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in)
     vars.distance_multiplier = psky->getDistanceMultiplier();
     vars.max_y = psky->getMaxY();
     vars.sun_norm = LLEnvironment::instance().getSunDirectionCFR();
-    vars.sunlight = psky->getSunlightColor();
-    vars.ambient = psky->getAmbientColor();    
+    vars.sunlight = psky->getSunlightColorClamped();
+    vars.ambient = psky->getAmbientColorClamped();
     vars.glow = psky->getGlow();
     vars.cloud_shadow = psky->getCloudShadow();
     vars.dome_radius = psky->getDomeRadius();
@@ -605,3 +607,112 @@ F32 azimuth(const LLVector3 &v)
 	}	
 	return azimuth;
 }
+
+bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b)
+{
+    if (a.hazeColor != b.hazeColor)
+    {
+        return false;
+    }
+
+    if (a.hazeColorBelowCloud != b.hazeColorBelowCloud)
+    {
+        return false;
+    }
+
+    if (a.cloudColorSun != b.cloudColorSun)
+    {
+        return false;
+    }
+
+    if (a.cloudColorAmbient != b.cloudColorAmbient)
+    {
+        return false;
+    }
+
+    if (a.cloudDensity != b.cloudDensity)
+    {
+        return false;
+    }
+
+    if (a.density_multiplier != b.density_multiplier)
+    {
+        return false;
+    }
+
+    if (a.haze_horizon != b.haze_horizon)
+    {
+        return false;
+    }
+
+    if (a.haze_density != b.haze_density)
+    {
+        return false;
+    }
+
+    if (a.blue_horizon != b.blue_horizon)
+    {
+        return false;
+    }
+
+    if (a.blue_density != b.blue_density)
+    {
+        return false;
+    }
+
+    if (a.dome_offset != b.dome_offset)
+    {
+        return false;
+    }
+
+    if (a.dome_radius != b.dome_radius)
+    {
+        return false;
+    }
+
+    if (a.cloud_shadow != b.cloud_shadow)
+    {
+        return false;
+    }
+
+    if (a.glow != b.glow)
+    {
+        return false;
+    }
+
+    if (a.ambient != b.ambient)
+    {
+        return false;
+    }
+
+    if (a.sunlight != b.sunlight)
+    {
+        return false;
+    }
+
+    if (a.sun_norm != b.sun_norm)
+    {
+        return false;
+    }
+
+    if (a.gamma != b.gamma)
+    {
+        return false;
+    }
+
+    if (a.max_y != b.max_y)
+    {
+        return false;
+    }
+
+    if (a.distance_multiplier != b.distance_multiplier)
+    {
+        return false;
+    }
+
+    // light_atten, light_transmittance, total_density
+    // are ignored as they always change when the values above do
+    // they're just shared calc across the sky map generation to save cycles
+
+    return true;
+}
diff --git a/indra/newview/lllegacyatmospherics.h b/indra/newview/lllegacyatmospherics.h
index 95700227f94fac8ca49a5a413c603861c8b55c0e..cdfcead7a4026f0e5b85f33c3c1edd27e02e6e91 100644
--- a/indra/newview/lllegacyatmospherics.h
+++ b/indra/newview/lllegacyatmospherics.h
@@ -206,7 +206,7 @@ class AtmosphericsVars
     {
     }
 
-    LL_FORCE_INLINE friend bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b);
+    friend bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b);
 
     LLColor3  hazeColor;
     LLColor3  hazeColorBelowCloud;
@@ -233,115 +233,6 @@ class AtmosphericsVars
     LLColor3 total_density;
 };
 
-bool operator==(const AtmosphericsVars& a, const AtmosphericsVars& b)
-{
-    if (a.hazeColor != b.hazeColor)
-    {
-        return false;
-    }
-
-    if (a.hazeColorBelowCloud != b.hazeColorBelowCloud)
-    {
-        return false;
-    }
-
-    if (a.cloudColorSun != b.cloudColorSun)
-    {
-        return false;
-    }
-
-    if (a.cloudColorAmbient != b.cloudColorAmbient)
-    {
-        return false;
-    }
-
-    if (a.cloudDensity != b.cloudDensity)
-    {
-        return false;
-    }
-
-    if (a.density_multiplier != b.density_multiplier)
-    {
-        return false;
-    }
-
-    if (a.haze_horizon != b.haze_horizon)
-    {
-        return false;
-    }
-
-    if (a.haze_density != b.haze_density)
-    {
-        return false;
-    }
-
-    if (a.blue_horizon != b.blue_horizon)
-    {
-        return false;
-    }
-
-    if (a.blue_density != b.blue_density)
-    {
-        return false;
-    }
-
-    if (a.dome_offset != b.dome_offset)
-    {
-        return false;
-    }
-
-    if (a.dome_radius != b.dome_radius)
-    {
-        return false;
-    }
-
-    if (a.cloud_shadow != b.cloud_shadow)
-    {
-        return false;
-    }
-
-    if (a.glow != b.glow)
-    {
-        return false;
-    }
-
-    if (a.ambient != b.ambient)
-    {
-        return false;
-    }
-
-    if (a.sunlight != b.sunlight)
-    {
-        return false;
-    }
-
-    if (a.sun_norm != b.sun_norm)
-    {
-        return false;
-    }
-
-    if (a.gamma != b.gamma)
-    {
-        return false;
-    }
-
-    if (a.max_y != b.max_y)
-    {
-        return false;
-    }
-
-    if (a.distance_multiplier != b.distance_multiplier)
-    {
-        return false;
-    }
-
-    // light_atten, light_transmittance, total_density
-    // are ignored as they always change when the values above do
-    // they're just shared calc across the sky map generation to save cycles
-
-    return true;
-}
-
 class LLAtmospherics
 {
 public:    
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index a699491e1bfbca510a86823b93b8d05aacd125e7..e2da4f63fb352506c4143ba940f68c21cc0b4d79 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -94,6 +94,7 @@ LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warning
 std::string gLastRunVersion;
 
 extern BOOL gResizeScreenTexture;
+extern BOOL gResizeShadowTexture;
 extern BOOL gDebugGL;
 ////////////////////////////////////////////////////////////////////////////
 // Listeners
@@ -190,6 +191,19 @@ bool handleRenderTransparentWaterChanged(const LLSD& newvalue)
 	return true;
 }
 
+
+static bool handleShadowsResized(const LLSD& newvalue)
+{
+	gPipeline.requestResizeShadowTexture();
+	return true;
+}
+
+static bool handleWindowResized(const LLSD& newvalue)
+{
+	gPipeline.requestResizeScreenTexture();
+	return true;
+}
+
 static bool handleReleaseGLBufferChanged(const LLSD& newvalue)
 {
 	if (gPipeline.isInit())
@@ -609,14 +623,14 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderUseTriStrips")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleWindowResized, _2));
 	gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
 	gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
 	gSavedSettings.getControl("RenderSpecularExponent")->getSignal()->connect(boost::bind(&handleLUTBufferChanged, _2));
 	gSavedSettings.getControl("RenderAnisotropic")->getSignal()->connect(boost::bind(&handleAnisotropicChanged, _2));
-	gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleShadowsResized, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("RenderGlowResolutionPow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index ddce419f191bd67863c393d9aae6e365d3a28655..09b9d5f83669a54494dcf85f84b100b4dfc74cea 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -94,6 +94,7 @@ BOOL gForceRenderLandFence = FALSE;
 BOOL gDisplaySwapBuffers = FALSE;
 BOOL gDepthDirty = FALSE;
 BOOL gResizeScreenTexture = FALSE;
+BOOL gResizeShadowTexture = FALSE;
 BOOL gWindowResized = FALSE;
 BOOL gSnapshot = FALSE;
 BOOL gShaderProfileFrame = FALSE;
@@ -262,6 +263,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		return;
 	}
 
+    if (gResizeShadowTexture)
+	{ //skip render on frames where window has been resized
+		gPipeline.resizeShadowTexture();
+		gResizeShadowTexture = FALSE;
+	}
+
 	if (LLPipeline::sRenderDeferred)
 	{ //hack to make sky show up in deferred snapshots
 		for_snapshot = FALSE;
diff --git a/indra/newview/llviewerdisplay.h b/indra/newview/llviewerdisplay.h
index f6467d7f93c4a65bdd0cb385732fcb87f34060a6..e8072193ea1836ea371e1d8e59763b077f14c196 100644
--- a/indra/newview/llviewerdisplay.h
+++ b/indra/newview/llviewerdisplay.h
@@ -40,6 +40,7 @@ extern BOOL	gTeleportDisplay;
 extern LLFrameTimer	gTeleportDisplayTimer;
 extern BOOL			gForceRenderLandFence;
 extern BOOL gResizeScreenTexture;
+extern BOOL gResizeShadowTexture;
 extern BOOL gWindowResized;
 
 #endif // LL_LLVIEWERDISPLAY_H
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index c874b3cf59c0204e1c41e9ebb019a6fc5f198f70..bdd0330cca434b64eb02bf7e29dd41056893366d 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -528,7 +528,7 @@ void LLViewerShaderMgr::setShaders()
         }
 
 		// Trigger a full rebuild of the fallback skybox / cubemap if we've toggled windlight shaders
-		if (mShaderLevel[SHADER_WINDLIGHT] != wl_class && gSky.mVOSkyp.notNull())
+		if (!wl_class || (mShaderLevel[SHADER_WINDLIGHT] != wl_class && gSky.mVOSkyp.notNull()))
 		{
 			gSky.mVOSkyp->forceSkyUpdate();
 		}
@@ -2281,6 +2281,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/underWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredUnderWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        gDeferredUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
 		success = gDeferredUnderWaterProgram.createShader(NULL, NULL);
 		llassert(success);
 	}
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index 78c782eb5f79eca23345ff1b32908baea0e197af..19299f55a22e1447430bbb3e86a1fcbfda1d39ea 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -64,6 +64,7 @@ namespace
     const S32 NUM_TILES_X = 8;
     const S32 NUM_TILES_Y = 4;
     const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y;
+    const S32 NUM_CUBEMAP_FACES = 6;
 
     // Heavenly body constants
     const F32 SUN_DISK_RADIUS	= 0.5f;
@@ -76,13 +77,12 @@ namespace
     const LLVector2 TEX10 = LLVector2(1.f, 0.f);
     const LLVector2 TEX11 = LLVector2(1.f, 1.f);
 
-    const F32 LIGHT_DIRECTION_THRESHOLD = (F32) cosf(DEG_TO_RAD * 1.f);
-    const F32 COLOR_CHANGE_THRESHOLD = 0.01f;
-
     LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATETIMER("VOSky Update Timer Tick");
+    LLTrace::BlockTimerStatHandle FTM_VOSKY_CALC("VOSky Update Calculations");
+    LLTrace::BlockTimerStatHandle FTM_VOSKY_CREATETEXTURES("VOSky Update Textures");
     LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATEFORCED("VOSky Update Forced");
 
-    F32Seconds UPDATE_EXPRY(2.0f);
+    F32Seconds UPDATE_EXPRY(0.25f);
 }
 /***************************************
 		SkyTex
@@ -416,6 +416,8 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	mCloudDensity(0.2f),
 	mWind(0.f),
 	mForceUpdate(FALSE),
+    mNeedUpdate(TRUE),
+    mCubeMapUpdateStage(-1),
 	mWorldScale(1.f),
 	mBumpSunDir(0.f, 0.f, 1.f)
 {
@@ -428,7 +430,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
     mForceUpdateThrottle.setTimerExpirySec(UPDATE_EXPRY);
     mForceUpdateThrottle.reset();
 
-	for (S32 i = 0; i < 6; i++)
+	for (S32 i = 0; i < NUM_CUBEMAP_FACES; i++)
 	{
 		mSkyTex[i].init(false);
 		mShinyTex[i].init(true);
@@ -491,20 +493,16 @@ void LLVOSky::init()
     m_atmosphericsVars.gamma = psky->getGamma();
 
 	// Initialize the cached normalized direction vectors
-	for (S32 side = 0; side < 6; ++side)
+	for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side)
 	{
 		for (S32 tile = 0; tile < NUM_TILES; ++tile)
 		{
 			initSkyTextureDirs(side, tile);
 			createSkyTexture(m_atmosphericsVars, side, tile, mSkyTex);
             createSkyTexture(m_atmosphericsVars, side, tile, mShinyTex, true);
-		}
-	}
-
-	for (S32 i = 0; i < 6; ++i)
-	{
-		mSkyTex[i].create(1.0f);
-		mShinyTex[i].create(1.0f);
+        }
+        mSkyTex[side].create(1.0f);
+        mShinyTex[side].create(1.0f);
 	}
 
 	initCubeMap();
@@ -553,7 +551,7 @@ void LLVOSky::calc()
 void LLVOSky::initCubeMap() 
 {
 	std::vector<LLPointer<LLImageRaw> > images;
-	for (S32 side = 0; side < 6; side++)
+	for (S32 side = 0; side < NUM_CUBEMAP_FACES; side++)
 	{
 		images.push_back(mShinyTex[side].getImageRaw());
 	}
@@ -575,7 +573,7 @@ void LLVOSky::initCubeMap()
 void LLVOSky::cleanupGL()
 {
 	S32 i;
-	for (i = 0; i < 6; i++)
+	for (i = 0; i < NUM_CUBEMAP_FACES; i++)
 	{
 		mSkyTex[i].cleanupGL();
 	}
@@ -588,7 +586,7 @@ void LLVOSky::cleanupGL()
 void LLVOSky::restoreGL()
 {
 	S32 i;
-	for (i = 0; i < 6; i++)
+	for (i = 0; i < NUM_CUBEMAP_FACES; i++)
 	{
 		mSkyTex[i].restoreGL();
 	}
@@ -608,7 +606,7 @@ void LLVOSky::restoreGL()
 		initCubeMap();
 	}
 
-    mForceUpdate = TRUE;
+    forceSkyUpdate();
 
 	if (mDrawable)
 	{
@@ -671,31 +669,31 @@ void LLVOSky::updateDirections(void)
 {
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
-    mLastSunLightingDirection  = mSun.getDirection();
-    mLastMoonLightingDirection = mMoon.getDirection();
-
     mSun.setDirection(psky->getSunDirection());
 	mMoon.setDirection(psky->getMoonDirection());
-
     mSun.setRotation(psky->getSunRotation());
 	mMoon.setRotation(psky->getMoonRotation());
-
 	mSun.renewDirection();
-	mSun.renewColor();
 	mMoon.renewDirection();
-	mMoon.renewColor();
 }
 
 void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time)
 {
 }
 
+void LLVOSky::forceSkyUpdate()
+{
+    mForceUpdate = TRUE;
+
+    memset(&m_lastAtmosphericsVars, 0x00, sizeof(AtmosphericsVars));
+
+    mCubeMapUpdateStage = -1;
+}
+
 bool LLVOSky::updateSky()
 {    
     LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
 
-    LLColor4 total_ambient = psky->getTotalAmbient();
-
 	if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)))
 	{
 		return TRUE;
@@ -712,13 +710,13 @@ bool LLVOSky::updateSky()
 		return TRUE;
 	}
 
+    bool is_alm_wl_sky = gPipeline.canUseWindLightShaders();
+
 	static S32 next_frame = 0;
-	const S32 total_no_tiles = 6 * NUM_TILES;
+	const S32 total_no_tiles = NUM_CUBEMAP_FACES * NUM_TILES;
 	const S32 cycle_frame_no = total_no_tiles + 1;
 
-	const S32 frame = next_frame;
-
-    mForceUpdate = mForceUpdate || (total_no_tiles == frame);
+    mNeedUpdate = mForceUpdate;
 
 	++next_frame;
 	next_frame = next_frame % cycle_frame_no;
@@ -727,117 +725,98 @@ bool LLVOSky::updateSky()
 	LLHeavenBody::setInterpVal( mInterpVal );
 	updateDirections();
 
-    LLVector3 direction = mSun.getDirection();
-	direction.normalize();
-	const F32 dot_sun  = direction * mLastSunLightingDirection;
-    const F32 dot_moon = direction * mLastMoonLightingDirection;
-
-	LLColor3 delta_color;
-	delta_color.setVec(mLastTotalAmbient.mV[0] - total_ambient.mV[0],
-						mLastTotalAmbient.mV[1] - total_ambient.mV[1],
-                        mLastTotalAmbient.mV[2] - total_ambient.mV[2]);
-
-    bool sun_direction_changed  = (dot_sun < LIGHT_DIRECTION_THRESHOLD);
-    bool moon_direction_changed = (dot_moon < LIGHT_DIRECTION_THRESHOLD);
-    bool color_changed          = (delta_color.length() >= COLOR_CHANGE_THRESHOLD);
-
-    mForceUpdate = mForceUpdate || sun_direction_changed;
-    mForceUpdate = mForceUpdate || moon_direction_changed;
-    mForceUpdate = mForceUpdate || color_changed;
-    mForceUpdate = mForceUpdate || !mInitialized;
+    if (!mCubeMap)
+    {
+        mCubeMapUpdateStage = NUM_CUBEMAP_FACES;
+        mForceUpdate = FALSE;
+        return TRUE;
+    }
 
-    bool is_alm_wl_sky = gPipeline.canUseWindLightShaders();
+    if (mCubeMapUpdateStage < 0)
+    {
+        LL_RECORD_BLOCK_TIME(FTM_VOSKY_CALC);
+        calc();
 
-    calc();
+        bool same_atmospherics = m_lastAtmosphericsVars == m_atmosphericsVars;
 
-    bool same_atmospherics = m_lastAtmosphericsVars == m_atmosphericsVars;
+        mNeedUpdate = mNeedUpdate || !same_atmospherics;
 
-    if (mForceUpdate && mForceUpdateThrottle.hasExpired() && !same_atmospherics)
-	{
+        if (mNeedUpdate && (mForceUpdateThrottle.hasExpired() || mForceUpdate))
+	    {
+            // start updating cube map sides
+            updateFog(LLViewerCamera::getInstance()->getFar());
+            mCubeMapUpdateStage = 0;
+            mForceUpdate = FALSE;
+        }
+    }
+    else if (mCubeMapUpdateStage == NUM_CUBEMAP_FACES)
+    {
         LL_RECORD_BLOCK_TIME(FTM_VOSKY_UPDATEFORCED);
+        LLSkyTex::stepCurrent();
 
-        mForceUpdateThrottle.setTimerExpirySec(UPDATE_EXPRY);
-
-		LLSkyTex::stepCurrent();
-		
-        m_lastAtmosphericsVars = m_atmosphericsVars;
-
-		if (!direction.isExactlyZero())
-		{
-            mLastTotalAmbient = total_ambient;
-			mInitialized = TRUE;
+        int tex = mSkyTex[0].getWhich(TRUE);
 
-			if (mCubeMap)
-			{
-				updateFog(LLViewerCamera::getInstance()->getFar());
-
-				for (int side = 0; side < 6; side++) 
-				{
-					for (int tile = 0; tile < NUM_TILES; tile++) 
-					{
-						createSkyTexture(m_atmosphericsVars, side, tile, mSkyTex);
-                        createSkyTexture(m_atmosphericsVars, side, tile, mShinyTex, true);
-					}
-				}
-			}
-
-            int tex = mSkyTex[0].getWhich(TRUE);
-
-			for (int side = 0; side < 6; side++) 
-			{
-                LLImageRaw* raw1 = nullptr;
-                LLImageRaw* raw2 = nullptr;
+        for (int side = 0; side < NUM_CUBEMAP_FACES; side++)
+        {
+            LLImageRaw* raw1 = nullptr;
+            LLImageRaw* raw2 = nullptr;
 
-                if (!is_alm_wl_sky)
-                {
-					raw1 = mSkyTex[side].getImageRaw(TRUE);
-					raw2 = mSkyTex[side].getImageRaw(FALSE);
-					raw2->copy(raw1);
-					mSkyTex[side].createGLImage(tex);
-                }
+            if (!is_alm_wl_sky)
+            {
+                raw1 = mSkyTex[side].getImageRaw(TRUE);
+                raw2 = mSkyTex[side].getImageRaw(FALSE);
+                raw2->copy(raw1);
+                mSkyTex[side].createGLImage(tex);
+            }
 
-				raw1 = mShinyTex[side].getImageRaw(TRUE);
-				raw2 = mShinyTex[side].getImageRaw(FALSE);
-				raw2->copy(raw1);
-				mShinyTex[side].createGLImage(tex);
-			}
-			next_frame = 0;	
+            raw1 = mShinyTex[side].getImageRaw(TRUE);
+            raw2 = mShinyTex[side].getImageRaw(FALSE);
+            raw2->copy(raw1);
+            mShinyTex[side].createGLImage(tex);
+        }
+        next_frame = 0;
 
-			// update the sky texture
-            if (!is_alm_wl_sky)
+        // update the sky texture
+        if (!is_alm_wl_sky)
+        {
+            for (S32 i = 0; i < NUM_CUBEMAP_FACES; ++i)
             {
-			    for (S32 i = 0; i < 6; ++i)
-			    {
-                    mSkyTex[i].create(1.0f);
-			    }
+                mSkyTex[i].create(1.0f);
             }
+        }
 
-            for (S32 i = 0; i < 6; ++i)
-			{
-				mShinyTex[i].create(1.0f);
-			}
+        for (S32 i = 0; i < NUM_CUBEMAP_FACES; ++i)
+        {
+            mShinyTex[i].create(1.0f);
+        }
 
-			// update the environment map
-			if (mCubeMap)
-			{
-				std::vector<LLPointer<LLImageRaw> > images;
-				images.reserve(6);
-				for (S32 side = 0; side < 6; side++)
-				{
-					images.push_back(mShinyTex[side].getImageRaw(TRUE));
-				}
-				mCubeMap->init(images);
-				gGL.getTexUnit(0)->disable();
-			}                    
-		}
+        // update the environment map
+        initCubeMap();
 
-		gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
-		mForceUpdate = FALSE;
-	}
+        m_lastAtmosphericsVars = m_atmosphericsVars;
 
-	if (mDrawable.notNull() && mDrawable->getFace(0) && !mDrawable->getFace(0)->getVertexBuffer())
+        mNeedUpdate = FALSE;
+        mForceUpdate = FALSE;
+
+        mForceUpdateThrottle.setTimerExpirySec(UPDATE_EXPRY);
+        gPipeline.markRebuild(gSky.mVOGroundp->mDrawable, LLDrawable::REBUILD_ALL, TRUE);
+
+        if (mDrawable.notNull() && mDrawable->getFace(0) && !mDrawable->getFace(0)->getVertexBuffer())
+	    {
+		    gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+	    }
+        mCubeMapUpdateStage = -1;
+    }
+    else if (mCubeMapUpdateStage >= 0 && mCubeMapUpdateStage < NUM_CUBEMAP_FACES)
 	{
-		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE);
+        LL_RECORD_BLOCK_TIME(FTM_VOSKY_CREATETEXTURES);
+        S32 side = mCubeMapUpdateStage;
+        for (int tile = 0; tile < NUM_TILES; tile++)
+        {
+            createSkyTexture(m_atmosphericsVars, side, tile, mSkyTex);
+            createSkyTexture(m_atmosphericsVars, side, tile, mShinyTex, true);
+        }
+        mCubeMapUpdateStage++;
 	}
 
 	return TRUE;
@@ -885,7 +864,7 @@ LLDrawable *LLVOSky::createDrawable(LLPipeline *pipeline)
 	poolp->setSkyTex(mSkyTex);
 	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_SKY);
 	
-	for (S32 i = 0; i < 6; ++i)
+	for (S32 i = 0; i < NUM_CUBEMAP_FACES; ++i)
 	{
 		mFace[FACE_SIDE0 + i] = mDrawable->addFace(poolp, NULL);
 	}
@@ -1047,7 +1026,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable)
 	U16 index_offset;
 	LLFace *face;	
 
-	for (S32 side = 0; side < 6; ++side)
+	for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side)
 	{
 		face = mFace[FACE_SIDE0 + side]; 
 
@@ -1603,10 +1582,7 @@ void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLV
 	    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
 	    mBumpSunDir.normalize();
     }
-
 	updateDirections();
-
-    mForceUpdate = true;
 }
 
 void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr)
@@ -1628,17 +1604,11 @@ void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr)
 	    mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot);
 	    mBumpSunDir.normalize();
     }
-
 	updateDirections();
-
-    mForceUpdate = true;
 }
 
 void LLVOSky::setMoonDirectionCFR(const LLVector3 &moon_dir_cfr)
 {
 	mMoon.setDirection(moon_dir_cfr);
-
 	updateDirections();
-
-    mForceUpdate = true;
 }
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 5f270855997926ad72b931f54ad2d741db5b64e1..b1a01a93663d08dbf30f3922eeee2550f1e94d1f 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -288,7 +288,7 @@ class LLVOSky : public LLStaticViewerObject
     void setSunScale(F32 sun_scale);
     void setMoonScale(F32 sun_scale);
 
-	void forceSkyUpdate(void)							{ mForceUpdate = TRUE; }
+	void forceSkyUpdate(void);
 
 public:
 	LLFace	*mFace[FACE_COUNT];
@@ -337,10 +337,10 @@ class LLVOSky : public LLStaticViewerObject
 	F32					mWind;
 	
 	bool				mInitialized;
-	bool				mForceUpdate;				//flag to force instantaneous update of cubemap
-	LLVector3			mLastSunLightingDirection;
-    LLVector3			mLastMoonLightingDirection;
-	LLColor3			mLastTotalAmbient;
+	bool				mForceUpdate;	
+    bool				mNeedUpdate;				// flag to force update of cubemap
+	S32					mCubeMapUpdateStage;		// state of cubemap uodate: -1 idle; 0-5 per-face updates; 6 finalizing
+
 	F32					mAmbientScale;
 	LLColor3			mNightColorShift;
 	F32					mInterpVal;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 448b65272bfcb335bc7bf41a1398dddffa973d48..7048b921b0ea257ba5d1d61e666e0e2a50e103c7 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -735,6 +735,23 @@ void LLPipeline::throttleNewMemoryAllocation(bool disable)
 	}
 }
 
+void LLPipeline::requestResizeScreenTexture()
+{
+    gResizeScreenTexture = TRUE;
+}
+
+void LLPipeline::requestResizeShadowTexture()
+{
+    gResizeShadowTexture = TRUE;
+}
+
+void LLPipeline::resizeShadowTexture()
+{
+    releaseShadowTargets();
+    allocateShadowBuffer(mScreenWidth, mScreenHeight);
+    gResizeShadowTexture = FALSE;
+}
+
 void LLPipeline::resizeScreenTexture()
 {
 	LL_RECORD_BLOCK_TIME(FTM_RESIZE_SCREEN_TEXTURE);
@@ -743,23 +760,12 @@ void LLPipeline::resizeScreenTexture()
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
 		GLuint resY = gViewerWindow->getWorldViewHeightRaw();
 	
-		if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight()))
+		if (gResizeScreenTexture || (resX != mScreen.getWidth()) || (resY != mScreen.getHeight()))
 		{
 			releaseScreenBuffers();
-		if (!allocateScreenBuffer(resX,resY))
-			{
-#if PROBABLE_FALSE_DISABLES_OF_ALM_HERE
-				//FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled
-			//NOTE: if the session closes successfully after this call, deferred rendering will be 
-			// disabled on future sessions
-			if (LLPipeline::sRenderDeferred)
-			{
-				gSavedSettings.setBOOL("RenderDeferred", FALSE);
-				LLPipeline::refreshCachedSettings();
-
-				}
-#endif
-			}
+            releaseShadowTargets();
+		    allocateScreenBuffer(resX,resY);
+            gResizeScreenTexture = FALSE;
 		}
 	}
 }
@@ -864,9 +870,6 @@ LLPipeline::eFBOStatus LLPipeline::doAllocateScreenBuffer(U32 resX, U32 resY)
 	return ret;
 }
 
- // must be even to avoid a stripe in the horizontal shadow blur
-inline U32 BlurHappySize(U32 x, U32 scale) { return (((x*scale)+1)&~1); }
-
 bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 {
 	refreshCachedSettings();
@@ -934,6 +937,54 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 			mDeferredLight.release();
 		}
 
+        allocateShadowBuffer(resX, resY);
+
+        //HACK make screenbuffer allocations start failing after 30 seconds
+        if (gSavedSettings.getBOOL("SimulateFBOFailure"))
+        {
+            return false;
+        }
+    }
+    else
+    {
+        mDeferredLight.release();
+
+        releaseShadowTargets();
+
+		mFXAABuffer.release();
+		mScreen.release();
+		mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
+		mDeferredDepth.release();
+		mOcclusionDepth.release();
+						
+		if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;		
+	}
+	
+	if (LLPipeline::sRenderDeferred)
+	{ //share depth buffer between deferred targets
+		mDeferredScreen.shareDepthBuffer(mScreen);
+	}
+
+	gGL.getTexUnit(0)->disable();
+
+	stop_glerror();
+
+	return true;
+}
+
+// must be even to avoid a stripe in the horizontal shadow blur
+inline U32 BlurHappySize(U32 x, F32 scale) { return U32( x * scale + 16.0f) & ~0xF; }
+
+bool LLPipeline::allocateShadowBuffer(U32 resX, U32 resY)
+{
+	refreshCachedSettings();
+	
+	if (LLPipeline::sRenderDeferred)
+	{
+		S32 shadow_detail = RenderShadowDetail;
+
+		const U32 occlusion_divisor = 3;
+
         F32 scale = RenderShadowResolutionScale;
 		U32 sun_shadow_map_width  = BlurHappySize(resX, scale);
 		U32 sun_shadow_map_height = BlurHappySize(resY, scale);
@@ -987,36 +1038,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
                 releaseShadowTarget(i);
             }
         }
-
-        //HACK make screenbuffer allocations start failing after 30 seconds
-        if (gSavedSettings.getBOOL("SimulateFBOFailure"))
-        {
-            return false;
-        }
     }
-    else
-    {
-        mDeferredLight.release();
-
-        releaseShadowTargets();
-
-		mFXAABuffer.release();
-		mScreen.release();
-		mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
-		mDeferredDepth.release();
-		mOcclusionDepth.release();
-						
-		if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;		
-	}
-	
-	if (LLPipeline::sRenderDeferred)
-	{ //share depth buffer between deferred targets
-		mDeferredScreen.shareDepthBuffer(mScreen);
-	}
-
-	gGL.getTexUnit(0)->disable();
-
-	stop_glerror();
 
 	return true;
 }
@@ -1185,6 +1207,11 @@ void LLPipeline::releaseLUTBuffers()
 	}
 }
 
+void LLPipeline::releaseShadowBuffers()
+{
+    releaseShadowTargets();
+}
+
 void LLPipeline::releaseScreenBuffers()
 {
 	mUIScreen.release();
@@ -1194,8 +1221,7 @@ void LLPipeline::releaseScreenBuffers()
 	mDeferredScreen.release();
 	mDeferredDepth.release();
 	mDeferredLight.release();
-	mOcclusionDepth.release();
-	releaseShadowTargets();
+	mOcclusionDepth.release();	
 }
 
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index cc9ec06f80072441d867523c119e30308f709edf..e75a09d75344607a2e663946aa667f27156c1630 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -100,10 +100,17 @@ class LLPipeline
 	void restoreGL();
 	void resetVertexBuffers();
 	void doResetVertexBuffers(bool forced = false);
+    void requestResizeScreenTexture(); // set flag only, no work, safer for callbacks...
+    void requestResizeShadowTexture(); // set flag only, no work, safer for callbacks...
+
 	void resizeScreenTexture();
+    void resizeShadowTexture();
+
 	void releaseGLBuffers();
 	void releaseLUTBuffers();
 	void releaseScreenBuffers();
+    void releaseShadowBuffers();
+
 	void createGLBuffers();
 	void createLUTBuffers();
 
@@ -125,6 +132,7 @@ class LLPipeline
 	//attempt to allocate screen buffers at resX, resY
 	//returns true if allocation successful, false otherwise
 	bool allocateScreenBuffer(U32 resX, U32 resY, U32 samples);
+    bool allocateShadowBuffer(U32 resX, U32 resY);
 
 	void allocatePhysicsBuffer();