From 07bff3129adaabb90f09b71fa65c8be0c3ecef5d Mon Sep 17 00:00:00 2001
From: Graham Linden <graham@lindenlab.com>
Date: Wed, 19 Dec 2018 14:59:19 -0800
Subject: [PATCH] Add new shaders for advanced atmo SH env lighting calcs.

---
 indra/llinventory/llsettingssky.cpp           |   1 -
 indra/newview/app_settings/settings.xml       |  26 ++
 .../shaders/class1/deferred/cofF.glsl         |   9 +-
 .../shaders/class3/deferred/deferredUtil.glsl |  75 +++++
 .../class3/deferred/depthToShadowVolumeG.glsl | 202 +++++++++++
 .../shaders/class3/deferred/gatherSkyShF.glsl |  70 ++++
 .../shaders/class3/deferred/gatherSkyShV.glsl |  40 +++
 .../shaders/class3/deferred/genSkyShF.glsl    | 112 +++++++
 .../shaders/class3/deferred/genSkyShV.glsl    |  37 +++
 .../shaders/class3/deferred/indirect.glsl     |  44 +++
 .../shaders/class3/deferred/lightUtil.glsl    | 117 +++++++
 .../class3/deferred/pointShadowBlurF.glsl     |  37 +++
 .../shaders/class3/deferred/shVisF.glsl       |  73 ++++
 .../shaders/class3/deferred/shVisV.glsl       |  33 ++
 .../class3/deferred/shadowAlphaBlendF.glsl    |  58 ++++
 .../class3/deferred/shadowAlphaBlendV.glsl    |  66 ++++
 .../class3/deferred/shadowAlphaMaskF.glsl     |  74 +++++
 .../class3/deferred/shadowAlphaMaskV.glsl     |  67 ++++
 .../shaders/class3/deferred/shadowCubeV.glsl  |  50 +++
 .../shaders/class3/deferred/shadowF.glsl      |  49 +++
 .../shaders/class3/deferred/shadowUtil.glsl   | 157 +++++++++
 .../shaders/class3/deferred/shadowV.glsl      |  62 ++++
 .../shaders/class3/deferred/softenLightF.glsl |   4 +-
 indra/newview/llviewerdisplay.cpp             |   5 +
 indra/newview/llviewermenu.cpp                |  23 +-
 indra/newview/llviewershadermgr.cpp           |  50 ++-
 indra/newview/llviewershadermgr.h             |   4 +
 indra/newview/pipeline.cpp                    | 313 +++++++++++++++++-
 indra/newview/pipeline.h                      |   7 +-
 29 files changed, 1838 insertions(+), 27 deletions(-)
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/indirect.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/lightUtil.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl
 create mode 100644 indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl

diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp
index 231077c2179..fb7f5e5c1c5 100644
--- a/indra/llinventory/llsettingssky.cpp
+++ b/indra/llinventory/llsettingssky.cpp
@@ -999,7 +999,6 @@ LLColor3 LLSettingsSky::getLightDiffuse() const
 
 LLColor3 LLSettingsSky::getAmbientColor() const
 {
-    // Todo: this causes complications, preferably to get rid of this duality
     if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(SETTING_AMBIENT))
     {
         return LLColor3(mSettings[SETTING_LEGACY_HAZE][SETTING_AMBIENT]);
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 94ce4f6df78..bb5ff191762 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8995,6 +8995,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>RenderDebugSH</key>
+    <map>
+      <key>Comment</key>
+      <string>Enable SH indirect lighting visualization.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
   <key>RenderMaxTextureIndex</key>
   <map>
     <key>Comment</key>
@@ -11959,6 +11970,21 @@
       <key>Value</key>
       <real>0.300000011921</real>
     </map>
+    <key>SkyMoonDefaultPosition</key>
+    <map>
+      <key>Comment</key>
+      <string>Default position of sun in sky (direction in world coordinates)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Vector3</string>
+      <key>Value</key>
+      <array>
+        <real>-1.0</real>
+        <real>0.0</real>
+        <real>-0.1</real>
+      </array>
+    </map>
     <key>SkyNightColorShift</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl
index fef1c5a5848..380d3820208 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/cofF.glsl
@@ -50,14 +50,7 @@ uniform vec2 screen_res;
 
 VARYING vec2 vary_fragcoord;
 
-float getDepth(vec2 pos_screen)
-{
-	float z = texture2DRect(depthMap, pos_screen.xy).r;
-	z = z*2.0-1.0;
-	vec4 ndc = vec4(0.0, 0.0, z, 1.0);
-	vec4 p = inv_proj*ndc;
-	return p.z/p.w;
-}
+float getDepth(vec2 pos_screen);
 
 float calc_cof(float depth)
 {
diff --git a/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl
new file mode 100644
index 00000000000..cccd01e0d73
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/deferredUtil.glsl
@@ -0,0 +1,75 @@
+/** 
+ * @file class3/deferred/deferredUtil.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+uniform sampler2DRect   normalMap;
+uniform sampler2DRect   depthMap;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+vec3 decode_normal(vec2 enc);
+
+vec2 getScreenCoordinate(vec2 screenpos)
+{
+    vec2 sc = screenpos.xy * 2.0;
+    if (screen_res.x > 0 && screen_res.y > 0)
+    {
+       sc /= screen_res;
+    }
+    return sc - vec2(1.0, 1.0);
+}
+
+vec3 getNorm(vec2 screenpos)
+{
+   vec2 enc_norm = texture2DRect(normalMap, screenpos.xy).xy;
+   return decode_normal(enc_norm);
+}
+
+float getDepth(vec2 pos_screen)
+{
+    float depth = texture2DRect(depthMap, pos_screen).r;
+    return depth;
+}
+
+vec4 getPosition(vec2 pos_screen)
+{
+    float depth = getDepth(pos_screen);
+    vec2 sc = getScreenCoordinate(pos_screen);
+    vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+    vec4 pos = inv_proj * ndc;
+    pos /= pos.w;
+    pos.w = 1.0;
+    return pos;
+}
+
+vec4 getPositionWithDepth(vec2 pos_screen, float depth)
+{
+    vec2 sc = getScreenCoordinate(pos_screen);
+    vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+    vec4 pos = inv_proj * ndc;
+    pos /= pos.w;
+    pos.w = 1.0;
+    return pos;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl b/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl
new file mode 100644
index 00000000000..5734e2abb27
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/depthToShadowVolumeG.glsl
@@ -0,0 +1,202 @@
+/** 
+ * @file depthToShadowVolumeG.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+#extension GL_ARB_geometry_shader4  : enable
+#extension GL_ARB_texture_rectangle : enable
+
+/*[EXTRA_CODE_HERE]*/
+
+layout (triangles) in;
+layout (triangle_strip, max_vertices = 128) out;
+
+uniform sampler2DRect depthMap;
+uniform mat4 shadowMatrix[6]; 
+uniform vec4 lightpos;
+
+VARYING vec2 vary_texcoord0;
+
+out vec3 to_vec;
+
+void cross_products(out vec4 ns[3], int a, int b, int c)
+{
+   ns[0] = cross(gl_PositionIn[b].xyz - gl_PositionIn[a].xyz, gl_PositionIn[c].xyz - gl_PositionIn[a].xyz);
+   ns[1] = cross(gl_PositionIn[c].xyz - gl_PositionIn[b].xyz, gl_PositionIn[a].xyz - gl_PositionIn[b].xyz);
+   ns[2] = cross(gl_PositionIn[a].xyz - gl_PositionIn[c].xyz, gl_PositionIn[b].xyz - gl_PositionIn[c].xyz);
+}
+
+vec3 getLightDirection(vec4 lightpos, vec3 pos)
+{
+
+    vec3 lightdir = lightpos.xyz - lightpos.w * pos;
+    return lightdir;
+}
+
+void emitTri(vec4 v[3])
+{
+    gl_Position = proj_matrix * v[0];
+    EmitVertex();
+
+    gl_Position = proj_matrix * v[1];
+    EmitVertex();
+
+    gl_Position = proj_matrix * v[2];
+    EmitVertex();
+
+    EndPrimitive();
+}
+
+void emitQuad(vec4 v[4]
+{
+    // Emit a quad as a triangle strip.
+    gl_Position = proj_matrix*v[0];
+    EmitVertex();
+
+    gl_Position = proj_matrix*v[1];
+    EmitVertex();
+
+    gl_Position = proj_matrix*v[2];
+    EmitVertex();
+
+    gl_Position = proj_matrix*v[3];
+    EmitVertex(); 
+
+    EndPrimitive();
+}
+
+void emitPrimitives(int layer)
+{
+    int i = layer;
+    gl_Layer = i;
+
+    vec4 depth1 = vec4(texture2DRect(depthMap, tc0).rg, texture2DRect(depthMap, tc1).rg));
+    vec3 depth2 = vec4(texture2DRect(depthMap, tc2).rg, texture2DRect(depthMap, tc3).rg));
+    vec3 depth3 = vec4(texture2DRect(depthMap, tc4).rg, texture2DRect(depthMap, tc5).rg));
+    vec3 depth4 = vec4(texture2DRect(depthMap, tc6).rg, texture2DRect(depthMap, tc7).rg));
+
+    depth1 = min(depth1, depth2);
+    depth1 = min(depth1, depth3);
+    depth1 = min(depth1, depth4);
+
+    vec2 depth = min(depth1.xy, depth1.zw);
+
+    int side = sqrt(gl_VerticesIn);
+
+    for (int j = 0; j < side; j++)
+    {
+        for (int k = 0; k < side; ++k)
+        {
+            vec3 pos = gl_PositionIn[(j * side) + k].xyz;
+            vec4 v = shadowMatrix[i] * vec4(pos, 1.0);
+            gl_Position = v;
+            to_vec = pos - light_position.xyz * depth;
+            EmitVertex();
+        }
+
+        EndPrimitive();
+    }
+
+    vec3 norms[3]; // Normals
+    vec3 lightdir3]; // Directions toward light
+
+    vec4 v[4]; // Temporary vertices
+
+    vec4 or_pos[3] =
+    {  // Triangle oriented toward light source
+        gl_PositionIn[0],
+        gl_PositionIn[2],
+        gl_PositionIn[4]
+    };
+
+    // Compute normal at each vertex.
+    cross_products(n, 0, 2, 4);
+
+    // Compute direction from vertices to light.
+    lightdir[0] = getLightDirection(lightpos, gl_PositionIn[0].xyz);
+    lightdir[1] = getLightDirection(lightpos, gl_PositionIn[2].xyz);
+    lightdir[2] = getLightDirection(lightpos, gl_PositionIn[4].xyz);
+
+    // Check if the main triangle faces the light.
+    bool faces_light = true;
+    if (!(dot(ns[0],d[0]) > 0
+         |dot(ns[1],d[1]) > 0
+         |dot(ns[2],d[2]) > 0))
+    {
+        // Flip vertex winding order in or_pos.
+        or_pos[1] = gl_PositionIn[4];
+        or_pos[2] = gl_PositionIn[2];
+        faces_light = false;
+    }
+
+    // Near cap: simply render triangle.
+    emitTri(or_pos);
+
+    // Far cap: extrude positions to infinity.
+    v[0] =vec4(lightpos.w * or_pos[0].xyz - lightpos.xyz,0);
+    v[1] =vec4(lightpos.w * or_pos[2].xyz - lightpos.xyz,0);
+    v[2] =vec4(lightpos.w * or_pos[1].xyz - lightpos.xyz,0);
+
+    emitTri(v);
+
+    // Loop over all edges and extrude if needed.
+    for ( int i=0; i<3; i++ ) 
+    {
+       // Compute indices of neighbor triangle.
+       int v0 = i*2;
+       int nb = (i*2+1);
+       int v1 = (i*2+2) % 6;
+       cross_products(n, v0, nb, v1);
+
+       // Compute direction to light, again as above.
+       d[0] =lightpos.xyz-lightpos.w*gl_PositionIn[v0].xyz;
+       d[1] =lightpos.xyz-lightpos.w*gl_PositionIn[nb].xyz;
+       d[2] =lightpos.xyz-lightpos.w*gl_PositionIn[v1].xyz;
+
+       bool is_parallel = gl_PositionIn[nb].w < 1e-5;
+
+       // Extrude the edge if it does not have a
+       // neighbor, or if it's a possible silhouette.
+       if (is_parallel ||
+          ( faces_light != (dot(ns[0],d[0])>0 ||
+                            dot(ns[1],d[1])>0 ||
+                            dot(ns[2],d[2])>0) ))
+       {
+           // Make sure sides are oriented correctly.
+           int i0 = faces_light ? v0 : v1;
+           int i1 = faces_light ? v1 : v0;
+
+           v[0] = gl_PositionIn[i0];
+           v[1] = vec4(lightpos.w*gl_PositionIn[i0].xyz - lightpos.xyz, 0);
+           v[2] = gl_PositionIn[i1];
+           v[3] = vec4(lightpos.w*gl_PositionIn[i1].xyz - lightpos.xyz, 0);
+
+           emitQuad(v);
+       }
+    }
+}
+
+void main()
+{
+    // Output
+    emitPrimitives(0);
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl
new file mode 100644
index 00000000000..34d26cddea8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShF.glsl
@@ -0,0 +1,70 @@
+/** 
+ * @file class3/deferred/gatherSkyShF.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$
+ */
+ 
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_data[3];
+#else
+#define frag_data gl_FragData
+#endif
+
+VARYING vec2 vary_frag;
+
+uniform vec2 screen_res;
+uniform sampler2D sh_input_r;
+uniform sampler2D sh_input_g;
+uniform sampler2D sh_input_b;
+
+void main()
+{
+    vec2 offset	  = vec2(2.0) / screen_res;
+
+    vec4 r = vec4(0);
+    vec4 g = vec4(0);
+    vec4 b = vec4(0);
+
+    vec2 tc = vary_frag * 2.0;
+
+	r += texture2D(sh_input_r, tc + vec2(0,        0));
+	r += texture2D(sh_input_r, tc + vec2(offset.x, 0));
+	r += texture2D(sh_input_r, tc + vec2(0,        offset.y));
+	r += texture2D(sh_input_r, tc + vec2(offset.x, offset.y));
+    r /= 4.0f;
+
+	g += texture2D(sh_input_g, tc + vec2(0,        0));
+	g += texture2D(sh_input_g, tc + vec2(offset.x, 0));
+	g += texture2D(sh_input_g, tc + vec2(0,        offset.y));
+	g += texture2D(sh_input_g, tc + vec2(offset.x, offset.y));
+    g /= 4.0f;
+
+	b += texture2D(sh_input_b, tc + vec2(0,        0));
+	b += texture2D(sh_input_b, tc + vec2(offset.x, 0));
+	b += texture2D(sh_input_b, tc + vec2(0,        offset.y));
+	b += texture2D(sh_input_b, tc + vec2(offset.x, offset.y));
+    b /= 4.0f;
+
+    frag_data[0] = r;
+    frag_data[1] = g;
+    frag_data[2] = b;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl
new file mode 100644
index 00000000000..337c8a50fe5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/gatherSkyShV.glsl
@@ -0,0 +1,40 @@
+/** 
+ * @file gatherSkyShV.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$
+ */
+ 
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec2 vary_frag;
+uniform vec2 screen_res;
+
+void main()
+{
+    // pass through untransformed fullscreen pos
+    float oo_divisor = screen_res.x / 64.0;
+    vec3 pos = (position.xyz * oo_divisor) + vec3(oo_divisor - 1, oo_divisor - 1, 0);
+	gl_Position = vec4(pos.xyz, 1.0);
+    vary_frag = texcoord0 * oo_divisor;
+}
+
diff --git a/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl b/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl
new file mode 100644
index 00000000000..c02e6d1e57d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/genSkyShF.glsl
@@ -0,0 +1,112 @@
+/** 
+ * @file class3/deferred/genSkyShF.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$
+ */
+ 
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_data[3];
+#else
+#define frag_data gl_FragData
+#endif
+
+VARYING vec2 vary_frag;
+
+uniform vec3 sun_dir;
+
+uniform sampler2D transmittance_texture;
+uniform sampler3D scattering_texture;
+uniform sampler3D single_mie_scattering_texture;
+uniform sampler2D irradiance_texture;
+uniform vec4 gamma;
+
+vec3 GetSkyLuminance(vec3 camPos, vec3 view_dir, float shadow_length, vec3 dir, out vec3 transmittance);
+
+vec3 calcDirection(vec2 tc)
+{
+     float phi = tc.y * 2.0 * 3.14159265;
+     float cosTheta = sqrt(1.0 - tc.x);
+     float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
+     return vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);
+}
+
+// reverse mapping above to convert a hemisphere direction into phi/theta values
+void getPhiAndThetaFromDirection(vec3 dir, out float phi, out float theta)
+{
+     float sin_theta;
+     float cos_theta;
+     cos_theta = dir.z;
+     theta     = acos(cos_theta);
+     sin_theta = sin(theta);
+     phi       = abs(sin_theta) > 0.0001 ? acos(dir.x / sin_theta) : 1.0;
+}
+
+// reverse mapping above to convert a hemisphere direction into an SH texture sample pos
+vec2 calcShUvFromDirection(vec3 dir)
+{
+    vec2 uv;
+    float phi;
+    float theta;
+    getPhiAndThetaFromDirection(dir, phi, theta);
+    uv.y = phi   / 2.0 * 3.14159265;
+    uv.x = theta / 2.0 * 3.14159265;
+    return uv;
+}
+
+void projectToL1(vec3 n, vec3 c, vec4 basis, out vec4 coeffs[3])
+{
+    coeffs[0] = vec4(basis.x, n * basis.yzw * c.r);
+    coeffs[1] = vec4(basis.x, n * basis.yzw * c.g);
+    coeffs[2] = vec4(basis.x, n * basis.yzw * c.b);
+}
+
+void main()
+{
+    float Y00 = sqrt(1.0 / 3.14159265) * 0.5;
+    float Y1x = sqrt(3.0 / 3.14159265) * 0.5;
+    float Y1y = Y1x;
+    float Y1z = Y1x;
+
+    vec4 L1 = vec4(Y00, Y1x, Y1y, Y1z);
+
+    vec3 view_direction = calcDirection(vary_frag);
+    vec3 sun_direction  = normalize(sun_dir);
+    vec3 cam_pos        = vec3(0, 0, 6360);
+
+    vec3 transmittance;
+    vec3 radiance = GetSkyLuminance(cam_pos, view_direction, 0.0f, sun_direction, transmittance);
+
+    vec3 color = vec3(1.0) - exp(-radiance * 0.0001);
+
+    color = pow(color, vec3(1.0/2.2));
+
+    vec4 coeffs[3];
+    coeffs[0] = vec4(0);
+    coeffs[1] = vec4(0);
+    coeffs[2] = vec4(0);
+
+    projectToL1(view_direction, color.rgb, L1, coeffs);
+
+    frag_data[0] = coeffs[0];
+    frag_data[1] = coeffs[1];
+    frag_data[2] = coeffs[2];
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl b/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl
new file mode 100644
index 00000000000..b466883dc7e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/genSkyShV.glsl
@@ -0,0 +1,37 @@
+/** 
+ * @file genSkyShV.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$
+ */
+ 
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec2 vary_frag;
+
+void main()
+{
+    // pass through untransformed fullscreen pos
+	gl_Position = vec4(position.xyz, 1.0);
+    vary_frag = texcoord0;
+}
+
diff --git a/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl b/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl
new file mode 100644
index 00000000000..33c5667cae9
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/indirect.glsl
@@ -0,0 +1,44 @@
+/** 
+ * @file class3/deferred/indirect.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+/*[EXTRA_CODE_HERE]*/
+
+uniform sampler2D sh_input_r;
+uniform sampler2D sh_input_g;
+uniform sampler2D sh_input_b;
+
+vec3 GetIndirect(vec3 norm)
+{
+    vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265));
+    vec4 l1r = texture2D(sh_input_r, vec2(0,0));
+    vec4 l1g = texture2D(sh_input_g, vec2(0,0));
+    vec4 l1b = texture2D(sh_input_b, vec2(0,0));
+    vec3 indirect = vec3(dot(l1r, l1tap * vec4(1, norm.xyz)),
+                         dot(l1g, l1tap * vec4(1, norm.xyz)),
+                         dot(l1b, l1tap * vec4(1, norm.xyz)));
+    indirect = clamp(indirect, vec3(0), vec3(1.0));
+    return indirect;
+}
+
diff --git a/indra/newview/app_settings/shaders/class3/deferred/lightUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/lightUtil.glsl
new file mode 100644
index 00000000000..8bb3f07fc64
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/lightUtil.glsl
@@ -0,0 +1,117 @@
+/** 
+ * @file lightInfo.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+struct DirectionalLightInfo
+{
+    vec4 pos;
+    float depth;
+    vec4 normal;
+    vec3 normalizedLightDirection;
+    vec3 normalizedToLight;
+    float lightIntensity;
+    vec3 lightDiffuseColor;
+    float specExponent;
+    float shadow;
+};
+
+struct SpotLightInfo
+{
+    vec4 pos;
+    float depth;
+    vec4 normal;
+    vec3 normalizedLightDirection;
+    vec3 normalizedToLight;
+    float lightIntensity;
+    float attenuation;
+    float distanceToLight;
+    vec3 lightDiffuseColor;
+    float innerHalfAngleCos;
+    float outerHalfAngleCos;
+    float spotExponent;
+    float specExponent;
+    float shadow;
+};
+
+struct PointLightInfo
+{
+    vec4 pos;
+    float depth;
+    vec4 normal;
+    vec3 normalizedToLight;
+    float lightIntensity;
+    float attenuation;
+    float distanceToLight;
+    vec3 lightDiffuseColor;
+    float lightRadius;
+    float specExponent;
+    vec3 worldspaceLightDirection;
+    float shadow;
+};
+
+float attenuate(float attenuationSelection, float distanceToLight)
+{
+// LLRENDER_REVIEW
+// sh/could eventually consume attenuation func defined in texture
+    return (attenuationSelection == 0.0f) ? 1.0f : // none
+           (attenuationSelection <  1.0f) ? (1.0f / distanceToLight) : // linear atten 
+           (attenuationSelection <  2.0f) ? (1.0f / (distanceToLight*distanceToLight)) // quadratic atten
+										  : (1.0f / (distanceToLight*distanceToLight*distanceToLight));	// cubic atten    
+}
+
+
+vec3 lightDirectional(struct DirectionalLightInfo dli)
+{
+    float lightIntensity = dli.lightIntensity;
+	lightIntensity *= dot(dli.normal.xyz, dli.normalizedLightDirection);
+    //lightIntensity *= directionalShadowSample(vec4(dli.pos.xyz, 1.0f), dli.depth, dli.directionalShadowMap, dli.directionalShadowMatrix);
+	return lightIntensity * dli.lightDiffuseColor;
+}
+
+
+vec3 lightSpot(struct SpotLightInfo sli)    
+{
+	float penumbraRange = (sli.outerHalfAngleCos - sli.innerHalfAngleCos);
+    float coneAngleCos = max(dot(sli.normalizedLightDirection, sli.normalizedToLight), 0.0);
+	float coneAttenFactor = (coneAngleCos <= sli.outerHalfAngleCos) ? 1.0f : pow(smoothstep(1,0, sli.outerHalfAngleCos / penumbraRange), sli.spotExponent);
+    float distanceAttenuation = attenuate(sli.attenuation, sli.distanceToLight);
+    float lightIntensity = sli.lightIntensity;
+    lightIntensity *= distanceAttenuation;
+	lightIntensity *= max(dot(sli.normal.xyz, sli.normalizedLightDirection), 0.0);
+	lightIntensity *= coneAttenFactor;
+    lightIntensity *= sli.shadow;
+	return lightIntensity * sli.lightDiffuseColor;
+}
+
+vec3 lightPoint(struct PointLightInfo pli)
+{
+    float padRadius = pli.lightRadius * 0.1; // distance for which to perform smoothed dropoff past light radius
+	float distanceAttenuation =	attenuate(pli.attenuation, pli.distanceToLight);
+    float lightIntensity = pli.lightIntensity;
+    lightIntensity*= distanceAttenuation;    
+	lightIntensity *= clamp((padRadius - pli.distanceToLight + pli.lightRadius) / padRadius, 0.0, 1.0);
+    lightIntensity *= pli.shadow;
+    lightIntensity *= max(dot(pli.normal.xyz, pli.normalizedToLight), 0.0);
+	return lightIntensity * pli.lightDiffuseColor;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl b/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl
new file mode 100644
index 00000000000..ca9ce3a2e1b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/pointShadowBlurF.glsl
@@ -0,0 +1,37 @@
+/** 
+ * @file pointShadowBlur.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+uniform samplerCube cube_map; 
+
+in vec3 to_vec;
+
+out vec4 fragColor;
+
+void main() 
+{
+	vec4 vcol = texture(cube_map, to_vec);
+	fragColor = vec4(vcol.rgb, 1.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl
new file mode 100644
index 00000000000..c8991f7a181
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shVisF.glsl
@@ -0,0 +1,73 @@
+/** 
+ * @file class3/deferred/shVisF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+#ifdef DEFINE_GL_FRAGCOLOR
+    out vec4 frag_color;
+#else
+    #define frag_color gl_FragColor
+#endif
+
+/////////////////////////////////////////////////////////////////////////
+// Fragment shader for L1 SH debug rendering
+/////////////////////////////////////////////////////////////////////////
+
+uniform sampler2D sh_input_r;
+uniform sampler2D sh_input_g;
+uniform sampler2D sh_input_b;
+
+uniform mat3 inv_modelviewprojection;
+
+VARYING vec4 vary_pos;
+
+void main(void) 
+{
+    vec2 coord = vary_pos.xy + vec2(0.5,0.5);
+
+    coord.x *= (1.6/0.9);
+
+    if (dot(coord, coord) > 0.25)
+    {
+        discard;
+    }
+
+    vec4 n = vec4(coord*2.0, 0.0, 1);
+    //n.y = -n.y;
+    n.z = sqrt(max(1.0-n.x*n.x-n.y*n.y, 0.0));
+    //n.xyz = inv_modelviewprojection * n.xyz;
+
+    vec4 l1tap = vec4(1.0/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265), sqrt(3)/sqrt(4*3.14159265));
+    vec4 l1r = texture2D(sh_input_r, vec2(0,0));
+    vec4 l1g = texture2D(sh_input_g, vec2(0,0));
+    vec4 l1b = texture2D(sh_input_b, vec2(0,0));
+    vec3 indirect = vec3(
+                      dot(l1r, l1tap * n),
+                      dot(l1g, l1tap * n),
+                      dot(l1b, l1tap * n));
+
+    //indirect = pow(indirect, vec3(0.45));
+    indirect *= 3.0;
+
+	frag_color = vec4(indirect, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl
new file mode 100644
index 00000000000..8f32dfde79d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shVisV.glsl
@@ -0,0 +1,33 @@
+/** 
+ * @file class3/deferred/shVisV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+ATTRIBUTE vec3 position;
+VARYING vec4 vary_pos;
+
+void main()
+{
+    // Output
+    vary_pos = vec4(position, 1);
+    gl_Position = vary_pos;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl
new file mode 100644
index 00000000000..01599d81c4a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendF.glsl
@@ -0,0 +1,58 @@
+/** 
+ * @file shadowAlphaMaskF.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+/*[EXTRA_CODE_HERE]*/
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2D diffuseMap;
+
+#if !DEPTH_CLAMP
+VARYING float pos_zd2;
+#endif
+
+VARYING float pos_w;
+
+VARYING float target_pos_x;
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+VARYING vec3 pos;
+
+vec4 computeMoments(float depth, float a);
+
+void main() 
+{
+	float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a;
+
+    frag_color = computeMoments(length(pos), float a);
+
+#if !DEPTH_CLAMP
+	gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0);
+#endif
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl
new file mode 100644
index 00000000000..3fb2bafca46
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaBlendV.glsl
@@ -0,0 +1,66 @@
+/** 
+ * @file shadowAlphaMaskV.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+uniform mat4 texture_matrix0;
+uniform mat4 modelview_projection_matrix;
+uniform float shadow_target_width;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec4 diffuse_color;
+ATTRIBUTE vec2 texcoord0;
+
+#if !DEPTH_CLAMP
+VARYING float pos_zd2;
+#endif
+
+VARYING float target_pos_x;
+VARYING vec4 pos;
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+void passTextureIndex();
+
+void main()
+{
+	//transform vertex
+	vec4 pre_pos = vec4(position.xyz, 1.0);
+	vec4 pos = modelview_projection_matrix * pre_pos;
+	target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x;
+
+	pos_w = pos.w;
+
+#if !DEPTH_CLAMP
+	pos_zd2 = pos.z * 0.5;
+	
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
+	
+	passTextureIndex();
+
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+	vertex_color = diffuse_color;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl
new file mode 100644
index 00000000000..d6ed5b6bb01
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskF.glsl
@@ -0,0 +1,74 @@
+/** 
+ * @file class3/deferred/shadowAlphaMaskF.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+/*[EXTRA_CODE_HERE]*/
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2D diffuseMap;
+
+#if !DEPTH_CLAMP
+VARYING float pos_zd2;
+#endif
+
+VARYING float pos_w;
+
+VARYING float target_pos_x;
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+vec4 getPosition(vec2 screen_coord);
+vec4 computeMoments(float depth, float a);
+
+void main() 
+{
+    vec4 pos = getPosition(vary_texcoord0.xy);
+
+    float alpha = diffuseLookup(vary_texcoord0.xy).a * vertex_color.a;
+
+    if (alpha < 0.05) // treat as totally transparent
+    {
+        discard;
+    }
+
+    if (alpha < 0.88) // treat as semi-transparent
+    {
+        if (fract(0.5*floor(target_pos_x / pos_w )) < 0.25)
+        {
+            discard;
+        }
+    }
+
+    frag_color = computeMoments(length(pos.xyz), alpha);
+    
+#if !DEPTH_CLAMP
+    gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0);
+#endif
+
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl
new file mode 100644
index 00000000000..bc7fe003f25
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowAlphaMaskV.glsl
@@ -0,0 +1,67 @@
+/** 
+ * @file class3/deferred/shadowAlphaMaskV.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+uniform mat4 texture_matrix0;
+uniform mat4 modelview_projection_matrix;
+uniform float shadow_target_width;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec4 diffuse_color;
+ATTRIBUTE vec2 texcoord0;
+
+#if !DEPTH_CLAMP
+VARYING float pos_zd2;
+#endif
+
+VARYING vec4 pos;
+VARYING float target_pos_x;
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+void passTextureIndex();
+
+void main()
+{
+	//transform vertex
+	vec4 pre_pos = vec4(position.xyz, 1.0);
+
+	pos = modelview_projection_matrix * pre_pos;
+
+	target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x;
+
+#if !DEPTH_CLAMP
+	pos_zd2 = pos.z * 0.5;
+	
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
+	
+	passTextureIndex();
+
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+
+	vertex_color = diffuse_color;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl
new file mode 100644
index 00000000000..923de09ada3
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowCubeV.glsl
@@ -0,0 +1,50 @@
+/** 
+ * @file class3/deferred/shadowCubeV.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+
+#if !DEPTH_CLAMP
+VARYING vec4 post_pos;
+#endif
+
+uniform vec3 box_center;
+uniform vec3 box_size;
+
+void main()
+{
+	//transform vertex
+	vec3 p = position*box_size+box_center;
+	vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0);
+
+#if !DEPTH_CLAMP
+	post_pos = pos;
+
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl
new file mode 100644
index 00000000000..5a6c8728c04
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowF.glsl
@@ -0,0 +1,49 @@
+/** 
+ * @file class3/deferred/shadowF.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+/*[EXTRA_CODE_HERE]*/
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2D diffuseMap;
+
+#if !DEPTH_CLAMP
+VARYING float pos_zd2;
+#endif
+
+VARYING vec4 pos;
+VARYING float target_pos_x;
+
+vec4 computeMoments(float depth, float a);
+
+void main() 
+{
+    frag_color = computeMoments(length(pos), 1.0);
+}
+
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl
new file mode 100644
index 00000000000..2f69a353e86
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowUtil.glsl
@@ -0,0 +1,157 @@
+/** 
+ * @file class3/deferred/shadowUtil.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, 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$
+ */
+
+uniform sampler2D       shadowMap0;
+uniform sampler2D       shadowMap1;
+uniform sampler2D       shadowMap2;
+uniform sampler2D       shadowMap3;
+uniform sampler2D       shadowMap4;
+uniform sampler2D       shadowMap5;
+
+uniform vec3 sun_dir;
+uniform vec3 moon_dir;
+uniform vec2 shadow_res;
+uniform vec2 proj_shadow_res;
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform float shadow_bias;
+
+uniform float spot_shadow_bias;
+uniform float spot_shadow_offset;
+
+float getDepth(vec2 screenpos);
+vec3 getNorm(vec2 screenpos);
+vec4 getPosition(vec2 pos_screen);
+
+float ReduceLightBleeding(float p_max, float Amount)
+{
+    return smoothstep(Amount, 1, p_max);
+}
+
+float ChebyshevUpperBound(vec2 m, float t, float min_v, float Amount)
+{
+    float p = (t <= m.x) ? 1.0 : 0.0;
+
+    float v = m.y - (m.x*m.x);
+    v = max(v, min_v);
+
+    float d = t - m.x;
+
+    float p_max = v / (v + d*d);
+
+    p_max = ReduceLightBleeding(p_max, Amount);
+
+    return max(p, p_max);
+}
+
+vec4 computeMoments(float depth, float a)
+{
+    float m1 = depth;
+    float dx = dFdx(depth);
+    float dy = dFdy(depth);
+    float m2 = m1*m1 + 0.25 * a * (dx*dx + dy*dy);
+    return vec4(m1, m2, a, max(dx, dy));
+}
+
+float vsmDirectionalSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix)
+{
+    vec4 lpos = shadowMatrix * stc;
+    vec4 moments = texture2D(shadowMap, lpos.xy);
+    return ChebyshevUpperBound(moments.rg, depth - shadow_bias * 256.0f, 0.125, 0.9);
+}
+
+float vsmSpotSample(vec4 stc, float depth, sampler2D shadowMap, mat4 shadowMatrix)
+{
+    vec4 lpos = shadowMatrix * stc;
+    vec4 moments = texture2D(shadowMap, lpos.xy);
+    lpos.xyz /= lpos.w;
+    lpos.xy *= 0.5;
+    lpos.xy += 0.5;
+    return ChebyshevUpperBound(moments.rg, depth - spot_shadow_bias * 16.0f, 0.125, 0.9);
+}
+
+#if VSM_POINT_SHADOWS
+float vsmPointSample(float lightDistance, vec3 lightDirection, samplerCube shadow_cube_map)
+{
+    vec4 moments = textureCube(shadow_cube_map, light_direction);
+    return ChebyshevUpperBound(moments.rg, light_distance, 0.01, 0.25);
+}
+#endif
+
+float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen)
+{
+	if (pos.z < -shadow_clip.w)
+    {
+        discard;
+    }
+
+    float depth = getDepth(pos_screen);
+
+    vec4 spos       = vec4(pos,1.0);
+    vec4 near_split = shadow_clip*-0.75;
+    vec4 far_split  = shadow_clip*-1.25;
+
+    float shadow = 0.0f;
+    float weight = 1.0;
+
+    if (spos.z < near_split.z)
+    {
+        shadow += vsmDirectionalSample(spos, depth, shadowMap3, shadow_matrix[3]);
+        weight += 1.0f;
+    }
+    if (spos.z < near_split.y)
+    {
+        shadow += vsmDirectionalSample(spos, depth, shadowMap2, shadow_matrix[2]);
+        weight += 1.0f;
+    }
+    if (spos.z < near_split.x)
+    {
+        shadow += vsmDirectionalSample(spos, depth, shadowMap1, shadow_matrix[1]);
+        weight += 1.0f;
+    }
+    if (spos.z > far_split.x)
+    {
+        shadow += vsmDirectionalSample(spos, depth, shadowMap0, shadow_matrix[0]);
+        weight += 1.0f;
+    }
+
+    shadow /= weight;
+
+    return shadow;
+}
+
+float sampleSpotShadow(vec3 pos, vec3 norm, int index, vec2 pos_screen)
+{
+	if (pos.z < -shadow_clip.w)
+    {
+        discard;
+    }
+
+    float depth = getDepth(pos_screen);
+
+    pos += norm * spot_shadow_offset;
+    return vsmSpotSample(vec4(pos, 1.0), depth, (index == 0) ? shadowMap4 : shadowMap5, shadow_matrix[4 + index]);
+}
+
diff --git a/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl
new file mode 100644
index 00000000000..9a5edaf091e
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class3/deferred/shadowV.glsl
@@ -0,0 +1,62 @@
+/** 
+ * @file class3/deferred/shadowV.glsl
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+uniform mat4 modelview_projection_matrix;
+uniform float shadow_target_width;
+uniform mat4 texture_matrix0;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+
+#if !DEPTH_CLAMP
+VARYING float pos_zd2;
+#endif
+
+VARYING vec4 pos;
+VARYING float target_pos_x;
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+void passTextureIndex();
+
+void main()
+{
+	//transform vertex
+	vec4 pre_pos = vec4(position.xyz, 1.0);
+
+	pos = modelview_projection_matrix * pre_pos;
+
+	target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x;
+
+#if !DEPTH_CLAMP
+	pos_zd2 = pos.z * 0.5;
+	
+	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
+	
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index ecf6858136e..b84d3efbaa7 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -40,15 +40,13 @@ uniform sampler2DRect lightMap;
 uniform sampler2DRect depthMap;
 uniform sampler2D     lightFunc;
 
-uniform float blur_size;
 uniform samplerCube environmentMap;
-
+uniform float blur_size;
 uniform float blur_fidelity;
 
 // Inputs
 uniform vec4 morphFactor;
 uniform vec3 camPosLocal;
-uniform vec4 gamma;
 uniform float cloud_shadow;
 uniform float max_y;
 uniform vec4 glow;
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 5d01e7e5845..2d4478bfdbb 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1021,6 +1021,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			}
 		}
 
+        if (LLPipeline::sRenderDeferred && gAtmosphere && gSavedSettings.getBOOL("RenderUseAdvancedAtmospherics"))
+        {
+            gPipeline.generateSkyIndirect();
+        }
+
 		if (LLPipeline::sRenderDeferred)
 		{
 			gPipeline.renderDeferredLighting(&gPipeline.mScreen);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index eeb60f75497..1bbda04ae65 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1211,6 +1211,20 @@ class LLAdvancedSelectedTextureInfo : public view_listener_t
 	}
 };
 
+////////////////////////////
+// TOGGLE SH LIGHTING VIS //
+////////////////////////////
+
+class LLAdvancedToggleDebugSH : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+        gPipeline.toggleRenderDebug(LLPipeline::RENDER_DEBUG_SH);
+        gSavedSettings.setBOOL("RenderDebugSH", gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SH));
+		return true;
+	}
+};
+
 //////////////////////
 // TOGGLE WIREFRAME //
 //////////////////////
@@ -6101,12 +6115,7 @@ class LLAvatarResetSkeleton: public view_listener_t
 {
     bool handleEvent(const LLSD& userdata)
     {
-		LLVOAvatar* avatar = NULL;
-        LLViewerObject *obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-        if (obj)
-        {
-            avatar = obj->getAvatar();
-        }
+		LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
 		if(avatar)
         {
             avatar->resetSkeleton(false);
@@ -8650,7 +8659,6 @@ class LLWorldEnableEnvPreset : public view_listener_t
 	}
 };
 
-
 /// Post-Process callbacks
 class LLWorldPostProcess : public view_listener_t
 {
@@ -8991,6 +8999,7 @@ void initialize_menus()
 	commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info));
 	view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
 	view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
+    view_listener_t::addMenu(new LLAdvancedToggleDebugSH(), "Advanced.ToggleDebugSH");
 	// Develop > Render
 	view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
 	view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO");
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index bb3ad4bea60..9a62ab232d5 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -242,6 +242,10 @@ LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
 LLGLSLShader			gDeferredSkinnedFullbrightProgram;
 LLGLSLShader			gNormalMapGenProgram;
 
+LLGLSLShader			gDeferredGenSkyShProgram;
+LLGLSLShader			gDeferredGatherSkyShProgram;
+LLGLSLShader			gDeferredShVisProgram;
+
 // Deferred materials shaders
 LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
 LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
@@ -350,6 +354,9 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredWLCloudProgram);
     mShaderList.push_back(&gDeferredWLMoonProgram);
     mShaderList.push_back(&gDeferredWLSunProgram);
+    mShaderList.push_back(&gDeferredGenSkyShProgram);
+    mShaderList.push_back(&gDeferredGatherSkyShProgram);
+    mShaderList.push_back(&gDeferredShVisProgram);
 }
 
 LLViewerShaderMgr::~LLViewerShaderMgr()
@@ -1276,6 +1283,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 			gDeferredMaterialProgram[i].unload();
 			gDeferredMaterialWaterProgram[i].unload();
 		}
+
+        gDeferredGenSkyShProgram.unload();
+        gDeferredGatherSkyShProgram.unload();
+        gDeferredShVisProgram.unload();
 		return TRUE;
 	}
 
@@ -2287,6 +2298,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	{
 		gDeferredCoFProgram.mName = "Deferred CoF Shader";
 		gDeferredCoFProgram.mShaderFiles.clear();
+        gDeferredCoFProgram.mFeatures.isDeferred = true;
 		gDeferredCoFProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredCoFProgram.mShaderFiles.push_back(make_pair("deferred/cofF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredCoFProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
@@ -2363,6 +2375,42 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
         llassert(success);
 	}
 
+    if (success && gAtmosphere && (mShaderLevel[SHADER_WINDLIGHT] > 2))
+	{
+		gDeferredGenSkyShProgram.mName = "Deferred Generate Sky Indirect SH Program";
+        gDeferredGenSkyShProgram.mFeatures.decodesNormal = true;
+
+		gDeferredGenSkyShProgram.mShaderFiles.clear();
+		gDeferredGenSkyShProgram.mShaderFiles.push_back(make_pair("deferred/genSkyShV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredGenSkyShProgram.mShaderFiles.push_back(make_pair("deferred/genSkyShF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredGenSkyShProgram.mShaderLevel = mShaderLevel[SHADER_WINDLIGHT];
+        gDeferredGenSkyShProgram.mExtraLinkObject = gAtmosphere->getAtmosphericShaderForLink();
+		success = gDeferredGenSkyShProgram.createShader(NULL, NULL);
+        llassert(success);
+	}
+
+    if (success && gAtmosphere && (mShaderLevel[SHADER_WINDLIGHT] > 2))
+	{
+		gDeferredGatherSkyShProgram.mName = "Deferred Gather Sky Indirect SH Program";
+		gDeferredGatherSkyShProgram.mShaderFiles.clear();
+		gDeferredGatherSkyShProgram.mShaderFiles.push_back(make_pair("deferred/gatherSkyShV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredGatherSkyShProgram.mShaderFiles.push_back(make_pair("deferred/gatherSkyShF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredGatherSkyShProgram.mShaderLevel = 3;
+		success = gDeferredGatherSkyShProgram.createShader(NULL, NULL);
+        llassert(success);
+	}
+
+    if (success)
+	{
+		gDeferredShVisProgram.mName = "Deferred SH Vis Program";
+		gDeferredShVisProgram.mShaderFiles.clear();
+		gDeferredShVisProgram.mShaderFiles.push_back(make_pair("deferred/shVisV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredShVisProgram.mShaderFiles.push_back(make_pair("deferred/shVisF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShVisProgram.mShaderLevel = 3;
+		success = gDeferredShVisProgram.createShader(NULL, NULL);
+        llassert(success);
+	}
+
     if (success)
 	{
 		gDeferredWLSunProgram.mName = "Deferred Windlight Sun Program";
@@ -3745,7 +3793,7 @@ BOOL LLViewerShaderMgr::loadShadersWindLight()
 
 #if USE_ADVANCED_ATMOSPHERICS
 // disabled until we can determine why low-end machines crash during this init...
-    if (mVertexShaderLevel[SHADER_WINDLIGHT] > 1)
+    if (gSavedSettings.getBOOL("RenderUseAdvancedAtmospherics") && mShaderLevel[SHADER_WINDLIGHT] > 2)
     {
         // Prepare precomputed atmospherics textures using libatmosphere
         LLAtmosphere::initClass();
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index ac2cfc11600..75438bcff7e 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -325,6 +325,10 @@ extern LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
 extern LLGLSLShader			gDeferredSkinnedFullbrightProgram;
 extern LLGLSLShader			gNormalMapGenProgram;
 
+extern LLGLSLShader			gDeferredGenSkyShProgram;
+extern LLGLSLShader			gDeferredGatherSkyShProgram;
+extern LLGLSLShader			gDeferredShVisProgram;
+
 // Deferred materials shaders
 extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
 extern LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 08e4a276163..828910c9c02 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -885,7 +885,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		S32 shadow_detail = RenderShadowDetail;
 		bool ssao = RenderDeferredSSAO;
 		
-		const U32 occlusion_divisor = 3;
+		const U32 occlusion_divisor = 4;
 
 		//allocate deferred rendering color buffers
 		if (!mDeferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
@@ -966,6 +966,18 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 			}
 		}
 
+        // for EEP atmospherics
+        bool allocated_sh0 = mSkySH.allocate(64, 64, GL_RGBA16F_ARB, FALSE, FALSE, LLTexUnit::TT_TEXTURE);
+        if (!allocated_sh0)
+        {
+        	return false;
+        }
+        else
+        {
+            mSkySH.addColorAttachment(GL_RGBA16F_ARB);
+			mSkySH.addColorAttachment(GL_RGBA16F_ARB);
+        }
+
 		U32 width = (U32) (resX*scale);
 		U32 height = width;
 
@@ -1009,6 +1021,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
         mWaterDeferredLight.release();
 
 		releaseShadowTargets();
+
 		mFXAABuffer.release();
 		mScreen.release();
 		mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
@@ -2637,7 +2650,7 @@ void LLPipeline::downsampleMinMaxDepthBuffer(LLRenderTarget& source, LLRenderTar
 	{
 		scratch_space->copyContents(source,
 			0, 0, source.getWidth(), source.getHeight(),
-			0, 0, scratch_space->getWidth(), scratch_space->getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+			0, 0, scratch_space->getWidth(), scratch_space->getHeight(), source.hasStencil() ? GL_DEPTH_BUFFER_BIT : GL_COLOR_BUFFER_BIT, GL_NEAREST);
 	}
 
 	dest.bindTarget();
@@ -2696,7 +2709,7 @@ void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& d
 	{
 		scratch_space->copyContents(source, 
 									0, 0, source.getWidth(), source.getHeight(), 
-									0, 0, scratch_space->getWidth(), scratch_space->getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+									0, 0, scratch_space->getWidth(), scratch_space->getHeight(), source.hasStencil() ? (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) : GL_COLOR_BUFFER_BIT, GL_NEAREST);
 	}
 
 	dest.bindTarget();
@@ -5369,6 +5382,55 @@ void LLPipeline::renderDebug()
 
 	visible_selected_groups.clear();
 
+    if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SH) && gSavedSettings.getBOOL("RenderUseAdvancedAtmospherics") && LLPipeline::sRenderDeferred)
+    {
+        bindDeferredShader(gDeferredShVisProgram);
+
+        S32 l1r_channel = gDeferredShVisProgram.enableTexture(LLShaderMgr::SH_INPUT_L1R, gPipeline.mSkySH.getUsage());
+	    if (l1r_channel > -1)
+	    {
+		    gPipeline.mSkySH.bindTexture(0,l1r_channel);
+		    gGL.getTexUnit(l1r_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	    }
+		
+        S32 l1b_channel = gDeferredShVisProgram.enableTexture(LLShaderMgr::SH_INPUT_L1G, gPipeline.mSkySH.getUsage());
+	    if (l1b_channel > -1)
+	    {
+		    gPipeline.mSkySH.bindTexture(1,l1b_channel);
+		    gGL.getTexUnit(l1b_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	    }
+
+        S32 l1g_channel = gDeferredShVisProgram.enableTexture(LLShaderMgr::SH_INPUT_L1B, gPipeline.mSkySH.getUsage());
+	    if (l1g_channel > -1)
+	    {
+		    gPipeline.mSkySH.bindTexture(2,l1g_channel);
+		    gGL.getTexUnit(l1g_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	    }
+        
+        LLGLDisable   blend(GL_BLEND);
+		LLGLDepthTest depth(GL_FALSE, GL_FALSE, GL_ALWAYS);
+
+        LLVector3 pos = LLViewerCamera::instance().getOrigin();
+        pos += LLViewerCamera::instance().getAtAxis() * 10.0f;
+
+        gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+        gGL.begin(LLRender::TRIANGLES);
+		gGL.texCoord2f(0.0f, 0.0f);
+		gGL.vertex2f(-1,-1);
+		
+		gGL.texCoord2f(0.0f, 1.0f);
+		gGL.vertex2f(-1,3);
+		
+		gGL.texCoord2f(1.0f, 0.0f);
+		gGL.vertex2f(3,-1);
+		
+		gGL.end();
+		gGL.flush();
+
+        unbindDeferredShader(gDeferredShVisProgram);
+    }
+
 	if (LLGLSLShader::sNoFixedFunction)
 	{
 		gUIProgram.bind();
@@ -8377,6 +8439,34 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
 		}
 	}
 
+    if (gAtmosphere)
+    {
+        // bind precomputed textures necessary for calculating sun and sky luminance
+        channel = shader.enableTexture(LLShaderMgr::TRANSMITTANCE_TEX, LLTexUnit::TT_TEXTURE);
+	    if (channel > -1)
+        {
+            shader.bindTexture(LLShaderMgr::TRANSMITTANCE_TEX, gAtmosphere->getTransmittance());
+        }
+
+        channel = shader.enableTexture(LLShaderMgr::SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D);
+	    if (channel > -1)
+        {
+            shader.bindTexture(LLShaderMgr::SCATTER_TEX, gAtmosphere->getScattering());
+        }
+
+        channel = shader.enableTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D);
+	    if (channel > -1)
+        {
+            shader.bindTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, gAtmosphere->getMieScattering());
+        }
+
+        channel = shader.enableTexture(LLShaderMgr::ILLUMINANCE_TEX, LLTexUnit::TT_TEXTURE);
+	    if (channel > -1)
+        {
+            shader.bindTexture(LLShaderMgr::ILLUMINANCE_TEX, gAtmosphere->getIlluminance());
+        }
+    }
+
 	shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV);
 	shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash);
 	shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise);
@@ -8667,6 +8757,27 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget* screen_target)
 				LLGLDepthTest depth(GL_FALSE);
 				LLGLDisable blend(GL_BLEND);
 				LLGLDisable test(GL_ALPHA_TEST);
+                
+                S32 l1r_channel = soften_shader.enableTexture(LLShaderMgr::SH_INPUT_L1R, mSkySH.getUsage());
+	            if (l1r_channel > -1)
+	            {
+		            mSkySH.bindTexture(0,l1r_channel);
+		            gGL.getTexUnit(l1r_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	            }
+		
+                S32 l1b_channel = soften_shader.enableTexture(LLShaderMgr::SH_INPUT_L1G, mSkySH.getUsage());
+	            if (l1b_channel > -1)
+	            {
+		            mSkySH.bindTexture(1,l1b_channel);
+		            gGL.getTexUnit(l1b_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	            }
+
+                S32 l1g_channel = soften_shader.enableTexture(LLShaderMgr::SH_INPUT_L1B, mSkySH.getUsage());
+	            if (l1g_channel > -1)
+	            {
+		            mSkySH.bindTexture(2,l1g_channel);
+		            gGL.getTexUnit(l1g_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	            }
 
 				//full screen blit
 				gGL.pushMatrix();
@@ -9753,8 +9864,15 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 		}
 
 		gGL.diffuseColor4f(1,1,1,1);
-		gGL.setColorMask(false, false);
-	
+
+        S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
+
+        // if not using VSM, disable color writes
+        if (shadow_detail <= 2)
+        {
+		    gGL.setColorMask(false, false);
+	    }
+
 		LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE);
 		
 		gGL.getTexUnit(0)->disable();
@@ -10090,6 +10208,183 @@ LLRenderTarget* LLPipeline::getShadowTarget(U32 i)
     return &mShadow[i];
 }
 
+static LLTrace::BlockTimerStatHandle FTM_GEN_SKY_INDIRECT("Gen Sky Indirect");
+
+void LLPipeline::generateSkyIndirect()
+{
+	if (!sRenderDeferred || !gSavedSettings.getBOOL("RenderUseAdvancedAtmospherics"))
+	{
+		return;
+	}
+
+	LL_RECORD_BLOCK_TIME(FTM_GEN_SKY_INDIRECT);
+
+	gGL.setColorMask(true, true);
+
+	LLVertexBuffer::unbind();
+
+	gGL.pushMatrix();
+	gGL.loadIdentity();
+	gGL.matrixMode(LLRender::MM_PROJECTION);
+	gGL.pushMatrix();
+	gGL.loadIdentity();
+
+    mSkySH.bindTarget();
+
+	bindDeferredShader(gDeferredGenSkyShProgram, &mSkySH);
+
+	gDeferredGenSkyShProgram.bind();
+
+    llassert(gAtmosphere);
+
+    int channel = -1;
+
+    if (gAtmosphere)
+    {
+        // bind precomputed textures necessary for calculating sun and sky luminance
+        channel = gDeferredGenSkyShProgram.enableTexture(LLShaderMgr::TRANSMITTANCE_TEX, LLTexUnit::TT_TEXTURE);
+	    if (channel > -1)
+        {
+            gDeferredGenSkyShProgram.bindTexture(LLShaderMgr::TRANSMITTANCE_TEX, gAtmosphere->getTransmittance());
+        }
+
+        channel = gDeferredGenSkyShProgram.enableTexture(LLShaderMgr::SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D);
+	    if (channel > -1)
+        {
+            gDeferredGenSkyShProgram.bindTexture(LLShaderMgr::SCATTER_TEX, gAtmosphere->getScattering());
+        }
+
+        channel = gDeferredGenSkyShProgram.enableTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, LLTexUnit::TT_TEXTURE_3D);
+	    if (channel > -1)
+        {
+            gDeferredGenSkyShProgram.bindTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX, gAtmosphere->getMieScattering());
+        }
+
+        channel = gDeferredGenSkyShProgram.enableTexture(LLShaderMgr::ILLUMINANCE_TEX, LLTexUnit::TT_TEXTURE);
+	    if (channel > -1)
+        {
+            gDeferredGenSkyShProgram.bindTexture(LLShaderMgr::ILLUMINANCE_TEX, gAtmosphere->getIlluminance());
+        }
+    }
+
+	gDeferredGenSkyShProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mSkySH.getWidth(), mSkySH.getHeight());
+
+    LLStrider<LLVector3>	vertices;
+	LLStrider<LLVector2>	texCoords;
+	LLStrider<U16>			indices;
+
+    if (!mDeferredVB->allocateBuffer(4, 6, TRUE))
+	{
+		LL_WARNS() << "Failed to allocate Vertex Buffer on full screen sky update" << LL_ENDL;
+	}
+
+	BOOL success = mDeferredVB->getVertexStrider(vertices)
+			    && mDeferredVB->getTexCoord0Strider(texCoords)
+			    && mDeferredVB->getIndexStrider(indices);
+
+	if(!success) 
+	{
+		LL_ERRS() << "Failed updating WindLight fullscreen sky geometry." << LL_ENDL;
+	}
+
+    *vertices++ = LLVector3(-1.0f, -1.0f, 0.0f);
+    *vertices++ = LLVector3( 1.0f, -1.0f, 0.0f);
+    *vertices++ = LLVector3(-1.0f,  1.0f, 0.0f);
+    *vertices++ = LLVector3( 1.0f,  1.0f, 0.0f);
+
+	*texCoords++ = LLVector2(0.0f, 0.0f);
+    *texCoords++ = LLVector2(1.0f, 0.0f);
+    *texCoords++ = LLVector2(0.0f, 1.0f);
+    *texCoords++ = LLVector2(1.0f, 1.0f);
+
+	*indices++ = 0;
+	*indices++ = 1;
+	*indices++ = 2;
+    *indices++ = 1;
+	*indices++ = 3;
+	*indices++ = 2;
+
+    mDeferredVB->flush();
+
+	glClearColor(0,0,0,0);
+	mSkySH.clear(GL_COLOR_BUFFER_BIT);
+
+    LLGLDisable blend(GL_BLEND);
+    LLGLDepthTest depth(GL_FALSE, GL_FALSE, GL_ALWAYS);
+
+    mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+	mDeferredVB->drawRange(LLRender::TRIANGLES, 0, mDeferredVB->getNumVerts() - 1, mDeferredVB->getNumIndices(), 0);
+	stop_glerror();
+
+	gDeferredGenSkyShProgram.disableTexture(LLShaderMgr::TRANSMITTANCE_TEX);
+	gDeferredGenSkyShProgram.disableTexture(LLShaderMgr::SCATTER_TEX);
+    gDeferredGenSkyShProgram.disableTexture(LLShaderMgr::SINGLE_MIE_SCATTER_TEX);
+    gDeferredGenSkyShProgram.disableTexture(LLShaderMgr::ILLUMINANCE_TEX);
+    gDeferredGenSkyShProgram.uniform3fv(LLShaderMgr::DEFERRED_SUN_DIR, 1, mTransformedSunDir.mV);
+
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	gGL.getTexUnit(0)->activate();
+	gDeferredGenSkyShProgram.unbind();
+
+    mSkySH.flush();
+
+#if GATHER_SKY_SH
+	gDeferredGatherSkyShProgram.bind();
+
+    S32 res = mSkySH[0].getWidth();
+    S32 ping = 0;
+
+    while (res > 1)
+    {
+        S32 pong = 1 - ping;
+	    S32 l1r_channel = gDeferredGatherSkyShProgram.enableTexture(LLShaderMgr::SH_INPUT_L1R, mSkySH[ping].getUsage());
+	    if (l1r_channel > -1)
+	    {
+		    mSkySH[ping].bindTexture(0,l1r_channel);
+		    gGL.getTexUnit(l1r_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	    }
+		
+        S32 l1b_channel = gDeferredGatherSkyShProgram.enableTexture(LLShaderMgr::SH_INPUT_L1G, mSkySH[ping].getUsage());
+	    if (l1b_channel > -1)
+	    {
+		    mSkySH[ping].bindTexture(1,l1b_channel);
+		    gGL.getTexUnit(l1b_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	    }
+
+        S32 l1g_channel = gDeferredGatherSkyShProgram.enableTexture(LLShaderMgr::SH_INPUT_L1B, mSkySH[ping].getUsage());
+	    if (l1g_channel > -1)
+	    {
+		    mSkySH[ping].bindTexture(2,l1g_channel);
+		    gGL.getTexUnit(l1g_channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+	    }
+
+        gDeferredGatherSkyShProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, res >> 1, res >> 1);
+
+        glViewport(0, 0, res >> 1, res >> 1);
+
+        mSkySH[pong].bindTarget();
+
+        mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+        mDeferredVB->drawRange(LLRender::TRIANGLES, 0, mDeferredVB->getNumVerts() - 1, mDeferredVB->getNumIndices(), 0);
+	    stop_glerror();
+		
+        mSkySH[pong].flush();
+
+	    gGL.getTexUnit(l1r_channel)->unbind(mSkySH[ping].getUsage());
+        gGL.getTexUnit(l1b_channel)->unbind(mSkySH[ping].getUsage());
+        gGL.getTexUnit(l1g_channel)->unbind(mSkySH[ping].getUsage());
+
+        ping ^= 1;
+        res >>= 1;
+    }
+#endif
+
+	gGL.matrixMode(LLRender::MM_PROJECTION);
+	gGL.popMatrix();
+	gGL.matrixMode(LLRender::MM_MODELVIEW);
+	gGL.popMatrix();	
+}
+
 static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow");
 
 void LLPipeline::generateSunShadow(LLCamera& camera)
@@ -10159,7 +10454,13 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE,
 					END_RENDER_TYPES);
 
-	gGL.setColorMask(false, false);
+    S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail");
+
+    // if not using VSM, disable color writes
+    if (shadow_detail <= 2)
+    {
+		gGL.setColorMask(false, false);
+	}
 
 	//get sun view matrix
 	
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index b631d5bf6c1..66cae8bf72d 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -286,6 +286,7 @@ class LLPipeline
 	void generateSunShadow(LLCamera& camera);
     LLRenderTarget* getShadowTarget(U32 i);
 
+    void generateSkyIndirect();
 	void generateHighlight(LLCamera& camera);
 	void renderHighlight(const LLViewerObject* obj, F32 fade);
 	void setHighlightObject(LLDrawable* obj) { mHighlightObject = obj; }
@@ -533,7 +534,8 @@ class LLPipeline
 		RENDER_DEBUG_ATTACHMENT_BYTES	=  0x20000000, // not used
 		RENDER_DEBUG_TEXEL_DENSITY		=  0x40000000,
 		RENDER_DEBUG_TRIANGLE_COUNT		=  0x80000000,
-		RENDER_DEBUG_IMPOSTORS			= 0x100000000
+		RENDER_DEBUG_IMPOSTORS			= 0x100000000,
+        RENDER_DEBUG_SH                  = 0x200000000,
 	};
 
 public:
@@ -650,6 +652,9 @@ class LLPipeline
 	//texture for making the glow
 	LLRenderTarget				mGlow[3];
 
+    // texture for SH indirect sky contribution
+	LLRenderTarget				mSkySH;
+
 	//noise map
 	U32					mNoiseMap;
 	U32					mTrueNoiseMap;
-- 
GitLab