diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp
index f6fd8e557a8a911179a465adc4f4b96dd6550145..7d1ce4ab86d11aaec2905f05dfaa21471f452a6d 100644
--- a/indra/llprimitive/llmaterial.cpp
+++ b/indra/llprimitive/llmaterial.cpp
@@ -181,3 +181,36 @@ bool LLMaterial::operator != (const LLMaterial& rhs) const
 {
 	return !(*this == rhs);
 }
+
+
+U32 LLMaterial::getShaderMask()
+{ //NEVER incorporate this value into the message system -- this function will vary depending on viewer implementation
+	U32 ret = 0;
+
+	//two least significant bits are "diffuse alpha mode"
+	ret = getDiffuseAlphaMode();
+
+	llassert(ret < SHADER_COUNT);
+
+	//next bit is whether or not specular map is present
+	const U32 SPEC_BIT = 0x4;
+
+	if (getSpecularID().notNull())
+	{
+		ret |= SPEC_BIT;
+	}
+
+	llassert(ret < SHADER_COUNT);
+	
+	//next bit is whether or not normal map is present
+	const U32 NORM_BIT = 0x8;
+	if (getNormalID().notNull())
+	{
+		ret |= NORM_BIT;
+	}
+
+	llassert(ret < SHADER_COUNT);
+
+	return ret;
+}
+
diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h
index 5b56d11cd2cad1b7bdbe78c7f914b0a579e0cdd0..fd35045e457aaa5ce2658845e9232c9d04fffa98 100644
--- a/indra/llprimitive/llmaterial.h
+++ b/indra/llprimitive/llmaterial.h
@@ -36,6 +36,20 @@
 class LLMaterial
 {
 public:
+
+	typedef enum
+	{
+		DIFFUSE_ALPHA_MODE_NONE = 0,
+		DIFFUSE_ALPHA_MODE_BLEND = 1,
+		DIFFUSE_ALPHA_MODE_MASK = 2,
+		DIFFUSE_ALPHA_MODE_EMISSIVE = 3
+	} eDiffuseAlphaMode;
+
+	typedef enum
+	{
+		SHADER_COUNT = 16
+	} eShaderCount;
+	
 	LLMaterial();
 	LLMaterial(const LLSD& material_data);
 
@@ -77,6 +91,8 @@ class LLMaterial
 	bool		operator == (const LLMaterial& rhs) const;
 	bool		operator != (const LLMaterial& rhs) const;
 
+	U32			getShaderMask();
+
 protected:
 	LLUUID		mNormalID;
 	F32			mNormalOffsetX;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index 4f7fc6a411be097660d72a4ec21fa8b4ee8624f8..5392466b25407a1d5bc5bad413c5f490857406ab 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -23,6 +23,12 @@
  * $/LicenseInfo$
  */
  
+#define DIFFUSE_ALPHA_MODE_IGNORE 0
+#define DIFFUSE_ALPHA_MODE_BLEND 1
+#define DIFFUSE_ALPHA_MODE_MASK 2
+#define DIFFUSE_ALPHA_MODE_GLOW 3
+
+
 #ifdef DEFINE_GL_FRAGCOLOR
 out vec4 frag_data[3];
 #else
@@ -31,36 +37,52 @@ out vec4 frag_data[3];
 
 uniform sampler2D diffuseMap;
 
+#if HAS_NORMAL_MAP
 uniform sampler2D bumpMap;
+#endif
 
+#if HAS_SPECULAR_MAP
 uniform sampler2D specularMap;
 uniform float env_intensity;
+#endif
+
 uniform vec4 specular_color;
 
-#ifdef ALPHA_TEST
+#if DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK
 uniform float minimum_alpha;
 #endif
 
+#if HAS_NORMAL_MAP
 VARYING vec3 vary_mat0;
 VARYING vec3 vary_mat1;
 VARYING vec3 vary_mat2;
+#else
+VARYING vec3 vary_normal;
+#endif
 
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+
 void main() 
 {
-	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy) * vertex_color;
+	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
+	col.rgb *= vertex_color.rgb;
 
-	#ifdef ALPHA_TEST
+#if DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK
 	if (col.a < minimum_alpha)
 	{
 		discard;
 	}
-	#endif
-	
+#endif
+
+#if HAS_SPECULAR_MAP
 	vec4 spec = texture2D(specularMap, vary_texcoord0.xy);
+#else
+	vec4 spec = specular_color;
+#endif
 
+#if HAS_NORMAL_MAP
 	vec4 norm = texture2D(bumpMap, vary_texcoord0.xy);
 
 	norm.xyz = norm.xyz * 2 - 1;
@@ -68,19 +90,29 @@ void main()
 	vec3 tnorm = vec3(dot(norm.xyz,vary_mat0),
 			  dot(norm.xyz,vary_mat1),
 			  dot(norm.xyz,vary_mat2));
+#else
+	vec4 norm = vec4(0,0,0,1.0);
+	vec3 tnorm = vary_normal;
+#endif
 
 	vec4 final_color = col;
-	final_color.rgb *= 1 - spec.a * env_intensity;
-
-	#ifndef EMISSIVE_MASK
+	
+#if DIFFUSE_ALPHA_MODE != DIFFUSE_ALPHA_MODE_GLOW
 	final_color.a = 0;
-	#endif
+#endif
 
 	vec4 final_specular = spec;
+#if HAS_SPECULAR_MAP
+	//final_color.rgb *= 1 - spec.a * env_intensity;
 	final_specular.rgb *= specular_color.rgb;
-	final_specular.a = specular_color.a * norm.a;
-
+	
 	vec4 final_normal = vec4(normalize(tnorm), spec.a * env_intensity);
+	final_specular.a = specular_color.a * spec.a;
+#else
+	vec4 final_normal = vec4(normalize(tnorm), 0.0);
+	final_specular.a = spec.a;
+#endif
+
 	final_normal.xyz = final_normal.xyz * 0.5 + 0.5;
 	
 	frag_data[0] = final_color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
index c8d38bb8f74e72dd4ad681f1fb43b94cec2f6b00..f92ad63100cbe18bd145502dd793c1413c7b4735 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
@@ -31,11 +31,17 @@ ATTRIBUTE vec3 position;
 ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
+
+#if HAS_NORMAL_MAP
 ATTRIBUTE vec3 binormal;
 
 VARYING vec3 vary_mat0;
 VARYING vec3 vary_mat1;
 VARYING vec3 vary_mat2;
+#else
+VARYING vec3 vary_normal;
+#endif
+
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
@@ -45,13 +51,18 @@ void main()
 	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
+
 	vec3 n = normalize(normal_matrix * normal);
+#if HAS_NORMAL_MAP
 	vec3 b = normalize(normal_matrix * binormal);
 	vec3 t = cross(b, n);
 	
 	vary_mat0 = vec3(t.x, b.x, n.x);
 	vary_mat1 = vec3(t.y, b.y, n.y);
 	vary_mat2 = vec3(t.z, b.z, n.z);
+#else
+	vary_normal = n;
+#endif
 	
 	vertex_color = diffuse_color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 2905cc91b6e86a25e04dcee6dd6f76177b0ff7c9..f50935c1a84195c0f46cc802fdad2d716104409c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -310,7 +310,7 @@ void main()
 			//add environmentmap
 			vec3 env_vec = env_mat * refnormpersp;
 			col = mix(col.rgb, textureCube(environmentMap, env_vec).rgb, 
-				max(spec.a-diffuse.a*2.0, 0.0)); 
+				max(norm.a-diffuse.a*2.0, 0.0)); 
 		}
 	
 		col = atmosLighting(col);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 9df9d7590577d7ecce14892d8bd95057ac014242..ff20b639722216e1dd912d65127a234d3704a618 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -278,8 +278,8 @@ void main()
 	vec2 tc = vary_fragcoord.xy;
 	float depth = texture2DRect(depthMap, tc.xy).r;
 	vec3 pos = getPosition_d(tc, depth).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	vec4 norm = texture2DRect(normalMap, tc);
+	norm.xyz = (norm.xyz-0.5)*2.0; // unpack norm
 		
 	float da = max(dot(norm.xyz, sun_dir.xyz), 0.0);
 	
@@ -319,7 +319,7 @@ void main()
 			//add environmentmap
 			vec3 env_vec = env_mat * refnormpersp;
 			col = mix(col.rgb, textureCube(environmentMap, env_vec).rgb, 
-				max(spec.a-diffuse.a*2.0, 0.0)); 
+				max(norm.a-diffuse.a*2.0, 0.0)); 
 		}
 			
 		col = atmosLighting(col);
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index caa57ad583e3cb78759c9d1dce5662494a552eb9..77067cc1ec5135881212b3cc1ae214426cc09b39 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -134,7 +134,22 @@ class LLRenderPass : public LLDrawPool
 		PASS_SHINY,
 		PASS_BUMP,
 		PASS_POST_BUMP,
-		PASS_MATERIALS,
+		PASS_MATERIAL,
+		PASS_MATERIAL_ALPHA,
+		PASS_MATERIAL_ALPHA_MASK,
+		PASS_MATERIAL_ALPHA_GLOW,
+		PASS_SPECMAP,
+		PASS_SPECMAP_BLEND,
+		PASS_SPECMAP_MASK,
+		PASS_SPECMAP_GLOW,
+		PASS_NORMMAP,
+		PASS_NORMMAP_BLEND,
+		PASS_NORMMAP_MASK,
+		PASS_NORMMAP_GLOW,
+		PASS_NORMSPEC,
+		PASS_NORMSPEC_BLEND,
+		PASS_NORMSPEC_MASK,
+		PASS_NORMSPEC_GLOW,
 		PASS_GLOW,
 		PASS_ALPHA,
 		PASS_ALPHA_MASK,
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index f0e1221f159b591a652e36ef87f2766c2a282d8e..b126dc3b4a262eeb1b318de10f294f9dbb318e1a 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -44,20 +44,75 @@ void LLDrawPoolMaterials::prerender()
 	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); 
 }
 
+S32 LLDrawPoolMaterials::getNumDeferredPasses()
+{
+	return 12;
+}
+
 void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 {
+	U32 shader_idx[] = 
+	{
+		0, //LLRenderPass::PASS_MATERIAL,
+		//1, //LLRenderPass::PASS_MATERIAL_ALPHA,
+		2, //LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+		3, //LLRenderPass::PASS_MATERIAL_ALPHA_GLOW,
+		4, //LLRenderPass::PASS_SPECMAP,
+		//5, //LLRenderPass::PASS_SPECMAP_BLEND,
+		6, //LLRenderPass::PASS_SPECMAP_MASK,
+		7, //LLRenderPass::PASS_SPECMAP_GLOW,
+		8, //LLRenderPass::PASS_NORMMAP,
+		//9, //LLRenderPass::PASS_NORMMAP_BLEND,
+		10, //LLRenderPass::PASS_NORMMAP_MASK,
+		11, //LLRenderPass::PASS_NORMMAP_GLOW,
+		12, //LLRenderPass::PASS_NORMSPEC,
+		//13, //LLRenderPass::PASS_NORMSPEC_BLEND,
+		14, //LLRenderPass::PASS_NORMSPEC_MASK,
+		15, //LLRenderPass::PASS_NORMSPEC_GLOW,
+	};
+	
+	mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
+	mShader->bind();
+
+	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+		
 	LLFastTimer t(FTM_RENDER_MATERIALS);
 }
 
 void LLDrawPoolMaterials::endDeferredPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_MATERIALS);
+
+	mShader->unbind();
+
 	LLRenderPass::endRenderPass(pass);
 }
 
 void LLDrawPoolMaterials::renderDeferred(S32 pass)
 {
-	U32 type = LLRenderPass::PASS_MATERIALS;
+	U32 type_list[] = 
+	{
+		LLRenderPass::PASS_MATERIAL,
+		//LLRenderPass::PASS_MATERIAL_ALPHA,
+		LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+		LLRenderPass::PASS_MATERIAL_ALPHA_GLOW,
+		LLRenderPass::PASS_SPECMAP,
+		//LLRenderPass::PASS_SPECMAP_BLEND,
+		LLRenderPass::PASS_SPECMAP_MASK,
+		LLRenderPass::PASS_SPECMAP_GLOW,
+		LLRenderPass::PASS_NORMMAP,
+		//LLRenderPass::PASS_NORMMAP_BLEND,
+		LLRenderPass::PASS_NORMMAP_MASK,
+		LLRenderPass::PASS_NORMMAP_GLOW,
+		LLRenderPass::PASS_NORMSPEC,
+		//LLRenderPass::PASS_NORMSPEC_BLEND,
+		LLRenderPass::PASS_NORMSPEC_MASK,
+		LLRenderPass::PASS_NORMSPEC_GLOW,
+	};
+
+	llassert(pass < sizeof(type_list)/sizeof(U32));
+
+	U32 type = type_list[pass];
 	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
 	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 	
@@ -65,27 +120,6 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 	{
 		LLDrawInfo& params = **i;
 		
-		switch (params.mDiffuseAlphaMode)
-		{
-			case 0:
-				mShader = &gDeferredMaterialShinyNormal;
-				mShader->bind();
-				break;
-			case 1: // Alpha blending not supported in the opaque draw pool.
-				return;
-			case 2:
-				mShader = &gDeferredMaterialShinyNormalAlphaTest;
-				mShader->bind();
-				mShader->setMinimumAlpha(params.mAlphaMaskCutoff);
-				break;
-			case 3:
-				mShader = &gDeferredMaterialShinyNormalEmissive;
-				mShader->bind();
-				break;
-		};
-		
-		
-		
 		mShader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]);
 		mShader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity);
 		
@@ -101,10 +135,9 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
 			bindSpecularMap(params.mSpecularMap);
 		}
 		
-		diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+		mShader->setMinimumAlpha(params.mAlphaMaskCutoff);
+
 		pushBatch(params, VERTEX_DATA_MASK, TRUE);
-		mShader->disableTexture(LLShaderMgr::DIFFUSE_MAP);
-		mShader->unbind();
 	}
 }
 
@@ -118,72 +151,6 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex)
 	mShader->bindTexture(LLShaderMgr::BUMP_MAP, tex);
 }
 
-void LLDrawPoolMaterials::beginRenderPass(S32 pass)
-{
-	LLFastTimer t(FTM_RENDER_MATERIALS);
-	
-	// Materials isn't supported under forward rendering.
-	// Use the simple shaders to handle it instead.
-	// This is basically replicated from LLDrawPoolSimple.
-	
-	if (LLPipeline::sUnderWaterRender)
-	{
-		mShader = &gObjectSimpleWaterProgram;
-	}
-	else
-	{
-		mShader = &gObjectSimpleProgram;
-	}
-	
-	if (mVertexShaderLevel > 0)
-	{
-		mShader->bind();
-	}
-	else
-	{
-		// don't use shaders!
-		if (gGLManager.mHasShaderObjects)
-		{
-			LLGLSLShader::bindNoShader();
-		}
-	}
-}
-
-void LLDrawPoolMaterials::endRenderPass(S32 pass)
-{
-	LLFastTimer t(FTM_RENDER_MATERIALS);
-	stop_glerror();
-	LLRenderPass::endRenderPass(pass);
-	stop_glerror();
-	if (mVertexShaderLevel > 0)
-	{
-		mShader->unbind();
-	}
-}
-
-void LLDrawPoolMaterials::render(S32 pass)
-{
-	LLGLDisable blend(GL_BLEND);
-	
-	{ //render simple
-		LLFastTimer t(FTM_RENDER_MATERIALS);
-		gPipeline.enableLightsDynamic();
-		
-		if (mVertexShaderLevel > 0)
-		{
-			U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX;
-			
-			pushBatches(LLRenderPass::PASS_MATERIALS, mask, TRUE, TRUE);
-		}
-		else
-		{
-			LLGLDisable alpha_test(GL_ALPHA_TEST);
-			renderTexture(LLRenderPass::PASS_MATERIALS, getVertexDataMask());
-		}
-	}
-}
-
-
 void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
 {
 	applyModelMatrix(params);
diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h
index e8838c64d672619e1fe443f951d00a53c099f193..1f5565afc85eda29babe23d79b6ac0c70f446a85 100644
--- a/indra/newview/lldrawpoolmaterials.h
+++ b/indra/newview/lldrawpoolmaterials.h
@@ -55,13 +55,11 @@ class LLDrawPoolMaterials : public LLRenderPass
 	
 	/*virtual*/ U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
 	
-	/*virtual*/ void render(S32 pass = 0);
-	/*virtual*/ void beginRenderPass( S32 pass );
-	/*virtual*/ void endRenderPass( S32 pass );
-	/*virtual*/ S32	 getNumPasses() {return 1;}
+	/*virtual*/ void render(S32 pass = 0) { }
+	/*virtual*/ S32	 getNumPasses() {return 0;}
 	/*virtual*/ void prerender();
 	
-	/*virtual*/ S32 getNumDeferredPasses() {return 1;}
+	/*virtual*/ S32 getNumDeferredPasses();
 	/*virtual*/ void beginDeferredPass(S32 pass);
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index ffd7f1f1af6ca869d86876870c2a8d468d464609..25e92e27d9b25cca08ca7636de8ecf5a7805e8e1 100644
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -554,7 +554,8 @@ void LLMaterialMgr::processGetQueue()
 		postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
 
 		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id));
-		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << "'\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
+		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialSize << " materials." 
+			<< "'\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
 		LLHTTPClient::post(capURL, postData, materialsResponder);
 	}
 }
@@ -670,7 +671,7 @@ void LLMaterialMgr::processPutQueue()
 			LLSD putData = LLSD::emptyMap();
 			putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
 
-			LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces" << LL_ENDL;
+			LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
 			LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2));
 			LLHTTPClient::put(capURL, putData, materialsResponder);
 		}
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index cef07984e06661a413d70c3d12c1493f99d05767..71cd87cc852405ba2b6f2ea61c26cdf92b876285 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1087,7 +1087,7 @@ void render_hud_attachments()
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
-		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_MATERIALS);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_MATERIAL);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 17bfc24f43ccb594951863a27972cd0c9446778a..4e38d2f7e9738c3da405acc3e4ec3eee2d785f4c 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -208,15 +208,7 @@ LLGLSLShader			gDeferredStarProgram;
 LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
-LLGLSLShader			gDeferredMaterialShiny;
-LLGLSLShader			gDeferredMaterialNormal;
-LLGLSLShader			gDeferredMaterialShinyNormal;
-LLGLSLShader			gDeferredMaterialShinyAlphaTest;
-LLGLSLShader			gDeferredMaterialNormalAlphaTest;
-LLGLSLShader			gDeferredMaterialShinyNormalAlphaTest;
-LLGLSLShader			gDeferredMaterialShinyEmissive;
-LLGLSLShader			gDeferredMaterialNormalEmissive;
-LLGLSLShader			gDeferredMaterialShinyNormalEmissive;
+LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT];
 
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mVertexShaderLevel(SHADER_COUNT, 0),
@@ -1116,12 +1108,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredWLCloudProgram.unload();
 		gDeferredStarProgram.unload();
 		gNormalMapGenProgram.unload();
-		gDeferredMaterialShiny.unload();
-		gDeferredMaterialNormal.unload();
-		gDeferredMaterialShinyAlphaTest.unload();
-		gDeferredMaterialNormalAlphaTest.unload();
-		gDeferredMaterialShinyEmissive.unload();
-		gDeferredMaterialNormalEmissive.unload();
+		for (U32 i = 0; i < LLMaterial::SHADER_COUNT; ++i)
+		{
+			gDeferredMaterialProgram[i].unload();
+		}
 		return TRUE;
 	}
 
@@ -1236,114 +1226,28 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredBumpProgram.createShader(NULL, NULL);
 	}
 	
-	if (success)
-	{
-		gDeferredMaterialShiny.mName = "Deferred Shiny Material Shader";
-		gDeferredMaterialShiny.mShaderFiles.clear();
-		gDeferredMaterialShiny.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialShiny.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialShiny.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialShiny.addPermutation("SHINY_MATERIAL", "1");
-		success = gDeferredMaterialShiny.createShader(NULL, NULL);
-	}
-	
-	if (success)
-	{
-		gDeferredMaterialNormal.mName = "Deferred Normal Mapped Material Shader";
-		gDeferredMaterialNormal.mShaderFiles.clear();
-		gDeferredMaterialNormal.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialNormal.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialNormal.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialNormal.addPermutation("NORMAL_MATERIAL", "1");
-		success = gDeferredMaterialNormal.createShader(NULL, NULL);
-	}
-	
-	if (success)
-	{
-		gDeferredMaterialShinyNormal.mName = "Deferred Normal Mapped Shiny Material Shader";
-		gDeferredMaterialShinyNormal.mShaderFiles.clear();
-		gDeferredMaterialShinyNormal.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialShinyNormal.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialShinyNormal.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialShinyNormal.addPermutation("NORMAL_MATERIAL", "1");
-		gDeferredMaterialShinyNormal.addPermutation("SHINY_MATERIAL", "1");
-		success = gDeferredMaterialShinyNormal.createShader(NULL, NULL);
-	}
-	
-	if (success)
-	{
-		gDeferredMaterialShinyAlphaTest.mName = "Deferred Alpha Tested Shiny Material Shader";
-		gDeferredMaterialShinyAlphaTest.mShaderFiles.clear();
-		gDeferredMaterialShinyAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialShinyAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialShinyAlphaTest.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialShinyAlphaTest.addPermutation("SHINY_MATERIAL", "1");
-		gDeferredMaterialShinyAlphaTest.addPermutation("ALPHA_TEST", "1");
-		success = gDeferredMaterialShinyAlphaTest.createShader(NULL, NULL);
-	}
-	
-	if (success)
-	{
-		gDeferredMaterialNormalAlphaTest.mName = "Deferred Alpha Tested Normal Mapped Material Shader";
-		gDeferredMaterialNormalAlphaTest.mShaderFiles.clear();
-		gDeferredMaterialNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialNormalAlphaTest.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialNormalAlphaTest.addPermutation("NORMAL_MATERIAL", "1");
-		gDeferredMaterialNormalAlphaTest.addPermutation("ALPHA_TEST", "1");
-		success = gDeferredMaterialNormalAlphaTest.createShader(NULL, NULL);
-	}
-	
-	if (success)
-	{
-		gDeferredMaterialNormalAlphaTest.mName = "Deferred Alpha Tested Shiny Normal Mapped Material Shader";
-		gDeferredMaterialShinyNormalAlphaTest.mShaderFiles.clear();
-		gDeferredMaterialShinyNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialShinyNormalAlphaTest.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialShinyNormalAlphaTest.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialShinyNormalAlphaTest.addPermutation("NORMAL_MATERIAL", "1");
-		gDeferredMaterialShinyNormalAlphaTest.addPermutation("SHINY_MATERIAL", "1");
-		gDeferredMaterialShinyNormalAlphaTest.addPermutation("ALPHA_TEST", "1");
-		success = gDeferredMaterialShinyNormalAlphaTest.createShader(NULL, NULL);
-	}
-	
-	if (success)
-	{
-		gDeferredMaterialShinyEmissive.mName = "Deferred Emissive Mask Shiny Material Shader";
-		gDeferredMaterialShinyEmissive.mShaderFiles.clear();
-		gDeferredMaterialShinyEmissive.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialShinyEmissive.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialShinyEmissive.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialShinyEmissive.addPermutation("SHINY_MATERIAL", "1");
-		gDeferredMaterialShinyEmissive.addPermutation("EMISSIVE_MASK", "1");
-		success = gDeferredMaterialShinyEmissive.createShader(NULL, NULL);
-	}
-	
-	if (success)
-	{
-		gDeferredMaterialNormalEmissive.mName = "Deferred Emissive Mask Normal Mapped Material Shader";
-		gDeferredMaterialNormalEmissive.mShaderFiles.clear();
-		gDeferredMaterialNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialNormalEmissive.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialNormalEmissive.addPermutation("NORMAL_MATERIAL", "1");
-		gDeferredMaterialNormalEmissive.addPermutation("EMISSIVE_MASK", "1");
-		success = gDeferredMaterialNormalEmissive.createShader(NULL, NULL);
-	}
-	
-	if (success)
+
+	for (U32 i = 0; i < LLMaterial::SHADER_COUNT; ++i)
 	{
-		gDeferredMaterialShinyNormalEmissive.mName = "Deferred Emissive Mask Normal Mapped Material Shader";
-		gDeferredMaterialShinyNormalEmissive.mShaderFiles.clear();
-		gDeferredMaterialShinyNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMaterialShinyNormalEmissive.mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMaterialShinyNormalEmissive.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-		gDeferredMaterialShinyNormalEmissive.addPermutation("NORMAL_MATERIAL", "1");
-		gDeferredMaterialShinyNormalEmissive.addPermutation("SHINY_MATERIAL", "1");
-		gDeferredMaterialShinyNormalEmissive.addPermutation("EMISSIVE_MASK", "1");
-		success = gDeferredMaterialShinyNormalEmissive.createShader(NULL, NULL);
+		if (success)
+		{
+			gDeferredMaterialProgram[i].mName = llformat("Deferred Material Shader %d", i);
+			
+			U32 alpha_mode = i & 0x3;
+
+			gDeferredMaterialProgram[i].mShaderFiles.clear();
+			gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredMaterialProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			gDeferredMaterialProgram[i].addPermutation("HAS_NORMAL_MAP", i & 0x8? "1" : "0");
+			gDeferredMaterialProgram[i].addPermutation("HAS_SPECULAR_MAP", i & 0x4 ? "1" : "0");
+			gDeferredMaterialProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+
+			success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
+		}
 	}
 
+	
 	if (success)
 	{
 		gDeferredTreeProgram.mName = "Deferred Tree Shader";
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 15bff6882ee8239818efe1b733da9623eff69145..f0bf352e755a67d2a5730650a56d5fd8c6aa257f 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -28,6 +28,7 @@
 #define LL_VIEWER_SHADER_MGR_H
 
 #include "llshadermgr.h"
+#include "llmaterial.h"
 
 class LLViewerShaderMgr: public LLShaderMgr
 {
@@ -363,14 +364,6 @@ extern LLGLSLShader			gDeferredStarProgram;
 extern LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
-extern LLGLSLShader			gDeferredMaterialShiny;
-extern LLGLSLShader			gDeferredMaterialNormal;
-extern LLGLSLShader			gDeferredMaterialShinyNormal;
-extern LLGLSLShader			gDeferredMaterialShinyAlphaTest;
-extern LLGLSLShader			gDeferredMaterialNormalAlphaTest;
-extern LLGLSLShader			gDeferredMaterialShinyNormalAlphaTest;
-extern LLGLSLShader			gDeferredMaterialShinyEmissive;
-extern LLGLSLShader			gDeferredMaterialNormalEmissive;
-extern LLGLSLShader			gDeferredMaterialShinyNormalEmissive;
+extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT];
 
 #endif
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 44eefd3c4abdf634df51d439f7398b8ec6b88938..f149c5088431659ddda1d8439cca1ff7895116bc 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -4143,16 +4143,16 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 				// We have a material.  Update our draw info accordingly.
 				draw_info->mMaterialID = &facep->getTextureEntry()->getMaterialID();
 				LLVector4 specColor;
-				specColor.mV[0] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightColor().mV[0] * (1.0 / 255);
-				specColor.mV[1] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightColor().mV[1] * (1.0 / 255);
-				specColor.mV[2] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightColor().mV[2] * (1.0 / 255);
-				specColor.mV[3] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightExponent() * (1.0 / 255);
+				specColor.mV[0] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightColor().mV[0] * (1.f / 255.f);
+				specColor.mV[1] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightColor().mV[1] * (1.f / 255.f);
+				specColor.mV[2] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightColor().mV[2] * (1.f / 255.f);
+				specColor.mV[3] = facep->getTextureEntry()->getMaterialParams()->getSpecularLightExponent() * (1.f / 255.f);
 				draw_info->mSpecColor = specColor;
-				draw_info->mEnvIntensity = facep->getTextureEntry()->getMaterialParams()->getEnvironmentIntensity() * (1.0 / 255);
-				draw_info->mAlphaMaskCutoff = facep->getTextureEntry()->getMaterialParams()->getAlphaMaskCutoff() * (1.0 / 255);
+				draw_info->mEnvIntensity = facep->getTextureEntry()->getMaterialParams()->getEnvironmentIntensity() * (1.f / 255.f);
+				draw_info->mAlphaMaskCutoff = facep->getTextureEntry()->getMaterialParams()->getAlphaMaskCutoff() * (1.f / 255.f);
 				draw_info->mDiffuseAlphaMode = facep->getTextureEntry()->getMaterialParams()->getDiffuseAlphaMode();
-				draw_info->mNormalMap = facep->getViewerObject()->getTENormalMap(facep->getTextureIndex());
-				draw_info->mSpecularMap = facep->getViewerObject()->getTESpecularMap(facep->getTextureIndex());
+				draw_info->mNormalMap = facep->getViewerObject()->getTENormalMap(facep->getTEOffset());
+				draw_info->mSpecularMap = facep->getViewerObject()->getTESpecularMap(facep->getTEOffset());
 			}
 		} else {
 			U8 shiny = facep->getTextureEntry()->getShiny();
@@ -5151,7 +5151,39 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 
 			BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE;
 		
-			if (is_alpha)
+			LLMaterial* mat = te->getMaterialParams().get();
+
+			if (mat && LLPipeline::sRenderDeferred && !hud_group)
+			{
+				U32 pass[] = 
+				{
+					LLRenderPass::PASS_MATERIAL,
+					LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_MATERIAL_ALPHA,
+					LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+					LLRenderPass::PASS_MATERIAL_ALPHA_GLOW,
+					LLRenderPass::PASS_SPECMAP,
+					LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_SPECMAP_BLEND,
+					LLRenderPass::PASS_SPECMAP_MASK,
+					LLRenderPass::PASS_SPECMAP_GLOW,
+					LLRenderPass::PASS_NORMMAP,
+					LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMMAP_BLEND,
+					LLRenderPass::PASS_NORMMAP_MASK,
+					LLRenderPass::PASS_NORMMAP_GLOW,
+					LLRenderPass::PASS_NORMSPEC,
+					LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMSPEC_BLEND,
+					LLRenderPass::PASS_NORMSPEC_MASK,
+					LLRenderPass::PASS_NORMSPEC_GLOW,
+				};
+
+				U32 mask = mat->getShaderMask();
+
+				llassert(mask < sizeof(pass)/sizeof(U32));
+
+				mask = llmin(mask, sizeof(pass)/sizeof(U32)-1);
+
+				registerFace(group, facep, pass[mask]);
+			}
+			else if (is_alpha)
 			{
 				// can we safely treat this as an alpha mask?
 				if (facep->getFaceColor().mV[3] <= 0.f)
@@ -5197,10 +5229,6 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 					{ //register in deferred bump pass
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
-					else if (te->getMaterialParams())
-					{
-						registerFace(group, facep, LLRenderPass::PASS_MATERIALS);
-					}
 					else
 					{ //register in deferred simple pass (deferred simple includes shiny)
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
@@ -5236,10 +5264,6 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 					{ //non-shiny or fullbright deferred bump
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
-					else if (te->getMaterialParams())
-					{
-						registerFace(group, facep, LLRenderPass::PASS_MATERIALS);
-					}
 					else
 					{ //all around simple
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index d8f7f8350a8c2b087eaeaf9164690c1437dff405..c5fedab8c03671bb9b2673f4770e37537c74a4d0 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -399,7 +399,7 @@ void validate_framebuffer_object();
 bool addDeferredAttachments(LLRenderTarget& target)
 {
 	return target.addColorAttachment(GL_RGBA) && //specular
-			target.addColorAttachment(GL_RGB10_A2); //normal+z
+			target.addColorAttachment(GL_RGBA); //normal+z
 }
 
 LLPipeline::LLPipeline() :
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 22a0ca6a2fb7f4590738085bc9100905edf43f60..fd4813e41537f6e7c0b7c02cd75de86545f31a33 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -437,7 +437,7 @@ class LLPipeline
 		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_MATERIALS				= LLRenderPass::PASS_MATERIALS,
+		RENDER_TYPE_PASS_MATERIAL				= LLRenderPass::PASS_MATERIAL,
 		RENDER_TYPE_PASS_GLOW					= LLRenderPass::PASS_GLOW,
 		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
 		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,