diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index 027c6eeadb796c3496ed5030688a71ab411be4ef..393074344b3c65df5b75a6f9c00f37cb9da1da17 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -51,7 +51,6 @@ vec3 linear_to_srgb(vec3 cl)
 	return 1.055 * pow(cl, vec3(0.41666)) - 0.055;
 }
 
-
 #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
 
 #ifdef DEFINE_GL_FRAGCOLOR
@@ -136,6 +135,57 @@ uniform vec3 light_direction[8];
 uniform vec3 light_attenuation[8]; 
 uniform vec3 light_diffuse[8];
 
+#ifdef WATER_FOG
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(getPositionEye());
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(getPositionEye() - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 vec3 calcDirectionalLight(vec3 n, vec3 l)
 {
 	float a = max(dot(n,l),0.0);
@@ -221,10 +271,6 @@ vec4 getPosition_d(vec2 pos_screen, float depth)
 	return pos;
 }
 
-vec3 getPositionEye()
-{
-	return vary_PositionEye;
-}
 vec3 getSunlitColor()
 {
 	return vary_SunlitColor;
@@ -417,6 +463,21 @@ out vec4 frag_data[3];
 #else
 #define frag_data gl_FragData
 #endif
+
+VARYING vec3 vary_position;
+
+#ifdef WATER_FOG
+vec3 vary_PositionEye;
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+void setPositionEye(vec3 e)
+{
+	vary_PositionEye = e;
+}
+#endif
+
 #endif
 
 uniform sampler2D diffuseMap;
@@ -672,7 +733,6 @@ void main()
 	//convert to linear space before adding local lights
 	col = srgb_to_linear(col);
 
-			
 	vec3 npos = normalize(-pos.xyz);
 
  #define LIGHT_LOOP(i) col.rgb = col.rgb + calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, final_specular, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare);
@@ -685,17 +745,19 @@ void main()
 		LIGHT_LOOP(6)
 		LIGHT_LOOP(7)
 
+	glare = min(glare, 1.0);
+	float al = max(diffcol.a,glare)*vertex_color.a;
 
-	//convert to gamma space for display on screen
-	col.rgb = linear_to_srgb(col.rgb);
-
+#ifdef WATER_FOG
+	frag_color = applyWaterFogDeferred(vec4(col.rgb, al));
+#else
 	frag_color.rgb = col.rgb;
-	glare = min(glare, 1.0);
-	frag_color.a = max(diffcol.a,glare)*vertex_color.a;
+	frag_color.a   = al;
+#endif
 
 #else
 	frag_data[0] = final_color;
 	frag_data[1] = final_specular; // XYZ = Specular color. W = Specular exponent.
 	frag_data[2] = final_normal; // XY = Normal.  Z = Env. intensity.
-#endif
+#endif%
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
index b25032866ba5b7d8a63832a18647f1a9502e36cb..154db0958361d97aad95604b52f329a2d3104087 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
@@ -43,10 +43,10 @@ uniform mat4 modelview_projection_matrix;
 uniform mat4 modelview_matrix;
 #endif
 
-VARYING vec3 vary_position;
-
 #endif
 
+VARYING vec3 vary_position;
+
 uniform mat4 texture_matrix0;
 
 ATTRIBUTE vec3 position;
@@ -84,15 +84,14 @@ void main()
 	mat = modelview_matrix * mat;
 
 	vec3 pos = (mat*vec4(position.xyz,1.0)).xyz;
-
-#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
 	vary_position = pos;
-#endif
+
 
 	gl_Position = projection_matrix*vec4(pos,1.0);
 
 #else
 	//transform vertex
+	vary_position = (modelview_projection_matrix * vec4(position.xyz, 1.0)).xyz;
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
 
 #endif
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index dc2519bd0a99d3b6b275e05738004d880f0382f1..1706d41da0c7c53f8017d35b6f0b9255037d5009 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -175,6 +175,53 @@ void setAtmosAttenuation(vec3 v)
 	vary_AtmosAttenuation = v;
 }
 
+
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(getPositionEye());
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(getPositionEye() - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 
 	vec3 P = inPositionEye;
@@ -389,6 +436,12 @@ void main()
 		{
 			col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a);
 			col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
+
+			#ifdef WATER_FOG
+				vec4 fogged = applyWaterFogDeferred(vec4(col, bloom));
+				col = fogged.rgb;
+				bloom = fogged.a;
+			#endif
 		}
 
 		col = srgb_to_linear(col);
@@ -398,6 +451,5 @@ void main()
 	}
 
 	frag_color.rgb = col;
-
 	frag_color.a = bloom;
 }
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 075299386e70a039a0389425130ab93c1e2e79f6..45abb87bad713ea4b3f1109de9b2625b4d911258 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -297,7 +297,14 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
 
 	pass += LLMaterial::SHADER_COUNT;
 
-	sVertexProgram = &gDeferredMaterialProgram[pass];
+	if (LLPipeline::sUnderWaterRender)
+	{
+		sVertexProgram = &(gDeferredMaterialWaterProgram[pass]);
+	}
+	else
+	{
+		sVertexProgram = &(gDeferredMaterialProgram[pass]);
+	}
 
 	gPipeline.bindDeferredShader(*sVertexProgram);
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
@@ -1092,7 +1099,14 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
 	{ //skip alpha passes
 		return;
 	}
-	sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
+	if (LLPipeline::sUnderWaterRender)
+	{
+		sVertexProgram = &gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT];
+	}
+	else
+	{
+		sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
+	}
 	sVertexProgram->bind();
 	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
 	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 08a36bddf181fe7b18666eb18f239218c356fdef..49619e6b1d0ba21c32c6bbc1520e1bd8aea117ee 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -71,7 +71,15 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 		15, //LLRenderPass::PASS_NORMSPEC_GLOW,
 	};
 	
-	mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
+	if (LLPipeline::sUnderWaterRender)
+	{
+		mShader = &(gDeferredMaterialWaterProgram[shader_idx[pass]]);
+	}
+	else
+	{
+		mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
+	}
+	
 	mShader->bind();
 
 	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index 7f7d9f65c60c048a26d02438e278dd21893f190f..d36b9ace94e57b1f4f58eeddc639725563e5f50e 100755
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -77,7 +77,7 @@ void LLDrawPoolSky::render(S32 pass)
 	}
 	
 	// don't render sky under water (background just gets cleared to fog color)
-	if(mVertexShaderLevel > 0 && LLPipeline::sUnderWaterRender)
+	if(mVertexShaderLevel > 0 /*&& !LLPipeline::sRenderDeferred*/ && LLPipeline::sUnderWaterRender)
 	{
 		return;
 	}
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 5ddc15df42769f22b08dcea0ef1b3a735c6c9f7a..5b0b173926b7221dbe816045c35665928cca5287 100755
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -522,13 +522,13 @@ void LLDrawPoolWater::shade()
 
 	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
 	
-	if (deferred_render)
+	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
 	{
-		shader = &gDeferredWaterProgram;
+		shader = &gUnderWaterProgram;
 	}
-	else if (eyedepth < 0.f && LLPipeline::sWaterReflections)
+	else if (deferred_render)
 	{
-		shader = &gUnderWaterProgram;
+		shader = &gDeferredWaterProgram;
 	}
 	else
 	{
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index b5faff7968215f467aabb38a2e2da8a3b674ca6f..56b58aaeb425792f81ee826c53771b489302c1b7 100755
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -99,12 +99,12 @@ LLViewerTexture *LLDrawPoolWLSky::getDebugTexture()
 void LLDrawPoolWLSky::beginRenderPass( S32 pass )
 {
 	sky_shader =
-		LLPipeline::sUnderWaterRender ?
+		(LLPipeline::sUnderWaterRender /*&& !LLPipeline::sRenderDeferred*/) ?
 			&gObjectFullbrightNoColorWaterProgram :
 			&gWLSkyProgram;
 
 	cloud_shader =
-			LLPipeline::sUnderWaterRender ?
+			(LLPipeline::sUnderWaterRender /*&& !LLPipeline::sRenderDeferred*/) ?
 				&gObjectFullbrightNoColorWaterProgram :
 				&gWLCloudProgram;
 }
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index e6718ca618510af0da815ecfdd7e77080afda395..d9fd171b4e53a80d39b5735467aefc138eda62d9 100755
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -893,7 +893,15 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			if (LLPipeline::sRenderDeferred)
 			{
 				gPipeline.mDeferredScreen.bindTarget();
-				glClearColor(1,0,1,1);
+				if (LLPipeline::sUnderWaterRender)
+				{
+					const LLColor4 &col = LLDrawPoolWater::sWaterFogColor;
+					glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
+				}
+				else
+				{
+					glClearColor(1,0,1,1);
+				}				
 				gPipeline.mDeferredScreen.clear();
 			}
 			else
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 6d9a0dd26145f7558c3d81f00171abfb0d0f80de..88593346c0abb80bed84521116e109d144f62bb4 100755
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -168,6 +168,7 @@ LLGLSLShader			gPostNightVisionProgram;
 // Deferred rendering shaders
 LLGLSLShader			gDeferredImpostorProgram;
 LLGLSLShader			gDeferredWaterProgram;
+LLGLSLShader			gDeferredUnderWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
 LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
@@ -189,6 +190,7 @@ LLGLSLShader			gDeferredMultiSpotLightProgram;
 LLGLSLShader			gDeferredSunProgram;
 LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
+LLGLSLShader			gDeferredSoftenWaterProgram;
 LLGLSLShader			gDeferredShadowProgram;
 LLGLSLShader			gDeferredShadowCubeProgram;
 LLGLSLShader			gDeferredShadowAlphaMaskProgram;
@@ -215,6 +217,7 @@ LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
+LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mVertexShaderLevel(SHADER_COUNT, 0),
@@ -280,14 +283,23 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
+	mShaderList.push_back(&gDeferredSoftenWaterProgram);
 	mShaderList.push_back(&gDeferredMaterialProgram[1]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[1]);
 	mShaderList.push_back(&gDeferredMaterialProgram[5]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[5]);
 	mShaderList.push_back(&gDeferredMaterialProgram[9]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[9]);
 	mShaderList.push_back(&gDeferredMaterialProgram[13]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[13]);
 	mShaderList.push_back(&gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT]);	
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredAlphaProgram);
 	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
@@ -1123,6 +1135,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSunProgram.unload();
 		gDeferredBlurLightProgram.unload();
 		gDeferredSoftenProgram.unload();
+		gDeferredSoftenWaterProgram.unload();
 		gDeferredShadowProgram.unload();
 		gDeferredShadowCubeProgram.unload();
 		gDeferredShadowAlphaMaskProgram.unload();
@@ -1141,6 +1154,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredPostGammaCorrectProgram.unload();
 		gFXAAProgram.unload();
 		gDeferredWaterProgram.unload();
+		gDeferredUnderWaterProgram.unload();
 		gDeferredWLSkyProgram.unload();
 		gDeferredWLCloudProgram.unload();
 		gDeferredStarProgram.unload();
@@ -1152,6 +1166,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 		{
 			gDeferredMaterialProgram[i].unload();
+			gDeferredMaterialWaterProgram[i].unload();
 		}
 		return TRUE;
 	}
@@ -1279,6 +1294,15 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 
+	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+
 	for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 	{
 		if (success)
@@ -1305,6 +1329,35 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 			success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
 		}
+
+		if (success)
+		{
+			gDeferredMaterialProgram[i].mName = llformat("Deferred Material Shader %d", i);
+
+			U32 alpha_mode = i & 0x3;
+
+			gDeferredMaterialWaterProgram[i].mShaderFiles.clear();
+			gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredMaterialWaterProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_NORMAL_MAP", i & 0x8? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SPECULAR_MAP", i & 0x4 ? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+			bool has_skin = i & 0x10;
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN",has_skin ? "1" : "0");
+
+			gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1");
+			gDeferredMaterialWaterProgram[i].mFeatures.hasWaterFog = true;
+			gDeferredMaterialWaterProgram[i].mShaderGroup = SHADER_WATER;
+
+			if (has_skin)
+			{
+				gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true;
+			}
+
+			success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);
+		}
 	}
 
 	gDeferredMaterialProgram[1].mFeatures.hasLighting = true;
@@ -1316,7 +1369,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 
-
+	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 	
 	if (success)
 	{
@@ -1582,6 +1642,21 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredWaterProgram.createShader(NULL, &mWaterUniforms);
 	}
 
+	if (success)
+	{
+		// load water shader
+		/*gDeferredUnderWaterProgram.mName = "Deferred Under Water Shader";
+		gDeferredUnderWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredUnderWaterProgram.mFeatures.hasGamma = true;
+		gDeferredUnderWaterProgram.mShaderFiles.clear();
+		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/underWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_WATER];
+		gDeferredUnderWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+
+		success = gDeferredUnderWaterProgram.createShader(NULL, &mWaterUniforms);*/
+	}
+
 	if (success)
 	{
 		gDeferredSoftenProgram.mName = "Deferred Soften Shader";
@@ -1599,6 +1674,26 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredSoftenProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredSoftenWaterProgram.mName = "Deferred Soften Underwater Shader";
+		gDeferredSoftenWaterProgram.mFeatures.hasWaterFog = true;
+		gDeferredSoftenWaterProgram.mShaderFiles.clear();
+		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+		gDeferredSoftenWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredSoftenWaterProgram.addPermutation("WATER_FOG", "1");
+		gDeferredSoftenWaterProgram.mShaderGroup = SHADER_WATER;
+
+		if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+		{ //if using SSAO, take screen space light map into account as if shadows are enabled
+			gDeferredSoftenWaterProgram.mShaderLevel = llmax(gDeferredSoftenWaterProgram.mShaderLevel, 2);
+		}
+
+		success = gDeferredSoftenWaterProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredShadowProgram.mName = "Deferred Shadow Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index f3a419b1f2c610592a4bd05c7dda4a97a9625f1d..34a0f6b89d0e063cbfdc8c850485074afd408294 100755
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -330,6 +330,7 @@ extern LLGLSLShader			gPostNightVisionProgram;
 // Deferred rendering shaders
 extern LLGLSLShader			gDeferredImpostorProgram;
 extern LLGLSLShader			gDeferredWaterProgram;
+extern LLGLSLShader			gDeferredUnderWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
 extern LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
@@ -350,6 +351,7 @@ extern LLGLSLShader			gDeferredSunProgram;
 extern LLGLSLShader			gDeferredBlurLightProgram;
 extern LLGLSLShader			gDeferredAvatarProgram;
 extern LLGLSLShader			gDeferredSoftenProgram;
+extern LLGLSLShader			gDeferredSoftenWaterProgram;
 extern LLGLSLShader			gDeferredShadowProgram;
 extern LLGLSLShader			gDeferredShadowCubeProgram;
 extern LLGLSLShader			gDeferredShadowAlphaMaskProgram;
@@ -377,5 +379,6 @@ extern LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
+extern LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
 #endif
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index aed73be3c19e0f84fef4b55591ef07e4aadcb190..e9fb94239e7ecd7f850f916ec70701fb2a1f53c0 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -8466,7 +8466,7 @@ void LLPipeline::renderDeferredLighting()
 		if (RenderDeferredAtmospheric)
 		{ //apply sunlight contribution 
 			LLFastTimer ftm(FTM_ATMOSPHERICS);
-			bindDeferredShader(gDeferredSoftenProgram);	
+			bindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);	
 			{
 				LLGLDepthTest depth(GL_FALSE);
 				LLGLDisable blend(GL_BLEND);
@@ -8488,7 +8488,7 @@ void LLPipeline::renderDeferredLighting()
 				gGL.popMatrix();
 			}
 
-			unbindDeferredShader(gDeferredSoftenProgram);
+			unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);
 		}
 
 		{ //render non-deferred geometry (fullbright, alpha, etc)
@@ -8725,9 +8725,11 @@ void LLPipeline::renderDeferredLighting()
 						count = 0; 
 						mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 						mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+// seems like this should be done here...
+						//unbindDeferredShader(gDeferredMultiLightProgram[idx]);
 					}
 				}
-				
+
 				unbindDeferredShader(gDeferredMultiLightProgram[0]);
 
 				bindDeferredShader(gDeferredMultiSpotLightProgram);
@@ -8972,7 +8974,7 @@ void LLPipeline::renderDeferredLightingToRenderTarget(LLRenderTarget* render_tar
 		if (RenderDeferredAtmospheric)
 		{ //apply sunlight contribution 
 			LLFastTimer ftm(FTM_ATMOSPHERICS);
-			bindDeferredShader(gDeferredSoftenProgram);	
+			bindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);	
 			{
 				LLGLDepthTest depth(GL_FALSE);
 				LLGLDisable blend(GL_BLEND);
@@ -8994,7 +8996,7 @@ void LLPipeline::renderDeferredLightingToRenderTarget(LLRenderTarget* render_tar
 				gGL.popMatrix();
 			}
 
-			unbindDeferredShader(gDeferredSoftenProgram);
+			unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);
 		}
 
 		{ //render non-deferred geometry (fullbright, alpha, etc)
@@ -9187,7 +9189,7 @@ void LLPipeline::renderDeferredLightingToRenderTarget(LLRenderTarget* render_tar
 			vert[2].set(3,1,0);
 
 			{
-				bindDeferredShader(gDeferredMultiLightProgram);
+				bindDeferredShader(gDeferredMultiLightProgram[0]);
 			
 				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 
@@ -9225,17 +9227,25 @@ void LLPipeline::renderDeferredLightingToRenderTarget(LLRenderTarget* render_tar
 					count++;
 					if (count == max_count || fullscreen_lights.empty())
 					{
-						gDeferredMultiLightProgram.uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
-						gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
-						gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
-						gDeferredMultiLightProgram.uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
+						U32 idx = count-1;
+						bindDeferredShader(gDeferredMultiLightProgram[idx]);
+
+						gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
+						gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
 						far_z = 0.f;
 						count = 0; 
+						mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 						mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+
+						// This "seems necessary"...ask davep if it's automagical
+						//
+						//unbindDeferredShader(gDeferredMultiLightProgram[idx]);
 					}
 				}
-				
-				unbindDeferredShader(gDeferredMultiLightProgram);
+
+				unbindDeferredShader(gDeferredMultiLightProgram[0]);
 
 				bindDeferredShader(gDeferredMultiSpotLightProgram);