diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
index 2ec859fdae2b05726c4655a735dd44fb1f461ec9..9405a125fd81c647f7c3650eb556ca56bc43d293 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
@@ -505,3 +505,28 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
 
     return color;
 }
+
+uniform vec4 waterPlane;
+uniform float waterSign;
+
+// discard if given position in eye space is on the wrong side of the waterPlane according to waterSign
+void waterClip(vec3 pos)
+{
+    // TODO: make this less branchy
+    if (waterSign > 0)
+    {
+        if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) < -0.1)
+        {
+            discard;
+        }
+    }
+    else
+    {
+        if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) > -0.1)
+        {
+            discard;
+        }
+    }
+
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index b4406aabc08a89058399c736dd59975f9802f03a..b3f15f81f18ba8e31009510f208918d47ee92c7e 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -69,6 +69,8 @@ uniform vec3 light_direction[8];
 uniform vec4 light_attenuation[8]; 
 uniform vec3 light_diffuse[8];
 
+void waterClip(vec3 pos);
+
 #ifdef WATER_FOG
 vec4 applyWaterFogView(vec3 pos, vec4 color);
 #endif
@@ -181,6 +183,7 @@ void main()
     frag *= screen_res;
     
     vec4 pos = vec4(vary_position, 1.0);
+    waterClip(pos.xyz);
     vec3 norm = vary_norm;
 
     float shadow = 1.0f;
@@ -295,6 +298,7 @@ void main()
 
 #endif // #else // FOR_IMPOSTOR
 
+    //color.rgb = waterPlane.xyz * 0.5 + 0.5;
     frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
index 9bbc4f87bf23b7abf4fb9248f0b5c2c1379d8210..922da0c4410065eb0f4da51bf8061e6468fbc6f3 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/pbralphaF.glsl
@@ -84,6 +84,8 @@ float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
 void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, 
         vec3 pos, vec3 norm, float glossiness);
 
+void waterClip(vec3 pos);
+
 // PBR interface
 vec3 pbrIbl(vec3 diffuseColor,
             vec3 specularColor,
@@ -139,6 +141,7 @@ void main()
     vec3  light_dir   = (sun_up_factor == 1) ? sun_dir : moon_dir;
     vec3  pos         = vary_position;
 
+    waterClip(pos);
 
 // IF .mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
 //    vec3 col = vertex_color.rgb * diffuseLookup(vary_texcoord0.xy).rgb;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
index 1150d400073257e661b3f6e7c6064fddbdc12631..8016022d78c0b7bf0c8e52c69ec2e044c6dcaa96 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
@@ -90,6 +90,7 @@ uniform vec4 light_attenuation[8];
 uniform vec3 light_diffuse[8];
 
 float getAmbientClamp();
+void waterClip(vec3 pos);
 
 vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance)
 {
@@ -219,6 +220,10 @@ vec2 encode_normal(vec3 n);
 
 void main()
 {
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
+    waterClip(vary_position.xyz);
+#endif
+
     vec2 pos_screen = vary_texcoord0.xy;
 
     vec4 diffcol = texture2D(diffuseMap, vary_texcoord0.xy);
@@ -277,7 +282,6 @@ void main()
 #endif
 
 #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
-
     //forward rendering, output lit linear color
     diffcol.rgb = srgb_to_linear(diffcol.rgb);
     final_specular.rgb = srgb_to_linear(final_specular.rgb);
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 70bc603a428ce8f9bf3b671ee56009949ffd63f3..74625423fe6eb5127e54d2aea5aaf45b82a6a612 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -882,7 +882,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 				{
 					LLFace* facep = getFace(i);
 					if (facep && 
-						(force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA))
+						(force_update || facep->isInAlphaPool()))
 					{
 						LLVector4a box;
 						box.setSub(facep->mExtents[1], facep->mExtents[0]);
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 015e5201795dd1091774ef953e45ab72157d792b..7305177e4a859f94072960f052b023a86c469e9e 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -86,9 +86,12 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
 	case POOL_GLOW:
 		poolp = new LLDrawPoolGlow();
 		break;
-	case POOL_ALPHA:
-		poolp = new LLDrawPoolAlpha();
+	case POOL_ALPHA_PRE_WATER:
+		poolp = new LLDrawPoolAlpha(LLDrawPool::POOL_ALPHA_PRE_WATER);
 		break;
+    case POOL_ALPHA_POST_WATER:
+        poolp = new LLDrawPoolAlpha(LLDrawPool::POOL_ALPHA_POST_WATER);
+        break;
 	case POOL_AVATAR:
 	case POOL_CONTROL_AV:
 		poolp = new LLDrawPoolAvatar(type);
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 2b7ace7ae546e69bf35d8c508d20b0abdb80b2a4..620438bb1b5e4710286fdf20c3475277ed4d6756 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -49,29 +49,32 @@ class LLDrawPool
 	{
 		// Correspond to LLPipeline render type
         // Also controls render order, so passes that don't use alpha masking/blending should come before
-        // other passes and occlusion culling should happen just before rendering alpha masked passes
-        // in order to take advantage of hierarchical Z
-        // NOTE: Keep in sync with gPoolNames
+        // other passes to preserve hierarchical Z for occlusion queries.  Occlusion queries happen just
+        // before grass, so grass should be the first alpha masked pool.  Other ordering should be done
+        // based on fill rate and likelihood to occlude future passes (faster, large occluders first).
+        //  
 		POOL_SIMPLE = 1,
 		POOL_GROUND,
 		POOL_FULLBRIGHT,
 		POOL_BUMP,
-		POOL_MATERIALS,
-		POOL_TERRAIN,	
-		POOL_SKY,
-		POOL_WL_SKY,
+		POOL_TERRAIN,
+        POOL_MATERIALS,
+        POOL_GRASS,
 		POOL_TREE,
 		POOL_ALPHA_MASK,
 		POOL_FULLBRIGHT_ALPHA_MASK,
-		POOL_GRASS,
+        POOL_SKY,
+        POOL_WL_SKY,
 		POOL_INVISIBLE, // see below *
 		POOL_AVATAR,
 		POOL_CONTROL_AV, // Animesh
-		POOL_VOIDWATER,
-		POOL_WATER,
 		POOL_GLOW,
-		POOL_ALPHA,
+		POOL_ALPHA_PRE_WATER,
+        POOL_VOIDWATER,
+        POOL_WATER,
+        POOL_ALPHA_POST_WATER,
 		POOL_PBR_OPAQUE,
+        POOL_ALPHA, // note there is no actual "POOL_ALPHA" but pre-water and post-water pools consume POOL_ALPHA faces
 		NUM_POOL_TYPES,
 		// * invisiprims work by rendering to the depth buffer but not the color buffer, occluding anything rendered after them
 		// - and the LLDrawPool types enum controls what order things are rendered in
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 8a912b00d9e7366f949892bb4712c928688fb895..0d9e83a97656681c0604b1f6410ee053287d4885 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -56,6 +56,8 @@ BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE;
 
 #define current_shader (LLGLSLShader::sCurBoundShaderPtr)
 
+LLVector4 LLDrawPoolAlpha::sWaterPlane;
+
 static BOOL deferred_render = FALSE;
 
 // minimum alpha before discarding a fragment
@@ -96,11 +98,13 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses()
 }
 
 // set some common parameters on the given shader to prepare for alpha rendering
-static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment)
+static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment, F32 water_sign)
 {
     static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma");
     F32 gamma = displayGamma;
 
+    static LLStaticHashedString waterSign("waterSign");
+
     // Does this deferred shader need environment uniforms set such as sun_dir, etc. ?
     // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering
     // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms()
@@ -115,6 +119,8 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
     }
     shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0);
     shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f));
+    shader->uniform1f(waterSign, water_sign);
+    shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, LLDrawPoolAlpha::sWaterPlane.mV);
 
     if (LLPipeline::sImpostorRender)
     {
@@ -132,7 +138,7 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
     //also prepare rigged variant
     if (shader->mRiggedVariant && shader->mRiggedVariant != shader)
     { 
-        prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment);
+        prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment, water_sign);
     }
 }
 
@@ -143,19 +149,39 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
     deferred_render = TRUE;
 
+    F32 water_sign = 1.f;
+
+    if (getType() == LLDrawPool::POOL_ALPHA_PRE_WATER)
+    {
+        water_sign = -1.f;
+    }
+
+    if (LLPipeline::sUnderWaterRender)
+    {
+        water_sign *= -1.f;
+    }
+
     // prepare shaders
     emissive_shader = (LLPipeline::sRenderDeferred)   ? &gDeferredEmissiveProgram    :
                       (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
-    prepare_alpha_shader(emissive_shader, true, false);
+    prepare_alpha_shader(emissive_shader, true, false, water_sign);
 
     fullbright_shader   = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram :
         (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightAlphaMaskProgram;
-    prepare_alpha_shader(fullbright_shader, true, true);
+    prepare_alpha_shader(fullbright_shader, true, true, water_sign);
 
     simple_shader   = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
         (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
-    prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
+    prepare_alpha_shader(simple_shader, false, true, water_sign); //prime simple shader (loads shadow relevant uniforms)
+
+
+    LLGLSLShader* materialShader = LLPipeline::sUnderWaterRender ? gDeferredMaterialWaterProgram : gDeferredMaterialProgram;
+    for (int i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
+    {
+        prepare_alpha_shader(&materialShader[i], false, false, water_sign);
+    }
 
+    prepare_alpha_shader(&gDeferredPBRAlphaProgram, false, false, water_sign);
 
     // first pass, render rigged objects only and render to depth buffer
     forwardRender(true);
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index fa8ef0f22763658f370e9241f14c60ff52fd7f1e..2c1ec309583ddd06aa37d0dbecc378c4a7454450 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -35,9 +35,13 @@ class LLFace;
 class LLColor4;
 class LLGLSLShader;
 
-class LLDrawPoolAlpha: public LLRenderPass
+class LLDrawPoolAlpha final: public LLRenderPass
 {
 public:
+
+    // set by llsettingsvo so lldrawpoolalpha has quick access to the water plane in eye space
+    static LLVector4 sWaterPlane;
+
 	enum
 	{
 		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
@@ -47,7 +51,7 @@ class LLDrawPoolAlpha: public LLRenderPass
 	};
 	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
 
-	LLDrawPoolAlpha(U32 type = LLDrawPool::POOL_ALPHA);
+	LLDrawPoolAlpha(U32 type);
 	/*virtual*/ ~LLDrawPoolAlpha();
 
 	/*virtual*/ S32 getNumPostDeferredPasses();
@@ -91,11 +95,4 @@ class LLDrawPoolAlpha: public LLRenderPass
     bool mRigged = false;
 };
 
-class LLDrawPoolAlphaPostWater : public LLDrawPoolAlpha
-{
-public:
-	LLDrawPoolAlphaPostWater();
-	virtual void render(S32 pass = 0);
-};
-
 #endif // LL_LLDRAWPOOLALPHA_H
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 431a9ebb296c14678902c713423f8768c390db99..4ae8335ca7e5744602e949de5c0cafefdf0a5e1a 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1342,7 +1342,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	if (rebuild_color)
 	{ //decide if shiny goes in alpha channel of color
 		if (tep && 
-			getPoolType() != LLDrawPool::POOL_ALPHA)  // <--- alpha channel MUST contain transparency, not shiny
+			!isInAlphaPool())  // <--- alpha channel MUST contain transparency, not shiny
 	{
 			LLMaterial* mat = tep->getMaterialParams().get();
 						
@@ -2601,3 +2601,10 @@ U64 LLFace::getSkinHash()
 {
     return mSkinInfo ? mSkinInfo->mHash : 0;
 }
+
+bool LLFace::isInAlphaPool() const
+{
+    return  getPoolType() == LLDrawPool::POOL_ALPHA ||
+        getPoolType() == LLDrawPool::POOL_ALPHA_PRE_WATER ||
+        getPoolType() == LLDrawPool::POOL_ALPHA_POST_WATER;
+}
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 4778a8110b66663a8796090c9e1d972c0ebd86d9..a5ea460061789727e6ff760688b6a2f880881d8e 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -237,6 +237,8 @@ class alignas(16) LLFace
     void setDrawOrderIndex(U32 index) { mDrawOrderIndex = index; }
     U32 getDrawOrderIndex() const { return mDrawOrderIndex; }
 
+    // return true if this face is in an alpha draw pool
+    bool isInAlphaPool() const;
 public: //aligned members
 	LLVector4a		mExtents[2];
 
diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp
index 6cd4c973d92ea31e6cc9b3e481baedf229233ae0..fdd988ddc0e8c29f6037243b680542e318b616cc 100644
--- a/indra/newview/llsettingsvo.cpp
+++ b/indra/newview/llsettingsvo.cpp
@@ -949,6 +949,8 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
 
         LLVector4 waterPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm));
 
+        LLDrawPoolAlpha::sWaterPlane = waterPlane;
+
         shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, waterPlane.mV);
 
         LLVector4 light_direction = env.getClampedLightNorm();
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 112d6697402e4ab0e6d889bd18c575e759f51894..b3bc831670a6ac54db3280c31452923a746ac250 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1221,6 +1221,8 @@ void render_hud_attachments()
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
+        gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA_PRE_WATER);
+        gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA_POST_WATER);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index d4c93eec06747bd63a487e221b2e7f9dc82ff416..e7dbdf2bea2231ed0304fe7bd4df86b1fe31ecb2 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -1924,6 +1924,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
             shader->mFeatures.hasTransport = true;
             shader->mFeatures.hasShadows = use_sun_shadow;
             shader->mFeatures.hasReflectionProbes = true;
+            shader->mFeatures.hasWaterFog = true;
 
             if (mShaderLevel[SHADER_DEFERRED] < 1)
             {
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index d312bb75d15a357eb35b4b528035cc3e70054d33..bbe6814ce1edd8d7c21cab8cee0b8647b1934ca3 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4212,7 +4212,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const
 			}
 		}
 
-		if (face->getPoolType() == LLDrawPool::POOL_ALPHA)
+		if (face->isInAlphaPool())
 		{
 			alpha = 1;
 		}
@@ -4576,7 +4576,7 @@ F32 LLVOVolume::getBinRadius()
 		{
 			LLFace* face = mDrawable->getFace(i);
 			if (!face) continue;
-			if (face->getPoolType() == LLDrawPool::POOL_ALPHA &&
+			if (face->isInAlphaPool() &&
 			    !face->canRenderAsMask())
 			{
 				alpha_wrap = TRUE;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 87a5cd9cc8ea28b0649e2307000d36d11d4e536a..2f4ab3ac45d89f6e8b0eb92b935f8d32214c56f2 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -281,33 +281,6 @@ static LLStaticHashedString sKern("kern");
 static LLStaticHashedString sKernScale("kern_scale");
 
 //----------------------------------------
-#if 0
-std::string gPoolNames[LLDrawPool::NUM_POOL_TYPES] =
-{
-	// Correspond to LLDrawpool enum render type
-	  "NONE"
-	, "POOL_SIMPLE"
-	, "POOL_GROUND"
-	, "POOL_FULLBRIGHT"
-	, "POOL_BUMP"
-	, "POOL_MATERIALS"
-	, "POOL_TERRAIN"
-	, "POOL_SKY"
-	, "POOL_WL_SKY"
-	, "POOL_TREE"
-	, "POOL_ALPHA_MASK"
-	, "POOL_FULLBRIGHT_ALPHA_MASK"
-	, "POOL_GRASS"
-	, "POOL_INVISIBLE"
-	, "POOL_AVATAR"
-	, "POOL_CONTROL_AV" // Animesh
-	, "POOL_VOIDWATER"
-	, "POOL_WATER"
-	, "POOL_GLOW"
-	, "POOL_ALPHA"
-	, "POOL_PBR_OPAQUE"
-};
-#endif
 
 void drawBox(const LLVector4a& c, const LLVector4a& r);
 void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
@@ -397,21 +370,6 @@ LLPipeline::LLPipeline() :
 	mGroupQ2Locked(false),
 	mResetVertexBuffers(false),
 	mLastRebuildPool(NULL),
-	mAlphaPool(NULL),
-	mSkyPool(NULL),
-	mTerrainPool(NULL),
-	mWaterPool(NULL),
-	mGroundPool(NULL),
-	mSimplePool(NULL),
-	mGrassPool(NULL),
-	mAlphaMaskPool(NULL),
-	mFullbrightAlphaMaskPool(NULL),
-	mFullbrightPool(NULL),
-	mInvisiblePool(NULL),
-	mGlowPool(NULL),
-	mBumpPool(NULL),
-	mMaterialsPool(NULL),
-	mWLSkyPool(NULL),
 	mLightMask(0),
 	mLightMovingMask(0),
 	mLightingDetail(0)
@@ -463,7 +421,8 @@ void LLPipeline::init()
     LL_WARNS() << "No GL errors yet. Pipeline initialization will continue." << LL_ENDL; // TODO: Remove after testing
 
 	//create render pass pools
-	getPool(LLDrawPool::POOL_ALPHA);
+	getPool(LLDrawPool::POOL_ALPHA_PRE_WATER);
+    getPool(LLDrawPool::POOL_ALPHA_POST_WATER);
 	getPool(LLDrawPool::POOL_SIMPLE);
 	getPool(LLDrawPool::POOL_ALPHA_MASK);
 	getPool(LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK);
@@ -671,8 +630,10 @@ void LLPipeline::cleanup()
 		LL_WARNS() << "Tree Pools not cleaned up" << LL_ENDL;
 	}
 		
-	delete mAlphaPool;
-	mAlphaPool = NULL;
+	delete mAlphaPoolPreWater;
+    mAlphaPoolPreWater = nullptr;
+    delete mAlphaPoolPostWater;
+    mAlphaPoolPostWater = nullptr;
 	delete mSkyPool;
 	mSkyPool = NULL;
 	delete mTerrainPool;
@@ -1589,9 +1550,12 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
 	case LLDrawPool::POOL_MATERIALS:
 		poolp = mMaterialsPool;
 		break;
-	case LLDrawPool::POOL_ALPHA:
-		poolp = mAlphaPool;
+	case LLDrawPool::POOL_ALPHA_PRE_WATER:
+		poolp = mAlphaPoolPreWater;
 		break;
+    case LLDrawPool::POOL_ALPHA_POST_WATER:
+        poolp = mAlphaPoolPostWater;
+        break;
 
 	case LLDrawPool::POOL_AVATAR:
 	case LLDrawPool::POOL_CONTROL_AV:
@@ -5733,17 +5697,28 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 			mMaterialsPool = new_poolp;
 		}
 		break;
-	case LLDrawPool::POOL_ALPHA:
-		if( mAlphaPool )
+	case LLDrawPool::POOL_ALPHA_PRE_WATER:
+		if( mAlphaPoolPreWater )
 		{
 			llassert(0);
-			LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << LL_ENDL;
+			LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Alpha pre-water pool" << LL_ENDL;
 		}
 		else
 		{
-			mAlphaPool = (LLDrawPoolAlpha*) new_poolp;
+			mAlphaPoolPreWater = (LLDrawPoolAlpha*) new_poolp;
 		}
 		break;
+    case LLDrawPool::POOL_ALPHA_POST_WATER:
+        if (mAlphaPoolPostWater)
+        {
+            llassert(0);
+            LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Alpha post-water pool" << LL_ENDL;
+        }
+        else
+        {
+            mAlphaPoolPostWater = (LLDrawPoolAlpha*)new_poolp;
+        }
+        break;
 
 	case LLDrawPool::POOL_AVATAR:
 	case LLDrawPool::POOL_CONTROL_AV:
@@ -5901,10 +5876,15 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		mMaterialsPool = NULL;
 		break;
 			
-	case LLDrawPool::POOL_ALPHA:
-		llassert( poolp == mAlphaPool );
-		mAlphaPool = NULL;
+	case LLDrawPool::POOL_ALPHA_PRE_WATER:
+		llassert( poolp == mAlphaPoolPreWater );
+		mAlphaPoolPreWater = nullptr;
 		break;
+    
+    case LLDrawPool::POOL_ALPHA_POST_WATER:
+        llassert(poolp == mAlphaPoolPostWater);
+        mAlphaPoolPostWater = nullptr;
+        break;
 
 	case LLDrawPool::POOL_AVATAR:
 	case LLDrawPool::POOL_CONTROL_AV:
@@ -9078,6 +9058,8 @@ void LLPipeline::renderDeferredLighting()
 
         pushRenderTypeMask();
         andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+                          LLPipeline::RENDER_TYPE_ALPHA_PRE_WATER,
+                          LLPipeline::RENDER_TYPE_ALPHA_POST_WATER,
                           LLPipeline::RENDER_TYPE_FULLBRIGHT,
                           LLPipeline::RENDER_TYPE_VOLUME,
                           LLPipeline::RENDER_TYPE_GLOW,
@@ -10296,6 +10278,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	pushRenderTypeMask();
 	andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
 					LLPipeline::RENDER_TYPE_ALPHA,
+                    LLPipeline::RENDER_TYPE_ALPHA_PRE_WATER,
+                    LLPipeline::RENDER_TYPE_ALPHA_POST_WATER,
 					LLPipeline::RENDER_TYPE_GRASS,
 					LLPipeline::RENDER_TYPE_FULLBRIGHT,
 					LLPipeline::RENDER_TYPE_BUMP,
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 23ddfb51e53d3cc7e286a88754a6cec407d11bb9..2c9b264fe6c78c0d31729407be24b62f1b9d9e78 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -477,6 +477,8 @@ class LLPipeline
 		RENDER_TYPE_VOIDWATER					= LLDrawPool::POOL_VOIDWATER,
 		RENDER_TYPE_WATER						= LLDrawPool::POOL_WATER,
  		RENDER_TYPE_ALPHA						= LLDrawPool::POOL_ALPHA,
+        RENDER_TYPE_ALPHA_PRE_WATER             = LLDrawPool::POOL_ALPHA_PRE_WATER,
+        RENDER_TYPE_ALPHA_POST_WATER            = LLDrawPool::POOL_ALPHA_POST_WATER,
 		RENDER_TYPE_GLOW						= LLDrawPool::POOL_GLOW,
 		RENDER_TYPE_PASS_SIMPLE 				= LLRenderPass::PASS_SIMPLE,
         RENDER_TYPE_PASS_SIMPLE_RIGGED = LLRenderPass::PASS_SIMPLE_RIGGED,
@@ -890,22 +892,23 @@ class LLPipeline
 	// For quick-lookups into mPools (mapped by texture pointer)
 	std::map<uintptr_t, LLDrawPool*>	mTerrainPools;
 	std::map<uintptr_t, LLDrawPool*>	mTreePools;
-	LLDrawPoolAlpha*			mAlphaPool;
-	LLDrawPool*					mSkyPool;
-	LLDrawPool*					mTerrainPool;
-	LLDrawPool*					mWaterPool;
-	LLDrawPool*					mGroundPool;
-	LLRenderPass*				mSimplePool;
-	LLRenderPass*				mGrassPool;
-	LLRenderPass*				mAlphaMaskPool;
-	LLRenderPass*				mFullbrightAlphaMaskPool;
-	LLRenderPass*				mFullbrightPool;
-	LLDrawPool*					mInvisiblePool;
-	LLDrawPool*					mGlowPool;
-	LLDrawPool*					mBumpPool;
-	LLDrawPool*					mMaterialsPool;
-	LLDrawPool*					mWLSkyPool;
-	LLDrawPool*					mPBROpaquePool;
+	LLDrawPoolAlpha*			mAlphaPoolPreWater = nullptr;
+    LLDrawPoolAlpha*            mAlphaPoolPostWater = nullptr;
+	LLDrawPool*					mSkyPool = nullptr;
+	LLDrawPool*					mTerrainPool = nullptr;
+	LLDrawPool*					mWaterPool = nullptr;
+	LLDrawPool*					mGroundPool = nullptr;
+	LLRenderPass*				mSimplePool = nullptr;
+	LLRenderPass*				mGrassPool = nullptr;
+	LLRenderPass*				mAlphaMaskPool = nullptr;
+	LLRenderPass*				mFullbrightAlphaMaskPool = nullptr;
+	LLRenderPass*				mFullbrightPool = nullptr;
+	LLDrawPool*					mInvisiblePool = nullptr;
+	LLDrawPool*					mGlowPool = nullptr;
+	LLDrawPool*					mBumpPool = nullptr;
+	LLDrawPool*					mMaterialsPool = nullptr;
+	LLDrawPool*					mWLSkyPool = nullptr;
+	LLDrawPool*					mPBROpaquePool = nullptr;
 	// Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar
 	
 public: