diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
index 936b166409f921e25f502635af21b60b2ab0ac07..bcf8bf626415da373bbd50d4a50222d0830d4a35 100644
--- a/indra/llinventory/llsettingsbase.cpp
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -693,6 +693,7 @@ void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf)
 F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_in)
 {
     LLSettingsBase::TrackPosition blendf = blendf_in;
+    llassert(!isnan(blendf));
     if (blendf >= 1.0)
     {
         triggerComplete();
diff --git a/indra/llinventory/llsettingsbase.h b/indra/llinventory/llsettingsbase.h
index 1f0589f5718aafa8c5bc87147471cae06a1e6b82..50276b801acc6843476cbc4ae9b5bee4e3d13743 100644
--- a/indra/llinventory/llsettingsbase.h
+++ b/indra/llinventory/llsettingsbase.h
@@ -467,6 +467,7 @@ class LLSettingsBlender : public PTR_NAMESPACE::enable_shared_from_this<LLSettin
 
 class LLSettingsBlenderTimeDelta : public LLSettingsBlender
 {
+protected:
     LOG_CLASS(LLSettingsBlenderTimeDelta);
 public:
     static const LLSettingsBase::BlendFactor MIN_BLEND_DELTA;
diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index eb8385281c971e1b3e1ded636d1c8ca98f3d0be4..6521ec8b4320e80eac0adfe928cacdca7979ac45 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -403,6 +403,7 @@ LLSettingsSky::LLSettingsSky(const LLSD &data) :
     mNextRainbowTextureId(),
     mNextHaloTextureId()
 {
+    mCanAutoAdjust = !data.has(SETTING_REFLECTION_PROBE_AMBIANCE);
 }
 
 LLSettingsSky::LLSettingsSky():
@@ -425,6 +426,8 @@ void LLSettingsSky::replaceSettings(LLSD settings)
     mNextBloomTextureId.setNull();
     mNextRainbowTextureId.setNull();
     mNextHaloTextureId.setNull();
+
+    mCanAutoAdjust = !settings.has(SETTING_REFLECTION_PROBE_AMBIANCE);
 }
 
 void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
@@ -437,6 +440,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother)
     mNextBloomTextureId = pother->mNextBloomTextureId;
     mNextRainbowTextureId = pother->mNextRainbowTextureId;
     mNextHaloTextureId = pother->mNextHaloTextureId;
+    mCanAutoAdjust = pother->mCanAutoAdjust;
 }
 
 void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) 
@@ -1429,18 +1433,23 @@ F32 LLSettingsSky::getSkyIceLevel() const
     return mSettings[SETTING_SKY_ICE_LEVEL].asReal();
 }
 
-F32 LLSettingsSky::getReflectionProbeAmbiance() const
+F32 LLSettingsSky::getReflectionProbeAmbiance(bool auto_adjust) const
 {
+    if (auto_adjust && canAutoAdjust())
+    {
+        return 1.f;
+    }
+
     return mSettings[SETTING_REFLECTION_PROBE_AMBIANCE].asReal();
 }
 
-F32 LLSettingsSky::getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale) const
+F32 LLSettingsSky::getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool auto_adjust) const
 {
     // feed cloud shadow back into reflection probe ambiance to mimic pre-reflection-probe behavior 
     // without brightening dark/interior spaces
-    F32 probe_ambiance = getReflectionProbeAmbiance();
+    F32 probe_ambiance = getReflectionProbeAmbiance(auto_adjust);
 
-    if (probe_ambiance > 0.f)
+    if (probe_ambiance > 0.f && probe_ambiance < 1.f)
     {
         probe_ambiance += (1.f - probe_ambiance) * getCloudShadow() * cloud_shadow_scale;
     }
diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h
index 7ae569dd4c70c5f860c6d8076d28226ce7d781e1..f55e9f063102580fce50c9f55a1ed1ffadacc742 100644
--- a/indra/llinventory/llsettingssky.h
+++ b/indra/llinventory/llsettingssky.h
@@ -134,10 +134,12 @@ class LLSettingsSky: public LLSettingsBase
     F32 getSkyIceLevel() const;
 
     // get the probe ambiance setting as stored in the sky settings asset
-    F32 getReflectionProbeAmbiance() const;
+    // auto_adjust - if true and canAutoAdjust() is true, return 1.0
+    F32 getReflectionProbeAmbiance(bool auto_adjust = false) const;
 
     // get the probe ambiance setting to use for rendering (adjusted by cloud shadow, aka cloud coverage)
-    F32 getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale) const;
+    // auto_adjust - if true and canAutoAdjust() is true, return 1.0
+    F32 getTotalReflectionProbeAmbiance(F32 cloud_shadow_scale, bool auto_adjust = false) const;
 
     // Return first (only) profile layer represented in LLSD
     LLSD getRayleighConfig() const;
@@ -334,6 +336,10 @@ class LLSettingsSky: public LLSettingsBase
                     F32 aniso_factor = 0.0f);
 
     virtual void        updateSettings() SETTINGS_OVERRIDE;
+
+    // if true, this sky is a candidate for auto-adjustment
+    bool canAutoAdjust() const { return mCanAutoAdjust; }
+
 protected:
     static const std::string SETTING_LEGACY_EAST_ANGLE;
     static const std::string SETTING_LEGACY_ENABLE_CLOUD_SCROLL;
@@ -377,6 +383,9 @@ class LLSettingsSky: public LLSettingsBase
     mutable LLColor4    mTotalAmbient;
     mutable LLColor4    mHazeColor;
 
+    // if true, this sky is a candidate for auto adjustment
+    bool mCanAutoAdjust = true;
+
     typedef std::map<std::string, S32> mapNameToUniformId_t;
 
     static mapNameToUniformId_t sNameToUniformMapping;
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index e012eb9a62f4a4e758e6c2beefe4ae968135b1ab..7fdef4a3b7d87b8389a1c80e1e372bb70f38709d 100644
--- a/indra/llrender/llgltexture.cpp
+++ b/indra/llrender/llgltexture.cpp
@@ -27,25 +27,6 @@
 #include "llgltexture.h"
 
 
-// static
-S32 LLGLTexture::getTotalNumOfCategories() 
-{
-	return MAX_GL_IMAGE_CATEGORY - (BOOST_HIGH - BOOST_SCULPTED) + 2 ;
-}
-
-// static
-//index starts from zero.
-S32 LLGLTexture::getIndexFromCategory(S32 category) 
-{
-	return (category < BOOST_HIGH) ? category : category - (BOOST_HIGH - BOOST_SCULPTED) + 1 ;
-}
-
-//static 
-S32 LLGLTexture::getCategoryFromIndex(S32 index)
-{
-	return (index < BOOST_HIGH) ? index : index + (BOOST_HIGH - BOOST_SCULPTED) - 1 ;
-}
-
 LLGLTexture::LLGLTexture(BOOL usemipmaps)
 {
 	init();
diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
index 3732333f8f28b89c3661ff58b030d3cf926a82d7..5c693fc93c12bea6b81ddba0a4449e825973f74b 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -49,8 +49,8 @@ class LLGLTexture : public LLTexture
 	enum EBoostLevel
 	{
 		BOOST_NONE 			= 0,
-		BOOST_AVATAR_BAKED	,
 		BOOST_AVATAR		,
+        BOOST_AVATAR_BAKED  ,
 		BOOST_SCULPTED      ,
 		
 		BOOST_HIGH 			= 10,
@@ -87,10 +87,6 @@ class LLGLTexture : public LLTexture
 		NO_DELETE = 99       //stay in memory, can not be removed.
 	} LLGLTextureState;
 
-	static S32 getTotalNumOfCategories() ;
-	static S32 getIndexFromCategory(S32 category) ;
-	static S32 getCategoryFromIndex(S32 index) ;
-
 protected:
 	virtual ~LLGLTexture();
 	LOG_CLASS(LLGLTexture);
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 1458b98bf5f2f44068e642f261d262f91d1b7fed..75d6ef6c4613409293ae3736d9bfbd8e8ff7bb48 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -1266,13 +1266,11 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("lightnorm");
 	mReservedUniforms.push_back("sunlight_color");
 	mReservedUniforms.push_back("ambient_color");
+    mReservedUniforms.push_back("sky_hdr_scale");
 	mReservedUniforms.push_back("blue_horizon");
-    mReservedUniforms.push_back("blue_horizon_linear");
-	mReservedUniforms.push_back("blue_density");
-    mReservedUniforms.push_back("blue_density_linear");
-	mReservedUniforms.push_back("haze_horizon");
+    mReservedUniforms.push_back("blue_density");
+    mReservedUniforms.push_back("haze_horizon");
 	mReservedUniforms.push_back("haze_density");
-    mReservedUniforms.push_back("haze_density_linear");
 	mReservedUniforms.push_back("cloud_shadow");
 	mReservedUniforms.push_back("density_multiplier");
 	mReservedUniforms.push_back("distance_multiplier");
@@ -1461,9 +1459,6 @@ void LLShaderMgr::initAttribsAndUniforms()
     mReservedUniforms.push_back("water_edge");
     mReservedUniforms.push_back("sun_up_factor");
     mReservedUniforms.push_back("moonlight_color");
-    mReservedUniforms.push_back("moonlight_linear");
-    mReservedUniforms.push_back("sunlight_linear");
-    mReservedUniforms.push_back("ambient_linear");
 
 	llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
 
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 2ab3ba71db1805298fc617818d0222c627ab69cf..46f352aa58c29fa69c0d51b7405d9aab15f8b296 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -102,13 +102,11 @@ class LLShaderMgr
         LIGHTNORM,                          //  "lightnorm"
         SUNLIGHT_COLOR,                     //  "sunlight_color"
         AMBIENT,                            //  "ambient_color"
+        SKY_HDR_SCALE,                      //  "sky_hdr_scale"
         BLUE_HORIZON,                       //  "blue_horizon"
-        BLUE_HORIZON_LINEAR,                //  "blue_horizon_linear"
         BLUE_DENSITY,                       //  "blue_density"
-        BLUE_DENSITY_LINEAR,                //  "blue_density_linear"
         HAZE_HORIZON,                       //  "haze_horizon"
         HAZE_DENSITY,                       //  "haze_density"
-        HAZE_DENSITY_LINEAR,                //  "haze_density_linear"
         CLOUD_SHADOW,                       //  "cloud_shadow"
         DENSITY_MULTIPLIER,                 //  "density_multiplier"
         DISTANCE_MULTIPLIER,                //  "distance_multiplier"
@@ -286,9 +284,6 @@ class LLShaderMgr
         WATER_EDGE_FACTOR,                  //  "water_edge"
         SUN_UP_FACTOR,                      //  "sun_up_factor"
         MOONLIGHT_COLOR,                    //  "moonlight_color"
-        MOONLIGHT_LINEAR,                    //  "moonlight_LINEAR"
-        SUNLIGHT_LINEAR,                     //  "sunlight_linear"
-        AMBIENT_LINEAR,                     //  "ambient_linear"
         END_RESERVED_UNIFORMS
     } eGLSLReservedUniforms;
     // clang-format on
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 533a3361e6a4e3c04be5e40282c90eb43e461dbf..c90c9c543ca3f264014a402c64e5132775bcc6dc 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9116,6 +9116,28 @@
     <key>Value</key>
     <real>500.0</real>
   </map>
+  <key>RenderSSAOIrradianceScale</key>
+  <map>
+    <key>Comment</key>
+    <string>Scaling factor for irradiance input to SSAO</string>
+    <key>Persist</key>
+    <integer>0</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.6</real>
+  </map>
+  <key>RenderSSAOIrradianceMax</key>
+  <map>
+    <key>Comment</key>
+    <string>Max factor for irradiance input to SSAO</string>
+    <key>Persist</key>
+    <integer>0</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.18</real>
+  </map>
   <key>RenderSSAOMaxScale</key>
   <map>
     <key>Comment</key>
@@ -10468,17 +10490,6 @@
     <key>Value</key>
     <integer>1</integer>
   </map>
-  <key>RenderReflectionProbeCount</key>
-  <map>
-    <key>Comment</key>
-    <string>Number of reflection probes (maximum is 256, requires restart)</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>S32</string>
-    <key>Value</key>
-    <integer>256</integer>
-  </map>
   <key>RenderReflectionProbeResolution</key>
   <map>
     <key>Comment</key>
@@ -10588,40 +10599,29 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>1.25</real>
-  </map>
-  <key>RenderReflectionProbeMaxLocalLightAmbiance</key>
-  <map>
-    <key>Comment</key>
-    <string>Maximum effective probe ambiance for local lights</string>
-    <key>Persist</key>
-    <integer>0</integer>
-    <key>Type</key>
-    <string>F32</string>
-    <key>Value</key>
-    <real>4.0</real>
+    <real>1.0</real>
   </map>
-  <key>RenderDynamicExposureMin</key>
+  <key>RenderSkyAutoAdjustLegacy</key>
   <map>
     <key>Comment</key>
-    <string>Minimum dynamic exposure amount</string>
+    <string>If true, automatically adjust legacy skies (those without a probe ambiance value) to take advantage of probes and HDR.</string>
     <key>Persist</key>
-    <integer>0</integer>
+    <integer>1</integer>
     <key>Type</key>
-    <string>F32</string>
+    <string>Boolean</string>
     <key>Value</key>
-    <real>0.6</real>
+    <integer>1</integer>
   </map>
-  <key>RenderDynamicExposureMax</key>
+  <key>RenderReflectionProbeMaxLocalLightAmbiance</key>
   <map>
     <key>Comment</key>
-    <string>Maximum dynamic exposure amount</string>
+    <string>Maximum effective probe ambiance for local lights</string>
     <key>Persist</key>
     <integer>0</integer>
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>1.5</real>
+    <real>4.0</real>
   </map>
   <key>RenderDynamicExposureCoefficient</key>
   <map>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
index 55e45ce0af6f308ae8eef896e77c06dc3ada5453..c8eaba64182f8d6ced4b73614494d8a2a225f4aa 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
@@ -387,7 +387,7 @@ vec3 pbrIbl(vec3 diffuseColor,
 {
     // retrieve a scale and bias to F0. See [1], Figure 3
 	vec2 brdf = BRDF(clamp(nv, 0, 1), 1.0-perceptualRough);
-	vec3 diffuseLight = irradiance*1.25;  //magic 1.25 to balance with legacy materials
+	vec3 diffuseLight = irradiance;
 	vec3 specularLight = radiance;
     
 	vec3 diffuse = diffuseLight * diffuseColor;
@@ -563,7 +563,7 @@ vec3 pbrBaseLight(vec3 diffuseColor, vec3 specularColor, float metallic, vec3 v,
     vec3 ibl_spec;
     color += pbrIbl(diffuseColor, specularColor, radiance, irradiance, ao, NdotV, perceptualRoughness, ibl_spec);
     
-    color += pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, norm, v, normalize(light_dir), specContrib) * sunlit * 3.9 * scol; //magic number to balance with legacy materials
+    color += pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, norm, v, normalize(light_dir), specContrib) * sunlit * 3.0 * scol; //magic number to balance with legacy materials
     specContrib *= sunlit * 2.75 * scol;
     specContrib += ibl_spec;
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index 385cd51969b000b80a9e9f386916cf92325a9ea3..b752307d1314f2940f09dd49495b205053e4f6f1 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -44,7 +44,7 @@ vec3 legacy_adjust_fullbright(vec3 c);
 vec3 legacy_adjust(vec3 c);
 vec3 linear_to_srgb(vec3 cl);
 vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
-void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao);
+void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
 
 #ifdef HAS_ALPHA_MASK
 uniform float minimum_alpha;
@@ -85,7 +85,7 @@ void main()
     vec3 amblit;
     vec3 additive;
     vec3 atten;
-    calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false);
+    calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten);
 #endif
 
 #ifdef WATER_FOG
diff --git a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
index ee425f97fc85c5376c7c0ae1af9688ffab5c4533..c8afacf9bb5757b8a2956d404e551aa431b48391 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/luminanceF.glsl
@@ -47,6 +47,6 @@ void main()
     tc.y -= 0.1; // HACK - nudge exposure sample down a little bit to favor ground over sky
     vec3 c = texture(diffuseRect, tc).rgb + texture(emissiveRect, tc).rgb;
     float L = lum(c);
-    frag_color = vec4(L);
+    frag_color = vec4(max(L, 0.0));
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl
index e9515a918779ecb0fa0ed4b9171d09fad1154c9c..6b960fae3349dab0255b5cc684d39da0f9e39ca5 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbralphaV.glsl
@@ -71,6 +71,7 @@ flat out float vary_sign;
 out vec3 vary_normal;
 
 vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
+vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
 
 
 void main()
@@ -102,9 +103,11 @@ void main()
   	vec3 t = normal_matrix * tangent.xyz;
 #endif //HAS_SKIN
 
-    vary_tangent = normalize(t);
+    n = normalize(n);
+
+    vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0));
     vary_sign = tangent.w;
-    vary_normal = normalize(n);
+    vary_normal = n;
 
 	vertex_color = diffuse_color;
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl
index e2c23ac8f017e93e1d3efb58710d8ea7ca48dcf6..160ae7a215d1d6889cba18527c0538e53180c25a 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueV.glsl
@@ -61,6 +61,7 @@ flat out float vary_sign;
 out vec3 vary_normal;
 
 vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
+vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
 
 void main()
 {
@@ -91,9 +92,11 @@ void main()
 	vec3 t = normal_matrix * tangent.xyz;
 #endif
 
-    vary_tangent = normalize(t);
+    n = normalize(n);
+
+    vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0));
     vary_sign = tangent.w;
-    vary_normal = normalize(n);
+    vary_normal = n;
 	
 	vertex_color = diffuse_color;
 }
@@ -107,8 +110,6 @@ uniform mat4 modelview_projection_matrix;
 uniform mat4 texture_matrix0;
 
 uniform vec4[2] texture_base_color_transform;
-uniform vec4[2] texture_normal_transform;
-uniform vec4[2] texture_metallic_roughness_transform;
 uniform vec4[2] texture_emissive_transform;
 
 in vec3 position;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
index a32296369cf403596988659e4838a5e4f7943328..53e4f02314599b5cc240ca9ee9191e3e1a303ad8 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
@@ -102,16 +102,12 @@ vec3 toneMap(vec3 color)
 {
 #ifndef NO_POST
     float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r;
-
+    
     color *= exposure * exp_scale;
 
     color = toneMapACES_Hill(color);
-#else
-    color *= 0.6;
 #endif
 
-    color = linear_to_srgb(color);
-
     return color;
 }
 
@@ -158,10 +154,10 @@ float noise(vec2 x) {
 
 vec3 legacyGamma(vec3 color)
 {
-    color = 1. - clamp(color, vec3(0.), vec3(1.));
-    color = 1. - pow(color, vec3(gamma)); // s/b inverted already CPU-side
+    vec3 c = 1. - clamp(color, vec3(0.), vec3(1.));
+    c = 1. - pow(c, vec3(gamma)); // s/b inverted already CPU-side
 
-    return color;
+    return c;
 }
 
 void main() 
@@ -169,12 +165,14 @@ void main()
     //this is the one of the rare spots where diffuseRect contains linear color values (not sRGB)
     vec4 diff = texture(diffuseRect, vary_fragcoord);
 
-    diff.rgb = toneMap(diff.rgb);
-
 #ifdef LEGACY_GAMMA
-#ifndef NO_POST
+    diff.rgb = linear_to_srgb(diff.rgb);
     diff.rgb = legacyGamma(diff.rgb);
+#else
+#ifndef NO_POST
+    diff.rgb = toneMap(diff.rgb);
 #endif
+    diff.rgb = linear_to_srgb(diff.rgb);
 #endif
 
     vec2 tc = vary_fragcoord.xy*screen_res*4.0;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl
index 71f7ec52c42fb9508324cb7f8008e9c4b1a868dc..636dfed4ba2814e94890dcf99b3f8bf84e3154a6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/textureUtilV.glsl
@@ -76,3 +76,47 @@ vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl
 
     return texcoord;
 }
+
+// Take the rotation only from both transforms and apply to the tangent. This
+// accounts for the change of the topology of the normal texture when a texture
+// rotation is applied to it.
+// *HACK: Assume the imported GLTF model did not have both normal texture
+// transforms and tangent vertices. The use of this function is inconsistent
+// with the GLTF sample viewer when that is the case. See getNormalInfo in
+// https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Viewer/47a191931461a6f2e14de48d6da0f0eb6ec2d147/source/Renderer/shaders/material_info.glsl
+// We may want to account for this case during GLTF model import.
+// -Cosmic,2023-06-06
+vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform)
+{
+    vec2 weights = vec2(0, 1);
+
+    // Apply texture animation first to avoid shearing and other artifacts (rotation only)
+    mat2 sl_rot_scale;
+    sl_rot_scale[0][0] = sl_animation_transform[0][0];
+    sl_rot_scale[0][1] = sl_animation_transform[0][1];
+    sl_rot_scale[1][0] = sl_animation_transform[1][0];
+    sl_rot_scale[1][1] = sl_animation_transform[1][1];
+    weights = sl_rot_scale * weights;
+    // Remove scale
+    weights = normalize(weights);
+
+    // Convert to left-handed coordinate system
+    weights.y = -weights.y;
+
+    // Apply KHR_texture_transform (rotation only)
+    float khr_rotation = khr_gltf_transform[0].z;
+    mat2 khr_rotation_mat = mat2(
+        cos(khr_rotation),-sin(khr_rotation),
+        sin(khr_rotation), cos(khr_rotation)
+    );
+    weights = khr_rotation_mat * weights;
+
+    // Convert back to right-handed coordinate system
+    weights.y = -weights.y;
+
+    // Similar to the MikkTSpace-compatible method of extracting the binormal
+    // from the normal and tangent, as seen in the fragment shader
+    vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz);
+
+    return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz);
+}
diff --git a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl
index 689c345b2cd6844250110de5b27e59c694282977..31b02377da73fa09ce1a9b5983fa0224beca0306 100644
--- a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl
@@ -113,18 +113,31 @@ vec3 inv_toneMapACES_Hill(vec3 color)
     return color;
 }
 
+// adjust legacy colors to back out tonemapping and exposure 
+//   NOTE: obsolete now that setting probe ambiance to zero removes tonemapping and exposure, but keeping for a minute
+//   while that change goes through testing - davep 6/1/2023
+#define LEGACY_ADJUST 0
+
 vec3 legacy_adjust(vec3 c)
 {
+#if LEGACY_ADJUST
     vec3 desat = rgb2hsv(c.rgb);
     desat.g *= 1.0-(1.0-desat.b)*0.5;
     desat.b += (1.0-desat.b)*0.1f;
     desat.rgb = hsv2rgb(desat);
     return desat;
+#else
+    return c;
+#endif
 }
 
 vec3 legacy_adjust_fullbright(vec3 c)
 {
-    float exp_scale = texture(exposureMap, vec2(0.5, 0.5)).r;
+#if LEGACY_ADJUST
+    float exp_scale = clamp(texture(exposureMap, vec2(0.5, 0.5)).r, 0.01, 10.0);
     return c / exp_scale * 1.34; //magic 1.34 arrived at by binary search for a value that reproduces midpoint grey consistenty
+#else
+    return c;
+#endif
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
index 0c3ea4231e97b820ae0232f522fef6960fcd2cb3..75a327d3d7b1c96b872ff61e797f6ba5d65fa829 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/sumLightsV.glsl
@@ -38,15 +38,7 @@ vec4 sumLights(vec3 pos, vec3 norm, vec4 color)
 	col.a = color.a;
 	
 	col.rgb = light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz);
-	col.rgb = scaleDownLight(col.rgb);
-
-#if defined(LOCAL_LIGHT_KILL)
-    col.rgb = vec3(0);
-#endif
-
-#if !defined(SUNLIGHT_KILL)
-	col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz));
-#endif
+    col.rgb += light_diffuse[1].rgb * sqrt(calcDirectionalLight(norm, -light_position[1].xyz)*0.5+0.25);
 
 	col.rgb = min(col.rgb*color.rgb, 1.0);
 	return col;	
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
similarity index 96%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
index e314555ef9edc321a02dd240f8857c2074464309..48cf234aa0a93797a2c4ac09e1d413eb94b3c928 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsF.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsF.glsl
@@ -30,7 +30,7 @@ vec3 scaleSoftClipFrag(vec3 light);
 vec3 srgb_to_linear(vec3 col);
 vec3 linear_to_srgb(vec3 col);
 
-uniform int sun_up_factor;
+uniform float sky_hdr_scale;
 
 vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten)
 { 
@@ -38,7 +38,7 @@ vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten)
     additive = srgb_to_linear(additive*2.0);
     // magic 1.25 here is to match the default RenderSkyHDRScale -- this parameter needs to be plumbed into sky settings or something
     // so it's available to all shaders that call atmosFragLighting instead of just softenLightF.glsl
-    additive *= sun_up_factor*1.25 + 1.0; 
+    additive *= sky_hdr_scale;
     light += additive;
     return light;
 }
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl
similarity index 79%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl
index 4e0933f9228aefb38776cac78789225b50707961..437fa0a6d549fdc8f4f7b238dec2ac8958ce1ee9 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsFuncs.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsFuncs.glsl
@@ -25,27 +25,21 @@
 
 uniform vec3  lightnorm;
 uniform vec3  sunlight_color;
-uniform vec3 sunlight_linear;
 uniform vec3  moonlight_color;
-uniform vec3 moonlight_linear;
 uniform int   sun_up_factor;
 uniform vec3  ambient_color;
-uniform vec3 ambient_linear;
 uniform vec3  blue_horizon;
-uniform vec3 blue_horizon_linear;
 uniform vec3  blue_density;
-uniform vec3 blue_density_linear;
 uniform float haze_horizon;
 uniform float haze_density;
-uniform float haze_density_linear;
 uniform float cloud_shadow;
 uniform float density_multiplier;
 uniform float distance_multiplier;
 uniform float max_y;
 uniform vec3  glow;
 uniform float scene_light_strength;
-uniform mat3  ssao_effect_mat;
 uniform float sun_moon_glow_factor;
+uniform float sky_hdr_scale;
 
 float getAmbientClamp() { return 1.0f; }
 
@@ -54,7 +48,7 @@ vec3 legacy_adjust(vec3 col);
 
 // return colors in sRGB space
 void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive,
-                         out vec3 atten, bool use_ao)
+                         out vec3 atten)
 {
     vec3 rel_pos = inPositionEye;
 
@@ -64,7 +58,7 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
     vec3  rel_pos_norm = normalize(rel_pos);
     float rel_pos_len  = length(rel_pos);
     
-    vec3  sunlight     = (sun_up_factor == 1) ? sunlight_color: moonlight_color * 0.7;  // magic 0.7 to match legacy color
+    vec3  sunlight     = (sun_up_factor == 1) ? sunlight_color: moonlight_color;
     
     // sunlight attenuation effect (hue and brightness) due to atmosphere
     // this is used later for sunlight modulation at various altitudes
@@ -117,20 +111,6 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
     // increase ambient when there are more clouds
     vec3 tmpAmbient = amb_color + (vec3(1.) - amb_color) * cloud_shadow * 0.5;
 
-    /*  decrease value and saturation (that in HSV, not HSL) for occluded areas
-     * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html
-     * // The following line of code performs the equivalent of:
-     * float ambAlpha = tmpAmbient.a;
-     * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis
-     * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue);
-     * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat,
-     * ambAlpha);
-     */
-    if (use_ao)
-    {
-        tmpAmbient = mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor);
-    }
-
     // Similar/Shared Algorithms:
     //     indra\llinventory\llsettingssky.cpp                                        -- LLSettingsSky::calculateLightSettings()
     //     indra\newview\app_settings\shaders\class1\windlight\atmosphericsFuncs.glsl -- calcAtmosphericVars()
@@ -141,7 +121,7 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
     // brightness of surface both sunlight and ambient
     
     sunlit = sunlight.rgb;
-    amblit = vec3(1,0,1); //should no longer be used, filled in by calcAtmosphericVarsLinear
+    amblit = tmpAmbient;
 
     additive *= vec3(1.0 - combined_haze);
 }
@@ -164,15 +144,16 @@ float ambientLighting(vec3 norm, vec3 light_dir)
 void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 additive,
                          out vec3 atten)
 {
-    calcAtmosphericVars(inPositionEye, light_dir, 1.0, sunlit, amblit, additive, atten, false);
+    calcAtmosphericVars(inPositionEye, light_dir, 1.0, sunlit, amblit, additive, atten);
 
-    // multiply by 2 to get same colors as when the "scaleSoftClip" implementation was doubling color values
+    // multiply to get similar colors as when the "scaleSoftClip" implementation was doubling color values
     // (allows for mixing of light sources other than sunlight e.g. reflection probes)
-    sunlit *= 2.0;
-
-    // squash ambient to approximate whatever weirdness legacy atmospherics were doing
-    amblit = ambient_color; // * (1.0+sun_up_factor*0.3);
+    sunlit *= 1.5;
+    amblit *= 0.5;
+    
+    // override amblit with ambient_color if sky probe ambiance is not zero
+    amblit = mix(amblit, ambient_color, clamp(sky_hdr_scale-1.0, 0.0, 1.0));
 
-    amblit *= ambientLighting(norm, light_dir);
     amblit = srgb_to_linear(amblit);
+    amblit *= ambientLighting(norm, light_dir);
 }
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersF.glsl
similarity index 100%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersF.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersF.glsl
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
similarity index 100%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsHelpersV.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsHelpersV.glsl
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
similarity index 96%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
index 3773f191e855c4b37d305a08100276d2af7de755..cc3617ba61b8f3a0f91afee4bcea22a5494788f3 100644
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
+++ b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsV.glsl
@@ -38,7 +38,7 @@ void setPositionEye(vec3 v);
 
 vec3 getAdditiveColor();
 
-void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao);
+void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
 
 void calcAtmospherics(vec3 inPositionEye) {
     vec3 P = inPositionEye;
@@ -48,7 +48,7 @@ void calcAtmospherics(vec3 inPositionEye) {
     vec3 tmpaddlit = vec3(1);
     vec3 tmpattenlit = vec3(1);
 	vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;	
-    calcAtmosphericVars(inPositionEye, light_dir, 1, tmpsunlit, tmpamblit, tmpaddlit, tmpattenlit, false);
+    calcAtmosphericVars(inPositionEye, light_dir, 1, tmpsunlit, tmpamblit, tmpaddlit, tmpattenlit);
     setSunlitColor(tmpsunlit);
     setAmblitColor(tmpamblit);
     setAdditiveColor(tmpaddlit);
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
similarity index 100%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsF.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsF.glsl
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
similarity index 100%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsV.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsV.glsl
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterF.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl
similarity index 100%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterF.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterF.glsl
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterV.glsl b/indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl
similarity index 100%
rename from indra/newview/app_settings/shaders/class2/windlight/atmosphericsVarsWaterV.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/atmosphericsVarsWaterV.glsl
diff --git a/indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl b/indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
similarity index 100%
rename from indra/newview/app_settings/shaders/class2/windlight/gammaF.glsl
rename to indra/newview/app_settings/shaders/class1/windlight/gammaF.glsl
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index ae8cd97b180a823d874a4e5fc011e50a78969dbd..cd57b47eae066cb8fce756054b3f38622347f067 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -274,6 +274,10 @@ void main()
 
     color.rgb = atmosFragLightingLinear(color.rgb, additive, atten);
 
+#ifdef WATER_FOG
+    color = applyWaterFogViewLinear(pos.xyz, color, sunlit_linear);
+#endif // WATER_FOG
+
     vec4 light = vec4(0,0,0,0);
     
    #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, diffuse_linear.rgb, pos.xyz, norm, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
@@ -291,11 +295,6 @@ void main()
     color.rgb += light.rgb;
 #endif // !defined(LOCAL_LIGHT_KILL)
 
-
-#ifdef WATER_FOG
-    color = applyWaterFogViewLinear(pos.xyz, color, sunlit_linear);
-#endif // WATER_FOG
-
 #endif // #else // FOR_IMPOSTOR
 
 #ifdef IS_HUD
diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
index 7b7b4a040cf196e7adfaff1da19972aeb67fe57c..d678973515aca8652c424aa52d8388fa537a6d52 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
@@ -84,6 +84,10 @@ vec3 linear_to_srgb(vec3 c);
 void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
 vec3 atmosFragLightingLinear(vec3 color, vec3 additive, vec3 atten);
 
+#ifdef WATER_FOG
+vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
+#endif
+
 void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
 float calcLegacyDistanceAttenuation(float distance, float falloff);
 float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
@@ -148,7 +152,7 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
         // spot*spot => GL_SPOT_EXPONENT=2
         float spot_atten = spot*spot;
 
-        vec3 intensity = spot_atten * dist_atten * lightColor * 3.9; //magic number to balance with legacy materials
+        vec3 intensity = spot_atten * dist_atten * lightColor * 3.0; //magic number to balance with legacy materials
 
         vec3 speccol;
         color = intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv, speccol);
@@ -237,6 +241,11 @@ void main()
 
     color.rgb = atmosFragLightingLinear(color.rgb, additive, atten);
     
+#ifdef WATER_FOG
+    vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0), sunlit_linear);
+    color = temp.rgb;
+#endif
+
     vec3 light = vec3(0);
 
     // Punctual lights
@@ -258,7 +267,7 @@ void main()
     glare = min(glare, 1.0);
     a = max(a, glare);
 
-    frag_color = vec4(color.rgb,a);
+    frag_color = max(vec4(color.rgb,a), vec4(0));
 }
 
 #else
@@ -311,7 +320,7 @@ void main()
     float a = basecolor.a*vertex_color.a;
     color += colorEmissive;
     color = linear_to_srgb(color);
-    frag_color = vec4(color.rgb,a);
+    frag_color = max(vec4(color.rgb,a), vec4(0));
 }
 
 #endif
diff --git a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
index 1c79748b49ee2476adbc6d0cbbf0b9107b2f4241..0d77e88831fd9c39f1122eceeb15e3418b23b187 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/fullbrightShinyF.glsl
@@ -42,7 +42,7 @@ uniform samplerCube environmentMap;
 vec3 atmosFragLighting(vec3 light, vec3 additive, vec3 atten);
 vec3 legacy_adjust_fullbright(vec3 c);
 vec3 legacy_adjust(vec3 c);
-void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten, bool use_ao);
+void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, out vec3 sunlit, out vec3 amblit, out vec3 additive, out vec3 atten);
 
 vec3 linear_to_srgb(vec3 c);
 vec3 srgb_to_linear(vec3 c);
@@ -71,7 +71,7 @@ void main()
     vec3 additive;
     vec3 atten;
     vec3 pos = vary_position;
-    calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false);
+    calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten);
 
     float env_intensity = vertex_color.a;
 
diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
index 77e3b9238532ab21e8c713d45993c1b7a6d3766b..5fb5647d35b8ee4fd66745579434513c910f3582 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
@@ -38,7 +38,7 @@ uniform float emissive_brightness;  // fullbright flag, 1.0 == fullbright, 0.0 o
 uniform int sun_up_factor;
 
 #ifdef WATER_FOG
-vec4 applyWaterFogView(vec3 pos, vec4 color);
+vec4 applyWaterFogViewLinear(vec3 pos, vec4 color, vec3 sunlit);
 #endif
 
 vec3 atmosFragLightingLinear(vec3 l, vec3 additive, vec3 atten);
@@ -49,6 +49,7 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float
 vec3 srgb_to_linear(vec3 cs);
 vec3 linear_to_srgb(vec3 cs);
 vec3 legacy_adjust(vec3 c);
+vec3 legacy_adjust_fullbright(vec3 c);
 
 #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
 
@@ -396,7 +397,7 @@ void main()
     }
 #endif
 
-    color = mix(color.rgb, diffcol.rgb, emissive);
+    color = mix(color.rgb, legacy_adjust_fullbright(diffcol.rgb), emissive);
 
     if (env > 0.0)
     {  // add environmentmap
@@ -410,6 +411,11 @@ void main()
 
     color.rgb = atmosFragLightingLinear(color.rgb, additive, atten); 
 
+#ifdef WATER_FOG
+    vec4 temp = applyWaterFogViewLinear(pos, vec4(color, 0.0), sunlit_linear);
+    color = temp.rgb;
+#endif
+
     vec3 npos = normalize(-pos.xyz);
     vec3 light = vec3(0, 0, 0);
 
@@ -430,11 +436,6 @@ void main()
     glare = min(glare, 1.0);
     float al = max(diffcol.a, glare) * vertex_color.a;
     
-#ifdef WATER_FOG
-    vec4 temp = applyWaterFogView(pos, vec4(color, 0.0));
-    color = temp.rgb;
-#endif
-
     frag_color = max(vec4(color, al), vec4(0));
 
 #else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer 
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index 2f3efaa94a7d1e862c6bbb5086071d90480519a4..409b46218b055b1e07ae00d758e45a9017d8350a 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -25,9 +25,6 @@
 
 #define FLT_MAX 3.402823466e+38
 
-#define REFMAP_COUNT 256
-#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider
-
 out vec4 frag_color;
 
 uniform sampler2D diffuseRect;
@@ -47,9 +44,14 @@ uniform sampler2D     lightFunc;
 uniform float blur_size;
 uniform float blur_fidelity;
 
+#if defined(HAS_SSAO)
+uniform float ssao_irradiance_scale;
+uniform float ssao_irradiance_max;
+#endif
+
 // Inputs
 uniform mat3 env_mat;
-
+uniform mat3  ssao_effect_mat;
 uniform vec3 sun_dir;
 uniform vec3 moon_dir;
 uniform int  sun_up_factor;
@@ -115,6 +117,16 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
                     vec3 l); //surface point to light
 
 
+void adjustIrradiance(inout vec3 irradiance, vec3 amblit_linear, float ambocc)
+{
+    // use sky settings ambient or irradiance map sample, whichever is brighter
+    irradiance = max(amblit_linear, irradiance);
+
+#if defined(HAS_SSAO)
+    irradiance = mix(ssao_effect_mat * min(irradiance.rgb*ssao_irradiance_scale, vec3(ssao_irradiance_max)), irradiance.rgb, ambocc);
+#endif
+}
+
 void main()
 {
     vec2  tc           = vary_fragcoord.xy;
@@ -176,7 +188,7 @@ void main()
         vec3 orm = texture(specularRect, tc).rgb; 
         float perceptualRoughness = orm.g;
         float metallic = orm.b;
-        float ao = orm.r * ambocc;
+        float ao = orm.r;
 
         vec3 colorEmissive = texture(emissiveRect, tc).rgb;
         // PBR IBL
@@ -184,16 +196,13 @@ void main()
         
         sampleReflectionProbes(irradiance, radiance, tc, pos.xyz, norm.xyz, gloss);
         
-        // Take maximium of legacy ambient vs irradiance sample as irradiance
-        // NOTE: ao is applied in pbrIbl (see pbrBaseLight), do not apply here
-        irradiance       = max(amblit_linear,irradiance);
+        adjustIrradiance(irradiance, amblit_linear, ambocc);
 
         vec3 diffuseColor;
         vec3 specularColor;
         calcDiffuseSpecular(baseColor.rgb, metallic, diffuseColor, specularColor);
 
         vec3 v = -normalize(pos.xyz);
-        color = vec3(1,0,1);
         color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten);
         
         if (do_atmospherics)
@@ -206,17 +215,15 @@ void main()
         //should only be true of WL sky, just port over base color value
         color = texture(emissiveRect, tc).rgb;
         color = srgb_to_linear(color);
-        if (sun_up_factor > 0)
-        {
-           color *= sky_hdr_scale + 1.0;
-        }
+        color *= sky_hdr_scale;
     }
     else
     {
         // legacy shaders are still writng sRGB to gbuffer
         baseColor.rgb = legacy_adjust(baseColor.rgb);
-
+        
         baseColor.rgb = srgb_to_linear(baseColor.rgb);
+        
         spec.rgb = srgb_to_linear(spec.rgb);
 
         float da          = clamp(dot(norm.xyz, light_dir.xyz), 0.0, 1.0);
@@ -227,11 +234,10 @@ void main()
 
         sampleReflectionProbesLegacy(irradiance, glossenv, legacyenv, tc, pos.xyz, norm.xyz, spec.a, envIntensity);
         
-        // use sky settings ambient or irradiance map sample, whichever is brighter
-        irradiance = max(amblit_linear, irradiance);
+        adjustIrradiance(irradiance, amblit_linear, ambocc);
 
         // apply lambertian IBL only (see pbrIbl)
-        color.rgb = irradiance * ambocc;
+        color.rgb = irradiance;
 
         vec3 sun_contrib = min(da, scol) * sunlit_linear;
         color.rgb += sun_contrib;
diff --git a/indra/newview/app_settings/shaders/class3/lighting/lightV.glsl b/indra/newview/app_settings/shaders/class3/lighting/lightV.glsl
index 30ad493331f5e9b3faba61aecc93554f31b790f2..77bbbabfae4cea4d67517ec33b4ba7f6697d5aae 100644
--- a/indra/newview/app_settings/shaders/class3/lighting/lightV.glsl
+++ b/indra/newview/app_settings/shaders/class3/lighting/lightV.glsl
@@ -23,21 +23,13 @@
  * $/LicenseInfo$
  */
  
-
-
-// All lights, no specular highlights
-vec3 atmosAmbient();
+// used for preview renders only
 vec4 sumLights(vec3 pos, vec3 norm, vec4 color);
-float getAmbientClamp();
 
 vec4 calcLighting(vec3 pos, vec3 norm, vec4 color)
 {
 	vec4 c = sumLights(pos, norm, color);
 
-#if !defined(AMBIENT_KILL)
-    c.rgb += atmosAmbient() * color.rgb * getAmbientClamp();
-#endif
- 
     return c;
 }
 
diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
deleted file mode 100644
index 4b663dd5b2ee751d20278bb7f87ba4214184d5d4..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * @file class3\lighting\sumLightsV.glsl
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2005, 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$
- */
- 
-
-float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight);
-
-vec3 atmosAffectDirectionalLight(float lightIntensity);
-vec3 scaleDownLight(vec3 light);
-
-uniform vec4 light_position[8];
-uniform vec3 light_direction[8];
-uniform vec4 light_attenuation[8]; 
-uniform vec3 light_diffuse[8];
-
-vec4 sumLights(vec3 pos, vec3 norm, vec4 color)
-{
-	vec4 col = vec4(0.0, 0.0, 0.0, color.a);
-	
-	// Collect normal lights (need to be divided by two, as we later multiply by 2)
-	
-	// Collect normal lights
-	col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z);
-	col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z);
-	col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z);
-	col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z);
-	col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z);
-	col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z);
-	col.rgb += light_diffuse[1].rgb*calcDirectionalLight(norm, light_position[1].xyz);
-    col.rgb = scaleDownLight(col.rgb);
-
-#if defined(LOCAL_LIGHT_KILL)
-    col.rgb = vec3(0);
-#endif
-
-	// Add windlight lights
-#if !defined(SUNLIGHT_KILL)
-	col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, light_position[0].xyz));
-#endif
-
-	col.rgb = min(col.rgb*color.rgb, 1.0);
-	
-	return col;	
-}
-
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index dd4530dae049fb0e391c979f00b9ef33bd86f321..ec2467200afc741bfa6408f054a6747f83851ef4 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 55
+version 57
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -60,7 +60,6 @@ Disregard128DefaultDrawDistance	1	1
 Disregard96DefaultDrawDistance	1	1
 RenderCompressTextures		1	1
 RenderShaderLightingMaxLevel	1	3
-RenderReflectionProbeCount  1   256
 RenderReflectionProbeLevel  1   3
 RenderDeferred				1	1
 RenderDeferredSSAO			1	1
@@ -103,7 +102,6 @@ RenderShadowDetail			1	0
 WLSkyDetail					1	96
 RenderFSAASamples			1	0
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   8
 RenderReflectionProbeLevel  1   0
 
 //
@@ -133,8 +131,7 @@ RenderShadowDetail			1	0
 WLSkyDetail					1	96
 RenderFSAASamples			1	0
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   16
-RenderReflectionProbeLevel  1   1
+RenderReflectionProbeLevel  1   0
 
 //
 // Medium Graphics Settings (standard)
@@ -163,8 +160,7 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	0
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   32
-RenderReflectionProbeLevel  1   2
+RenderReflectionProbeLevel  1   1
 
 //
 // Medium High Graphics Settings (deferred enabled)
@@ -193,7 +189,6 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	1
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   64
 RenderReflectionProbeLevel  1   2
 
 //
@@ -223,7 +218,6 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	1
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   128
 RenderReflectionProbeLevel  1   3
 
 //
@@ -253,7 +247,6 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	1
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   256
 RenderReflectionProbeLevel  1   3
 
 //
@@ -282,8 +275,7 @@ RenderShadowDetail			1	2
 RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	1
-RenderScreenSpaceReflections 1  1
-RenderReflectionProbeCount  1   256
+RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   3
 
 //
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index ef7827e59629c6ab84097cfec6bdc3c18a16998d..0687a3cea1d03c7c02e772a1a49568b2aa6329f4 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 50
+version 52
 // The version number above should be incremented IF AND ONLY IF some
 // change has been made that is sufficiently important to justify
 // resetting the graphics preferences of all users to the recommended
@@ -71,7 +71,6 @@ RenderGLMultiThreadedMedia         1   0
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	2
 RenderScreenSpaceReflections 1  1
-RenderReflectionProbeCount  1   256
 RenderReflectionProbeLevel  1   3
 
 //
@@ -101,7 +100,6 @@ RenderFSAASamples			1	0
 RenderReflectionsEnabled    1   0
 RenderReflectionProbeDetail	1	0
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   8
 RenderReflectionProbeLevel  1   0
 
 //
@@ -131,8 +129,7 @@ RenderFSAASamples			1	0
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	0
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   16
-RenderReflectionProbeLevel  1   1
+RenderReflectionProbeLevel  1   0
 
 //
 // Medium Graphics Settings (standard)
@@ -161,8 +158,7 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	0
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   32
-RenderReflectionProbeLevel  1   2
+RenderReflectionProbeLevel  1   0
 
 //
 // Medium High Graphics Settings (deferred enabled)
@@ -191,8 +187,7 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	0
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   64
-RenderReflectionProbeLevel  1   2
+RenderReflectionProbeLevel  1   0
 
 //
 // High Graphics Settings (deferred + SSAO)
@@ -221,8 +216,7 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	1
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   128
-RenderReflectionProbeLevel  1   3
+RenderReflectionProbeLevel  1   1
 
 //
 // High Ultra Graphics Settings (deferred + SSAO + shadows)
@@ -251,8 +245,7 @@ RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	1
 RenderScreenSpaceReflections 1  0
-RenderReflectionProbeCount  1   256
-RenderReflectionProbeLevel  1   3
+RenderReflectionProbeLevel  1   2
 
 //
 // Ultra graphics (REALLY PURTY!)
@@ -280,8 +273,7 @@ RenderShadowDetail			1	2
 RenderFSAASamples			1	2
 RenderReflectionsEnabled    1   1
 RenderReflectionProbeDetail	1	1
-RenderScreenSpaceReflections 1  1
-RenderReflectionProbeCount  1   256
+RenderScreenSpaceReflections 1  0
 RenderReflectionProbeLevel  1   3
 
 //
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 5b158d857ab364c471abfd2f7d54abcc2a9b2af2..6aa2316589662ae67bf222a68b89c2100eaa299b 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -58,8 +58,6 @@ BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
 
 LLVector4 LLDrawPoolAlpha::sWaterPlane;
 
-static BOOL deferred_render = FALSE;
-
 // minimum alpha before discarding a fragment
 static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255
 
@@ -155,7 +153,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
     { // don't render alpha objects on the other side of the water plane if water is opaque
         return;
     }
-    deferred_render = TRUE;
 
     F32 water_sign = 1.f;
 
@@ -200,7 +197,10 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
         prepare_alpha_shader(&materialShader[i], false, true, water_sign);
     }
 
-    pbr_shader = LLPipeline::sRenderingHUDs ? &gHUDPBRAlphaProgram : &gDeferredPBRAlphaProgram;
+    pbr_shader = 
+        (LLPipeline::sUnderWaterRender) ? &gDeferredPBRAlphaWaterProgram : 
+        (LLPipeline::sRenderingHUDs) ? &gHUDPBRAlphaProgram : 
+        &gDeferredPBRAlphaProgram;
 
     prepare_alpha_shader(pbr_shader, false, true, water_sign);
 
@@ -232,8 +232,6 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
 
         gGL.setColorMask(true, false);
     }
-
-    deferred_render = FALSE;
 }
 
 void LLDrawPoolAlpha::forwardRender(bool rigged)
@@ -411,7 +409,7 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material)
     }
     else
     {
-        if (deferred_render && use_material && current_shader)
+        if (!LLPipeline::sRenderingHUDs && use_material && current_shader)
         {
             if (draw->mNormalMap)
             {
@@ -691,10 +689,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                 }
                 else
                 {
-                    if (deferred_render)
-                    {
-                        mat = params.mMaterial;
-                    }
+                    mat = LLPipeline::sRenderingHUDs ? nullptr : params.mMaterial;
 
                     if (params.mFullbright)
                     {
@@ -719,7 +714,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                     {
                         target_shader = fullbright_shader;
                     }
-                    else if (deferred_render && mat)
+                    else if (mat)
                     {
                         U32 mask = params.mShaderMask;
 
@@ -766,7 +761,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                     F32 brightness = 1.0f;
 
                     // We have a material.  Supply the appropriate data here.
-                    if (mat && deferred_render)
+                    if (mat)
                     {
                         spec_color = params.mSpecColor;
                         env_intensity = params.mEnvIntensity;
@@ -781,11 +776,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                     }
                 }
 
-				//if (params.mGroup) // TOO LATE
-				//{
-				//	params.mGroup->rebuildMesh();
-				//}
-
                 if (params.mAvatar != nullptr)
                 {
                     if (lastAvatar != params.mAvatar ||
@@ -805,8 +795,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
                 bool tex_setup = TexSetup(&params, (mat != nullptr));
 
 				{
-					//LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test);
-
 					gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor);
 
                     bool reset_minimum_alpha = false;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 19b23609a6a8991f936d3312427868fd06949049..f3a6c4a3a7920d2dac89c294740695908a20c139 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -597,49 +597,14 @@ void LLDrawPoolAvatar::beginSkinned()
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
 
-	if (sShaderLevel > 0)
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gAvatarWaterProgram;
-			sShaderLevel = llmin((U32) 1, sShaderLevel);
-		}
-		else
-		{
-			sVertexProgram = &gAvatarProgram;
-		}
-	}
-	else
-	{
-		if (LLPipeline::sUnderWaterRender)
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorWaterProgram;
-		}
-		else
-		{
-			sVertexProgram = &gObjectAlphaMaskNoColorProgram;
-		}
-	}
-	
-	if (sShaderLevel > 0)  // for hardware blending
-	{
-		sRenderingSkinned = TRUE;
+    // used for preview only
 
-		sVertexProgram->bind();
-		sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
-		gGL.getTexUnit(0)->activate();
-	}
-	else
-	{
-		if(gPipeline.shadersLoaded())
-		{
-			// software skinning, use a basic shader for windlight.
-			// TODO: find a better fallback method for software skinning.
-			sVertexProgram->bind();
-		}
-	}
+	sVertexProgram = &gAvatarProgram;
+	
+	sRenderingSkinned = TRUE;
 
-		sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
+	sVertexProgram->bind();
+    sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha);
 }
 
 void LLDrawPoolAvatar::endSkinned()
@@ -704,7 +669,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 	if (pass == -1)
 	{
 		for (S32 i = 1; i < getNumPasses(); i++)
-		{ //skip foot shadows
+		{ //skip impostor pass
 			prerender();
 			beginRenderPass(i);
 			renderAvatars(single_avatar, i);
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 7fdb3fbdaf160100b73d2c22213c02c9f570820f..425acd339298a79d9843b101993d34f141eb45f3 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -170,7 +170,7 @@ void LLViewerDynamicTexture::postRender(BOOL success)
 	camera->setOrigin(mCamera);
 	camera->setAxes(mCamera);
 	camera->setAspect(mCamera.getAspect());
-	camera->setView(mCamera.getView());
+	camera->setViewNoBroadcast(mCamera.getView());
 	camera->setNear(mCamera.getNear());
 }
 
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index b14fbefeb97ec6226f276c90cd58aeeb08c367ab..d73a486877642b858c9c2d1d9379cb2c5e694493 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -168,6 +168,9 @@ namespace
     // Find normalized track position of given time along full length of cycle
     inline LLSettingsBase::TrackPosition convert_time_to_position(const LLSettingsBase::Seconds& time, const LLSettingsBase::Seconds& len)
     {
+        // early out to avoid divide by zero.  if len is zero then jump to end position
+        if (len == 0.f) return 1.f;
+
         LLSettingsBase::TrackPosition position = LLSettingsBase::TrackPosition(fmod((F64)time, (F64)len) / (F64)len);
         return llclamp(position, 0.0f, 1.0f);
     }
@@ -1179,13 +1182,14 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironm
         return;
     }
 
-    DayInstance::ptr_t environment = getEnvironmentInstance(env, true);
+    bool reset_probes = false;
 
+    DayInstance::ptr_t environment = getEnvironmentInstance(env, true);
 
     if (fixed.first)
     {
         logEnvironment(env, fixed.first, env_version);
-        environment->setSky(fixed.first);
+        reset_probes = environment->setSky(fixed.first);
         environment->setFlags(DayInstance::NO_ANIMATE_SKY);
     }
     else if (!environment->getSky())
@@ -1196,7 +1200,7 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironm
             // and then add water/sky on top
             // This looks like it will result in sky using single keyframe instead of whole day if day is present
             // when setting static water without static sky
-            environment->setSky(mCurrentEnvironment->getSky());
+            reset_probes = environment->setSky(mCurrentEnvironment->getSky());
             environment->setFlags(DayInstance::NO_ANIMATE_SKY);
         }
         else
@@ -1214,7 +1218,7 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironm
 
             if (substitute && substitute->getSky())
             {
-                environment->setSky(substitute->getSky());
+                reset_probes = environment->setSky(substitute->getSky());
                 environment->setFlags(DayInstance::NO_ANIMATE_SKY);
             }
             else
@@ -1266,7 +1270,10 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironm
         }
     }
 
-    gPipeline.mReflectionMapManager.reset();
+    if (reset_probes)
+    { // the sky changed in a way that merits a reset of reflection probes
+        gPipeline.mReflectionMapManager.reset();
+    }
 
     if (!mSignalEnvChanged.empty())
         mSignalEnvChanged(env, env_version);
@@ -1741,19 +1748,8 @@ void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, con
             //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL;
             break;
         case LLSD::TypeReal:
-        {
-            F32 v = value.asReal();
-            switch (it.second.getShaderKey())
-            { // convert to linear color space if this is a color parameter
-            case LLShaderMgr::HAZE_HORIZON:
-            case LLShaderMgr::HAZE_DENSITY:
-            case LLShaderMgr::CLOUD_SHADOW:
-                //v = sRGBtoLinear(v);
-                break;
-            }
-            shader->uniform1f(it.second.getShaderKey(), v);
+            shader->uniform1f(it.second.getShaderKey(), value.asReal());
             //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL;
-        }
             break;
 
         case LLSD::TypeBoolean:
@@ -2788,10 +2784,12 @@ void LLEnvironment::DayInstance::setDay(const LLSettingsDay::ptr_t &pday, LLSett
 }
 
 
-void LLEnvironment::DayInstance::setSky(const LLSettingsSky::ptr_t &psky)
+bool LLEnvironment::DayInstance::setSky(const LLSettingsSky::ptr_t &psky)
 {
     mInitialized = false;
 
+    bool changed = psky == nullptr || mSky == nullptr || mSky->getHash() != psky->getHash();
+    
     bool different_sky = mSky != psky;
     
     mSky = psky;
@@ -2805,6 +2803,8 @@ void LLEnvironment::DayInstance::setSky(const LLSettingsSky::ptr_t &psky)
         LLEnvironment::getAtmosphericModelSettings(settings, psky);
         gAtmosphere->configureAtmosphericModel(settings);
     }
+
+    return changed;
 }
 
 void LLEnvironment::DayInstance::setWater(const LLSettingsWater::ptr_t &pwater)
diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h
index 4383f54f2551dc5ae9d23a02160f7f58f2fd68e5..82bfc4ec513f7b6a83f2e44b4ad8d40d582bf380 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -264,7 +264,7 @@ class LLEnvironment : public LLSimpleton<LLEnvironment>
         virtual bool                    applyTimeDelta(const LLSettingsBase::Seconds& delta);
 
         virtual void                    setDay(const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset);
-        virtual void                    setSky(const LLSettingsSky::ptr_t &psky);
+        bool                            setSky(const LLSettingsSky::ptr_t &psky);
         virtual void                    setWater(const LLSettingsWater::ptr_t &pwater);
 
         void                            initialize();
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index ed3dc37043d27ac1c1ddc8ee1857836c6e769e6c..6e29450ff329071bb4296cbd5d62a8ab5de89327 100644
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -1113,18 +1113,17 @@ BOOL	LLPreviewAnimation::render()
 	LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * 
 		LLQuaternion(mCameraYaw, LLVector3::z_axis);
 
+    LLViewerCamera* camera = LLViewerCamera::getInstance();
+
 	LLQuaternion av_rot = avatarp->mRoot->getWorldRotation() * camera_rot;
-	LLViewerCamera::getInstance()->setOriginAndLookAt(
+	camera->setOriginAndLookAt(
 		target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + mCameraOffset) * av_rot),		// camera
 		LLVector3::z_axis,																	// up
 		target_pos + (mCameraOffset  * av_rot) );											// point of interest
 
-	LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
-	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
-
-	mCameraRelPos = LLViewerCamera::getInstance()->getOrigin() - avatarp->mHeadp->getWorldPosition();
-
-	//avatarp->setAnimationData("LookAtPoint", (void *)&mCameraRelPos);
+	camera->setViewNoBroadcast(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom);
+    camera->setAspect((F32) mFullWidth / (F32) mFullHeight);
+	camera->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
 
 	//SJB: Animation is updated in LLVOAvatar::updateCharacter
 	
diff --git a/indra/newview/llfloaterbvhpreview.h b/indra/newview/llfloaterbvhpreview.h
index 20d15d96033b35bf4d5c0e383c4a5d74dcd08253..9dfefc5a5fa2b4f54156acd86085ee0688da3743 100644
--- a/indra/newview/llfloaterbvhpreview.h
+++ b/indra/newview/llfloaterbvhpreview.h
@@ -64,7 +64,6 @@ class LLPreviewAnimation : public LLViewerDynamicTexture
 	F32					mCameraPitch;
 	F32					mCameraZoom;
 	LLVector3			mCameraOffset;
-	LLVector3			mCameraRelPos;
 	LLPointer<LLVOAvatar>			mDummyAvatar;
 };
 
diff --git a/indra/newview/llfloaterenvironmentadjust.cpp b/indra/newview/llfloaterenvironmentadjust.cpp
index 4d1139986729273b5840deb036cc6904250f9f9e..f9e896347926a08edfaa07424e7a73420f37393c 100644
--- a/indra/newview/llfloaterenvironmentadjust.cpp
+++ b/indra/newview/llfloaterenvironmentadjust.cpp
@@ -201,6 +201,8 @@ void LLFloaterEnvironmentAdjust::refresh()
     getChild<LLUICtrl>(FIELD_SKY_MOON_AZIMUTH)->setValue(azimuth);
     getChild<LLUICtrl>(FIELD_SKY_MOON_ELEVATION)->setValue(elevation);
     getChild<LLVirtualTrackball>(FIELD_SKY_MOON_ROTATION)->setRotation(quat);
+
+    updateGammaLabel();
 }
 
 
@@ -478,9 +480,25 @@ void LLFloaterEnvironmentAdjust::onReflectionProbeAmbianceChanged()
     if (!mLiveSky) return;
     F32 ambiance = getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->getValue().asReal();
     mLiveSky->setReflectionProbeAmbiance(ambiance);
+
+    updateGammaLabel();
     mLiveSky->update();
 }
 
+void LLFloaterEnvironmentAdjust::updateGammaLabel()
+{
+    if (!mLiveSky) return;
+    F32 ambiance = mLiveSky->getReflectionProbeAmbiance();
+    if (ambiance != 0.f)
+    {
+        childSetValue("scene_gamma_label", getString("hdr_string"));
+    }
+    else
+    {
+        childSetValue("scene_gamma_label", getString("brightness_string"));
+    }
+}
+
 void LLFloaterEnvironmentAdjust::onEnvironmentUpdated(LLEnvironment::EnvSelection_t env, S32 version)
 {
     if (env == LLEnvironment::ENV_LOCAL)
diff --git a/indra/newview/llfloaterenvironmentadjust.h b/indra/newview/llfloaterenvironmentadjust.h
index 43c0ba0495b24514807ddc9558497cd3ecafa224..db893cca1225b81a35389f5fcbabc1916548d831 100644
--- a/indra/newview/llfloaterenvironmentadjust.h
+++ b/indra/newview/llfloaterenvironmentadjust.h
@@ -83,7 +83,7 @@ class LLFloaterEnvironmentAdjust : public LLFloater
     void                        onWaterMapChanged();
 
     void                        onReflectionProbeAmbianceChanged();
-
+    void                        updateGammaLabel();
     void                        onButtonReset();
 
     void                        onEnvironmentUpdated(LLEnvironment::EnvSelection_t env, S32 version);
diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp
index 886abfb1324912194805b7818ec57df3bda41225..7f37f98568e7ed990d0578238f4fbd8aabac6eed 100644
--- a/indra/newview/llmaniprotate.cpp
+++ b/indra/newview/llmaniprotate.cpp
@@ -1714,6 +1714,7 @@ LLVector3 LLManipRotate::intersectRayWithSphere( const LLVector3& ray_pt, const
 }
 
 // Utility function.  Should probably be moved to another class.
+// x,y - mouse position in scaled window coordinates (NOT GL viewport coordinates)
 //static
 void LLManipRotate::mouseToRay( S32 x, S32 y, LLVector3* ray_pt, LLVector3* ray_dir )
 {
@@ -1727,10 +1728,8 @@ void LLManipRotate::mouseToRay( S32 x, S32 y, LLVector3* ray_pt, LLVector3* ray_
 	}
 	else
 	{
-		*ray_pt = gAgentCamera.getCameraPositionAgent();
-		LLViewerCamera::getInstance()->projectScreenToPosAgent(x, y, ray_dir);
-		*ray_dir -= *ray_pt;
-		ray_dir->normVec();
+    	*ray_pt = gAgentCamera.getCameraPositionAgent();
+        *ray_dir = gViewerWindow->mouseDirectionGlobal(x, y);
 	}
 }
 
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 5f910d95c2adcf43f6aff8284aa361b8d955dd6b..b98855a51f9e3bb536c367e352012569d40250fc 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1739,7 +1739,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
         out << "Invalid level of detail: " << which_lod;
         LL_WARNS() << out.str() << LL_ENDL;
         LLFloaterModelPreview::addStringToLog(out, false);
-        assert(lod >= -1 && lod < LLModel::NUM_LODS);
+        llassert(which_lod >= -1 && which_lod < LLModel::NUM_LODS);
         return;
     }
 
diff --git a/indra/newview/llpaneleditsky.cpp b/indra/newview/llpaneleditsky.cpp
index d17845ebc508564fb9c3a64622f0bd69408459a5..a14af27e59d03a08c8b99a132e89f478d0934f43 100644
--- a/indra/newview/llpaneleditsky.cpp
+++ b/indra/newview/llpaneleditsky.cpp
@@ -213,6 +213,8 @@ void LLPanelSettingsSkyAtmosTab::refresh()
     getChild<LLUICtrl>(FIELD_SKY_DENSITY_DROPLET_RADIUS)->setValue(droplet_radius);
     getChild<LLUICtrl>(FIELD_SKY_DENSITY_ICE_LEVEL)->setValue(ice_level);
     getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->setValue(rp_ambiance);
+
+    updateGammaLabel();
 }
 
 //-------------------------------------------------------------------------
@@ -321,11 +323,29 @@ void LLPanelSettingsSkyAtmosTab::onReflectionProbeAmbianceChanged()
 {
     if (!mSkySettings) return;
     F32 ambiance = getChild<LLUICtrl>(FIELD_REFLECTION_PROBE_AMBIANCE)->getValue().asReal();
+
     mSkySettings->setReflectionProbeAmbiance(ambiance);
     mSkySettings->update();
     setIsDirty();
+
+    updateGammaLabel();
 }
 
+
+void LLPanelSettingsSkyAtmosTab::updateGammaLabel()
+{
+    if (!mSkySettings) return;
+    F32 ambiance = mSkySettings->getReflectionProbeAmbiance();
+    if (ambiance != 0.f)
+    {
+        childSetValue("scene_gamma_label", getString("hdr_string"));
+    }
+    else
+    {
+        childSetValue("scene_gamma_label", getString("brightness_string"));
+    }
+
+}
 //==========================================================================
 LLPanelSettingsSkyCloudTab::LLPanelSettingsSkyCloudTab() :
     LLPanelSettingsSky()
diff --git a/indra/newview/llpaneleditsky.h b/indra/newview/llpaneleditsky.h
index cd89e02eeac3a647d9e69aaf38f37a3309442e69..33af667ab7b5d3ef066d9a55c958313f6dd11d9c 100644
--- a/indra/newview/llpaneleditsky.h
+++ b/indra/newview/llpaneleditsky.h
@@ -80,6 +80,7 @@ class LLPanelSettingsSkyAtmosTab : public LLPanelSettingsSky
     void                    onDropletRadiusChanged();
     void                    onIceLevelChanged();
     void                    onReflectionProbeAmbianceChanged();
+    void                    updateGammaLabel();
 
 };
 
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 2235453e470657ed14092ee30f29f96b78d3a04b..15d41c4161b8edf63c7f934e7ce443d29295f84f 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -915,7 +915,8 @@ void LLReflectionMapManager::updateUniforms()
     LLSettingsSky::ptr_t psky = environment.getCurrentSky();
 
     static LLCachedControl<F32> cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f);
-    F32 minimum_ambiance = psky->getTotalReflectionProbeAmbiance(cloud_shadow_scale);
+    static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
+    F32 minimum_ambiance = psky->getTotalReflectionProbeAmbiance(cloud_shadow_scale, should_auto_adjust);
 
     F32 ambscale = gCubeSnapshot && !isRadiancePass() ? 0.f : 1.f;
     F32 radscale = gCubeSnapshot && !isRadiancePass() ? 0.5f : 1.f;
@@ -1205,9 +1206,7 @@ void LLReflectionMapManager::renderDebug()
 
 void LLReflectionMapManager::initReflectionMaps()
 {
-    static LLCachedControl<S32> probe_count(gSavedSettings, "RenderReflectionProbeCount", LL_MAX_REFLECTION_PROBE_COUNT);
-
-    U32 count = llclamp((S32) probe_count, 1, LL_MAX_REFLECTION_PROBE_COUNT);
+    U32 count = LL_MAX_REFLECTION_PROBE_COUNT;
 
     if (mTexture.isNull() || mReflectionProbeCount != count || mReset)
     {
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index c0618de41077cd4f5e1bea34e0609a67128647b2..5a3901cae9f29aca4886af3afda31a01bc455da2 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -177,7 +177,7 @@ class alignas(16) LLReflectionMapManager
 
     LLPointer<LLReflectionMap> mDefaultProbe;  // default reflection probe to fall back to for pixels with no probe influences (should always be at cube index 0)
 
-    // number of reflection probes to use for rendering (based on saved setting RenderReflectionProbeCount)
+    // number of reflection probes to use for rendering
     U32 mReflectionProbeCount;
 
     // resolution of reflection probes
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index a7a5a9223c9cc510088f20f1e2af18e70d4fce46..6321dbc085f51659463bbcf7087beba8ffa1a880 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -717,54 +717,43 @@ void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
     LLColor3 ambient(getTotalAmbient());
 
     F32 g = getGamma();
-    if (ambient != LLColor3::black && getReflectionProbeAmbiance() == 0.f)
-    { //desaturate ambient for legacy compatibility
-        F32 h, s, l;
-        ambient.calcHSL(&h, &s, &l);
-        s *= 0.5f;
-        l *= 1.f / (g + llmax(g-1.f, 0.f));
-        ambient.setHSL(h, s, l);
-    }
+
+    static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
+
+    static LLCachedControl<F32> cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f);
+    F32 probe_ambiance = getTotalReflectionProbeAmbiance(cloud_shadow_scale);
 
     if (irradiance_pass)
     { // during an irradiance map update, disable ambient lighting (direct lighting only) and desaturate sky color (avoid tinting the world blue)
-        shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, LLVector3::zero.mV);
         shader->uniform3fv(LLShaderMgr::AMBIENT, LLVector3::zero.mV);
     }
     else
     {
-        if (psky->getReflectionProbeAmbiance() == 0.f)
+        if (psky->getReflectionProbeAmbiance() != 0.f)
         {
-            LLVector3 ambcol(ambient.mV);
-            F32 cloud_shadow = psky->getCloudShadow();
-            LLVector3 tmpAmbient = ambcol + ((LLVector3::all_one - ambcol) * cloud_shadow * 0.5f);
-
-            shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, linearColor3v(tmpAmbient));
-            shader->uniform3fv(LLShaderMgr::AMBIENT, tmpAmbient.mV);
+            shader->uniform3fv(LLShaderMgr::AMBIENT, getAmbientColor().mV);
+            shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, sqrtf(g)*2.0); // use a modifier here so 1.0 maps to the "most desirable" default and the maximum value doesn't go off the rails
+        }
+        else if (psky->canAutoAdjust() && should_auto_adjust)
+        { // auto-adjust legacy sky to take advantage of probe ambiance 
+            shader->uniform3fv(LLShaderMgr::AMBIENT, (ambient * 0.5f).mV);
+            shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, 2.f);
+            probe_ambiance = 1.f;
         }
         else
         {
-            shader->uniform3fv(LLShaderMgr::AMBIENT_LINEAR, linearColor3v(getAmbientColor() / 3.f)); // note magic number 3.f comes from SLIDER_SCALE_SUN_AMBIENT
+            shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, 1.f);
             shader->uniform3fv(LLShaderMgr::AMBIENT, LLVector3(ambient.mV));
         }
     }
 
-    shader->uniform3fv(LLShaderMgr::BLUE_HORIZON_LINEAR, linearColor3v(getBlueHorizon() / 2.f)); // note magic number of 2.f comes from SLIDER_SCALE_BLUE_HORIZON_DENSITY
-    shader->uniform3fv(LLShaderMgr::BLUE_DENSITY_LINEAR, linearColor3v(getBlueDensity() / 2.f));
-
-    shader->uniform3fv(LLShaderMgr::SUNLIGHT_LINEAR, linearColor3v(sunDiffuse));
-    shader->uniform3fv(LLShaderMgr::MOONLIGHT_LINEAR,linearColor3v(moonDiffuse));
-
-    static LLCachedControl<F32> cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f);
-    shader->uniform1f(LLShaderMgr::REFLECTION_PROBE_AMBIANCE, getTotalReflectionProbeAmbiance(cloud_shadow_scale));
+    shader->uniform1f(LLShaderMgr::REFLECTION_PROBE_AMBIANCE, probe_ambiance);
 
     shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, getIsSunUp() ? 1 : 0);
     shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, getSunMoonGlowFactor());
     shader->uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, getDensityMultiplier());
     shader->uniform1f(LLShaderMgr::DISTANCE_MULTIPLIER, getDistanceMultiplier());
 
-    shader->uniform1f(LLShaderMgr::HAZE_DENSITY_LINEAR, sRGBtoLinear(getHazeDensity()));
-
     shader->uniform1f(LLShaderMgr::GAMMA, g);
 }
 
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index 5d8e80cc412b0f7af2a8bc21125e52cd1081bd99..b37f08283de1851415c97722b4f49364f9cc1daa 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -819,9 +819,13 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
 	return all_verts;
 }
 
+extern BOOL gCubeSnapshot;
+
 // changes local camera and broadcasts change
 /* virtual */ void LLViewerCamera::setView(F32 vertical_fov_rads)
 {
+    llassert(!gCubeSnapshot);
+
 	F32 old_fov = LLViewerCamera::getInstance()->getView();
 
 	// cap the FoV
@@ -847,6 +851,11 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
 	LLCamera::setView(vertical_fov_rads); // call base implementation
 }
 
+void LLViewerCamera::setViewNoBroadcast(F32 vertical_fov_rads)
+{
+    LLCamera::setView(vertical_fov_rads);
+}
+
 void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) 
 {
 	vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index b5841772ed87103042cf0782e5557c4d36440a5d..78ca2b3076470eb989441f8a0de873bb52e9983d 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -87,8 +87,8 @@ class alignas(16) LLViewerCamera : public LLCamera, public LLSimpleton<LLViewerC
 	LLVector3 roundToPixel(const LLVector3 &pos_agent);
 
 	// Sets the current matrix
-	/* virtual */ void setView(F32 vertical_fov_rads);
-
+	/* virtual */ void setView(F32 vertical_fov_rads); // NOTE: broadcasts to simulator
+    void setViewNoBroadcast(F32 vertical_fov_rads);  // set FOV without broadcasting to simulator (for temporary local cameras)
 	void setDefaultFOV(F32 fov) ;
 	F32 getDefaultFOV() { return mCameraFOVDefault; }
 
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index d0dd02426e156f61b2825af5c8396f6ddec71841..02108e861a65f3e17d8198f429f8abc3ef552d2f 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -3014,7 +3014,7 @@ LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage()
         return nullptr; // not ready for updating
     }
 
-    llassert(!mTextureId.isNull());
+    //llassert(!mTextureId.isNull());
     // *TODO: Consider enabling mipmaps (they have been disabled for a long time). Likely has a significant performance impact for tiled/high texture repeat media. Mip generation in a shader may also be an option if necessary.
     LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId, USE_MIPMAPS );
  
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 921620190e7748cdffa5731001d2d1f7263222c2..b9042b3496e485f8ce1815e3bf2957fb5d1b28e3 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -2831,18 +2831,6 @@ bool enable_object_edit_gltf_material()
     return func.mCanModify && func.mMaterialId.notNull();
 }
 
-bool enable_object_save_gltf_material()
-{
-    if (!LLMaterialEditor::capabilitiesAvailable())
-    {
-        return false;
-    }
-
-    LLSelectedTEGetmatIdAndPermissions func;
-    LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
-    return func.mCanCopy && func.mMaterialId.notNull();
-}
-
 bool enable_object_open()
 {
 	// Look for contents in root object, which is all the LLFloaterOpenObject
@@ -2974,11 +2962,6 @@ void handle_object_edit_gltf_material()
     LLMaterialEditor::loadLive();
 }
 
-void handle_object_save_gltf_material()
-{
-    LLMaterialEditor::savePickedMaterialAs();
-}
-
 void handle_attachment_edit(const LLUUID& inv_item_id)
 {
 	if (isAgentAvatarValid())
@@ -9659,14 +9642,12 @@ void initialize_menus()
 	commit.add("Object.Edit", boost::bind(&handle_object_edit));
     commit.add("Object.Edit", boost::bind(&handle_object_edit));
     commit.add("Object.EditGLTFMaterial", boost::bind(&handle_object_edit_gltf_material));
-    commit.add("Object.SaveGLTFMaterial", boost::bind(&handle_object_save_gltf_material));
 	commit.add("Object.Inspect", boost::bind(&handle_object_inspect));
 	commit.add("Object.Open", boost::bind(&handle_object_open));
 	commit.add("Object.Take", boost::bind(&handle_take));
 	commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector));
     enable.add("Object.EnableInspect", boost::bind(&enable_object_inspect));
     enable.add("Object.EnableEditGLTFMaterial", boost::bind(&enable_object_edit_gltf_material));
-    enable.add("Object.EnableSaveGLTFMaterial", boost::bind(&enable_object_save_gltf_material));
 	enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
 	enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
 	enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index b98d8368035725e3dff7b7280a8ea989b1b86d79..f14e3ed737c06c587ae6453262522b1bc69f6a0e 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -127,6 +127,8 @@
 
 extern void on_new_message(const LLSD& msg);
 
+extern BOOL gCubeSnapshot;
+
 //
 // Constants
 //
@@ -3294,6 +3296,8 @@ const F32 MAX_HEAD_ROT_QDOT = 0.99999f;			// ~= 0.5 degrees -- if its greater th
 void send_agent_update(BOOL force_send, BOOL send_reliable)
 {
     LL_PROFILE_ZONE_SCOPED;
+    llassert(!gCubeSnapshot);
+
 	if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
 	{
 		// We don't care if they want to send an agent update, they're not allowed to until the simulator
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 5ea52aca79d819323b8ada747c3495a0a6d48ec9..5ec78df6c48731b7accfae2f795f3ed824824a18 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -118,7 +118,6 @@ LLGLSLShader		gPathfindingNoNormalsProgram;
 
 //avatar shader handles
 LLGLSLShader		gAvatarProgram;
-LLGLSLShader		gAvatarWaterProgram;
 LLGLSLShader		gAvatarEyeballProgram;
 LLGLSLShader		gImpostorProgram;
 
@@ -222,6 +221,8 @@ LLGLSLShader            gDeferredSkinnedPBROpaqueProgram;
 LLGLSLShader            gHUDPBRAlphaProgram;
 LLGLSLShader            gDeferredPBRAlphaProgram;
 LLGLSLShader            gDeferredSkinnedPBRAlphaProgram;
+LLGLSLShader            gDeferredPBRAlphaWaterProgram;
+LLGLSLShader            gDeferredSkinnedPBRAlphaWaterProgram;
 
 //helper for making a rigged variant of a given shader
 bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader)
@@ -256,7 +257,6 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
     mShaderList.push_back(&gSkinnedObjectFullbrightAlphaMaskProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNoColorProgram);
 	mShaderList.push_back(&gObjectAlphaMaskNoColorWaterProgram);
-	mShaderList.push_back(&gAvatarWaterProgram);
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
@@ -296,8 +296,10 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
     mShaderList.push_back(&gDeferredWLMoonProgram);
     mShaderList.push_back(&gDeferredWLSunProgram);
     mShaderList.push_back(&gDeferredPBRAlphaProgram);
+    mShaderList.push_back(&gDeferredPBRAlphaWaterProgram);
     mShaderList.push_back(&gHUDPBRAlphaProgram);
     mShaderList.push_back(&gDeferredSkinnedPBRAlphaProgram);
+    mShaderList.push_back(&gDeferredSkinnedPBRAlphaWaterProgram);
     mShaderList.push_back(&gDeferredPostGammaCorrectProgram); // for gamma
     mShaderList.push_back(&gNoPostGammaCorrectProgram);
     mShaderList.push_back(&gLegacyPostGammaCorrectProgram);
@@ -639,8 +641,7 @@ std::string LLViewerShaderMgr::loadBasicShaders()
 
 	bool has_reflection_probes = gSavedSettings.getBOOL("RenderReflectionsEnabled") && gGLManager.mGLVersion > 3.99f;
 
-	S32 probe_count = llclamp(gSavedSettings.getS32("RenderReflectionProbeCount"), 1, LL_MAX_REFLECTION_PROBE_COUNT);
-    S32 probe_level = llclamp(gSavedSettings.getS32("RenderReflectionProbeLevel"), 0, 3);
+	S32 probe_level = llclamp(gSavedSettings.getS32("RenderReflectionProbeLevel"), 0, 3);
 
     if (ambient_kill)
     {
@@ -676,7 +677,6 @@ std::string LLViewerShaderMgr::loadBasicShaders()
 
 	if (has_reflection_probes)
 	{
-		attribs["REFMAP_COUNT"] = std::to_string(probe_count);
         attribs["REFMAP_LEVEL"] = std::to_string(probe_level);
 		attribs["REF_SAMPLE_COUNT"] = "32";
 	}
@@ -1022,6 +1022,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         gDeferredSkinnedPBROpaqueProgram.unload();
         gDeferredPBRAlphaProgram.unload();
         gDeferredSkinnedPBRAlphaProgram.unload();
+        gDeferredPBRAlphaWaterProgram.unload();
+        gDeferredSkinnedPBRAlphaWaterProgram.unload();
 
 		return TRUE;
 	}
@@ -1413,6 +1415,62 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         shader->mRiggedVariant->mFeatures.hasLighting = true;
     }
 
+    if (success)
+    {
+        LLGLSLShader* shader = &gDeferredPBRAlphaWaterProgram;
+        shader->mName = "Deferred PBR Alpha Underwater Shader";
+                          
+        shader->mFeatures.calculatesLighting = false;
+        shader->mFeatures.hasLighting = false;
+        shader->mFeatures.isAlphaLighting = true;
+        shader->mFeatures.hasWaterFog = true;
+        shader->mFeatures.hasSrgb = true;
+        shader->mFeatures.encodesNormal = true;
+        shader->mFeatures.calculatesAtmospherics = true;
+        shader->mFeatures.hasAtmospherics = true;
+        shader->mFeatures.hasGamma = true;
+        shader->mFeatures.hasShadows = use_sun_shadow;
+        shader->mFeatures.isDeferred = true; // include deferredUtils
+        shader->mFeatures.hasReflectionProbes = mShaderLevel[SHADER_DEFERRED];
+
+        shader->mShaderGroup = LLGLSLShader::SG_WATER;
+
+        shader->mShaderFiles.clear();
+        shader->mShaderFiles.push_back(make_pair("deferred/pbralphaV.glsl", GL_VERTEX_SHADER));
+        shader->mShaderFiles.push_back(make_pair("deferred/pbralphaF.glsl", GL_FRAGMENT_SHADER));
+
+        shader->clearPermutations();
+
+        U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+        shader->addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+        shader->addPermutation("HAS_NORMAL_MAP", "1");
+        shader->addPermutation("HAS_SPECULAR_MAP", "1"); // PBR: Packed: Occlusion, Metal, Roughness
+        shader->addPermutation("HAS_EMISSIVE_MAP", "1");
+        shader->addPermutation("USE_VERTEX_COLOR", "1");
+        shader->addPermutation("WATER_FOG", "1");
+
+        if (use_sun_shadow)
+        {
+            shader->addPermutation("HAS_SUN_SHADOW", "1");
+        }
+
+        shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+        success = make_rigged_variant(*shader, gDeferredSkinnedPBRAlphaWaterProgram);
+        if (success)
+        {
+            success = shader->createShader(NULL, NULL);
+        }
+        llassert(success);
+
+        // Alpha Shader Hack
+        // See: LLRender::syncMatrices()
+        shader->mFeatures.calculatesLighting = true;
+        shader->mFeatures.hasLighting = true;
+
+        shader->mRiggedVariant->mFeatures.calculatesLighting = true;
+        shader->mRiggedVariant->mFeatures.hasLighting = true;
+    }
+
     if (success)
     {
         LLGLSLShader* shader = &gHUDPBRAlphaProgram;
@@ -2856,7 +2914,6 @@ BOOL LLViewerShaderMgr::loadShadersAvatar()
 	if (mShaderLevel[SHADER_AVATAR] == 0)
 	{
 		gAvatarProgram.unload();
-		gAvatarWaterProgram.unload();
 		gAvatarEyeballProgram.unload();
 		return TRUE;
 	}
@@ -2878,26 +2935,6 @@ BOOL LLViewerShaderMgr::loadShadersAvatar()
 		gAvatarProgram.mShaderLevel = mShaderLevel[SHADER_AVATAR];
 		success = gAvatarProgram.createShader(NULL, NULL);
 			
-		if (success)
-		{
-			gAvatarWaterProgram.mName = "Avatar Water Shader";
-			gAvatarWaterProgram.mFeatures.hasSkinning = true;
-			gAvatarWaterProgram.mFeatures.calculatesAtmospherics = true;
-			gAvatarWaterProgram.mFeatures.calculatesLighting = true;
-			gAvatarWaterProgram.mFeatures.hasWaterFog = true;
-			gAvatarWaterProgram.mFeatures.hasAtmospherics = true;
-			gAvatarWaterProgram.mFeatures.hasLighting = true;
-			gAvatarWaterProgram.mFeatures.hasAlphaMask = true;
-			gAvatarWaterProgram.mFeatures.disableTextureIndex = true;
-			gAvatarWaterProgram.mShaderFiles.clear();
-			gAvatarWaterProgram.mShaderFiles.push_back(make_pair("avatar/avatarV.glsl", GL_VERTEX_SHADER));
-			gAvatarWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER));
-			// Note: no cloth under water:
-			gAvatarWaterProgram.mShaderLevel = llmin(mShaderLevel[SHADER_AVATAR], 1);	
-			gAvatarWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;				
-			success = gAvatarWaterProgram.createShader(NULL, NULL);
-		}
-
 		/// Keep track of avatar levels
 		if (gAvatarProgram.mShaderLevel != mShaderLevel[SHADER_AVATAR])
 		{
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 492e60b840a62274d48a80263e8df52e6d88669f..76e81e17b7ed38283e2c26ef3bdf738d5353d2cb 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -196,7 +196,6 @@ extern LLGLSLShader			gPathfindingNoNormalsProgram;
 
 // avatar shader handles
 extern LLGLSLShader			gAvatarProgram;
-extern LLGLSLShader			gAvatarWaterProgram;
 extern LLGLSLShader			gAvatarEyeballProgram;
 extern LLGLSLShader			gImpostorProgram;
 
@@ -277,5 +276,6 @@ extern LLGLSLShader         gHUDPBROpaqueProgram;
 extern LLGLSLShader         gPBRGlowProgram;
 extern LLGLSLShader         gDeferredPBROpaqueProgram;
 extern LLGLSLShader         gDeferredPBRAlphaProgram;
+extern LLGLSLShader         gDeferredPBRAlphaWaterProgram;
 extern LLGLSLShader         gHUDPBRAlphaProgram;
 #endif
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 29c8700105959e153e562fb40781bdb54cd0a0f5..cb585888488211446ac33e8d67cf8af342b31562 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -489,20 +489,6 @@ bool LLViewerTexture::isMemoryForTextureLow()
     return (gpu < MIN_FREE_TEXTURE_MEMORY); // || (physical < MIN_FREE_MAIN_MEMORY);
 }
 
-//static
-bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
-{
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
-    const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50);
-    const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200);
-
-    S32Megabytes gpu;
-    S32Megabytes physical;
-    getGPUMemoryForTextures(gpu, physical);
-
-    return (gpu > DESIRED_FREE_TEXTURE_MEMORY); // && (physical > DESIRED_FREE_MAIN_MEMORY);
-}
-
 //static
 void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical)
 {
@@ -3115,7 +3101,8 @@ void LLViewerLODTexture::processTextureStats()
         //
 
         S32 current_discard = getDiscardLevel();
-        if (mBoostLevel < LLGLTexture::BOOST_SCULPTED && current_discard >= 0)
+        if (mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED && 
+            current_discard >= 0)
         {
             if (current_discard < (mDesiredDiscardLevel-1) && !mForceToSaveRawImage)
             { // should scale down
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 34118c86cd7d5a1f2b54c5e6cd3ebdad6a9a5348..35fb0a2237d0d5bc0be2e9f9c8067b81cb7eb9c1 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -186,7 +186,6 @@ class LLViewerTexture : public LLGLTexture
 
 	virtual void switchToCachedImage();
 	
-	static bool isMemoryForTextureSuficientlyFree();
 	static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical);
 
 public:
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index d4c5e5535e5e9df669acbb62a942db2c6427c608..9c4474f1d3ce39501237fa75226b1eb58f7b43cc 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1013,33 +1013,6 @@ void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debu
 	addImageToList(tex);
 }
 
-/*
- static U8 get_image_type(LLViewerFetchedTexture* imagep, LLHost target_host)
- {
- // Having a target host implies this is a baked image.  I don't
- // believe that boost level has been set at this point. JC
- U8 type_from_host = (target_host.isOk() 
- ? LLImageBase::TYPE_AVATAR_BAKE 
- : LLImageBase::TYPE_NORMAL);
- S32 boost_level = imagep->getBoostLevel();
- U8 type_from_boost = ( (boost_level == LLViewerFetchedTexture::BOOST_AVATAR_BAKED 
- || boost_level == LLViewerFetchedTexture::BOOST_AVATAR_BAKED_SELF)
- ? LLImageBase::TYPE_AVATAR_BAKE 
- : LLImageBase::TYPE_NORMAL);
- if (type_from_host == LLImageBase::TYPE_NORMAL
- && type_from_boost == LLImageBase::TYPE_AVATAR_BAKE)
- {
- LL_WARNS() << "TAT: get_image_type() type_from_host doesn't match type_from_boost"
- << " host " << target_host
- << " boost " << imagep->getBoostLevel()
- << " imageid " << imagep->getID()
- << LL_ENDL;
- imagep->dump();
- }
- return type_from_host;
- }
- */
-
 F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 2aaaecfb3839d09b9fdbd3383299cff5c529d96d..8516bbc7ec70574f2985675f77e51ef36774dc97 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -5326,7 +5326,7 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea
 
     // camera constants for the square, cube map capture image
     camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV
-    camera->setView(F_PI_BY_TWO);
+    camera->setViewNoBroadcast(F_PI_BY_TWO);
     camera->yaw(0.0);
     camera->setOrigin(origin);
     camera->setNear(near_clip);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 4b38a0ddc3e0feaef5c586f56ea18e7ad49c29f1..c7a2cea62733193f4cad1c1dd9d3287a7cf32eb2 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -7073,6 +7073,7 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
 	size.mul(0.5f);
 
 	mImpostorPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
+    mPixelArea = mImpostorPixelArea;
 
 	F32 range = mDrawable->mDistanceWRTCamera;
 
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index e8604464ae3d2def40dbcdca8e936f99db07fc86..f1dc503c9e5b49d0a763d486383723f45dc9e19d 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -684,7 +684,7 @@ class LLVOAvatar :
 	//--------------------------------------------------------------------
 public:
 	virtual LLViewerTexture::EBoostLevel 	getAvatarBoostLevel() const { return LLGLTexture::BOOST_AVATAR; }
-	virtual LLViewerTexture::EBoostLevel 	getAvatarBakedBoostLevel() const { return LLGLTexture::BOOST_AVATAR_BAKED_SELF; }
+	virtual LLViewerTexture::EBoostLevel 	getAvatarBakedBoostLevel() const { return LLGLTexture::BOOST_AVATAR_BAKED; }
 	virtual S32 						getTexImageSize() const;
 	/*virtual*/ S32						getTexImageArea() const { return getTexImageSize()*getTexImageSize(); }
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 21129938599ab71a08cf7829c112f10a39b1acb1..147d87e0a47e1828b5df8887f5f4fe476e2de44a 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1283,7 +1283,9 @@ void LLPipeline::createLUTBuffers()
 
     mExposureMap.allocate(1, 1, GL_R16F);
     mExposureMap.bindTarget();
+    glClearColor(1, 1, 1, 0);
     mExposureMap.clear();
+    glClearColor(0, 0, 0, 0);
     mExposureMap.flush();
 
     mLuminanceMap.allocate(256, 256, GL_R16F, false, LLTexUnit::TT_TEXTURE, LLTexUnit::TMG_AUTO);
@@ -6752,22 +6754,27 @@ void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) {
 		static LLStaticHashedString noiseVec("noiseVec");
 		static LLStaticHashedString dynamic_exposure_params("dynamic_exposure_params");
 		static LLCachedControl<F32> dynamic_exposure_coefficient(gSavedSettings, "RenderDynamicExposureCoefficient", 0.175f);
-		static LLCachedControl<F32> dynamic_exposure_min(gSavedSettings, "RenderDynamicExposureMin", 0.125f);
-		static LLCachedControl<F32> dynamic_exposure_max(gSavedSettings, "RenderDynamicExposureMax", 1.3f);
+        static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
 
-        F32 exposure_max = dynamic_exposure_max;
         LLSettingsSky::ptr_t sky = LLEnvironment::instance().getCurrentSky();
 
-        if (sky->getReflectionProbeAmbiance() > 0.f)
-        { //not a legacy sky, use gamma as a boost to max exposure
-            exposure_max = llmax(exposure_max - 1.f, 0.f);
-            exposure_max *= sky->getGamma();
-            exposure_max += 1.f;
-        }
+        F32 probe_ambiance = LLEnvironment::instance().getCurrentSky()->getReflectionProbeAmbiance(should_auto_adjust);
+        F32 exp_min = 1.f;
+        F32 exp_max = 1.f;
+                
+        if (probe_ambiance > 0.f)
+        {
+            F32 hdr_scale = sqrtf(LLEnvironment::instance().getCurrentSky()->getGamma())*2.f;
 
+            if (hdr_scale > 1.f)
+            {
+                exp_min = 1.f / hdr_scale;
+                exp_max = hdr_scale;
+            }
+        }
 		gExposureProgram.uniform1f(dt, gFrameIntervalSeconds);
 		gExposureProgram.uniform2f(noiseVec, ll_frand() * 2.0 - 1.0, ll_frand() * 2.0 - 1.0);
-		gExposureProgram.uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, dynamic_exposure_min, exposure_max);
+		gExposureProgram.uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, exp_min, exp_max);
 
 		mScreenTriangleVB->setBuffer();
 		mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
@@ -6790,8 +6797,12 @@ void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) {
 
 		// Apply gamma correction to the frame here.
 
+        static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
+        
+        LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
+
         LLGLSLShader& shader = no_post && gFloaterTools->isAvailable() ? gNoPostGammaCorrectProgram : // no post (no gamma, no exposure, no tonemapping)
-            LLEnvironment::instance().getCurrentSky()->getReflectionProbeAmbiance() == 0.f ? gLegacyPostGammaCorrectProgram :
+            psky->getReflectionProbeAmbiance(should_auto_adjust) == 0.f ? gLegacyPostGammaCorrectProgram :
             gDeferredPostGammaCorrectProgram;
         
         shader.bind();
@@ -7847,14 +7858,18 @@ void LLPipeline::renderDeferredLighting()
             LL_PROFILE_GPU_ZONE("atmospherics");
             bindDeferredShader(soften_shader);
 
-            static LLCachedControl<F32> sky_scale(gSavedSettings, "RenderSkyHDRScale", 1.f);
-            static LLStaticHashedString sky_hdr_scale("sky_hdr_scale");
+            static LLCachedControl<F32> ssao_scale(gSavedSettings, "RenderSSAOIrradianceScale", 0.5f);
+            static LLCachedControl<F32> ssao_max(gSavedSettings, "RenderSSAOIrradianceMax", 0.25f);
+            static LLStaticHashedString ssao_scale_str("ssao_irradiance_scale");
+            static LLStaticHashedString ssao_max_str("ssao_irradiance_max");
+            
+            soften_shader.uniform1f(ssao_scale_str, ssao_scale);
+            soften_shader.uniform1f(ssao_max_str, ssao_max);
 
             LLEnvironment &environment = LLEnvironment::instance();
             soften_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
             soften_shader.uniform3fv(LLShaderMgr::LIGHTNORM, 1, environment.getClampedLightNorm().mV);
-            soften_shader.uniform1f(sky_hdr_scale, sky_scale);
-
+            
             soften_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
 
             {
diff --git a/indra/newview/skins/default/xui/en/floater_adjust_environment.xml b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml
index 5258bdbaf22a1a47981652327b9547dbdea687a9..518a83f846a393ffeb6e0b8af59c69948293fbb2 100644
--- a/indra/newview/skins/default/xui/en/floater_adjust_environment.xml
+++ b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml
@@ -10,6 +10,8 @@
          min_height="275"
          single_instance="true"
          can_resize="false">
+  <string name="hdr_string">HDR Scale:</string>
+  <string name="brightness_string">Brightness:</string>
     <layout_stack name="outer_stack"
                   width="845"
                   height="275"
@@ -245,25 +247,6 @@
                             top_pad="5"
                             width="185"
                             can_edit_text="true"/>
-                    <text follows="left|top"
-                          name="scene_gamma_label"
-                          height="10"
-                          layout="topleft"
-                          left_delta="-5"
-                          top_pad="15"
-                          width="80">Brightness:</text>
-                    <slider decimal_digits="2"
-                            follows="left|top"
-                            height="16"
-                            increment="0.01"
-                            initial_value="0"
-                            layout="topleft"
-                            left_delta="5"
-                            max_val="20"
-                            name="scene_gamma"
-                            top_pad="5"
-                            width="185"
-                            can_edit_text="true"/>
                   <text follows="left|top"
                           height="10"
                           layout="topleft"
@@ -283,6 +266,25 @@
                           top_pad="5"
                           width="185"
                           can_edit_text="true"/>
+                    <text follows="left|top"
+                          name="scene_gamma_label"
+                          height="10"
+                          layout="topleft"
+                          left_delta="-5"
+                          top_pad="15"
+                          width="80">Brightness:</text>
+                    <slider decimal_digits="2"
+                            follows="left|top"
+                            height="16"
+                            increment="0.01"
+                            initial_value="0"
+                            layout="topleft"
+                            left_delta="5"
+                            max_val="20"
+                            name="scene_gamma"
+                            top_pad="5"
+                            width="185"
+                            can_edit_text="true"/>
                 </layout_panel>
                 <layout_panel border="false"
                               name="lp_3"
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index fd806739031949c98841f649f8f901c05161c9bd..c1a94a2128c7b1c586971b4daf39dd37e653b2b3 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -600,6 +600,20 @@
       function="Pref.RenderOptionUpdate" />
   </check_box>
 
+  <check_box
+  control_name="RenderSkyAutoAdjustLegacy"
+  height="16"
+  initial_value="true"
+  label="Auto-adjust Legacy Sky"
+  layout="topleft"
+  left="420"
+  name="AutoAdjustLegacySky"
+  top_delta="16"
+  width="240">
+    <check_box.commit_callback
+      function="Pref.RenderOptionUpdate" />
+  </check_box>
+
   <check_box
     control_name="RenderDepthOfField"
     height="16"
diff --git a/indra/newview/skins/default/xui/en/menu_attachment_self.xml b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
index 630a1981dfa66fec8de7ef5856dfdd1b909e48d9..943bfb8122dc0893d5b23beef88c2dfba412df55 100644
--- a/indra/newview/skins/default/xui/en/menu_attachment_self.xml
+++ b/indra/newview/skins/default/xui/en/menu_attachment_self.xml
@@ -13,21 +13,13 @@
          function="EnableEdit" />
     </menu_item_call>
     <menu_item_call
-     label="Edit PBR Material"
+     label="Edit PBR material"
      name="EditGLTFMaterial">
         <menu_item_call.on_click
          function="Object.EditGLTFMaterial" />
         <menu_item_call.on_enable
          function="Object.EnableEditGLTFMaterial"/>
     </menu_item_call>
-    <menu_item_call
-     label="Save material to inventory"
-     name="SaveGLTFMaterial">
-        <menu_item_call.on_click
-         function="Object.SaveGLTFMaterial" />
-        <menu_item_call.on_enable
-         function="Object.EnableSaveGLTFMaterial"/>
-    </menu_item_call>
     <menu_item_call
      enabled="false"
      label="Detach item"
diff --git a/indra/newview/skins/default/xui/en/menu_object.xml b/indra/newview/skins/default/xui/en/menu_object.xml
index 6d37c158157cf4aa46da501f3404518ae152f25c..5507c9f3a1aba8e8080bb383b4ef09cb7e2c2321 100644
--- a/indra/newview/skins/default/xui/en/menu_object.xml
+++ b/indra/newview/skins/default/xui/en/menu_object.xml
@@ -22,21 +22,13 @@
         function="EnableEdit"/>
   </menu_item_call>
   <menu_item_call
-      label="Edit PBR Material"
+      label="Edit PBR material"
       name="EditGLTFMaterial">
     <menu_item_call.on_click
         function="Object.EditGLTFMaterial" />
-    <menu_item_call.on_enable
+    <menu_item_call.on_visible
         function="Object.EnableEditGLTFMaterial"/>
   </menu_item_call>
-  <menu_item_call
-      label="Save material to inventory"
-      name="SaveGLTFMaterial">
-    <menu_item_call.on_click
-        function="Object.SaveGLTFMaterial" />
-    <menu_item_call.on_enable
-        function="Object.EnableSaveGLTFMaterial"/>
-  </menu_item_call>
   <menu_item_call
       label="Build"
       name="Build">
@@ -54,26 +46,25 @@
     <menu_item_call.on_enable
         function="Object.EnableOpen" />
   </menu_item_call>
+  <menu_item_separator layout="topleft" />
   <menu_item_call
-      enabled="false"
-      label="Sit Here"
+      label="Sit here"
       name="Object Sit">
     <menu_item_call.on_click
         function="Object.SitOrStand" />
-    <menu_item_call.on_enable
+    <menu_item_call.on_visible
         function="Object.EnableSit" />
   </menu_item_call>
   <menu_item_call
-      enabled="false"
-      label="Stand Up"
+      label="Stand up"
       name="Object Stand Up">
     <menu_item_call.on_click
         function="Object.SitOrStand" />
-    <menu_item_call.on_enable
+    <menu_item_call.on_visible
         function="Object.EnableStandUp" />
   </menu_item_call>
   <menu_item_call
-      label="Object Profile"
+      label="Object profile"
       name="Object Inspect">
     <menu_item_call.on_click
         function="Object.Inspect" />
@@ -81,13 +72,13 @@
         function="Object.EnableInspect" />
   </menu_item_call>
   <menu_item_call
-      label="Zoom In"
+      label="Zoom in"
       name="Zoom In">
     <menu_item_call.on_click
         function="Object.ZoomIn" />
   </menu_item_call>
   <menu_item_call
-      label="Show in linksets"
+      label="Show in Region Objects"
       name="show_in_linksets">
     <menu_item_call.on_click
         function="Pathfinding.Linksets.Select" />
@@ -108,7 +99,7 @@
   </menu_item_call>
   <menu_item_separator layout="topleft" />
   <context_menu
-      label="Put On"
+      label="Put on"
       name="Put On" >
     <menu_item_call
         enabled="false"
@@ -185,7 +176,7 @@
   </menu_item_call>
   <menu_item_call
       enabled="false"
-      label="Take Copy"
+      label="Take copy"
       name="Take Copy">
     <menu_item_call.on_click
         function="Tools.TakeCopy" />
@@ -223,7 +214,7 @@
        layout="topleft" />
   <menu_item_call
      enabled="false"
-     label="Block Particle Owner"
+     label="Block particle owner"
      name="Mute Particle">
     <menu_item_call.on_click
      function="Particle.Mute" />
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index 74a44b6b090948ca3d9309acd124fbc804da6035..fe74cea2f12fcf06f472ae503d17a33235170158 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -315,6 +315,25 @@ width="120">
       function="Pref.RenderExceptions"/>
   </button>
 
+  <slider
+    control_name="RenderExposure"
+    decimal_digits="1"
+    follows="left|top"
+    height="16"
+    increment="0.1"
+    initial_value="160"
+    label="Brightness (exposure)"
+    label_width="145"
+    layout="topleft"
+    left="30"
+    min_val="0.5"
+    max_val="1.5"
+    name="RenderExposure"
+    show_text="true"
+    top_pad="14"
+    width="260">
+  </slider>
+
 <!-- End of Basic Settings block -->
 
   <button
diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml
index 58d125a88e76a9ea055bbb4fa5a739b81db3cd85..36a485e498dcc48600494ffa471c63b584698b63 100644
--- a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml
+++ b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml
@@ -7,6 +7,8 @@
         left="0"
         name="panel_settings_sky_atmos"
         top="0">
+  <string name="hdr_string">HDR Scale:</string>
+  <string name="brightness_string">Brightness:</string>
     <layout_stack
             name="main_ls"
             follows="all"
@@ -228,29 +230,6 @@
                             name="ice_level"
                             width="207"
                             can_edit_text="true"/>
-                    <text
-                            name="scene_gamma_label"
-                            follows="left|top"
-                            height="10"
-                            layout="topleft"
-                            left_delta="-5"
-                            top_delta="25"
-                            width="80">
-                        Brightness:
-                    </text>
-                    <slider
-                            decimal_digits="2"
-                            follows="left|top"
-                            height="16"
-                            increment="0.01"
-                            initial_value="0"
-                            layout="topleft"
-                            left_delta="5"
-                            max_val="20"
-                            name="scene_gamma"
-                            top_delta="20"
-                            width="207"
-                            can_edit_text="true"/>
                 </layout_panel>            
                 <layout_panel
                         name="right_lp"
@@ -338,8 +317,9 @@
                             layout="topleft"
                             left_delta="-5"
                             top_delta="25"
+                            tooltip="Irradiance control.  When not zero, enables HDR lighting model."
                             width="200">
-                    Reflection Probe Ambiance:
+                    Reflection Probe Ambiance (HDR):
                   </text>
                   <slider
                           decimal_digits="2"
@@ -355,6 +335,29 @@
                           top_delta="20"
                           width="219"
                           can_edit_text="true"/>
+                  <text
+                            name="scene_gamma_label"
+                            follows="left|top"
+                            height="10"
+                            layout="topleft"
+                            left_delta="-5"
+                            top_delta="25"
+                            width="80">
+                    Brightness:
+                  </text>
+                  <slider
+                          decimal_digits="2"
+                          follows="left|top"
+                          height="16"
+                          increment="0.01"
+                          initial_value="0"
+                          layout="topleft"
+                          left_delta="5"
+                          max_val="20"
+                          name="scene_gamma"
+                          top_delta="20"
+                          width="207"
+                          can_edit_text="true"/>
                 </layout_panel>            
             </layout_stack>                
         </layout_panel>
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
index 67bdd189c1ff46eadff47fab15789b1b9c5f522b..51e6099cebd30d35ec81a540d0d36632dbbe7a0f 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -132,12 +132,24 @@
              name="object_horizontal"
              top_pad="4"
              width="278" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left="12"
+             top_pad="12"
+             name="label_matmedia"
+             width="90">
+                Material
+            </text>
             <combo_box
              height="23"
              layout="topleft"
              left="10"
              name="combobox matmedia"
-             top_pad="17"
+             top_pad="5"
              width="90">
                 <combo_box.item
                  label="Blinn-Phong"
@@ -156,7 +168,7 @@
             height="84"
             layout="topleft"
             left_pad="5"
-            top_delta="-10"
+            top_delta="-20"
             width="150"
             visible = "false"
             name="radio_material_type">