From 9950c22a5568b55ff896734185e0e1181a93fcf0 Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Wed, 12 May 2010 03:59:01 -0500
Subject: Fix for fullbright bump not working in deferred render. Fix for
 shadow artifacts around split frusta. Tweak for shadow aliasing with
 projectors. Fix for crash on exit in mesh thread.

---
 indra/newview/app_settings/settings.xml            |   6 +-
 .../shaders/class2/deferred/sunLightF.glsl         |   3 +-
 indra/newview/lldrawpool.h                         |   1 +
 indra/newview/lldrawpoolbump.cpp                   |  44 ++-
 indra/newview/lldrawpoolbump.h                     |   8 +-
 indra/newview/lldrawpoolsimple.cpp                 |   3 +-
 indra/newview/llviewercontrol.cpp                  |   3 +
 indra/newview/llviewerdisplay.cpp                  |   8 +-
 indra/newview/llvovolume.cpp                       |  39 +-
 indra/newview/pipeline.cpp                         | 394 ++++++++++++++-------
 indra/newview/pipeline.h                           |  30 +-
 11 files changed, 364 insertions(+), 175 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 623f0f3b01..4c72b03b2e 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -6604,7 +6604,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>-0.0005</real>
+    <real>0.0</real>
   </map>
   <key>RenderSpotShadowOffset</key>
   <map>
@@ -6615,7 +6615,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>-0.01</real>
+    <real>0.04</real>
   </map>
 
   <key>RenderShadowResolutionScale</key>
@@ -6751,7 +6751,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>1</real>
+    <real>8</real>
   </map>
 
   <key>RenderDeferred</key>
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index 413835515a..794c4d2761 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -77,7 +77,6 @@ float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
 
 float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl)
 {
-	stc.z += spot_shadow_offset;
 	stc.xyz /= stc.w;
 	stc.z += spot_shadow_bias*scl;
 	
@@ -182,7 +181,7 @@ void main()
 	gl_FragColor[0] = shadow;
 	gl_FragColor[1] = 1.0;
 	
-	spos = vec4(shadow_pos, 1.0);
+	spos = vec4(shadow_pos+norm*spot_shadow_offset, 1.0);
 	
 	//spotlight shadow 1
 	vec4 lpos = shadow_matrix[4]*spos;
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index e46d503db3..ec870f59c6 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -133,6 +133,7 @@ public:
 		PASS_FULLBRIGHT_SHINY,
 		PASS_SHINY,
 		PASS_BUMP,
+		PASS_POST_BUMP,
 		PASS_GLOW,
 		PASS_ALPHA,
 		PASS_ALPHA_MASK,
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 906615ade8..967ce3fc5c 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -659,9 +659,9 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi
 }
 
 //static
-void LLDrawPoolBump::beginBump()
+void LLDrawPoolBump::beginBump(U32 pass)
 {	
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches(pass))
 	{
 		return;
 	}
@@ -704,9 +704,9 @@ void LLDrawPoolBump::beginBump()
 }
 
 //static
-void LLDrawPoolBump::renderBump()
+void LLDrawPoolBump::renderBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches(pass))
 	{
 		return;
 	}
@@ -719,13 +719,13 @@ void LLDrawPoolBump::renderBump()
 	/// Get rid of z-fighting with non-bump pass.
 	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
 	glPolygonOffset(-1.0f, -1.0f);
-	renderBump(LLRenderPass::PASS_BUMP, sVertexMask);
+	renderBump(pass, sVertexMask);
 }
 
 //static
-void LLDrawPoolBump::endBump()
+void LLDrawPoolBump::endBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches(pass))
 	{
 		return;
 	}
@@ -808,17 +808,41 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
 
 void LLDrawPoolBump::beginPostDeferredPass(S32 pass)
 {
-	beginFullbrightShiny();
+	switch (pass)
+	{
+	case 0:
+		beginFullbrightShiny();
+		break;
+	case 1:
+		beginBump(LLRenderPass::PASS_POST_BUMP);
+		break;
+	}
 }
 
 void LLDrawPoolBump::endPostDeferredPass(S32 pass)
 {
-	endFullbrightShiny();
+	switch (pass)
+	{
+	case 0:
+		endFullbrightShiny();
+		break;
+	case 1:
+		endBump(LLRenderPass::PASS_POST_BUMP);
+		break;
+	}
 }
 
 void LLDrawPoolBump::renderPostDeferred(S32 pass)
 {
-	renderFullbrightShiny();
+	switch (pass)
+	{
+	case 0:
+		renderFullbrightShiny();
+		break;
+	case 1:
+		renderBump(LLRenderPass::PASS_POST_BUMP);
+		break;
+	}
 }
 
 ////////////////////////////////////////////////////////////////
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 127c9efe85..a75653e68e 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -76,9 +76,9 @@ public:
 	void renderFullbrightShiny();
 	void endFullbrightShiny();
 
-	void beginBump();
-	void renderBump();
-	void endBump();
+	void beginBump(U32 pass = LLRenderPass::PASS_BUMP);
+	void renderBump(U32 pass = LLRenderPass::PASS_BUMP);
+	void endBump(U32 pass = LLRenderPass::PASS_BUMP);
 
 	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
 	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
@@ -88,7 +88,7 @@ public:
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
 
-	virtual S32 getNumPostDeferredPasses() { return 1; }
+	virtual S32 getNumPostDeferredPasses() { return 2; }
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index c8e6f95ab6..91191287cd 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -151,7 +151,8 @@ void LLDrawPoolSimple::render(S32 pass)
 		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
 
 		if (LLPipeline::sRenderDeferred)
-		{
+		{ //if deferred rendering is enabled, bump faces aren't reigstered as simple
+			//render bump faces here as simple so bump faces will appear under water
 			renderTexture(LLRenderPass::PASS_BUMP, getVertexDataMask());
 		}
 	}
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index a8004f26ed..701df86de4 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -505,6 +505,9 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	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("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 360cee9f73..3cd7af6433 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -946,9 +946,10 @@ void render_hud_attachments()
 		bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
 		
 		//only render hud objects
-		U32 mask = gPipeline.getRenderTypeMask();
+		gPipeline.pushRenderTypeMask();
+		
 		// turn off everything
-		gPipeline.setRenderTypeMask(0);
+		gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
 		// turn on HUD
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
 		// turn on HUD particles
@@ -1002,7 +1003,8 @@ void render_hud_attachments()
 		render_hud_elements();
 
 		//restore type mask
-		gPipeline.setRenderTypeMask(mask);
+		gPipeline.popRenderTypeMask();
+
 		if (has_ui)
 		{
 			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index aaa6e8007f..b120f5abf3 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3349,7 +3349,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		model_mat = &(drawable->getRegion()->mRenderMatrix);
 	}
 
-	U8 bump = (type == LLRenderPass::PASS_BUMP ? facep->getTextureEntry()->getBumpmap() : 0);
+
+	U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
 	
 	LLViewerTexture* tex = facep->getTexture();
 
@@ -4052,66 +4053,76 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				&& group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD 
 				&& LLPipeline::sRenderBump 
 				&& te->getShiny())
-			{
+			{ //shiny
 				if (tex->getPrimaryFormat() == GL_ALPHA)
-				{
+				{ //invisiprim+shiny
 					registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
 					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
 				}
 				else if (LLPipeline::sRenderDeferred)
-				{
+				{ //deferred rendering
 					if (te->getFullbright())
-					{
+					{ //register in post deferred fullbright shiny pass
 						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
+						if (te->getBumpmap())
+						{ //register in post deferred bump pass
+							registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
+						}
 					}
 					else if (te->getBumpmap())
-					{
+					{ //register in deferred bump pass
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
 					else
-					{
+					{ //register in deferred simple pass (deferred simple includes shiny)
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
 						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 					}
 				}
 				else if (fullbright)
-				{						
+				{	//not deferred, register in standard fullbright shiny pass					
 					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
 				}
 				else
-				{
+				{ //not deferred or fullbright, register in standard shiny pass
 					registerFace(group, facep, LLRenderPass::PASS_SHINY);
 				}
 			}
 			else
-			{
+			{ //not alpha and not shiny
 				if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA)
-				{
+				{ //invisiprim
 					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
 				}
 				else if (fullbright)
-				{
+				{ //fullbright
 					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
+					{ //if this is the deferred render and a bump map is present, register in post deferred bump
+						registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
+					}
 				}
 				else
 				{
 					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
-					{
+					{ //non-shiny or fullbright deferred bump
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
 					else
-					{
+					{ //all around simple
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
 						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 					}
 				}
 				
+				//not sure why this is here -- shiny HUD attachments maybe?  -- davep 5/11/2010
 				if (!is_alpha && te->getShiny() && LLPipeline::sRenderBump)
 				{
 					registerFace(group, facep, LLRenderPass::PASS_SHINY);
 				}
 			}
 			
+			//not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010
 			if (!is_alpha && !LLPipeline::sRenderDeferred)
 			{
 				llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index da01ae44db..a066b7fc0d 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -331,7 +331,6 @@ LLPipeline::LLPipeline() :
 	mInitialized(FALSE),
 	mVertexShadersEnabled(FALSE),
 	mVertexShadersLoaded(0),
-	mRenderTypeMask(0),
 	mRenderDebugFeatureMask(0),
 	mRenderDebugMask(0),
 	mOldRenderDebugMask(0),
@@ -385,7 +384,11 @@ void LLPipeline::init()
 	LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
 	resetFrameStats();
 
-	mRenderTypeMask = 0xffffffff;	// All render types start on
+	for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+	{
+		mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
+	}
+
 	mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
 	mRenderDebugMask = 0;	// All debug starts off
 
@@ -2217,14 +2220,13 @@ static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
 
 void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 {
-	const U32 face_mask = (1 << LLPipeline::RENDER_TYPE_AVATAR) |
-						  (1 << LLPipeline::RENDER_TYPE_GROUND) |
-						  (1 << LLPipeline::RENDER_TYPE_TERRAIN) |
-						  (1 << LLPipeline::RENDER_TYPE_TREE) |
-						  (1 << LLPipeline::RENDER_TYPE_SKY) |
-						  (1 << LLPipeline::RENDER_TYPE_WATER);
-
-	if (mRenderTypeMask & face_mask)
+	if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
+					  LLPipeline::RENDER_TYPE_GROUND,
+					  LLPipeline::RENDER_TYPE_TERRAIN,
+					  LLPipeline::RENDER_TYPE_TREE,
+					  LLPipeline::RENDER_TYPE_SKY,
+					  LLPipeline::RENDER_TYPE_WATER,
+					  LLPipeline::END_RENDER_TYPES))
 	{
 		//clear faces from face pools
 		LLFastTimer t(FTM_RESET_DRAWORDER);
@@ -5072,8 +5074,7 @@ void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
 //static
 void LLPipeline::toggleRenderType(U32 type)
 {
-	U32 bit = (1<<type);
-	gPipeline.mRenderTypeMask ^= bit;
+	gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
 }
 
 //static
@@ -6695,15 +6696,16 @@ void LLPipeline::renderDeferredLighting()
 			LLGLDisable stencil(GL_STENCIL_TEST);
 			gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
-			U32 render_mask = mRenderTypeMask;
-			mRenderTypeMask =	mRenderTypeMask & 
-								((1 << LLPipeline::RENDER_TYPE_SKY) |
-								(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
-								(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+			gPipeline.pushRenderTypeMask();
+			
+			gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+										LLPipeline::RENDER_TYPE_CLOUDS,
+										LLPipeline::RENDER_TYPE_WL_SKY,
+										LLPipeline::END_RENDER_TYPES);
 								
 			
 			renderGeomPostDeferred(*LLViewerCamera::getInstance());
-			mRenderTypeMask = render_mask;
+			gPipeline.popRenderTypeMask();
 		}
 
 		BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
@@ -7025,29 +7027,30 @@ void LLPipeline::renderDeferredLighting()
 		LLGLDisable blend(GL_BLEND);
 		LLGLDisable stencil(GL_STENCIL_TEST);
 
-		U32 render_mask = mRenderTypeMask;
-		mRenderTypeMask =	mRenderTypeMask & 
-							((1 << LLPipeline::RENDER_TYPE_ALPHA) |
-							(1 << LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-							(1 << LLPipeline::RENDER_TYPE_VOLUME) |
-							(1 << LLPipeline::RENDER_TYPE_GLOW) |
-							(1 << LLPipeline::RENDER_TYPE_BUMP) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_GLOW) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_GRASS) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_INVISIBLE) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY) |
-							(1 << LLPipeline::RENDER_TYPE_AVATAR));
+		pushRenderTypeMask();
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+						 LLPipeline::RENDER_TYPE_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_VOLUME,
+						 LLPipeline::RENDER_TYPE_GLOW,
+						 LLPipeline::RENDER_TYPE_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_GLOW,
+						 LLPipeline::RENDER_TYPE_PASS_GRASS,
+						 LLPipeline::RENDER_TYPE_PASS_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+						 LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+						 LLPipeline::RENDER_TYPE_AVATAR,
+						 END_RENDER_TYPES);
 		
 		renderGeomPostDeferred(*LLViewerCamera::getInstance());
-		mRenderTypeMask = render_mask;
+		popRenderTypeMask();
 	}
 
 	{
@@ -7301,8 +7304,8 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
 		LLPipeline::sUseOcclusion = llmin(occlusion, 1);
 		
-		U32 type_mask = gPipeline.mRenderTypeMask;
-
+		gPipeline.pushRenderTypeMask();
+		
 		glh::matrix4f projection = glh_get_current_projection();
 		glh::matrix4f mat;
 
@@ -7370,43 +7373,48 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			glCullFace(GL_FRONT);
 
 			static LLCullResult ref_result;
-			U32 ref_mask = 0;
+		
 			if (LLDrawPoolWater::sNeedsDistortionUpdate)
 			{
 				//initial sky pass (no user clip plane)
 				{ //mask out everything but the sky
-					U32 tmp = mRenderTypeMask;
-					mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
-										(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+					gPipeline.pushRenderTypeMask();
+					gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+												LLPipeline::RENDER_TYPE_WL_SKY,
+												LLPipeline::END_RENDER_TYPES);
 					static LLCullResult result;
 					updateCull(camera, result);
 					llpushcallstacks ;
 					stateSort(camera, result);
-					mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
-										(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
-										(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+					andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+										LLPipeline::RENDER_TYPE_CLOUDS,
+										LLPipeline::RENDER_TYPE_WL_SKY,
+										LLPipeline::END_RENDER_TYPES);
+
 					renderGeom(camera, TRUE);
-					mRenderTypeMask = tmp;
+					gPipeline.popRenderTypeMask();
 				}
 
-				U32 mask = mRenderTypeMask;
-				mRenderTypeMask &=	~((1<<LLPipeline::RENDER_TYPE_WATER) |
-									  (1<<LLPipeline::RENDER_TYPE_GROUND) |
-									  (1<<LLPipeline::RENDER_TYPE_SKY) |
-									  (1<<LLPipeline::RENDER_TYPE_CLOUDS));	
+				gPipeline.pushRenderTypeMask();
+				
+				clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+									LLPipeline::RENDER_TYPE_GROUND,
+									LLPipeline::RENDER_TYPE_SKY,
+									LLPipeline::RENDER_TYPE_CLOUDS,
+									LLPipeline::END_RENDER_TYPES);	
 
 				S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
 				if (detail > 0)
 				{ //mask out selected geometry based on reflection detail
 					if (detail < 4)
 					{
-						mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_PARTICLES);
+						clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
 						if (detail < 3)
 						{
-							mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_AVATAR);
+							clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
 							if (detail < 2)
 							{
-								mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_VOLUME);
+								clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
 							}
 						}
 					}
@@ -7418,18 +7426,17 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					stateSort(camera, ref_result);
 				}	
 				
-				ref_mask = mRenderTypeMask;
-				mRenderTypeMask = mask;
-			}
-			if (LLDrawPoolWater::sNeedsDistortionUpdate)
-			{
-				mRenderTypeMask = ref_mask;
-				if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
+				if (LLDrawPoolWater::sNeedsDistortionUpdate)
 				{
-					gPipeline.grabReferences(ref_result);
-					LLGLUserClipPlane clip_plane(plane, mat, projection);
-					renderGeom(camera);
+					if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
+					{
+						gPipeline.grabReferences(ref_result);
+						LLGLUserClipPlane clip_plane(plane, mat, projection);
+						renderGeom(camera);
+					}
 				}
+
+				gPipeline.popRenderTypeMask();
 			}	
 			glCullFace(GL_BACK);
 			glPopMatrix();
@@ -7443,18 +7450,20 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 		if (last_update)
 		{
 			camera.setFar(camera_in.getFar());
-			mRenderTypeMask = type_mask & (~(1<<LLPipeline::RENDER_TYPE_WATER) |
-											(1<<LLPipeline::RENDER_TYPE_GROUND));	
+			clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+								LLPipeline::RENDER_TYPE_GROUND,
+								END_RENDER_TYPES);	
 			stop_glerror();
 
 			LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
 
 			if (LLPipeline::sUnderWaterRender)
 			{
-				mRenderTypeMask &=	~((1<<LLPipeline::RENDER_TYPE_GROUND) |
-									  (1<<LLPipeline::RENDER_TYPE_SKY) |
-									  (1<<LLPipeline::RENDER_TYPE_CLOUDS) |
-									  (1<<LLPipeline::RENDER_TYPE_WL_SKY));		
+				clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
+									LLPipeline::RENDER_TYPE_SKY,
+									LLPipeline::RENDER_TYPE_CLOUDS,
+									LLPipeline::RENDER_TYPE_WL_SKY,
+									END_RENDER_TYPES);		
 			}
 			LLViewerCamera::updateFrustumPlanes(camera);
 
@@ -7496,7 +7505,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 		}
 		glClearColor(0.f, 0.f, 0.f, 0.f);
 		gViewerWindow->setup3DViewport();
-		mRenderTypeMask = type_mask;
+		gPipeline.popRenderTypeMask();
 		LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
 		LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
 		LLViewerCamera::getInstance()->setUserClipPlane(LLPlane(-pnorm, -pd));
@@ -7951,21 +7960,22 @@ void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<L
 	sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
 	static LLCullResult result;
 
-	U32 type_mask = mRenderTypeMask;
+	pushRenderTypeMask();
 
-	mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
-								   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-								   (1<<LLPipeline::RENDER_TYPE_BUMP) |
-								   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
-								   (1<<LLPipeline::RENDER_TYPE_TREE) | 
-								   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
-								   (1<<LLPipeline::RENDER_TYPE_WATER) |
-								   (1<<LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW) |
-								   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-									(1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
-									(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-									(1 << LLPipeline::RENDER_TYPE_PASS_SHINY));
+	andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+								 LLPipeline::RENDER_TYPE_FULLBRIGHT,
+								 LLPipeline::RENDER_TYPE_BUMP,
+								 LLPipeline::RENDER_TYPE_VOLUME,
+								 LLPipeline::RENDER_TYPE_TREE, 
+								 LLPipeline::RENDER_TYPE_TERRAIN,
+								 LLPipeline::RENDER_TYPE_WATER,
+								 LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+								 LLPipeline::RENDER_TYPE_AVATAR,
+								 LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+								 LLPipeline::RENDER_TYPE_PASS_BUMP,
+								 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+								 LLPipeline::RENDER_TYPE_PASS_SHINY,
+								 END_RENDER_TYPES);
 
 
 	
@@ -8034,7 +8044,7 @@ void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<L
 	LLPipeline::sShadowRender = FALSE;
 	sMinRenderSize = 0.f;
 
-	mRenderTypeMask = type_mask;
+	popRenderTypeMask();
 
 }
 
@@ -8131,23 +8141,24 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		last_projection[i] = gGLLastProjection[i];
 	}
 
-	U32 type_mask = mRenderTypeMask;
-	mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
-								   (1<<LLPipeline::RENDER_TYPE_ALPHA) |
-								   (1<<LLPipeline::RENDER_TYPE_GRASS) |
-								   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-								   (1<<LLPipeline::RENDER_TYPE_BUMP) |
-								   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
-								   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
-								   (1<<LLPipeline::RENDER_TYPE_TREE) | 
-								   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
-								   (1<<LLPipeline::RENDER_TYPE_WATER) |
-								   (1<<LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY));
+	pushRenderTypeMask();
+	andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+					LLPipeline::RENDER_TYPE_ALPHA,
+					LLPipeline::RENDER_TYPE_GRASS,
+					LLPipeline::RENDER_TYPE_FULLBRIGHT,
+					LLPipeline::RENDER_TYPE_BUMP,
+					LLPipeline::RENDER_TYPE_VOLUME,
+					LLPipeline::RENDER_TYPE_AVATAR,
+					LLPipeline::RENDER_TYPE_TREE, 
+					LLPipeline::RENDER_TYPE_TERRAIN,
+					LLPipeline::RENDER_TYPE_WATER,
+					LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+					LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+					LLPipeline::RENDER_TYPE_PASS_BUMP,
+					LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+					LLPipeline::RENDER_TYPE_PASS_SHINY,
+					LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+					END_RENDER_TYPES);
 
 	gGL.setColorMask(false, false);
 
@@ -8232,7 +8243,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 				mShadowFrustPoints[2].clear();
 				mShadowFrustPoints[3].clear();
 			}
-			mRenderTypeMask = type_mask;
+			popRenderTypeMask();
 			return;
 		}
 
@@ -8318,10 +8329,11 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		for (U32 i = 0; i < 4; i++)
 		{
 			LLVector3 delta = frust[i+4]-eye;
+			delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
 			delta.normVec();
 			F32 dp = delta*pn;
-			frust[i] = eye + (delta*dist[j])/dp;
-			frust[i+4] = eye + (delta*dist[j+1])/dp;
+			frust[i] = eye + (delta*dist[j]*0.95f)/dp;
+			frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
 		}
 						
 		shadow_cam.calcAgentFrustumPlanes(frust);
@@ -8834,7 +8846,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		gGLLastProjection[i] = last_projection[i];
 	}
 
-	mRenderTypeMask = type_mask;
+	popRenderTypeMask();
 }
 
 void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
@@ -8873,35 +8885,34 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	U32 mask;
 	BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
 
+	pushRenderTypeMask();
+	
 	if (muted)
 	{
-		mask  = 1 << LLPipeline::RENDER_TYPE_AVATAR;
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
 	}
 	else
 	{
-		mask  = (1<<LLPipeline::RENDER_TYPE_VOLUME) |
-				(1<<LLPipeline::RENDER_TYPE_AVATAR) |
-				(1<<LLPipeline::RENDER_TYPE_BUMP) |
-				(1<<LLPipeline::RENDER_TYPE_GRASS) |
-				(1<<LLPipeline::RENDER_TYPE_SIMPLE) |
-				(1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-				(1<<LLPipeline::RENDER_TYPE_ALPHA) | 
-				(1<<LLPipeline::RENDER_TYPE_INVISIBLE) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_INVISIBLE) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
+						LLPipeline::RENDER_TYPE_AVATAR,
+						LLPipeline::RENDER_TYPE_BUMP,
+						LLPipeline::RENDER_TYPE_GRASS,
+						LLPipeline::RENDER_TYPE_SIMPLE,
+						LLPipeline::RENDER_TYPE_FULLBRIGHT,
+						LLPipeline::RENDER_TYPE_ALPHA, 
+						LLPipeline::RENDER_TYPE_INVISIBLE,
+						LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+						LLPipeline::RENDER_TYPE_PASS_ALPHA,
+						LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+						LLPipeline::RENDER_TYPE_PASS_SHINY,
+						LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+						LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+						END_RENDER_TYPES);
 	}
 	
-	mask = mask & gPipeline.getRenderTypeMask();
-	U32 saved_mask = gPipeline.mRenderTypeMask;
-	gPipeline.mRenderTypeMask = mask;
-
 	S32 occlusion = sUseOcclusion;
 	sUseOcclusion = 0;
 	sReflectionRender = sRenderDeferred ? FALSE : TRUE;
@@ -9075,7 +9086,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	sReflectionRender = FALSE;
 	sImpostorRender = FALSE;
 	sShadowRender = FALSE;
-	gPipeline.mRenderTypeMask = saved_mask;
+	popRenderTypeMask();
 
 	glMatrixMode(GL_PROJECTION);
 	glPopMatrix();
@@ -9116,4 +9127,121 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
 	return sCull->endAlphaGroups();
 }
 
+BOOL LLPipeline::hasRenderType(const U32 type) const
+{
+	return mRenderTypeEnabled[type];
+}
+
+void LLPipeline::setRenderTypeMask(U32 type, ...)
+{
+	va_list args;
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		mRenderTypeEnabled[type] = TRUE;
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+}
+
+BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
+{
+	va_list args;
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		if (mRenderTypeEnabled[type])
+		{
+			return TRUE;
+		}
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+
+	return FALSE;
+}
+
+void LLPipeline::pushRenderTypeMask()
+{
+	std::string cur_mask;
+	cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
+	mRenderTypeEnableStack.push(cur_mask);
+}
+
+void LLPipeline::popRenderTypeMask()
+{
+	if (mRenderTypeEnableStack.empty())
+	{
+		llerrs << "Depleted render type stack." << llendl;
+	}
+
+	memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
+	mRenderTypeEnableStack.pop();
+}
+
+void LLPipeline::andRenderTypeMask(U32 type, ...)
+{
+	va_list args;
+
+	BOOL tmp[NUM_RENDER_TYPES];
+	for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+	{
+		tmp[i] = FALSE;
+	}
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		if (mRenderTypeEnabled[type]) 
+		{
+			tmp[type] = TRUE;
+		}
+
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+
+	for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
+	{
+		mRenderTypeEnabled[i] = tmp[i];
+	}
+
+}
+
+void LLPipeline::clearRenderTypeMask(U32 type, ...)
+{
+	va_list args;
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		mRenderTypeEnabled[type] = FALSE;
+		
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+}
+
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index be878ae667..2c14b94847 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -46,6 +46,8 @@
 #include "lldrawable.h"
 #include "llrendertarget.h"
 
+#include <stack>
+
 class LLViewerTexture;
 class LLEdge;
 class LLFace;
@@ -279,12 +281,25 @@ public:
 	LLCullResult::sg_list_t::iterator beginAlphaGroups();
 	LLCullResult::sg_list_t::iterator endAlphaGroups();
 	
+
 	void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES);
-	BOOL hasRenderType(const U32 type) const				{ return (type && (mRenderTypeMask & (1<<type))) ? TRUE : FALSE; }
+
 	BOOL hasRenderDebugFeatureMask(const U32 mask) const	{ return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; }
 	BOOL hasRenderDebugMask(const U32 mask) const			{ return (mRenderDebugMask & mask) ? TRUE : FALSE; }
-	void setRenderTypeMask(const U32 mask)					{ mRenderTypeMask = mask; }
-	U32  getRenderTypeMask() const							{ return mRenderTypeMask; }
+	
+
+
+	BOOL hasRenderType(const U32 type) const;
+	BOOL hasAnyRenderType(const U32 type, ...) const;
+
+	void setRenderTypeMask(U32 type, ...);
+	void orRenderTypeMask(U32 type, ...);
+	void andRenderTypeMask(U32 type, ...);
+	void clearRenderTypeMask(U32 type, ...);
+	
+	void pushRenderTypeMask();
+	void popRenderTypeMask();
+
 	static void toggleRenderType(U32 type);
 
 	// For UI control of render features
@@ -362,6 +377,7 @@ public:
 		RENDER_TYPE_PASS_FULLBRIGHT_SHINY		= LLRenderPass::PASS_FULLBRIGHT_SHINY,
 		RENDER_TYPE_PASS_SHINY					= LLRenderPass::PASS_SHINY,
 		RENDER_TYPE_PASS_BUMP					= LLRenderPass::PASS_BUMP,
+		RENDER_TYPE_PASS_POST_BUMP				= LLRenderPass::PASS_POST_BUMP,
 		RENDER_TYPE_PASS_GLOW					= LLRenderPass::PASS_GLOW,
 		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
 		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,
@@ -372,7 +388,9 @@ public:
 		RENDER_TYPE_VOLUME,
 		RENDER_TYPE_PARTICLES,
 		RENDER_TYPE_CLOUDS,
-		RENDER_TYPE_HUD_PARTICLES
+		RENDER_TYPE_HUD_PARTICLES,
+		NUM_RENDER_TYPES,
+		END_RENDER_TYPES = NUM_RENDER_TYPES
 	};
 
 	enum LLRenderDebugFeatureMask
@@ -539,7 +557,9 @@ public:
 	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed
 
 protected:
-	U32						mRenderTypeMask;
+	BOOL					mRenderTypeEnabled[NUM_RENDER_TYPES];
+	std::stack<std::string> mRenderTypeEnableStack;
+
 	U32						mRenderDebugFeatureMask;
 	U32						mRenderDebugMask;
 
-- 
cgit v1.2.3