diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 30b66ae5428807f62dec7e1e4618f77402413750..3a4139bace90b58fbd600471570d971949b0443f 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1083,12 +1083,17 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
 }
 
 // static
-void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
+void LLImageGL::deleteTextures(S32 numTextures, U32 *textures, bool immediate)
 {
 	for (S32 i = 0; i < numTextures; i++)
 	{
 		sDeadTextureList.push_back(textures[i]);
 	}
+
+	if (immediate)
+	{
+		LLImageGL::deleteDeadTextures();
+	}
 }
 
 // static
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 6c980984c0a5facb3433480f363b3414d10b257f..2cfb15b0d9d4d03c30efa2e8de9f1be2fcafedf4 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -98,7 +98,7 @@ class LLImageGL : public LLRefCount
 	// These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() 
 	// for tracking purposes and will be deprecated in the future
 	static void generateTextures(S32 numTextures, U32 *textures);
-	static void deleteTextures(S32 numTextures, U32 *textures);
+	static void deleteTextures(S32 numTextures, U32 *textures, bool immediate = false);
 	static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
 
 	BOOL createGLTexture() ;
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 64caf77b87027aa8484710eb6960038b3d4b89f2..ddd6072fff3c89b3853bde848df461ea32b3daf0 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -289,7 +289,7 @@ void LLRenderTarget::release()
 		}
 		else
 		{
-			LLImageGL::deleteTextures(1, &mDepth);
+			LLImageGL::deleteTextures(1, &mDepth, true);
 			stop_glerror();
 		}
 		mDepth = 0;
@@ -318,7 +318,7 @@ void LLRenderTarget::release()
 
 	if (mTex.size() > 0)
 	{
-		LLImageGL::deleteTextures(mTex.size(), &mTex[0]);
+		LLImageGL::deleteTextures(mTex.size(), &mTex[0], true);
 		mTex.clear();
 	}
 
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 98a0a93084e1762281ba02da11ec5daff2490b6e..b8f9c60ca90116a2a2ec167e8bd8d52736c7cae0 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -374,6 +374,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 	GLcharARB* text[1024];
 	GLuint count = 0;
 
+	//copy preprocessor definitions into buffer
+	for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter)
+	{
+		std::string define = "#define " + iter->first + " " + iter->second + "\n";
+		text[count++] = (GLcharARB *) strdup(define.c_str());
+	}
 
 	//copy file into memory
 	while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(buff) ) 
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index c54c4608d7f043a9822b35272291d294569ffe15..9ee11b98c8fe20df3e1e1badbb34933412e9a0ff 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -60,6 +60,9 @@ class LLShaderMgr
 
 	std::vector<std::string> mReservedUniforms;
 
+	//preprocessor definitions (name/value)
+	std::map<std::string, std::string> mDefinitions;
+
 protected:
 
 	// our parameter manager singleton instance
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index d9f021b114f4919327c70f62c967750f98887d22..98d034c2b5f0d181a45d6cd54c10a374e808e376 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -26,7 +26,7 @@ uniform vec2 screen_res;
 
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
@@ -39,7 +39,7 @@ vec4 getPosition(vec2 pos_screen)
 
 void main() 
 {
-        vec2 tc = vary_fragcoord.xy;
+    vec2 tc = vary_fragcoord.xy;
 	vec3 norm = texture2DRect(normalMap, tc).xyz;
 	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	vec3 pos = getPosition(tc).xyz;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightMSF.glsl
index 113197c871687f2ede893524ad10d63c45b3e952..4366376d99d31e344570604ca6b1dfd656ab37ea 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightMSF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightMSF.glsl
@@ -28,12 +28,12 @@ uniform vec2 screen_res;
 vec4 texture2DMS(sampler2DMS tex, ivec2 tc)
 {
 	vec4 ret = vec4(0,0,0,0);
-	for (int i = 0; i < 4; i++)
+	for (int i = 0; i < samples; i++)
 	{
 		ret += texelFetch(tex, tc, i);
 	}
 
-	return ret * 0.25;
+	return ret/samples;
 }
 
 vec4 getPosition(ivec2 pos_screen)
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 609fc4f14ffa68aa634e0356d88891d022131ed7..e10fb105e80607f5be58721497bb92c65e83563b 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -36,7 +36,7 @@ uniform mat4 inv_proj;
 
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..16e97109f9225c1dcc2b7bc8de0a506628c4cf4f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightMSF.glsl
@@ -0,0 +1,137 @@
+/** 
+ * @file multiPointLightF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+uniform sampler2DMS depthMap;
+uniform sampler2DMS diffuseRect;
+uniform sampler2DMS specularRect;
+uniform sampler2DMS normalMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+
+
+uniform vec3 env_mat[3];
+uniform float sun_wash;
+
+uniform int light_count;
+
+#define MAX_LIGHT_COUNT		16
+uniform vec4 light[MAX_LIGHT_COUNT];
+uniform vec4 light_col[MAX_LIGHT_COUNT];
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform float far_z;
+
+uniform mat4 inv_proj;
+
+vec4 getPosition(ivec2 pos_screen, int sample)
+{
+	float depth = texelFetch(depthMap, pos_screen, sample).r;
+	vec2 sc = vec2(pos_screen.xy)*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	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;
+}
+
+void main() 
+{
+	vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res;
+	ivec2 itc = ivec2(frag);
+
+	int wght = 0;
+	vec3 fcol = vec3(0,0,0);
+
+	for (int s = 0; s < samples; ++s)
+	{
+		vec3 pos = getPosition(itc, s).xyz;
+		if (pos.z >= far_z)
+		{
+			vec3 norm = texelFetch(normalMap, itc, s).xyz;
+			norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+			norm = normalize(norm);
+			vec4 spec = texelFetch(specularRect, itc, s);
+			vec3 diff = texelFetch(diffuseRect, itc, s).rgb;
+			float noise = texture2D(noiseMap, frag.xy/128.0).b;
+			vec3 out_col = vec3(0,0,0);
+			vec3 npos = normalize(-pos);
+
+			// As of OSX 10.6.7 ATI Apple's crash when using a variable size loop
+			for (int i = 0; i < MAX_LIGHT_COUNT; ++i)
+			{
+				bool light_contrib = (i < light_count);
+		
+				vec3 lv = light[i].xyz-pos;
+				float dist2 = dot(lv,lv);
+				dist2 /= light[i].w;
+				if (dist2 > 1.0)
+				{
+					light_contrib = false;
+				}
+		
+				float da = dot(norm, lv);
+				if (da < 0.0)
+				{
+					light_contrib = false;
+				}
+		
+				if (light_contrib)
+				{
+					lv = normalize(lv);
+					da = dot(norm, lv);
+					
+					float fa = light_col[i].a+1.0;
+					float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+					dist_atten *= noise;
+
+					float lit = da * dist_atten;
+			
+					vec3 col = light_col[i].rgb*lit*diff;
+					//vec3 col = vec3(dist2, light_col[i].a, lit);
+			
+					if (spec.a > 0.0)
+					{
+						//vec3 ref = dot(pos+lv, norm);
+				
+						float sa = dot(normalize(lv+npos),norm);
+				
+						if (sa > 0.0)
+						{
+							sa = texture2D(lightFunc,vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
+							sa *= noise;
+							col += da*sa*light_col[i].rgb*spec.rgb;
+						}
+					}
+			
+					out_col += col;
+				}
+			}
+	
+			fcol += out_col;
+			++wght;
+		}
+	}
+
+	if (wght <= 0)
+	{
+		discard;
+	}
+
+	gl_FragColor.rgb = fcol/wght;
+	gl_FragColor.a = 0.0;
+
+	
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..bdaa8e59c4d170af3cead9646c83e0042e728ddf
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightMSF.glsl
@@ -0,0 +1,233 @@
+/** 
+ * @file multiSpotLightF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+
+#version 120
+
+//class 1 -- no shadows
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+uniform sampler2DMS diffuseRect;
+uniform sampler2DMS specularRect;
+uniform sampler2DMS depthMap;
+uniform sampler2DMS normalMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+uniform int proj_shadow_idx;
+uniform float shadow_fade;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
+vec4 getPosition(ivec2 pos_screen, int sample)
+{
+	float depth = texelFetch(depthMap, pos_screen, sample).r;
+	vec2 sc = vec2(pos_screen.xy)*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	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;
+}
+
+void main() 
+{
+	int wght = 0;
+
+	vec3 fcol = vec3(0,0,0);
+
+	vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res;
+	
+	ivec2 itc = ivec2(frag.xy);
+
+	for (int i = 0; i < samples; ++i)
+	{
+		vec3 pos = getPosition(itc, i).xyz;
+		vec3 lv = vary_light.xyz-pos.xyz;
+		float dist2 = dot(lv,lv);
+		dist2 /= vary_light.w;
+		if (dist2 <= 1.0)
+		{
+			vec3 norm = texelFetch(normalMap, itc, i).xyz*2.0-1.0;
+	
+			norm = normalize(norm);
+			float l_dist = -dot(lv, proj_n);
+	
+			vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+			if (proj_tc.z >= 0.0)
+			{
+				proj_tc.xyz /= proj_tc.w;
+	
+				float fa = gl_Color.a+1.0;
+				float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+				if (dist_atten > 0.0)
+				{
+					lv = proj_origin-pos.xyz;
+					lv = normalize(lv);
+					float da = dot(norm, lv);
+		
+					vec3 col = vec3(0,0,0);
+		
+					vec3 diff_tex = texelFetch(diffuseRect, itc, i).rgb;
+		
+					float noise = texture2D(noiseMap, frag.xy/128.0).b;
+					if (proj_tc.z > 0.0 &&
+						proj_tc.x < 1.0 &&
+						proj_tc.y < 1.0 &&
+						proj_tc.x > 0.0 &&
+						proj_tc.y > 0.0)
+					{
+						float lit = 0.0;
+						float amb_da = proj_ambiance;
+		
+						if (da > 0.0)
+						{
+							float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+							float lod = diff * proj_lod;
+			
+							vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
+		
+							vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+							lit = da * dist_atten * noise;
+			
+							col = lcol*lit*diff_tex;
+							amb_da += (da*0.5)*proj_ambiance;
+						}
+		
+						//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+						vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
+							
+						amb_da += (da*da*0.5+0.5)*proj_ambiance;
+				
+						amb_da *= dist_atten * noise;
+			
+						amb_da = min(amb_da, 1.0-lit);
+			
+						col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+					}
+	
+	
+					vec4 spec = texelFetch(specularRect, itc, i);
+					if (spec.a > 0.0)
+					{
+						vec3 ref = reflect(normalize(pos), norm);
+		
+						//project from point pos in direction ref to plane proj_p, proj_n
+						vec3 pdelta = proj_p-pos;
+						float ds = dot(ref, proj_n);
+		
+						if (ds < 0.0)
+						{
+							vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+							vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+
+							if (stc.z > 0.0)
+							{
+								stc.xy /= stc.w;
+
+								float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+								stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
+								if (stc.x < 1.0 &&
+									stc.y < 1.0 &&
+									stc.x > 0.0 &&
+									stc.y > 0.0)
+								{
+									vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+									col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb;
+								}
+							}
+						}
+					}
+	
+					fcol += col;
+					++wght;
+				}
+			}
+		}
+	}
+
+	if (wght <= 0)
+	{
+		discard;
+	}
+
+	gl_FragColor.rgb = fcol/wght;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index 22ed9dcd40ec25f456f91c5dc0e92333e41dfb27..0d771109fb23a9d0e43c76f290781f31e74a9418 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -30,7 +30,7 @@ uniform vec4 viewport;
 
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = (pos_screen.xy-viewport.xy)*2.0;
 	sc /= viewport.zw;
 	sc -= vec2(1.0,1.0);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightMSF.glsl
index 22ed9dcd40ec25f456f91c5dc0e92333e41dfb27..23b5e7673547e5003114e581cb5cb3703180fa24 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightMSF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightMSF.glsl
@@ -8,14 +8,15 @@
  #version 120
 
 #extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
 
-uniform sampler2DRect diffuseRect;
-uniform sampler2DRect specularRect;
-uniform sampler2DRect normalMap;
-uniform samplerCube environmentMap;
+uniform sampler2DMS depthMap;
+uniform sampler2DMS diffuseRect;
+uniform sampler2DMS specularRect;
+uniform sampler2DMS normalMap;
 uniform sampler2D noiseMap;
 uniform sampler2D lightFunc;
-uniform sampler2DRect depthMap;
+
 
 uniform vec3 env_mat[3];
 uniform float sun_wash;
@@ -28,10 +29,10 @@ uniform vec2 screen_res;
 uniform mat4 inv_proj;
 uniform vec4 viewport;
 
-vec4 getPosition(vec2 pos_screen)
+vec4 getPosition(ivec2 pos_screen, int sample)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
-	vec2 sc = (pos_screen.xy-viewport.xy)*2.0;
+	float depth = texelFetch(depthMap, pos_screen, sample).r;
+	vec2 sc = (vec2(pos_screen.xy)-viewport.xy)*2.0;
 	sc /= viewport.zw;
 	sc -= vec2(1.0,1.0);
 	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
@@ -48,53 +49,60 @@ void main()
 	frag.xyz = frag.xyz*0.5+0.5;
 	frag.xy *= screen_res;
 	
-	vec3 pos = getPosition(frag.xy).xyz;
-	vec3 lv = vary_light.xyz-pos;
-	float dist2 = dot(lv,lv);
-	dist2 /= vary_light.w;
-	if (dist2 > 1.0)
-	{
-		discard;
-	}
-	
-	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
-	float da = dot(norm, lv);
-	if (da < 0.0)
+	ivec2 itc = ivec2(frag.xy);
+
+	int wght = 0;
+	vec3 fcol = vec3(0,0,0);
+
+	for (int s = 0; s < samples; ++s)
 	{
-		discard;
-	}
-	
-	norm = normalize(norm);
-	lv = normalize(lv);
-	da = dot(norm, lv);
+		vec3 pos = getPosition(itc, s).xyz;
+		vec3 lv = vary_light.xyz-pos;
+		float dist2 = dot(lv,lv);
+		dist2 /= vary_light.w;
+		if (dist2 <= 1.0)
+		{
+			vec3 norm = texelFetch(normalMap, itc, s).xyz;
+			norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+			float da = dot(norm, lv);
+			if (da >= 0.0)
+			{
+				norm = normalize(norm);
+				lv = normalize(lv);
+				da = dot(norm, lv);
 	
-	float noise = texture2D(noiseMap, frag.xy/128.0).b;
+				float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	
-	vec3 col = texture2DRect(diffuseRect, frag.xy).rgb;
-	float fa = gl_Color.a+1.0;
-	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
-	float lit = da * dist_atten * noise;
+				vec3 col = texelFetch(diffuseRect, itc, s).rgb;
+				float fa = gl_Color.a+1.0;
+				float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+				float lit = da * dist_atten * noise;
 	
-	col = gl_Color.rgb*lit*col;
+				col = gl_Color.rgb*lit*col;
 
-	vec4 spec = texture2DRect(specularRect, frag.xy);
-	if (spec.a > 0.0)
-	{
-		float sa = dot(normalize(lv-normalize(pos)),norm);
-		if (sa > 0.0)
-		{
-			sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
-			sa *= noise;
-			col += da*sa*gl_Color.rgb*spec.rgb;
+				vec4 spec = texelFetch(specularRect, itc, s);
+				if (spec.a > 0.0)
+				{
+					float sa = dot(normalize(lv-normalize(pos)),norm);
+					if (sa > 0.0)
+					{
+						sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
+						sa *= noise;
+						col += da*sa*gl_Color.rgb*spec.rgb;
+					}
+				}
+
+				fcol += col;
+				++wght;
+			}
 		}
 	}
 	
-	if (dot(col, col) <= 0.0)
+	if (wght <= 0)
 	{
 		discard;
 	}
 		
-	gl_FragColor.rgb = col;	
+	gl_FragColor.rgb = fcol/wght;	
 	gl_FragColor.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
index 8e74feb61565cac9f6d4736bc04c72909a293867..2377947e7f224014dfb0d171409f3ef16c79809c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
@@ -10,14 +10,9 @@
 varying vec4 vary_light;
 varying vec4 vary_fragcoord;
 
-uniform vec2 screen_res;
-uniform float near_clip;
-
 void main()
 {
 	//transform vertex
-	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
-
 	vec4 pos = gl_ModelViewProjectionMatrix * gl_Vertex;
 	vary_fragcoord = pos;
 		
@@ -25,6 +20,8 @@ void main()
 	tex.w = 1.0;
 	
 	vary_light = gl_MultiTexCoord0;
+	
+	gl_Position = pos;
 		
 	gl_FrontColor = gl_Color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
index 77f1b2224c20f04f66b79b948fc5be3a3844f6ea..d389add03bc81921d90464bf75c99a0a6b49e492 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredF.glsl
@@ -29,7 +29,7 @@ varying vec2 vary_fragcoord;
 
 float getDepth(vec2 pos_screen)
 {
-	float z = texture2DRect(depthMap, pos_screen.xy).a;
+	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;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredMSF.glsl
index a34f882c39f85a83b8c8313ffd69b63bc27a8fe0..711c6dc96dfc091a6698f3cb61a0602b04499b0d 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredMSF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredMSF.glsl
@@ -31,12 +31,12 @@ varying vec2 vary_fragcoord;
 vec4 texture2DMS(sampler2DMS tex, ivec2 tc)
 {
 	vec4 ret = vec4(0,0,0,0);
-	for (int i = 0; i < 4; ++i)
+	for (int i = 0; i < samples; ++i)
 	{
 		ret += texelFetch(tex, tc, i);
 	}
 
-	return ret * 0.25;
+	return ret/samples;
 }
 
 float getDepth(ivec2 pos_screen)
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFMSF.glsl
index 7b14974f8b1a60d80010a294269f9be4b635d9e7..359b26b7d46f17aa551fc4627ae6c2d9a9b4be38 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFMSF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredNoDoFMSF.glsl
@@ -18,13 +18,14 @@ varying vec2 vary_fragcoord;
 
 vec4 texture2DMS(sampler2DMS tex, ivec2 tc)
 {
-	vec4 ret = texelFetch(tex,tc,0);
-	ret += texelFetch(tex,tc,1);
-	ret += texelFetch(tex,tc,2);
-	ret += texelFetch(tex,tc,3);
-	ret *= 0.25;
+	vec4 ret = vec4(0,0,0,0);
 
-	return ret;
+	for (int i = 0; i < samples; ++i)
+	{
+		 ret += texelFetch(tex,tc,i);
+	}
+
+	return ret/samples;
 }
 
 void main() 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 29340c7e9f01bc8d44ad910fe56c4d0e243a6a4d..c1147feff66107224f9982040a5e1d4a12df4bf4 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -259,7 +259,7 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	float depth = texture2DRect(depthMap, tc.xy).a;
+	float depth = texture2DRect(depthMap, tc.xy).r;
 	vec3 pos = getPosition_d(tc, depth).xyz;
 	vec3 norm = texture2DRect(normalMap, tc).xyz;
 	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl
index 4c38d91499f3ba35958788290e443305c0c2b388..fcba4f57e6f855993e14459bd60022775cd4d3d6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightMSF.glsl
@@ -251,18 +251,18 @@ vec3 scaleSoftClip(vec3 light)
 
 vec4 texture2DMS(sampler2DMS tex, ivec2 tc)
 {
-	vec4 ret = texelFetch(tex,tc,0);
-	ret += texelFetch(tex,tc,1);
-	ret += texelFetch(tex,tc,2);
-	ret += texelFetch(tex,tc,3);
-	ret *= 0.25;
+	vec4 ret = vec4(0,0,0,0);
 
-	return ret;
+	for (int i = 0; i < samples; ++i)
+	{
+		 ret += texelFetch(tex,tc,i);
+	}
+
+	return ret/samples;
 }
 
 void main() 
 {
-	int samples = 4;
 	vec2 tc = vary_fragcoord.xy;
 	ivec2 itc = ivec2(tc);
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..3a9d9266bb7f92985681b0a62dcf1f477c04378c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightMSF.glsl
@@ -0,0 +1,234 @@
+/** 
+ * @file multiSpotLightF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+
+#version 120
+
+//class 1 -- no shadows
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+uniform sampler2DMS diffuseRect;
+uniform sampler2DMS specularRect;
+uniform sampler2DMS depthMap;
+uniform sampler2DMS normalMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+uniform int proj_shadow_idx;
+uniform float shadow_fade;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
+vec4 getPosition(ivec2 pos_screen, int sample)
+{
+	float depth = texelFetch(depthMap, pos_screen, sample).r;
+	vec2 sc = vec2(pos_screen.xy)*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	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;
+}
+
+void main() 
+{
+	vec4 frag = vary_fragcoord;
+	frag.xyz /= frag.w;
+	frag.xyz = frag.xyz*0.5+0.5;
+	frag.xy *= screen_res;
+	ivec2 itc = ivec2(frag.xy);
+
+	vec3 fcol = vec3(0,0,0);
+	int wght = 0;
+	
+	for (int i = 0; i < samples; ++i)
+	{
+		vec3 pos = getPosition(itc, i).xyz;
+		vec3 lv = vary_light.xyz-pos.xyz;
+		float dist2 = dot(lv,lv);
+		dist2 /= vary_light.w;
+		if (dist2 <= 1.0)
+		{
+			vec3 norm = texelFetch(normalMap, itc, i).xyz*2.0-1.0;
+	
+			norm = normalize(norm);
+			float l_dist = -dot(lv, proj_n);
+	
+			vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+			if (proj_tc.z >= 0.0)
+			{
+				proj_tc.xyz /= proj_tc.w;
+	
+				float fa = gl_Color.a+1.0;
+				float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+				if (dist_atten > 0.0)
+				{
+					lv = proj_origin-pos.xyz;
+					lv = normalize(lv);
+					float da = dot(norm, lv);
+		
+					vec3 col = vec3(0,0,0);
+		
+					vec3 diff_tex = texelFetch(diffuseRect, itc, i).rgb;
+		
+					float noise = texture2D(noiseMap, frag.xy/128.0).b;
+					if (proj_tc.z > 0.0 &&
+						proj_tc.x < 1.0 &&
+						proj_tc.y < 1.0 &&
+						proj_tc.x > 0.0 &&
+						proj_tc.y > 0.0)
+					{
+						float lit = 0.0;
+						float amb_da = proj_ambiance;
+		
+						if (da > 0.0)
+						{
+							float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+							float lod = diff * proj_lod;
+			
+							vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
+		
+							vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+							lit = da * dist_atten * noise;
+			
+							col = lcol*lit*diff_tex;
+							amb_da += (da*0.5)*proj_ambiance;
+						}
+		
+						//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+						vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
+							
+						amb_da += (da*da*0.5+0.5)*proj_ambiance;
+				
+						amb_da *= dist_atten * noise;
+			
+						amb_da = min(amb_da, 1.0-lit);
+			
+						col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+					}
+	
+	
+					vec4 spec = texelFetch(specularRect, itc, i);
+					if (spec.a > 0.0)
+					{
+						vec3 ref = reflect(normalize(pos), norm);
+		
+						//project from point pos in direction ref to plane proj_p, proj_n
+						vec3 pdelta = proj_p-pos;
+						float ds = dot(ref, proj_n);
+		
+						if (ds < 0.0)
+						{
+							vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+							vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+
+							if (stc.z > 0.0)
+							{
+								stc.xy /= stc.w;
+
+								float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+								stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
+								if (stc.x < 1.0 &&
+									stc.y < 1.0 &&
+									stc.x > 0.0 &&
+									stc.y > 0.0)
+								{
+									vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+									col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb;
+								}
+							}
+						}
+					}
+	
+					fcol += col;
+					++wght;
+				}
+			}
+		}
+	}
+
+	if (wght <= 0)
+	{
+		discard;
+	}
+
+	gl_FragColor.rgb = fcol/wght;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..b1c25b7fd340475b7e5ca58ea77235b1ba4a862b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/starsF.glsl
@@ -0,0 +1,19 @@
+/** 
+ * @file starsF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+uniform sampler2D diffuseMap;
+
+void main() 
+{
+	vec4 col = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].xy);
+	
+	gl_FragData[0] = col;
+	gl_FragData[1] = vec4(0,0,0,0);
+	gl_FragData[2] = vec4(0,0,1,0);	
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/starsV.glsl b/indra/newview/app_settings/shaders/class1/deferred/starsV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..1f0376ce6b5bea38e253e0b26e59384ec5835637
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/starsV.glsl
@@ -0,0 +1,17 @@
+/** 
+ * @file starsV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+
+void main()
+{
+	//transform vertex
+	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
+	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	gl_FrontColor = gl_Color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
index cd91351ad411e91b425f478e65f6123f583ea01b..d1e83597429533bc6f9f96a493e9478c54b64c18 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
@@ -35,7 +35,7 @@ uniform float shadow_offset;
 
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOMSF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOMSF.glsl
index 49b45dedd64bf0175b1444ecd7fedaf3e9126f61..ce0ebc54f8b84a35ca53f6b243c7fcbea36b3fc0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOMSF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOMSF.glsl
@@ -101,8 +101,6 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm, int sample)
 
 void main() 
 {
-	int samples = 4;
-
 	vec2 pos_screen = vary_fragcoord.xy;
 	ivec2 itc = ivec2(pos_screen);
 		
diff --git a/indra/newview/app_settings/shaders/class1/effects/glowExtractMSF.glsl b/indra/newview/app_settings/shaders/class1/effects/glowExtractMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..c03a0c61bdc5b0507065c276c36ae897cbe98f6a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/effects/glowExtractMSF.glsl
@@ -0,0 +1,38 @@
+/** 
+ * @file glowExtractF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+uniform sampler2DMS diffuseMap;
+uniform float minLuminance;
+uniform float maxExtractAlpha;
+uniform vec3 lumWeights;
+uniform vec3 warmthWeights;
+uniform float warmthAmount;
+
+void main()
+{
+	ivec2 itc = ivec2(gl_TexCoord[0].xy);
+	vec4 fcol = vec4(0,0,0,0);
+
+	for (int i = 0; i < samples; i++)
+	{
+		vec4 col = texelFetch(diffuseMap, itc, i);	
+
+		/// CALCULATING LUMINANCE (Using NTSC lum weights)
+		/// http://en.wikipedia.org/wiki/Luma_%28video%29
+		float lum = smoothstep(minLuminance, minLuminance+1.0, dot(col.rgb, lumWeights ) );
+		float warmth = smoothstep(minLuminance, minLuminance+1.0, max(col.r * warmthWeights.r, max(col.g * warmthWeights.g, col.b * warmthWeights.b)) ); 
+	
+		fcol += vec4(col.rgb, max(col.a, mix(lum, warmth, warmthAmount) * maxExtractAlpha));
+	}
+
+	gl_FragColor = fcol/samples;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
index 3155f3f9295a3602e8eaa1915910fd58226a48d8..30e1702e9fe12496ec1335148d0ce9efef6f46b9 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
@@ -22,7 +22,7 @@ uniform vec2 screen_res;
 
 float getDepth(vec2 pos_screen)
 {
-	float z = texture2DRect(depthMap, pos_screen.xy).a;
+	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;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeMSF.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeMSF.glsl
index a47ee678f6a4cc8d467bddc30deecd66cec4ae02..38100d15235d48a33fcb26677807f03043fdea99 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/edgeMSF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/edgeMSF.glsl
@@ -21,8 +21,9 @@ uniform float norm_cutoff;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
-float getDepth(float z)
+float getDepth(ivec2 pos_screen, int sample)
 {
+	float z = texelFetch(depthMap, pos_screen, sample).r;
 	z = z*2.0-1.0;
 	vec4 ndc = vec4(0.0, 0.0, z, 1.0);
 	vec4 p = inv_proj*ndc;
@@ -31,7 +32,6 @@ float getDepth(float z)
 
 void main() 
 {
-
 	float e = 0;
 	
 	ivec2 itc = ivec2(vary_fragcoord.xy);
@@ -40,24 +40,24 @@ void main()
 	{	
 		vec3 norm = texelFetch(normalMap, itc, i).xyz;
 		norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
-		float depth = getDepth(texelFetch(depthMap, itc, i).r);
+		float depth = getDepth(itc, i);
 	
 		vec2 tc = vary_fragcoord.xy;
 	
-		float sc = 0.75;
+		int sc = 1;
 	
 		vec2 de;
-		de.x = (depth-getDepth(tc+vec2(sc, sc))) + (depth-getDepth(tc+vec2(-sc, -sc)));
-		de.y = (depth-getDepth(tc+vec2(-sc, sc))) + (depth-getDepth(tc+vec2(sc, -sc)));
+		de.x = (depth-getDepth(itc+ivec2(sc, sc),i)) + (depth-getDepth(itc+ivec2(-sc, -sc), i));
+		de.y = (depth-getDepth(itc+ivec2(-sc, sc),i)) + (depth-getDepth(itc+ivec2(sc, -sc), i));
 		de /= depth;
 		de *= de;
 		de = step(depth_cutoff, de);
 	
 		vec2 ne;
-		vec3 nexnorm = texture2DRect(normalMap, tc+vec2(-sc,-sc)).rgb;
+		vec3 nexnorm = texelFetch(normalMap, itc+ivec2(-sc,-sc), i).rgb;
 		nexnorm = vec3((nexnorm.xy-0.5)*2.0,nexnorm.z); // unpack norm
 		ne.x = dot(nexnorm, norm);
-		vec3 neynorm = texture2DRect(normalMap, tc+vec2(sc,sc)).rgb;
+		vec3 neynorm = texelFetch(normalMap, itc+ivec2(sc,sc), i).rgb;
 		neynorm = vec3((neynorm.xy-0.5)*2.0,neynorm.z); // unpack norm
 		ne.y = dot(neynorm, norm);
 	
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
index d6cd984ebe1bfa037c4a20740c21a4087fc87cf9..de987b1233802a3760ae88c016fc1c2b38a8733d 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -91,7 +91,7 @@ vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
 
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightMSF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..c6f0ea2a5d8318a68437b4bcb0130f6888cbeef4
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightMSF.glsl
@@ -0,0 +1,244 @@
+/** 
+ * @file multiSpotLightF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+uniform sampler2DMS diffuseRect;
+uniform sampler2DMS specularRect;
+uniform sampler2DMS depthMap;
+uniform sampler2DMS normalMap;
+uniform sampler2DMS lightMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+uniform int proj_shadow_idx;
+uniform float shadow_fade;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
+vec4 getPosition(ivec2 pos_screen, int sample)
+{
+	float depth = texelFetch(depthMap, pos_screen, sample).r;
+	vec2 sc = vec2(pos_screen.xy)*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	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;
+}
+
+void main() 
+{
+	int wght = 0;
+
+	vec3 fcol = vec3(0,0,0);
+
+	vec2 frag = (vary_fragcoord.xy*0.5+0.5)*screen_res;
+	
+	ivec2 itc = ivec2(frag.xy);
+
+	for (int i = 0; i < samples; i++)
+	{
+		vec3 pos = getPosition(itc, i).xyz;
+		vec3 lv = vary_light.xyz-pos.xyz;
+		float dist2 = dot(lv,lv);
+		dist2 /= vary_light.w;
+		if (dist2 <= 1.0)
+		{
+			float shadow = 1.0;
+	
+			if (proj_shadow_idx >= 0)
+			{
+				vec4 shd = texelFetch(lightMap, itc, i);
+				float sh[2];
+				sh[0] = shd.b;
+				sh[1] = shd.a;
+				shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0);
+			}
+	
+			vec3 norm = texelFetch(normalMap, itc, i).xyz;
+			norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+	
+			norm = normalize(norm);
+			float l_dist = -dot(lv, proj_n);
+	
+			vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+			if (proj_tc.z >= 0.0)
+			{
+				proj_tc.xyz /= proj_tc.w;
+	
+				float fa = gl_Color.a+1.0;
+				float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+				if (dist_atten > 0.0)
+				{
+					lv = proj_origin-pos.xyz;
+					lv = normalize(lv);
+					float da = dot(norm, lv);
+		
+					vec3 col = vec3(0,0,0);
+		
+					vec3 diff_tex = texelFetch(diffuseRect, itc, i).rgb;
+		
+					float noise = texture2D(noiseMap, frag.xy/128.0).b;
+					if (proj_tc.z > 0.0 &&
+						proj_tc.x < 1.0 &&
+						proj_tc.y < 1.0 &&
+						proj_tc.x > 0.0 &&
+						proj_tc.y > 0.0)
+					{
+						float lit = 0.0;
+						float amb_da = proj_ambiance;
+		
+						if (da > 0.0)
+						{
+							float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+							float lod = diff * proj_lod;
+			
+							vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
+		
+							vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+							lit = da * dist_atten * noise;
+			
+							col = lcol*lit*diff_tex*shadow;
+							amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
+						}
+		
+						//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+						vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
+							
+						amb_da += (da*da*0.5+0.5)*proj_ambiance;
+				
+						amb_da *= dist_atten * noise;
+			
+						amb_da = min(amb_da, 1.0-lit);
+			
+						col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+					}
+	
+	
+					vec4 spec = texelFetch(specularRect, itc, i);
+					if (spec.a > 0.0)
+					{
+						vec3 ref = reflect(normalize(pos), norm);
+		
+						//project from point pos in direction ref to plane proj_p, proj_n
+						vec3 pdelta = proj_p-pos;
+						float ds = dot(ref, proj_n);
+		
+						if (ds < 0.0)
+						{
+							vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+							vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+
+							if (stc.z > 0.0)
+							{
+								stc.xy /= stc.w;
+
+								float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+								stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
+								if (stc.x < 1.0 &&
+									stc.y < 1.0 &&
+									stc.x > 0.0 &&
+									stc.y > 0.0)
+								{
+									vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+									col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb*shadow;
+								}
+							}
+						}
+					}
+
+					fcol += col;
+					wght++;
+				}
+			}
+		}
+	}
+	
+	if (wght <= 0)
+	{
+		discard;
+	}
+
+	gl_FragColor.rgb = fcol/wght;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 0160e84278fc665f06adde57cda481a1b9d39f52..dfa196414264fef96cea42c99b58325aeb47663a 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -71,7 +71,7 @@ vec4 getPosition_d(vec2 pos_screen, float depth)
 
 vec4 getPosition(vec2 pos_screen)
 { //get position in screen space (world units) given window coordinate and depth map
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	return getPosition_d(pos_screen, depth);
 }
 
@@ -258,7 +258,7 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	float depth = texture2DRect(depthMap, tc.xy).a;
+	float depth = texture2DRect(depthMap, tc.xy).r;
 	vec3 pos = getPosition_d(tc, depth).xyz;
 	vec3 norm = texture2DRect(normalMap, tc).xyz;
 	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
@@ -288,54 +288,8 @@ void main()
 		float sa = dot(refnormpersp, vary_light.xyz);
 		vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
 
-		/*
-		// screen-space cheap fakey reflection map
-		//
-		vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz));
-		depth -= 0.5; // unbias depth
-		// first figure out where we'll make our 2D guess from
-		vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth;
-		// Offset the guess source a little according to a trivial
-		// checkerboard dither function and spec.a.
-		// This is meant to be similar to sampling a blurred version
-		// of the diffuse map.  LOD would be better in that regard.
-		// The goal of the blur is to soften reflections in surfaces
-		// with low shinyness, and also to disguise our lameness.
-		float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0
-		float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5);
-		ref2d += vec2(checkoffset, checkoffset);
-		ref2d += tc.xy; // use as offset from destination
-		// Get attributes from the 2D guess point.
-		// We average two samples of diffuse (not of anything else) per
-		// pixel to try to reduce aliasing some more.
-		vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb +
-				     texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb);
-		float refdepth = texture2DRect(depthMap, ref2d).a;
-		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
-		float refshad = texture2DRect(lightMap, ref2d).r;
-		vec3 refn = texture2DRect(normalMap, ref2d).rgb;
-		refn = vec3((refn.xy-0.5)*2.0,refn.z); // unpack norm
-		refn = normalize(refn);
-		// figure out how appropriate our guess actually was
-		float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos)));
-		// darken reflections from points which face away from the reflected ray - our guess was a back-face
-		//refapprop *= step(dot(refnorm, refn), 0.0);
-		refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant
-		// get appropriate light strength for guess-point
-		// reflect light direction to increase the illusion that
-		// these are reflections.
-		vec3 reflight = reflect(lightnorm.xyz, norm.xyz);
-		float reflit = min(max(dot(refn, reflight.xyz), 0.0), refshad);
-		// apply sun color to guess-point, dampen according to inappropriateness of guess
-		float refmod = min(refapprop, reflit);
-		vec3 refprod = vary_SunlitColor * refcol.rgb * refmod;
-		vec3 ssshiny = (refprod * spec.a);
-		ssshiny *= 0.3; // dampen it even more
-		*/
-		vec3 ssshiny = vec3(0,0,0);
-
 		// add the two types of shiny together
-		col += (ssshiny + dumbshiny) * spec.rgb;
+		col += dumbshiny * spec.rgb;
 	}
 	
 	col = atmosLighting(col);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl
index 7d4548d6d90c463c9e51e06a1a5bccdf004f2f48..71482d0c7bd9d60a951cde4107fb26afa26dd28f 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightMSF.glsl
@@ -252,7 +252,6 @@ vec3 scaleSoftClip(vec3 light)
 
 void main() 
 {
-	int samples = 4;
 	vec2 tc = vary_fragcoord.xy;
 	ivec2 itc = ivec2(tc);
 
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightMSF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..099a45718a1043cb6995ae261971039d1e538737
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightMSF.glsl
@@ -0,0 +1,245 @@
+/** 
+ * @file multiSpotLightF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+uniform sampler2DMS diffuseRect;
+uniform sampler2DMS specularRect;
+uniform sampler2DMS depthMap;
+uniform sampler2DMS normalMap;
+uniform sampler2DMS lightMap;
+uniform sampler2D noiseMap;
+uniform sampler2D lightFunc;
+uniform sampler2D projectionMap;
+
+uniform mat4 proj_mat; //screen space to light space
+uniform float proj_near; //near clip for projection
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform vec3 proj_n;
+uniform float proj_focus; //distance from plane to begin blurring
+uniform float proj_lod;  //(number of mips in proj map)
+uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
+uniform float proj_ambiance;
+uniform float near_clip;
+uniform float far_clip;
+
+uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
+uniform float sun_wash;
+uniform int proj_shadow_idx;
+uniform float shadow_fade;
+
+varying vec4 vary_light;
+
+varying vec4 vary_fragcoord;
+uniform vec2 screen_res;
+
+uniform mat4 inv_proj;
+
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
+vec4 getPosition(ivec2 pos_screen, int sample)
+{
+	float depth = texelFetch(depthMap, pos_screen, sample).r;
+	vec2 sc = vec2(pos_screen.xy)*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	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;
+}
+
+void main() 
+{
+	vec4 frag = vary_fragcoord;
+	frag.xyz /= frag.w;
+	frag.xyz = frag.xyz*0.5+0.5;
+	frag.xy *= screen_res;
+	ivec2 itc = ivec2(frag.xy);
+	
+	vec3 fcol = vec3(0,0,0);
+	int wght = 0;
+
+	for (int i = 0; i < samples; i++)
+	{
+		vec3 pos = getPosition(itc, i).xyz;
+		vec3 lv = vary_light.xyz-pos.xyz;
+		float dist2 = dot(lv,lv);
+		dist2 /= vary_light.w;
+		if (dist2 <= 1.0)
+		{
+			float shadow = 1.0;
+	
+			if (proj_shadow_idx >= 0)
+			{
+				vec4 shd = texelFetch(lightMap, itc, i);
+				float sh[2];
+				sh[0] = shd.b;
+				sh[1] = shd.a;
+				shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0);
+			}
+	
+			vec3 norm = texelFetch(normalMap, itc, i).xyz;
+			norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+	
+			norm = normalize(norm);
+			float l_dist = -dot(lv, proj_n);
+	
+			vec4 proj_tc = (proj_mat * vec4(pos.xyz, 1.0));
+			if (proj_tc.z >= 0.0)
+			{
+				proj_tc.xyz /= proj_tc.w;
+	
+				float fa = gl_Color.a+1.0;
+				float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+				if (dist_atten > 0.0)
+				{
+					lv = proj_origin-pos.xyz;
+					lv = normalize(lv);
+					float da = dot(norm, lv);
+		
+					vec3 col = vec3(0,0,0);
+		
+					vec3 diff_tex = texelFetch(diffuseRect, itc, i).rgb;
+		
+					float noise = texture2D(noiseMap, frag.xy/128.0).b;
+					if (proj_tc.z > 0.0 &&
+						proj_tc.x < 1.0 &&
+						proj_tc.y < 1.0 &&
+						proj_tc.x > 0.0 &&
+						proj_tc.y > 0.0)
+					{
+						float lit = 0.0;
+						float amb_da = proj_ambiance;
+		
+						if (da > 0.0)
+						{
+							float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
+							float lod = diff * proj_lod;
+			
+							vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
+		
+							vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
+			
+							lit = da * dist_atten * noise;
+			
+							col = lcol*lit*diff_tex*shadow;
+							amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
+						}
+		
+						//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+						vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
+							
+						amb_da += (da*da*0.5+0.5)*proj_ambiance;
+				
+						amb_da *= dist_atten * noise;
+			
+						amb_da = min(amb_da, 1.0-lit);
+			
+						col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+					}
+	
+	
+					vec4 spec = texelFetch(specularRect, itc, i);
+					if (spec.a > 0.0)
+					{
+						vec3 ref = reflect(normalize(pos), norm);
+		
+						//project from point pos in direction ref to plane proj_p, proj_n
+						vec3 pdelta = proj_p-pos;
+						float ds = dot(ref, proj_n);
+		
+						if (ds < 0.0)
+						{
+							vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+			
+							vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+
+							if (stc.z > 0.0)
+							{
+								stc.xy /= stc.w;
+
+								float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+								stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
+								if (stc.x < 1.0 &&
+									stc.y < 1.0 &&
+									stc.x > 0.0 &&
+									stc.y > 0.0)
+								{
+									vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+									col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb*shadow;
+								}
+							}
+						}
+					}
+
+					fcol += col;
+					wght++;
+				}
+			}
+		}
+	}
+	
+	if (wght <= 0)
+	{
+		discard;
+	}
+
+	gl_FragColor.rgb = fcol/wght;	
+	gl_FragColor.a = 0.0;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index 4369b3b34ff8da6af4aabcf4b57e58b02024dd2b..b724c134b9e5928f8eee8d8fb5d7d750ed2612d4 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -45,7 +45,7 @@ uniform float spot_shadow_offset;
 
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightMSF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..dd6fa958c994725ae96b69099f7cfa09f58d2e12
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightMSF.glsl
@@ -0,0 +1,202 @@
+/** 
+ * @file sunLightMSF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * $/LicenseInfo$
+ */
+ 
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+//class 2, shadows, no SSAO
+
+uniform sampler2DMS depthMap;
+uniform sampler2DMS normalMap;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
+uniform sampler2DShadow shadowMap4;
+uniform sampler2DShadow shadowMap5;
+
+
+// Inputs
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform float ssao_radius;
+uniform float ssao_max_radius;
+uniform float ssao_factor;
+uniform float ssao_factor_inv;
+
+varying vec2 vary_fragcoord;
+varying vec4 vary_light;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+uniform vec2 shadow_res;
+uniform vec2 proj_shadow_res;
+
+uniform float shadow_bias;
+uniform float shadow_offset;
+
+uniform float spot_shadow_bias;
+uniform float spot_shadow_offset;
+
+vec4 getPosition(ivec2 pos_screen, int sample)
+{
+	float depth = texelFetch(depthMap, pos_screen.xy, sample).r;
+	vec2 sc = vec2(pos_screen.xy)*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	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;
+}
+
+float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias*scl;
+	
+	float cs = shadow2DRect(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs);
+			
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += spot_shadow_bias*scl;
+	
+	float cs = shadow2D(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	vec2 off = 1.5/proj_shadow_res;
+	
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs);
+				
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	ivec2 itc = ivec2(pos_screen);
+
+	//try doing an unproject here
+	
+	vec4 fcol = vec4(0,0,0,0);
+
+	for (int i = 0; i < samples; i++)
+	{
+		vec4 pos = getPosition(itc, i);
+	
+		vec4 nmap4 = texelFetch(normalMap, itc, i);
+		nmap4 = vec4((nmap4.xy-0.5)*2.0,nmap4.z,nmap4.w); // unpack norm
+		float displace = nmap4.w;
+		vec3 norm = nmap4.xyz;
+	
+		/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
+		{
+			gl_FragColor = vec4(0.0); // doesn't matter
+			return;
+		}*/
+	
+		float shadow = 1.0;
+		float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
+
+		vec3 shadow_pos = pos.xyz + displace*norm;
+		vec3 offset = vary_light.xyz * (1.0-dp_directional_light);
+	
+		vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0);
+	
+		if (spos.z > -shadow_clip.w)
+		{	
+			if (dp_directional_light == 0.0)
+			{
+				// if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup
+				shadow = 0.0;
+			}
+			else
+			{
+				vec4 lpos;
+			
+				if (spos.z < -shadow_clip.z)
+				{
+					lpos = shadow_matrix[3]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap3, lpos, 0.25);
+					shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+				}
+				else if (spos.z < -shadow_clip.y)
+				{
+					lpos = shadow_matrix[2]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap2, lpos, 0.5);
+				}
+				else if (spos.z < -shadow_clip.x)
+				{
+					lpos = shadow_matrix[1]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap1, lpos, 0.75);
+				}
+				else
+				{
+					lpos = shadow_matrix[0]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap0, lpos, 1.0);
+				}
+		
+				// take the most-shadowed value out of these two:
+				//  * the blurred sun shadow in the light (shadow) map
+				//  * an unblurred dot product between the sun and this norm
+				// the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting
+				shadow = min(shadow, dp_directional_light);
+			
+				//lpos.xy /= lpos.w*32.0;
+				//if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1)
+				//{
+				//	shadow = 0.0;
+				//}
+			
+			}
+		}
+		else
+		{
+			// more distant than the shadow map covers
+			shadow = 1.0;
+		}
+	
+		fcol[0] += shadow;
+		fcol[1] += 1.0;
+
+		spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0);
+	
+		//spotlight shadow 1
+		vec4 lpos = shadow_matrix[4]*spos;
+		fcol[2] += pcfShadow(shadowMap4, lpos, 0.8); 
+	
+		//spotlight shadow 2
+		lpos = shadow_matrix[5]*spos;
+		fcol[3] += pcfShadow(shadowMap5, lpos, 0.8); 
+	}
+
+	gl_FragColor = fcol/samples;
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
index 847b36b1ace5722cf0a4cdec723bc75b2549c177..68e18162f678c612740d9e1f1ed045892a447272 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
@@ -45,7 +45,7 @@ uniform float spot_shadow_offset;
 
 vec4 getPosition(vec2 pos_screen)
 {
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	float depth = texture2DRect(depthMap, pos_screen.xy).r;
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOMSF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOMSF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..d28741f945f86797108b9144627839d53de07014
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOMSF.glsl
@@ -0,0 +1,241 @@
+/** 
+ * @file sunLightSSAOF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+ 
+#version 120
+
+#extension GL_ARB_texture_rectangle : enable
+#extension GL_ARB_texture_multisample : enable
+
+//class 2 -- shadows and SSAO
+
+uniform sampler2DMS depthMap;
+uniform sampler2DMS normalMap;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
+uniform sampler2DShadow shadowMap4;
+uniform sampler2DShadow shadowMap5;
+uniform sampler2D noiseMap;
+
+// Inputs
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform float ssao_radius;
+uniform float ssao_max_radius;
+uniform float ssao_factor;
+uniform float ssao_factor_inv;
+
+varying vec2 vary_fragcoord;
+varying vec4 vary_light;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+uniform vec2 shadow_res;
+uniform vec2 proj_shadow_res;
+
+uniform float shadow_bias;
+uniform float shadow_offset;
+
+uniform float spot_shadow_bias;
+uniform float spot_shadow_offset;
+
+vec4 getPosition(ivec2 pos_screen, int sample)
+{
+	float depth = texelFetch(depthMap, pos_screen, sample).r;
+	vec2 sc = vec2(pos_screen.xy)*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	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;
+}
+
+//calculate decreases in ambient lighting when crowded out (SSAO)
+float calcAmbientOcclusion(vec4 pos, vec3 norm, int sample)
+{
+	float ret = 1.0;
+
+	vec2 kern[8];
+	// exponentially (^2) distant occlusion samples spread around origin
+	kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+	kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+	kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+	kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+	kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+	kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+	kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+	kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+
+	vec2 pos_screen = vary_fragcoord.xy;
+	vec3 pos_world = pos.xyz;
+	vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
+		
+	float angle_hidden = 0.0;
+	int points = 0;
+		
+	float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+		
+	// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+	for (int i = 0; i < 8; i++)
+	{
+		ivec2 samppos_screen = ivec2(pos_screen + scale * reflect(kern[i], noise_reflect));
+		vec3 samppos_world = getPosition(samppos_screen, sample).xyz; 
+			
+		vec3 diff = pos_world - samppos_world;
+		float dist2 = dot(diff, diff);
+			
+		// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+		// --> solid angle shrinking by the square of distance
+		//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+		//(k should vary inversely with # of samples, but this is taken care of later)
+			
+		angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
+			
+		// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
+		points = points + int(diff.z > -1.0);
+	}
+		
+	angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
+		
+	ret = (1.0 - (float(points != 0) * angle_hidden));
+	
+	return min(ret, 1.0);
+}
+
+float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias*scl;
+	
+	float cs = shadow2DRect(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs);
+			
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += spot_shadow_bias*scl;
+	
+	float cs = shadow2D(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	vec2 off = 1.5/proj_shadow_res;
+	
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs);
+	
+			
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	ivec2 itc = ivec2(pos_screen);
+	vec4 fcol = vec4(0,0,0,0);
+
+	for (int i = 0; i < samples; i++)
+	{
+		vec4 pos = getPosition(itc, i);
+	
+		vec4 nmap4 = texelFetch(normalMap, itc, i);
+		nmap4 = vec4((nmap4.xy-0.5)*2.0,nmap4.z,nmap4.w); // unpack norm
+		float displace = nmap4.w;
+		vec3 norm = nmap4.xyz;
+	
+		float shadow = 1.0;
+		float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
+
+		vec3 shadow_pos = pos.xyz + displace*norm;
+		vec3 offset = vary_light.xyz * (1.0-dp_directional_light);
+	
+		vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0);
+	
+		if (spos.z > -shadow_clip.w)
+		{	
+			if (dp_directional_light == 0.0)
+			{
+				// if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup
+				shadow = 0.0;
+			}
+			else
+			{
+				vec4 lpos;
+			
+				if (spos.z < -shadow_clip.z)
+				{
+					lpos = shadow_matrix[3]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap3, lpos, 0.25);
+					shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+				}
+				else if (spos.z < -shadow_clip.y)
+				{
+					lpos = shadow_matrix[2]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap2, lpos, 0.5);
+				}
+				else if (spos.z < -shadow_clip.x)
+				{
+					lpos = shadow_matrix[1]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap1, lpos, 0.75);
+				}
+				else
+				{
+					lpos = shadow_matrix[0]*spos;
+					lpos.xy *= shadow_res;
+					shadow = pcfShadow(shadowMap0, lpos, 1.0);
+				}
+		
+				// take the most-shadowed value out of these two:
+				//  * the blurred sun shadow in the light (shadow) map
+				//  * an unblurred dot product between the sun and this norm
+				// the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting
+				shadow = min(shadow, dp_directional_light);
+			
+			}
+		}
+		else
+		{
+			// more distant than the shadow map covers
+			shadow = 1.0;
+		}
+	
+		
+		fcol[0] += shadow;
+		fcol[1] += calcAmbientOcclusion(pos, norm, i);
+
+		spos.xyz = shadow_pos+offset*spot_shadow_offset;
+	
+		//spotlight shadow 1
+		vec4 lpos = shadow_matrix[4]*spos;
+		fcol[2] += pcfShadow(shadowMap4, lpos, 0.8); 
+	
+		//spotlight shadow 2
+		lpos = shadow_matrix[5]*spos;
+		fcol[3] += pcfShadow(shadowMap5, lpos, 0.8); 
+	}
+		
+	gl_FragColor = fcol / samples;
+}
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index 66b834ab116a0772075dfb0aea924b9e1268b2d7..409b18d5229cb6c2c0cccd8620ce9dad9873f938 100644
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -278,11 +278,13 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass)
 
 	renderSkyHaze(camHeightLocal);
 
-	/*LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
+	LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin();
 	glPushMatrix();
 
+		
 		glTranslatef(origin.mV[0], origin.mV[1], origin.mV[2]);
 
+		gDeferredStarProgram.bind();
 		// *NOTE: have to bind a texture here since register combiners blending in
 		// renderStars() requires something to be bound and we might as well only
 		// bind the moon's texture once.		
@@ -292,8 +294,9 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass)
 
 		renderStars();
 		
+		gDeferredStarProgram.unbind();
 
-	glPopMatrix();*/
+	glPopMatrix();
 
 	renderSkyClouds(camHeightLocal);
 
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 379bbe614d62161a5d83a0cabd4cca2830c4db84..00a0b87d933eaa22528dd0e9e65f6c6d272df3b8 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -183,6 +183,21 @@ static bool handleReleaseGLBufferChanged(const LLSD& newvalue)
 	return true;
 }
 
+static bool handleFSAASamplesChanged(const LLSD& newvalue)
+{
+	if (gPipeline.isInit())
+	{
+		gPipeline.releaseGLBuffers();
+		gPipeline.createGLBuffers();
+
+		if (LLPipeline::sRenderDeferred)
+		{
+			LLViewerShaderMgr::instance()->setShaders();
+		}
+	}
+	return true;
+}
+
 static bool handleAnisotropicChanged(const LLSD& newvalue)
 {
 	LLImageGL::sGlobalUseAnisotropic = newvalue.asBoolean();
@@ -568,7 +583,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderSpecularExponent")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
-	gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleFSAASamplesChanged, _2));
 	gSavedSettings.getControl("RenderAnisotropic")->getSignal()->connect(boost::bind(&handleAnisotropicChanged, _2));
 	gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 84fb1eb5d00f549f08ec02192daaedaf239f944e..911a8bb65ffcea6d0e3ea997fd98aa6ab11e53e1 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -140,6 +140,7 @@ LLGLSLShader			gDeferredPostProgram;
 LLGLSLShader			gDeferredPostNoDoFProgram;
 LLGLSLShader			gDeferredWLSkyProgram;
 LLGLSLShader			gDeferredWLCloudProgram;
+LLGLSLShader			gDeferredStarProgram;
 LLGLSLShader			gLuminanceGatherProgram;
 
 
@@ -193,6 +194,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredAvatarAlphaProgram);
 	mShaderList.push_back(&gDeferredWLSkyProgram);
 	mShaderList.push_back(&gDeferredWLCloudProgram);
+	mShaderList.push_back(&gDeferredStarProgram);
 }
 
 LLViewerShaderMgr::~LLViewerShaderMgr()
@@ -350,6 +352,9 @@ void LLViewerShaderMgr::setShaders()
 		return;
 	}
 
+	//setup preprocessor definitions
+	LLShaderMgr::instance()->mDefinitions["samples"] = llformat("%d", gSavedSettings.getU32("RenderFSAASamples"));
+
 	reentrance = true;
 
 	// Make sure the compiled shader map is cleared before we recompile shaders.
@@ -836,6 +841,8 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 {
 	BOOL success = TRUE;
 
+	bool multisample = gSavedSettings.getU32("RenderFSAASamples") > 0 && gGLManager.mHasTextureMultisample;
+
 	if (mVertexShaderLevel[SHADER_EFFECT] == 0)
 	{
 		gGlowProgram.unload();
@@ -861,10 +868,21 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
 	
 	if (success)
 	{
+		std::string fragment;
+
+		if (gSavedSettings.getU32("RenderFSAASamples") > 0 && LLRenderTarget::sUseFBO && gGLManager.mHasTextureMultisample)
+		{
+			fragment = "effects/glowExtractMSF.glsl";
+		}
+		else
+		{
+			fragment = "effects/glowExtractF.glsl";
+		}
+
 		gGlowExtractProgram.mName = "Glow Extract Shader (Post)";
 		gGlowExtractProgram.mShaderFiles.clear();
 		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractV.glsl", GL_VERTEX_SHADER_ARB));
-		gGlowExtractProgram.mShaderFiles.push_back(make_pair("effects/glowExtractF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gGlowExtractProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB));
 		gGlowExtractProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
 		success = gGlowExtractProgram.createShader(NULL, &mGlowExtractUniforms);
 		if (!success)
@@ -957,6 +975,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredWaterProgram.unload();
 		gDeferredWLSkyProgram.unload();
 		gDeferredWLCloudProgram.unload();
+		gDeferredStarProgram.unload();
 		return TRUE;
 	}
 
@@ -1046,40 +1065,83 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 	if (success)
 	{
+		std::string fragment;
+
+		if (multisample)
+		{
+			fragment = "deferred/pointLightMSF.glsl";
+		}
+		else
+		{
+			fragment = "deferred/pointLightF.glsl";
+		}
+
 		gDeferredLightProgram.mName = "Deferred Light Shader";
 		gDeferredLightProgram.mShaderFiles.clear();
 		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredLightProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB));
 		gDeferredLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredLightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
 	{
+		std::string fragment;
+		if (multisample)
+		{
+			fragment = "deferred/multiPointLightMSF.glsl";
+		}
+		else
+		{
+			fragment = "deferred/multiPointLightF.glsl";
+		}
+
 		gDeferredMultiLightProgram.mName = "Deferred MultiLight Shader";
 		gDeferredMultiLightProgram.mShaderFiles.clear();
 		gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB));
 		gDeferredMultiLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredMultiLightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
 	{
+		std::string fragment;
+
+		if (multisample)
+		{
+			fragment = "deferred/spotLightMSF.glsl";
+		}
+		else
+		{
+			fragment = "deferred/multiSpotLightF.glsl";
+		}
+
 		gDeferredSpotLightProgram.mName = "Deferred SpotLight Shader";
 		gDeferredSpotLightProgram.mShaderFiles.clear();
 		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB));
 		gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredSpotLightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
 	{
+		std::string fragment;
+
+		if (multisample)
+		{
+			fragment = "deferred/multiSpotLightMSF.glsl";
+		}
+		else
+		{
+			fragment = "deferred/multiSpotLightF.glsl";
+		}
+
 		gDeferredMultiSpotLightProgram.mName = "Deferred MultiSpotLight Shader";
 		gDeferredMultiSpotLightProgram.mShaderFiles.clear();
 		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB));
 		gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL);
 	}
@@ -1343,6 +1405,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredWLCloudProgram.createShader(NULL, &mWLUniforms);
 	}
 
+	if (success)
+	{
+		gDeferredStarProgram.mName = "Deferred Star Program";
+		gDeferredStarProgram.mShaderFiles.clear();
+		gDeferredStarProgram.mShaderFiles.push_back(make_pair("deferred/starsV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredStarProgram.mShaderFiles.push_back(make_pair("deferred/starsF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredStarProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredStarProgram.mShaderGroup = LLGLSLShader::SG_SKY;
+		success = gDeferredStarProgram.createShader(NULL, &mWLUniforms);
+	}
+
 	if (mVertexShaderLevel[SHADER_DEFERRED] > 1)
 	{
 		if (success)
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index b13775742b1ed09870d80ac965aedf1ffa74d16f..f5371f06190d651efd4357d7ae57f3683e96f98a 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -376,7 +376,7 @@ extern LLGLSLShader			gDeferredFullbrightProgram;
 extern LLGLSLShader			gDeferredAvatarAlphaProgram;
 extern LLGLSLShader			gDeferredWLSkyProgram;
 extern LLGLSLShader			gDeferredWLCloudProgram;
-
+extern LLGLSLShader			gDeferredStarProgram;
 extern LLGLSLShader			gLuminanceGatherProgram;
 
 //current avatar shader parameter pointer
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index ef3cbe52783361ce68b6bec6c3649aff70184551..ffe3b4b1a4e55224c7bcca719e7c8e5f767d9fa1 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -589,8 +589,8 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
 	mScreenWidth = resX;
 	mScreenHeight = resY;
 	
-	//never use more than 4 samples for render targets
-	U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 4);
+	U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 16);
+
 	if (gGLManager.mIsATI)
 	{ //disable multisampling of render targets where ATI is involved
 		samples = 0;
@@ -6170,11 +6170,8 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 		gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
 		
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);		
-		gGL.getTexUnit(0)->disable();
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
-		gGL.getTexUnit(0)->bind(&mScreen);
-
+		mScreen.bindTexture(0, 0);
+		
 		gGL.color4f(1,1,1,1);
 		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
 		gGL.begin(LLRender::TRIANGLE_STRIP);
@@ -6189,7 +6186,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 		
 		gGL.end();
 		
-		gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+		gGL.getTexUnit(0)->unbind(mScreen.getUsage());
 
 		mGlow[2].flush();
 	}
@@ -6217,7 +6214,6 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 
 	for (S32 i = 0; i < kernel; i++)
 	{
-		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		{
 			LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
 			mGlow[i%2].bindTarget();