diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl
index 025bcdaf3e18bf4940d2fdb09568f23fc004b1b4..13619a82d30bcdff504e9f7aba30e7e707f9096a 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl
@@ -35,10 +35,26 @@ float getDepth(vec2 pos_screen);
 
 vec4 getWaterFogView(vec3 pos);
 
+uniform int above_water;
+
 void main()
 {
     vec2  tc           = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5;
     float depth        = getDepth(tc.xy);
+
+    if (above_water > 0)
+    { 
+        // we want to depth test when the camera is above water, but some GPUs have a hard time
+        // with depth testing against render targets that are bound for sampling in the same shader
+        // so we do it manually here
+
+        float cur_depth = vary_fragcoord.z/vary_fragcoord.w*0.5+0.5;
+        if (cur_depth > depth)
+        {
+            discard;
+        }
+    }
+
     vec4  pos          = getPositionWithDepth(tc, depth);
     vec4  norm         = texture(normalMap, tc);
 
diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl
index ddb1b7968111df9fcd38ba274fda220363d981ad..223e55eb69487d45edac47d99e7a27cfe92bed01 100644
--- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl
@@ -30,7 +30,6 @@ uniform sampler2D bumpMap;
 
 #ifdef TRANSPARENT_WATER
 uniform sampler2D screenTex;
-uniform sampler2D screenDepth;
 #endif
 
 uniform vec4 fogCol;
diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
index b7292832f6fafcca3afbf8d2e2cf55e7c82c19a4..34281281536018c6c15371fded9a5d75bdb2a17d 100644
--- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
@@ -76,7 +76,7 @@ uniform sampler2D bumpMap2;
 uniform float     blend_factor;
 #ifdef TRANSPARENT_WATER
 uniform sampler2D screenTex;
-uniform sampler2D screenDepth;
+uniform sampler2D depthMap;
 #endif
 
 uniform sampler2D refTex;
@@ -210,7 +210,7 @@ void main()
 
 #ifdef TRANSPARENT_WATER
     vec4 fb = texture(screenTex, distort2);
-    float depth = texture(screenDepth, distort2).r;
+    float depth = texture(depthMap, distort2).r;
     vec3 refPos = getPositionWithNDC(vec3(distort2*2.0-vec2(1.0), depth*2.0-1.0));
 
     if (refPos.z > pos.z-0.05)
@@ -218,7 +218,7 @@ void main()
         //we sampled an above water sample, don't distort
         distort2 = distort;
         fb = texture(screenTex, distort2);
-        depth = texture(screenDepth, distort2).r;
+        depth = texture(depthMap, distort2).r;
         refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0));
     }
 
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 14f3142e1b55c3c942b02bf3996d12d862488e90..ca93815de7cf4dc983a4341cbefd22ab3f4ee022 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -206,7 +206,7 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
             }
         }
 
-        gPipeline.bindDeferredShader(*shader);
+        gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis);
 
         //bind normal map
         S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP);
@@ -238,7 +238,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
 
         // bind reflection texture from RenderTarget
         S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
-        S32 screenDepth = shader->enableTexture(LLShaderMgr::WATER_SCREENDEPTH);
 
         F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] };
 
@@ -255,11 +254,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
             gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
         }
 
-        if (screenDepth > -1)
-        {
-            gGL.getTexUnit(screenDepth)->bind(&gPipeline.mWaterDis, true);
-        }
-
         if (mShaderLevel == 1)
         {
             fog_color.mV[VW] = log(fog_density) / log(2);
@@ -342,7 +336,6 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
         shader->disableTexture(LLShaderMgr::BUMP_MAP);
         shader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
         shader->disableTexture(LLShaderMgr::WATER_REFTEX);
-        shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH);
 
         // clean up
         gPipeline.unbindDeferredShader(*shader);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index f80a053e162042eba16864a38450270ebc918f8b..318fcb721577e15748ded2d054545e048ddd73af 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -875,10 +875,9 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 
     mRT->deferredScreen.shareDepthBuffer(mRT->screen);
 
-	if (!is_aux_alloc && LLPipeline::sRenderTransparentWater)
-	{ //water reflection texture
-		if (!mWaterDis.allocate(resX, resY, screenFormat, true)) return false;
-	}
+    //water reflection texture (always needed as scratch space whether or not transparent water is enabled)
+    mWaterDis.allocate(resX, resY, GL_RGBA16F, true);
+
 
 	//if (shadow_detail > 0 || ssao || gSavedSettings.getU32("RenderSharpenMethod") != ALRenderUtil::SHARPEN_NONE)
 	{ //only need mRT->deferredLight for shadows OR ssao OR sharpening
@@ -7610,7 +7609,7 @@ void LLPipeline::bindDeferredShaderFast(LLGLSLShader& shader)
     }
 }
 
-void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target)
+void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target, LLRenderTarget* depth_target)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
     LLRenderTarget* deferred_target       = &mRT->deferredScreen;
@@ -7649,7 +7648,14 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
     channel = shader.enableTexture(LLShaderMgr::DEFERRED_DEPTH, deferred_target->getUsage());
     if (channel > -1)
     {
-        gGL.getTexUnit(channel)->bind(deferred_target, TRUE);
+        if (depth_target)
+        {
+            gGL.getTexUnit(channel)->bind(depth_target, TRUE);
+        }
+        else
+        {
+            gGL.getTexUnit(channel)->bind(deferred_target, TRUE);
+        }
         stop_glerror();
     }
 
@@ -8310,16 +8316,41 @@ void LLPipeline::doAtmospherics()
 
     if (RenderDeferredAtmospheric)
     {
+        {
+            // copy depth buffer for use in haze shader (use water displacement map as temp storage)
+            LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+
+            LLRenderTarget& src = gPipeline.mRT->screen;
+            LLRenderTarget& depth_src = gPipeline.mRT->deferredScreen;
+            LLRenderTarget& dst = gPipeline.mWaterDis;
+
+            mRT->screen.flush();
+            dst.bindTarget();
+            gCopyDepthProgram.bind();
+
+            S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP);
+            S32 depth_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DEFERRED_DEPTH);
+
+            gGL.getTexUnit(diff_map)->bind(&src);
+            gGL.getTexUnit(depth_map)->bind(&depth_src, true);
+
+            gGL.setColorMask(false, false);
+            gPipeline.mScreenTriangleVB->setBuffer();
+            gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+
+            dst.flush();
+            mRT->screen.bindTarget();
+        }
+
         LLGLEnable blend(GL_BLEND);
         gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA);
-
         gGL.setColorMask(true, true);
 
         // apply haze
         LLGLSLShader& haze_shader = gHazeProgram;
 
         LL_PROFILE_GPU_ZONE("haze");
-        bindDeferredShader(haze_shader);
+        bindDeferredShader(haze_shader, nullptr, &mWaterDis);
 
         LLEnvironment& environment = LLEnvironment::instance();
         haze_shader.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0);
@@ -8345,6 +8376,32 @@ void LLPipeline::doWaterHaze()
 
     if (RenderDeferredAtmospheric)
     {
+        // copy depth buffer for use in haze shader (use water displacement map as temp storage)
+        {
+            LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+
+            LLRenderTarget& src = gPipeline.mRT->screen;
+            LLRenderTarget& depth_src = gPipeline.mRT->deferredScreen;
+            LLRenderTarget& dst = gPipeline.mWaterDis;
+
+            mRT->screen.flush();
+            dst.bindTarget();
+            gCopyDepthProgram.bind();
+
+            S32 diff_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DIFFUSE_MAP);
+            S32 depth_map = gCopyDepthProgram.getTextureChannel(LLShaderMgr::DEFERRED_DEPTH);
+
+            gGL.getTexUnit(diff_map)->bind(&src);
+            gGL.getTexUnit(depth_map)->bind(&depth_src, true);
+
+            gGL.setColorMask(false, false);
+            gPipeline.mScreenTriangleVB->setBuffer();
+            gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+
+            dst.flush();
+            mRT->screen.bindTarget();
+        }
+
         LLGLEnable blend(GL_BLEND);
         gGL.blendFunc(LLRender::BF_ONE, LLRender::BF_SOURCE_ALPHA, LLRender::BF_ZERO, LLRender::BF_SOURCE_ALPHA);
 
@@ -8354,7 +8411,7 @@ void LLPipeline::doWaterHaze()
         LLGLSLShader& haze_shader = gHazeWaterProgram;
 
         LL_PROFILE_GPU_ZONE("haze");
-        bindDeferredShader(haze_shader);
+        bindDeferredShader(haze_shader, nullptr, &mWaterDis);
 
         haze_shader.uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
 
@@ -8372,7 +8429,7 @@ void LLPipeline::doWaterHaze()
         else
         {
             //render water patches like LLDrawPoolWater does
-            LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_LEQUAL);
+            LLGLDepthTest depth(GL_FALSE);
             LLGLDisable   cull(GL_CULL_FACE);
 
             gGLLastMatrix = NULL;
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index d20a833dea08387a77ef6e2c99b6e5fcc6b285d2..8507e5d5e6595626cc46ee252f7b8045a301f47a 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -285,7 +285,7 @@ class LLPipeline
     // if setup is true, wil lset texture compare mode function and filtering options
     void bindShadowMaps(LLGLSLShader& shader);
     void bindDeferredShaderFast(LLGLSLShader& shader);
-	void bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target = nullptr);
+	void bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target = nullptr, LLRenderTarget* depth_target = nullptr);
 	void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep);
 
 	void unbindDeferredShader(LLGLSLShader& shader);