Bug 926128 - Use a single configurable shader in OpenGL layers backend. r=vlad, r=nical
☠☠ backed out by 5bb07c1ae9f5 ☠ ☠
authorAndreas Gal <gal@uci.edu>
Fri, 01 Nov 2013 09:29:20 -0400
changeset 153042 f24ee0606ea6dde62653d13b9d980806189cd3ee
parent 153041 38a50c61c285dc932512dd80f1bf6d2049488b2e
child 153043 d9aa2d2a9939cb68cb37476273ce9cb056cb1b74
push id25566
push userryanvm@gmail.com
push dateFri, 01 Nov 2013 18:40:05 +0000
treeherdermozilla-central@5bb07c1ae9f5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad, nical
bugs926128
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 926128 - Use a single configurable shader in OpenGL layers backend. r=vlad, r=nical
gfx/layers/CompositorTypes.h
gfx/layers/Effects.h
gfx/layers/basic/BasicCompositor.cpp
gfx/layers/d3d11/CompositorD3D11.cpp
gfx/layers/d3d11/CompositorD3D11.h
gfx/layers/d3d9/CompositorD3D9.cpp
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ColorLayerOGL.cpp
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/FPSCounter.h
gfx/layers/opengl/GLManager.cpp
gfx/layers/opengl/GLManager.h
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/LayerManagerOGLProgram.cpp
gfx/layers/opengl/LayerManagerOGLProgram.h
gfx/layers/opengl/LayerManagerOGLShaders.h
gfx/layers/opengl/LayerManagerOGLShaders.txt
gfx/layers/opengl/TextureHostOGL.h
gfx/layers/opengl/ThebesLayerOGL.cpp
widget/cocoa/nsChildView.mm
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -116,20 +116,17 @@ const DiagnosticFlags DIAGNOSTIC_REGION_
 
 /**
  * See gfx/layers/Effects.h
  */
 enum EffectTypes
 {
   EFFECT_MASK,
   EFFECT_MAX_SECONDARY, // sentinel for the count of secondary effect types
-  EFFECT_BGRX,
-  EFFECT_RGBX,
-  EFFECT_BGRA,
-  EFFECT_RGBA,
+  EFFECT_RGB,
   EFFECT_YCBCR,
   EFFECT_COMPONENT_ALPHA,
   EFFECT_SOLID_COLOR,
   EFFECT_RENDER_TARGET,
   EFFECT_MAX  //sentinel for the count of all effect types
 };
 
 /**
--- a/gfx/layers/Effects.h
+++ b/gfx/layers/Effects.h
@@ -108,66 +108,27 @@ struct EffectRenderTarget : public Textu
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() { return "EffectRenderTarget"; }
   virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
 #endif
 
   RefPtr<CompositingRenderTarget> mRenderTarget;
 };
 
-struct EffectBGRX : public TexturedEffect
+struct EffectRGB : public TexturedEffect
 {
-  EffectBGRX(TextureSource *aBGRXTexture,
-             bool aPremultiplied,
-             gfx::Filter aFilter,
-             bool aFlipped = false)
-    : TexturedEffect(EFFECT_BGRX, aBGRXTexture, aPremultiplied, aFilter)
-  {}
-
-#ifdef MOZ_LAYERS_HAVE_LOG
-  virtual const char* Name() { return "EffectBGRX"; }
-#endif
-};
-
-struct EffectRGBX : public TexturedEffect
-{
-  EffectRGBX(TextureSource *aRGBXTexture,
-             bool aPremultiplied,
-             gfx::Filter aFilter)
-    : TexturedEffect(EFFECT_RGBX, aRGBXTexture, aPremultiplied, aFilter)
+  EffectRGB(TextureSource *aTexture,
+            bool aPremultiplied,
+            gfx::Filter aFilter,
+            bool aFlipped = false)
+    : TexturedEffect(EFFECT_RGB, aTexture, aPremultiplied, aFilter)
   {}
 
 #ifdef MOZ_LAYERS_HAVE_LOG
-  virtual const char* Name() { return "EffectRGBX"; }
-#endif
-};
-
-struct EffectBGRA : public TexturedEffect
-{
-  EffectBGRA(TextureSource *aBGRATexture,
-             bool aPremultiplied,
-             gfx::Filter aFilter)
-    : TexturedEffect(EFFECT_BGRA, aBGRATexture, aPremultiplied, aFilter)
-  {}
-
-#ifdef MOZ_LAYERS_HAVE_LOG
-  virtual const char* Name() { return "EffectBGRA"; }
-#endif
-};
-
-struct EffectRGBA : public TexturedEffect
-{
-  EffectRGBA(TextureSource *aRGBATexture,
-             bool aPremultiplied,
-             gfx::Filter aFilter)
-    : TexturedEffect(EFFECT_RGBA, aRGBATexture, aPremultiplied, aFilter)
-  {}
-
-#ifdef MOZ_LAYERS_HAVE_LOG
-  virtual const char* Name() { return "EffectRGBA"; }
+  virtual const char* Name() { return "EffectRGB"; }
 #endif
 };
 
 struct EffectYCbCr : public TexturedEffect
 {
   EffectYCbCr(TextureSource *aSource, gfx::Filter aFilter)
     : TexturedEffect(EFFECT_YCBCR, aSource, false, aFilter)
   {}
@@ -227,30 +188,22 @@ struct EffectChain
 inline TemporaryRef<TexturedEffect>
 CreateTexturedEffect(gfx::SurfaceFormat aFormat,
                      TextureSource* aSource,
                      const gfx::Filter& aFilter)
 {
   MOZ_ASSERT(aSource);
   RefPtr<TexturedEffect> result;
   switch (aFormat) {
-  case gfx::FORMAT_B8G8R8A8:
-    result = new EffectBGRA(aSource, true, aFilter);
-    break;
-  case gfx::FORMAT_B8G8R8X8:
-    result = new EffectBGRX(aSource, true, aFilter);
-    break;
+  case gfx::FORMAT_R8G8B8A8:
   case gfx::FORMAT_R8G8B8X8:
-    result = new EffectRGBX(aSource, true, aFilter);
-    break;
+  case gfx::FORMAT_B8G8R8A8:
+  case gfx::FORMAT_B8G8R8X8:
   case gfx::FORMAT_R5G6B5:
-    result = new EffectRGBX(aSource, true, aFilter);
-    break;
-  case gfx::FORMAT_R8G8B8A8:
-    result = new EffectRGBA(aSource, true, aFilter);
+    result = new EffectRGB(aSource, true, aFilter);
     break;
   case gfx::FORMAT_YUV:
     result = new EffectYCbCr(aSource, aFilter);
     break;
   default:
     MOZ_CRASH("unhandled program type");
   }
 
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -365,20 +365,17 @@ BasicCompositor::DrawQuad(const gfx::Rec
       EffectSolidColor* effectSolidColor =
         static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
 
       dest->FillRect(aRect,
                      ColorPattern(effectSolidColor->mColor),
                      DrawOptions(aOpacity));
       break;
     }
-    case EFFECT_BGRA:
-    case EFFECT_BGRX:
-    case EFFECT_RGBA:
-    case EFFECT_RGBX: {
+    case EFFECT_RGB: {
       TexturedEffect* texturedEffect =
           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
       TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();
 
       DrawSurfaceWithTextureCoords(dest, aRect,
                                    source->GetSurface(),
                                    texturedEffect->mTextureCoords,
                                    aOpacity, sourceMask, maskTransform);
--- a/gfx/layers/d3d11/CompositorD3D11.cpp
+++ b/gfx/layers/d3d11/CompositorD3D11.cpp
@@ -445,28 +445,29 @@ CompositorD3D11::SetRenderTarget(Composi
     static_cast<CompositingRenderTargetD3D11*>(aRenderTarget);
   ID3D11RenderTargetView* view = newRT->mRTView;
   mCurrentRT = newRT;
   mContext->OMSetRenderTargets(1, &view, nullptr);
   PrepareViewport(newRT->GetSize(), gfxMatrix());
 }
 
 void
-CompositorD3D11::SetPSForEffect(Effect* aEffect, MaskType aMaskType)
+CompositorD3D11::SetPSForEffect(Effect* aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat)
 {
   switch (aEffect->mType) {
   case EFFECT_SOLID_COLOR:
     mContext->PSSetShader(mAttachments->mSolidColorShader[aMaskType], nullptr, 0);
     return;
-  case EFFECT_BGRA:
   case EFFECT_RENDER_TARGET:
     mContext->PSSetShader(mAttachments->mRGBAShader[aMaskType], nullptr, 0);
     return;
-  case EFFECT_BGRX:
-    mContext->PSSetShader(mAttachments->mRGBShader[aMaskType], nullptr, 0);
+  case EFFECT_RGB:
+    mContext->PSSetShader((aFormat == FORMAT_B8G8R8A8 || aFormat == FORMAT_R8G8B8A8)
+                          ? mAttachments->mRGBAShader[aMaskType]
+                          : mAttachments->mRGBShader[aMaskType], nullptr, 0);
     return;
   case EFFECT_YCBCR:
     mContext->PSSetShader(mAttachments->mYCbCrShader[aMaskType], nullptr, 0);
     return;
   case EFFECT_COMPONENT_ALPHA:
     mContext->PSSetShader(mAttachments->mComponentAlphaShader[aMaskType], nullptr, 0);
     return;
   default:
@@ -494,17 +495,17 @@ CompositorD3D11::DrawQuad(const gfx::Rec
   bool restoreBlendMode = false;
 
   MaskType maskType = MaskNone;
 
   if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
     if (aTransform.Is2D()) {
       maskType = Mask2d;
     } else {
-      MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EFFECT_BGRA);
+      MOZ_ASSERT(aEffectChain.mPrimaryEffect->mType == EFFECT_RGB);
       maskType = Mask3d;
     }
 
     EffectMask* maskEffect =
       static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
     TextureSourceD3D11* source = maskEffect->mMaskTexture->AsSourceD3D11();
 
     RefPtr<ID3D11ShaderResourceView> view;
@@ -525,35 +526,35 @@ CompositorD3D11::DrawQuad(const gfx::Rec
   scissor.left = aClipRect.x;
   scissor.right = aClipRect.XMost();
   scissor.top = aClipRect.y;
   scissor.bottom = aClipRect.YMost();
   mContext->RSSetScissorRects(1, &scissor);
   mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
   mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0);
 
-  SetPSForEffect(aEffectChain.mPrimaryEffect, maskType);
-
   switch (aEffectChain.mPrimaryEffect->mType) {
   case EFFECT_SOLID_COLOR: {
+      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, FORMAT_UNKNOWN);
       Color color =
         static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get())->mColor;
       mPSConstants.layerColor[0] = color.r * color.a * aOpacity;
       mPSConstants.layerColor[1] = color.g * color.a * aOpacity;
       mPSConstants.layerColor[2] = color.b * color.a * aOpacity;
       mPSConstants.layerColor[3] = color.a * aOpacity;
     }
     break;
-  case EFFECT_BGRX:
-  case EFFECT_BGRA:
+  case EFFECT_RGB:
   case EFFECT_RENDER_TARGET:
     {
       TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
 
+      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, texturedEffect->mTexture->GetFormat());
+
       mVSConstants.textureCoords = texturedEffect->mTextureCoords;
 
       TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();
 
       RefPtr<ID3D11ShaderResourceView> view;
       mDevice->CreateShaderResourceView(source->GetD3D11Texture(), nullptr, byRef(view));
 
       ID3D11ShaderResourceView* srView = view;
@@ -566,16 +567,18 @@ CompositorD3D11::DrawQuad(const gfx::Rec
 
       SetSamplerForFilter(texturedEffect->mFilter);
     }
     break;
   case EFFECT_YCBCR: {
       EffectYCbCr* ycbcrEffect =
         static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
 
+      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, ycbcrEffect->mTexture->GetFormat());
+
       SetSamplerForFilter(FILTER_LINEAR);
 
       mVSConstants.textureCoords = ycbcrEffect->mTextureCoords;
 
       TextureSourceD3D11* source = ycbcrEffect->mTexture->AsSourceD3D11();
       TextureSourceD3D11::YCbCrTextures textures = source->GetYCbCrTextures();
 
       RefPtr<ID3D11ShaderResourceView> views[3];
@@ -588,16 +591,19 @@ CompositorD3D11::DrawQuad(const gfx::Rec
     }
     break;
   case EFFECT_COMPONENT_ALPHA:
     {
       MOZ_ASSERT(gfxPlatform::ComponentAlphaEnabled());
       MOZ_ASSERT(mAttachments->mComponentBlendState);
       EffectComponentAlpha* effectComponentAlpha =
         static_cast<EffectComponentAlpha*>(aEffectChain.mPrimaryEffect.get());
+
+      SetPSForEffect(aEffectChain.mPrimaryEffect, maskType, effectComponentAlpha->mTexture->GetFormat());
+
       TextureSourceD3D11* sourceOnWhite = effectComponentAlpha->mOnWhite->AsSourceD3D11();
       TextureSourceD3D11* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceD3D11();
       SetSamplerForFilter(effectComponentAlpha->mFilter);
 
       mVSConstants.textureCoords = effectComponentAlpha->mTextureCoords;
       RefPtr<ID3D11ShaderResourceView> views[2];
       mDevice->CreateShaderResourceView(sourceOnBlack->GetD3D11Texture(), nullptr, byRef(views[0]));
       mDevice->CreateShaderResourceView(sourceOnWhite->GetD3D11Texture(), nullptr, byRef(views[1]));
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -152,17 +152,17 @@ public:
 private:
   // ensure mSize is up to date with respect to mWidget
   void EnsureSize();
   void VerifyBufferSize();
   void UpdateRenderTarget();
   bool CreateShaders();
   void UpdateConstantBuffers();
   void SetSamplerForFilter(gfx::Filter aFilter);
-  void SetPSForEffect(Effect *aEffect, MaskType aMaskType);
+  void SetPSForEffect(Effect *aEffect, MaskType aMaskType, gfx::SurfaceFormat aFormat);
   void PaintToTarget();
 
   RefPtr<ID3D11DeviceContext> mContext;
   RefPtr<ID3D11Device> mDevice;
   RefPtr<IDXGISwapChain> mSwapChain;
   RefPtr<CompositingRenderTargetD3D11> mDefaultRT;
   RefPtr<CompositingRenderTargetD3D11> mCurrentRT;
 
--- a/gfx/layers/d3d9/CompositorD3D9.cpp
+++ b/gfx/layers/d3d9/CompositorD3D9.cpp
@@ -167,25 +167,26 @@ CompositorD3D9::SetRenderTarget(Composit
   MOZ_ASSERT(aRenderTarget);
   RefPtr<CompositingRenderTargetD3D9> oldRT = mCurrentRT;
   mCurrentRT = static_cast<CompositingRenderTargetD3D9*>(aRenderTarget);
   mCurrentRT->BindRenderTarget(device());
   PrepareViewport(mCurrentRT->GetSize(), gfxMatrix());
 }
 
 static DeviceManagerD3D9::ShaderMode
-ShaderModeForEffectType(EffectTypes aEffectType)
+ShaderModeForEffectType(EffectTypes aEffectType, gfx::SurfaceFormat aFormat)
 {
   switch (aEffectType) {
   case EFFECT_SOLID_COLOR:
     return DeviceManagerD3D9::SOLIDCOLORLAYER;
-  case EFFECT_BGRA:
   case EFFECT_RENDER_TARGET:
     return DeviceManagerD3D9::RGBALAYER;
-  case EFFECT_BGRX:
+  case EFFECT_RGB:
+    if (aFormat == FORMAT_B8G8R8A8 || aFormat == FORMAT_R8G8B8A8)
+      return DeviceManagerD3D9::RGBALAYER;
     return DeviceManagerD3D9::RGBLAYER;
   case EFFECT_YCBCR:
     return DeviceManagerD3D9::YCBCRLAYER;
   }
 
   MOZ_CRASH("Bad effect type");
 }
 
@@ -254,18 +255,17 @@ CompositorD3D9::DrawQuad(const gfx::Rect
 
       device()->SetPixelShaderConstantF(CBvColor, color, 1);
 
       maskTexture = mDeviceManager
         ->SetShaderMode(DeviceManagerD3D9::SOLIDCOLORLAYER, maskType);
     }
     break;
   case EFFECT_RENDER_TARGET:
-  case EFFECT_BGRX:
-  case EFFECT_BGRA:
+  case EFFECT_RGB:
     {
       TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
 
       Rect textureCoords = texturedEffect->mTextureCoords;
       device()->SetVertexShaderConstantF(CBvTextureCoords,
                                          ShaderConstantRect(
                                            textureCoords.x,
@@ -275,17 +275,18 @@ CompositorD3D9::DrawQuad(const gfx::Rect
                                          1);
 
       SetSamplerForFilter(texturedEffect->mFilter);
 
       TextureSourceD3D9* source = texturedEffect->mTexture->AsSourceD3D9();
       device()->SetTexture(0, source->GetD3D9Texture());
 
       maskTexture = mDeviceManager
-        ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType),
+        ->SetShaderMode(ShaderModeForEffectType(aEffectChain.mPrimaryEffect->mType,
+                                                texturedEffect->mTexture->GetFormat()),
                         maskType);
 
       isPremultiplied = texturedEffect->mPremultiplied;
     }
     break;
   case EFFECT_YCBCR:
     {
       EffectYCbCr* ycbcrEffect =
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -342,16 +342,17 @@ CanvasLayerOGL::RenderLayer(int aPreviou
   if (mPixmap && !mDelayedUpdates) {
     sDefGLXLib.BindTexImage(mPixmap);
   }
 #endif
 
   gl()->ApplyFilterToBoundTexture(mFilter);
 
   program->Activate();
+  program->SetProjectionMatrix(mOGLManager->mProjMatrix);
   if (mLayerProgram == RGBARectLayerProgramType ||
       mLayerProgram == RGBXRectLayerProgramType) {
     // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
     program->SetTexCoordMultiplier(mBounds.width, mBounds.height);
   }
   program->SetLayerQuadRect(drawRect);
   program->SetLayerTransform(GetEffectiveTransform());
   program->SetTextureTransform(gfx3DMatrix());
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -35,16 +35,17 @@ RenderColorLayer(ColorLayer* aLayer, Lay
   color.r *= opacity;
   color.g *= opacity;
   color.b *= opacity;
   color.a = opacity;
 
   ShaderProgramOGL *program = aManager->GetProgram(ColorLayerProgramType,
                                                    aLayer->GetMaskLayer());
   program->Activate();
+  program->SetProjectionMatrix(aManager->mProjMatrix);
   program->SetLayerQuadRect(aLayer->GetBounds());
   program->SetLayerTransform(aLayer->GetEffectiveTransform());
   program->SetRenderOffset(aOffset);
   program->SetRenderColor(color);
   program->LoadMask(aLayer->GetMaskLayer());
 
   aManager->BindAndDrawQuad(program);
 }
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -34,31 +34,114 @@
 #include "nsAString.h"
 #include "nsIConsoleService.h"          // for nsIConsoleService, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsMathUtils.h"                // for NS_roundf
 #include "nsRect.h"                     // for nsIntRect
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"                   // for nsString, nsAutoCString, etc
+#include "LayerManagerOGLShaders.h"     // for shader programs
 
 #if MOZ_ANDROID_OMTC
 #include "TexturePoolOGL.h"
 #endif
 #include "GeckoProfiler.h"
 
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 using namespace mozilla::gl;
 
+enum ShaderFeatures {
+  ENABLE_RENDER_COLOR=0x01,
+  ENABLE_TEXTURE_RECT=0x02,
+  ENABLE_TEXTURE_EXTERNAL=0x04,
+  ENABLE_TEXTURE_YCBCR=0x08,
+  ENABLE_TEXTURE_COMPONENT_ALPHA=0x10,
+  ENABLE_TEXTURE_NO_ALPHA=0x20,
+  ENABLE_TEXTURE_RB_SWAP=0x40,
+  ENABLE_OPACITY=0x80,
+  ENABLE_BLUR=0x100,
+  ENABLE_COLOR_MATRIX=0x200,
+  ENABLE_MASK=0x400
+};
+
+void
+ShaderConfigOGL::SetRenderColor(bool aEnabled)
+{
+  SetFeature(ENABLE_RENDER_COLOR, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetTextureTarget(GLenum aTarget)
+{
+  SetFeature(ENABLE_TEXTURE_EXTERNAL | ENABLE_TEXTURE_RECT, false);
+  switch (aTarget) {
+  case LOCAL_GL_TEXTURE_EXTERNAL:
+    SetFeature(ENABLE_TEXTURE_EXTERNAL, true);
+    break;
+  case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
+    SetFeature(ENABLE_TEXTURE_RECT, true);
+    break;
+  }
+}
+
+void
+ShaderConfigOGL::SetRBSwap(bool aEnabled)
+{
+  SetFeature(ENABLE_TEXTURE_RB_SWAP, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetNoAlpha(bool aEnabled)
+{
+  SetFeature(ENABLE_TEXTURE_NO_ALPHA, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetOpacity(bool aEnabled)
+{
+  SetFeature(ENABLE_OPACITY, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetYCbCr(bool aEnabled)
+{
+  SetFeature(ENABLE_TEXTURE_YCBCR, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetComponentAlpha(bool aEnabled)
+{
+  SetFeature(ENABLE_TEXTURE_COMPONENT_ALPHA, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetColorMatrix(bool aEnabled)
+{
+  SetFeature(ENABLE_COLOR_MATRIX, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetBlur(bool aEnabled)
+{
+  SetFeature(ENABLE_BLUR, aEnabled);
+}
+
+void
+ShaderConfigOGL::SetMask(bool aEnabled)
+{
+  SetFeature(ENABLE_MASK, aEnabled);
+}
+
 static inline IntSize ns2gfxSize(const nsIntSize& s) {
   return IntSize(s.width, s.height);
 }
 
 // Draw the given quads with the already selected shader. Texture coordinates
 // are supplied if the shader requires them.
 static void
 DrawQuads(GLContext *aGLContext,
@@ -152,27 +235,24 @@ AddDigits(GLContext::RectTriangles &aRec
                    t.x, t.y, t.x + t.width, t.y + t.height,
                    false);
     divisor /= 10;
     ++aOffset;
   }
 }
 
 void
-FPSState::DrawFPS(TimeStamp aNow,
-                  unsigned int aFillRatio,
-                  GLContext* aContext,
-                  ShaderProgramOGL* aProgram)
+CompositorOGL::DrawFPS()
 {
-  if (!mTexture) {
+  if (!mFPSTexture) {
     // Bind the number of textures we need, in this case one.
-    aContext->fGenTextures(1, &mTexture);
-    aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
-    aContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
+    mGLContext->fGenTextures(1, &mFPSTexture);
+    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mFPSTexture);
+    mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MIN_FILTER,LOCAL_GL_NEAREST);
+    mGLContext->fTexParameteri(LOCAL_GL_TEXTURE_2D,LOCAL_GL_TEXTURE_MAG_FILTER,LOCAL_GL_NEAREST);
 
     const char *text =
       "                                         "
       " XXX XX  XXX XXX X X XXX XXX XXX XXX XXX "
       " X X  X    X   X X X X   X     X X X X X "
       " X X  X  XXX XXX XXX XXX XXX   X XXX XXX "
       " X X  X  X     X   X   X X X   X X X   X "
       " XXX XXX XXX XXX   X XXX XXX   X XXX   X "
@@ -182,67 +262,79 @@ FPSState::DrawFPS(TimeStamp aNow,
     uint32_t* buf = (uint32_t *) malloc(64 * 8 * sizeof(uint32_t));
     for (int i = 0; i < 7; i++) {
       for (int j = 0; j < 41; j++) {
         uint32_t purple = 0xfff000ff;
         uint32_t white  = 0xffffffff;
         buf[i * 64 + j] = (text[i * 41 + j] == ' ') ? purple : white;
       }
     }
-    aContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
+    mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 64, 8, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, buf);
     free(buf);
   }
 
-  mVBOs.Reset();
+  TimeStamp now = TimeStamp::Now();
+
+  unsigned int fps = unsigned(mFPS->mCompositionFps.AddFrameAndGetFps(now));
+  unsigned int txnFps = unsigned(mFPS->mTransactionFps.GetFpsAt(now));
+
+  float fillRatio = 0;
+  if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
+    fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
+    if (fillRatio > 999.0f)
+      fillRatio = 999.0f;
+  }
 
   GLint viewport[4];
-  aContext->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
+  mGLContext->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
   gfx::IntSize viewportSize(viewport[2], viewport[3]);
 
-  unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
-  unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow));
-
   GLContext::RectTriangles rects;
   AddDigits(rects, viewportSize, 0, fps);
   AddDigits(rects, viewportSize, 4, txnFps);
-  AddDigits(rects, viewportSize, 8, aFillRatio);
+  AddDigits(rects, viewportSize, 8, unsigned(fillRatio));
 
   // Turn necessary features on
-  aContext->fEnable(LOCAL_GL_BLEND);
-  aContext->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
+  mGLContext->fEnable(LOCAL_GL_BLEND);
+  mGLContext->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
 
-  aContext->fActiveTexture(LOCAL_GL_TEXTURE0);
-  aContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+  mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mFPSTexture);
+
+  ShaderConfigOGL config = GetShaderConfigFor(LOCAL_GL_TEXTURE_2D,
+                                              gfx::SurfaceFormat::FORMAT_R8G8B8X8);
+  ShaderProgramOGL *program = GetShaderProgramFor(config);
 
-  aProgram->Activate();
-  aProgram->SetTextureUnit(0);
-  aProgram->SetLayerQuadRect(gfx::Rect(0.f, 0.f, viewport[2], viewport[3]));
-  aProgram->SetLayerOpacity(1.f);
-  aProgram->SetTextureTransform(gfx3DMatrix());
-  aProgram->SetLayerTransform(gfx3DMatrix());
-  aProgram->SetRenderOffset(0, 0);
+  program->Activate();
+  program->SetProjectionMatrix(mProjMatrix);
+  program->SetTextureUnit(0);
+  program->SetLayerQuadRect(gfx::Rect(0.f, 0.f, viewport[2], viewport[3]));
+  program->SetTextureTransform(gfx3DMatrix());
+  program->SetLayerTransform(gfx3DMatrix());
+  program->SetRenderOffset(0, 0);
 
-  aContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
+  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
                                LOCAL_GL_ONE, LOCAL_GL_ZERO);
 
-  DrawQuads(aContext, mVBOs, aProgram, rects);
+  DrawQuads(mGLContext, mVBOs, program, rects);
 }
 
 #ifdef CHECK_CURRENT_PROGRAM
 int ShaderProgramOGL::sCurrentProgramKey = 0;
 #endif
 
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
+  , mFPSTexture(0)
   , mDestroyed(false)
 {
   MOZ_COUNT_CTOR(CompositorOGL);
   sBackend = LAYERS_OPENGL;
 }
 
 CompositorOGL::~CompositorOGL()
 {
@@ -266,29 +358,16 @@ CompositorOGL::CreateContext()
     context = gl::GLContextProvider::CreateForWindow(mWidget);
 
   if (!context) {
     NS_WARNING("Failed to create CompositorOGL context");
   }
   return context.forget();
 }
 
-void
-CompositorOGL::AddPrograms(ShaderProgramType aType)
-{
-  for (uint32_t maskType = MaskNone; maskType < NumMaskTypes; ++maskType) {
-    if (ProgramProfileOGL::ProgramExists(aType, static_cast<MaskType>(maskType))) {
-      mPrograms[aType].mVariations[maskType] = new ShaderProgramOGL(this->gl(),
-        ProgramProfileOGL::GetProfileFor(aType, static_cast<MaskType>(maskType)));
-    } else {
-      mPrograms[aType].mVariations[maskType] = nullptr;
-    }
-  }
-}
-
 GLuint
 CompositorOGL::GetTemporaryTexture(GLenum aTextureUnit)
 {
   size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
   // lazily grow the array of temporary textures
   if (mTextures.Length() <= index) {
     size_t prevLength = mTextures.Length();
     mTextures.SetLength(index + 1);
@@ -309,19 +388,18 @@ CompositorOGL::Destroy()
 {
   if (gl()) {
     gl()->MakeCurrent();
     if (mTextures.Length() > 0) {
       gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]);
     }
     mVBOs.Flush(gl());
     if (mFPS) {
-      if (mFPS->mTexture > 0)
-        gl()->fDeleteTextures(1, &mFPS->mTexture);
-      mFPS->mVBOs.Flush(gl());
+      if (mFPSTexture > 0)
+        gl()->fDeleteTextures(1, &mFPSTexture);
     }
   }
   mTextures.SetLength(0);
   if (!mDestroyed) {
     mDestroyed = true;
     CleanupResources();
   }
 }
@@ -332,17 +410,17 @@ CompositorOGL::CleanupResources()
   if (!mGLContext)
     return;
 
   nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext();
   if (!ctx) {
     ctx = mGLContext;
   }
 
-  mPrograms.Clear();
+  mPrograms.clear();
 
   ctx->MakeCurrent();
 
   ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 
   if (mQuadVBO) {
     ctx->fDeleteBuffers(1, &mQuadVBO);
     mQuadVBO = 0;
@@ -385,23 +463,20 @@ CompositorOGL::Initialize()
   mHasBGRA =
     mGLContext->IsExtensionSupported(gl::GLContext::EXT_texture_format_BGRA8888) ||
     mGLContext->IsExtensionSupported(gl::GLContext::EXT_bgra);
 
   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
   mGLContext->fEnable(LOCAL_GL_BLEND);
 
-  mPrograms.AppendElements(NumProgramTypes);
-  for (int type = 0; type < NumProgramTypes; ++type) {
-    AddPrograms(static_cast<ShaderProgramType>(type));
-  }
-
   // initialise a common shader to check that we can actually compile a shader
-  if (!mPrograms[RGBALayerProgramType].mVariations[MaskNone]->Initialize()) {
+  RefPtr<EffectSolidColor> effect = new EffectSolidColor(Color(0, 0, 0, 0));
+  ShaderConfigOGL config = GetShaderConfigFor(effect);
+  if (!GetShaderProgramFor(config)) {
     return false;
   }
 
   if (mGLContext->WorkAroundDriverBugs()) {
     /**
     * We'll test the ability here to bind NPOT textures to a framebuffer, if
     * this fails we'll try ARB_texture_rectangle.
     */
@@ -634,29 +709,17 @@ CompositorOGL::PrepareViewport(const gfx
     viewMatrix.Translate(gfxPoint(mRenderOffset.x, mRenderOffset.y));
   }
 
   viewMatrix = aWorldTransform * viewMatrix;
 
   gfx3DMatrix matrix3d = gfx3DMatrix::From2D(viewMatrix);
   matrix3d._33 = 0.0f;
 
-  SetLayerProgramProjectionMatrix(matrix3d);
-}
-
-void
-CompositorOGL::SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix)
-{
-  for (unsigned int i = 0; i < mPrograms.Length(); ++i) {
-    for (uint32_t mask = MaskNone; mask < NumMaskTypes; ++mask) {
-      if (mPrograms[i].mVariations[mask]) {
-        mPrograms[i].mVariations[mask]->CheckAndSetProjectionMatrix(aMatrix);
-      }
-    }
-  }
+  mProjMatrix = matrix3d;
 }
 
 TemporaryRef<CompositingRenderTarget>
 CompositorOGL::CreateRenderTarget(const IntRect &aRect, SurfaceInitMode aInit)
 {
   GLuint tex = 0;
   GLuint fbo = 0;
   CreateFBOWithTexture(aRect, aInit, 0, &fbo, &tex);
@@ -925,41 +988,136 @@ CompositorOGL::CreateFBOWithTexture(cons
   mGLContext->fBindTexture(mFBOTextureTarget, 0);
 
   mGLContext->fGenFramebuffers(1, &fbo);
 
   *aFBO = fbo;
   *aTexture = tex;
 }
 
-ShaderProgramType
-CompositorOGL::GetProgramTypeForEffect(Effect *aEffect) const
+ShaderConfigOGL
+CompositorOGL::GetShaderConfigFor(Effect *aEffect, MaskType aMask) const
 {
+  ShaderConfigOGL config;
+
   switch(aEffect->mType) {
   case EFFECT_SOLID_COLOR:
-    return ColorLayerProgramType;
-  case EFFECT_RGBA:
-  case EFFECT_RGBX:
-  case EFFECT_BGRA:
-  case EFFECT_BGRX:
+    config.SetRenderColor(true);
+    break;
+  case EFFECT_YCBCR:
+    config.SetYCbCr(true);
+    break;
+  case EFFECT_COMPONENT_ALPHA:
+    config.SetComponentAlpha(true);
+    break;
+  case EFFECT_RENDER_TARGET:
+    config.SetTextureTarget(mFBOTextureTarget);
+    break;
+  default:
   {
+    MOZ_ASSERT(aEffect->mType == EFFECT_RGB);
     TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffect);
     TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
-
-    return ShaderProgramFromTargetAndFormat(source->GetTextureTarget(),
-                                            source->GetFormat());
+    MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_EXTERNAL,
+                  source->GetFormat() == gfx::FORMAT_R8G8B8A8);
+    MOZ_ASSERT_IF(source->GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                  source->GetFormat() == gfx::FORMAT_R8G8B8A8 ||
+                  source->GetFormat() == gfx::FORMAT_R8G8B8X8 ||
+                  source->GetFormat() == gfx::FORMAT_R5G6B5);
+    config = GetShaderConfigFor(source->GetTextureTarget(),
+                                source->GetFormat());
+    break;
+  }
   }
-  case EFFECT_YCBCR:
-    return YCbCrLayerProgramType;
-  case EFFECT_RENDER_TARGET:
-    return GetFBOLayerProgramType();
-  default:
-    return RGBALayerProgramType;
+  config.SetMask(aMask != MaskNone);
+  return config;
+}
+
+ShaderConfigOGL
+CompositorOGL::GetShaderConfigFor(GLenum aTarget, gfx::SurfaceFormat aFormat) const
+{
+  ShaderConfigOGL config;
+  config.SetTextureTarget(aTarget);
+  config.SetRBSwap(aFormat == gfx::FORMAT_B8G8R8A8 ||
+                   aFormat == gfx::FORMAT_B8G8R8X8);
+  config.SetNoAlpha(aFormat == gfx::FORMAT_B8G8R8X8 ||
+                    aFormat == gfx::FORMAT_R8G8B8X8 ||
+                    aFormat == gfx::FORMAT_R5G6B5);
+  return config;
+}
+
+ShaderProgramOGL*
+CompositorOGL::GetShaderProgramFor(const ShaderConfigOGL &aConfig)
+{
+  std::map<ShaderConfigOGL, ShaderProgramOGL *>::iterator iter = mPrograms.find(aConfig);
+  if (iter != mPrograms.end())
+    return iter->second;
+
+  ProgramProfileOGL profile(sUnifiedLayerVS, sUnifiedLayerFS);
+
+  typedef ProgramProfileOGL::Argument Argument;
+  profile.mUniforms.AppendElement(Argument("uLayerTransform"));
+  profile.mUniforms.AppendElement(Argument("uLayerQuadTransform"));
+  profile.mUniforms.AppendElement(Argument("uMatrixProj"));
+  profile.mUniforms.AppendElement(Argument("uRenderTargetOffset"));
+  profile.mAttributes.AppendElement(Argument("aVertexCoord"));
+  if (aConfig.mFeatures & ENABLE_RENDER_COLOR) {
+    profile.mDefines.AppendElement("#define ENABLE_RENDER_COLOR");
+    profile.mUniforms.AppendElement(Argument("uRenderColor"));
+  } else {
+    profile.mUniforms.AppendElement(Argument("uTextureTransform"));
+    profile.mAttributes.AppendElement(Argument("aTexCoord"));
+    if (aConfig.mFeatures & ENABLE_OPACITY) {
+      profile.mDefines.AppendElement("#define ENABLE_OPACITY");
+      profile.mUniforms.AppendElement(Argument("uLayerOpacity"));
+    }
+    if (aConfig.mFeatures & ENABLE_TEXTURE_YCBCR) {
+      profile.mDefines.AppendElement("#define ENABLE_TEXTURE_YCBCR");
+      profile.mUniforms.AppendElement(Argument("uYTexture"));
+      profile.mUniforms.AppendElement(Argument("uCbTexture"));
+      profile.mUniforms.AppendElement(Argument("uCrTexture"));
+      profile.mTextureCount = 3;
+    } else if (aConfig.mFeatures & ENABLE_TEXTURE_COMPONENT_ALPHA) {
+      profile.mDefines.AppendElement("#define ENABLE_TEXTURE_COMPONENT_ALPHA");
+      profile.mUniforms.AppendElement(Argument("uBlackTexture"));
+      profile.mUniforms.AppendElement(Argument("uWhiteTexture"));
+      profile.mUniforms.AppendElement(Argument("uTexturePass2"));
+      profile.mTextureCount = 2;
+    } else {
+      profile.mUniforms.AppendElement(Argument("uTexture"));
+      profile.mTextureCount = 1;
+    }
+    if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
+      profile.mDefines.AppendElement("#define ENABLE_TEXTURE_RECT");
+    }
+    if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
+      profile.mDefines.AppendElement("#define ENABLE_TEXTURE_EXTERNAL");
+    }
+    if (aConfig.mFeatures & ENABLE_TEXTURE_NO_ALPHA) {
+      profile.mDefines.AppendElement("#define ENABLE_TEXTURE_NO_ALPHA");
+    }
+    if (aConfig.mFeatures & ENABLE_TEXTURE_RB_SWAP) {
+      profile.mDefines.AppendElement("#define ENABLE_TEXTURE_RB_SWAP");
+    }
+    if (aConfig.mFeatures & ENABLE_BLUR) {
+      profile.mDefines.AppendElement("#define ENABLE_BLUR");
+    }
+    if (aConfig.mFeatures & ENABLE_COLOR_MATRIX) {
+      profile.mDefines.AppendElement("#define ENABLE_COLOR_MATRIX");
+    }
   }
+  ShaderProgramOGL *shader = new ShaderProgramOGL(gl(), profile);
+  if (!shader->Initialize()) {
+    delete shader;
+    return nullptr;
+  }
+
+  mPrograms[aConfig] = shader;
+  return shader;
 }
 
 struct MOZ_STACK_CLASS AutoBindTexture
 {
   AutoBindTexture() : mTexture(nullptr) {}
   AutoBindTexture(TextureSourceOGL* aTexture, GLenum aTextureUnit)
    : mTexture(nullptr) { Bind(aTexture, aTextureUnit); }
   ~AutoBindTexture()
@@ -1028,84 +1186,77 @@ CompositorOGL::DrawQuad(const Rect& aRec
                  ? Mask3d
                  : Mask2d;
   } else {
     maskType = MaskNone;
   }
 
   mPixelsFilled += aRect.width * aRect.height;
 
-  ShaderProgramType programType = GetProgramTypeForEffect(aEffectChain.mPrimaryEffect);
-  ShaderProgramOGL *program = GetProgram(programType, maskType);
-  program->Activate();
-  if (programType == RGBARectLayerProgramType ||
-      programType == RGBXRectLayerProgramType) {
-    TexturedEffect* texturedEffect =
-        static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
-    TextureSourceOGL* source = texturedEffect->mTexture->AsSourceOGL();
-    // This is used by IOSurface that use 0,0...w,h coordinate rather then 0,0..1,1.
-    program->SetTexCoordMultiplier(source->GetSize().width, source->GetSize().height);
-  }
-  program->SetLayerQuadRect(aRect);
-  program->SetLayerTransform(aTransform);
-  program->SetRenderOffset(aOffset.x, aOffset.y);
+  // Determine the color if this is a color shader and fold the opacity into
+  // the color since color shaders don't have an opacity uniform.
+  Color color;
+  if (aEffectChain.mPrimaryEffect->mType == EFFECT_SOLID_COLOR) {
+    EffectSolidColor* effectSolidColor =
+      static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
+    color = effectSolidColor->mColor;
 
-  switch (aEffectChain.mPrimaryEffect->mType) {
-    case EFFECT_SOLID_COLOR: {
-      EffectSolidColor* effectSolidColor =
-        static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
-
-      Color color = effectSolidColor->mColor;
-      /* Multiply color by the layer opacity, as the shader
-       * ignores layer opacity and expects a final color to
-       * write to the color buffer.  This saves a needless
-       * multiply in the fragment shader.
-       */
+    if (aOpacity != 1.f) {
       Float opacity = aOpacity * color.a;
       color.r *= opacity;
       color.g *= opacity;
       color.b *= opacity;
       color.a = opacity;
+      aOpacity = 1.f;
+    }
+  }
 
+  ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType);
+  config.SetOpacity(aOpacity != 1.f);
+  ShaderProgramOGL *program = GetShaderProgramFor(config);
+  program->Activate();
+  program->SetProjectionMatrix(mProjMatrix);
+  program->SetLayerQuadRect(aRect);
+  program->SetLayerTransform(aTransform);
+  program->SetRenderOffset(aOffset.x, aOffset.y);
+  if (aOpacity != 1.f)
+    program->SetLayerOpacity(aOpacity);
+
+  switch (aEffectChain.mPrimaryEffect->mType) {
+    case EFFECT_SOLID_COLOR: {
       program->SetRenderColor(color);
 
       AutoBindTexture bindMask;
       if (maskType != MaskNone) {
         bindMask.Bind(sourceMask, LOCAL_GL_TEXTURE0);
         program->SetMaskTextureUnit(0);
         program->SetMaskLayerTransform(maskQuadTransform);
       }
 
       BindAndDrawQuad(program);
     }
     break;
 
-  case EFFECT_BGRA:
-  case EFFECT_BGRX:
-  case EFFECT_RGBA:
-  case EFFECT_RGBX: {
+  case EFFECT_RGB: {
       TexturedEffect* texturedEffect =
           static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
-      Rect textureCoords;
       TextureSource *source = texturedEffect->mTexture;
 
       if (!texturedEffect->mPremultiplied) {
         mGLContext->fBlendFuncSeparate(LOCAL_GL_SRC_ALPHA, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                        LOCAL_GL_ONE, LOCAL_GL_ONE);
       }
 
       AutoBindTexture bindSource(source->AsSourceOGL(), LOCAL_GL_TEXTURE0);
-  
-      program->SetTextureTransform(source->AsSourceOGL()->GetTextureTransform());
 
       mGLContext->ApplyFilterToBoundTexture(source->AsSourceOGL()->GetTextureTarget(),
                                             ThebesFilter(texturedEffect->mFilter));
 
+      program->SetTextureTransform(source->AsSourceOGL()->GetEffectiveTextureTransform());
       program->SetTextureUnit(0);
-      program->SetLayerOpacity(aOpacity);
 
       AutoBindTexture bindMask;
       if (maskType != MaskNone) {
         mGLContext->fActiveTexture(LOCAL_GL_TEXTURE1);
         bindMask.Bind(sourceMask, LOCAL_GL_TEXTURE1);
         program->SetMaskTextureUnit(1);
         program->SetMaskLayerTransform(maskQuadTransform);
       }
@@ -1137,17 +1288,16 @@ CompositorOGL::DrawQuad(const Rect& aRec
       AutoBindTexture bindY(sourceY, LOCAL_GL_TEXTURE0);
       mGLContext->ApplyFilterToBoundTexture(filter);
       AutoBindTexture bindCb(sourceCb, LOCAL_GL_TEXTURE1);
       mGLContext->ApplyFilterToBoundTexture(filter);
       AutoBindTexture bindCr(sourceCr, LOCAL_GL_TEXTURE2);
       mGLContext->ApplyFilterToBoundTexture(filter);
 
       program->SetYCbCrTextureUnits(Y, Cb, Cr);
-      program->SetLayerOpacity(aOpacity);
       program->SetTextureTransform(gfx3DMatrix());
 
       AutoBindTexture bindMask;
       if (maskType != MaskNone) {
         bindMask.Bind(sourceMask, LOCAL_GL_TEXTURE3);
         program->SetMaskTextureUnit(3);
         program->SetMaskLayerTransform(maskQuadTransform);
       }
@@ -1155,37 +1305,30 @@ CompositorOGL::DrawQuad(const Rect& aRec
     }
     break;
   case EFFECT_RENDER_TARGET: {
       EffectRenderTarget* effectRenderTarget =
         static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
       RefPtr<CompositingRenderTargetOGL> surface
         = static_cast<CompositingRenderTargetOGL*>(effectRenderTarget->mRenderTarget.get());
 
-      ShaderProgramOGL *program = GetProgram(GetFBOLayerProgramType(), maskType);
-
       surface->BindTexture(LOCAL_GL_TEXTURE0, mFBOTextureTarget);
 
-      program->Activate();
+      program->SetTextureTransform((mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB)
+                                   ? gfx3DMatrix::ScalingMatrix(aRect.width, aRect.height, 1.0f)
+                                   : gfx3DMatrix());
       program->SetTextureUnit(0);
-      program->SetLayerOpacity(aOpacity);
-      program->SetTextureTransform(gfx3DMatrix());
 
       AutoBindTexture bindMask;
       if (maskType != MaskNone) {
         bindMask.Bind(sourceMask, LOCAL_GL_TEXTURE1);
         program->SetMaskTextureUnit(1);
         program->SetMaskLayerTransform(maskQuadTransform);
       }
 
-      if (program->GetTexCoordMultiplierUniformLocation() != -1) {
-        // 2DRect case, get the multiplier right for a sampler2DRect
-        program->SetTexCoordMultiplier(aRect.width, aRect.height);
-      }
-
       // Drawing is always flipped, but when copying between surfaces we want to avoid
       // this. Pass true for the flip parameter to introduce a second flip
       // that cancels the other one out.
       BindAndDrawQuad(program, true);
     }
     break;
   case EFFECT_COMPONENT_ALPHA: {
       MOZ_ASSERT(gfxPlatform::ComponentAlphaEnabled());
@@ -1195,57 +1338,44 @@ CompositorOGL::DrawQuad(const Rect& aRec
       TextureSourceOGL* sourceOnBlack = effectComponentAlpha->mOnBlack->AsSourceOGL();
 
       if (!sourceOnBlack->IsValid() ||
           !sourceOnWhite->IsValid()) {
         NS_WARNING("Invalid layer texture for component alpha");
         return;
       }
 
-      for (int32_t pass = 1; pass <=2; ++pass) {
-        ShaderProgramOGL* program;
-        if (pass == 1) {
-          ShaderProgramType type = gl()->GetPreferredARGB32Format() == LOCAL_GL_BGRA ?
-                                   ComponentAlphaPass1RGBProgramType :
-                                   ComponentAlphaPass1ProgramType;
-          program = GetProgram(type, maskType);
-          gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
-                                   LOCAL_GL_ONE, LOCAL_GL_ONE);
-        } else {
-          ShaderProgramType type = gl()->GetPreferredARGB32Format() == LOCAL_GL_BGRA ?
-                                   ComponentAlphaPass2RGBProgramType :
-                                   ComponentAlphaPass2ProgramType;
-          program = GetProgram(type, maskType);
-          gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
-                                   LOCAL_GL_ONE, LOCAL_GL_ONE);
-        }
+      AutoBindTexture bindSourceOnBlack(sourceOnBlack, LOCAL_GL_TEXTURE0);
+      AutoBindTexture bindSourceOnWhite(sourceOnWhite, LOCAL_GL_TEXTURE1);
+
+      program->SetBlackTextureUnit(0);
+      program->SetWhiteTextureUnit(1);
+      program->SetTextureTransform(gfx3DMatrix());
 
-        AutoBindTexture bindSourceOnBlack(sourceOnBlack, LOCAL_GL_TEXTURE0);
-        AutoBindTexture bindSourceOnWhite(sourceOnWhite, LOCAL_GL_TEXTURE1);
+      AutoBindTexture bindMask;
+      if (maskType != MaskNone) {
+        bindMask.Bind(sourceMask, LOCAL_GL_TEXTURE2);
+        program->SetMaskTextureUnit(2);
+        program->SetMaskLayerTransform(maskQuadTransform);
+      }
 
-        program->Activate();
-        program->SetBlackTextureUnit(0);
-        program->SetWhiteTextureUnit(1);
-        program->SetLayerOpacity(aOpacity);
-        program->SetLayerTransform(aTransform);
-        program->SetTextureTransform(gfx3DMatrix());
-        program->SetRenderOffset(aOffset.x, aOffset.y);
-        program->SetLayerQuadRect(aRect);
-        AutoBindTexture bindMask;
-        if (maskType != MaskNone) {
-          bindMask.Bind(sourceMask, LOCAL_GL_TEXTURE2);
-          program->SetMaskTextureUnit(2);
-          program->SetMaskLayerTransform(maskQuadTransform);
-        }
+      // Pass 1.
+      gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
+                               LOCAL_GL_ONE, LOCAL_GL_ONE);
+      program->SetTexturePass2(false);
+      BindAndDrawQuadWithTextureRect(program, effectComponentAlpha->mTextureCoords, effectComponentAlpha->mOnBlack);
 
-        BindAndDrawQuadWithTextureRect(program, effectComponentAlpha->mTextureCoords, effectComponentAlpha->mOnBlack);
+      // Pass 2.
+      gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
+                               LOCAL_GL_ONE, LOCAL_GL_ONE);
+      program->SetTexturePass2(true);
+      BindAndDrawQuadWithTextureRect(program, effectComponentAlpha->mTextureCoords, effectComponentAlpha->mOnBlack);
 
-        mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
-                                       LOCAL_GL_ONE, LOCAL_GL_ONE);
-      }
+      mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+                                     LOCAL_GL_ONE, LOCAL_GL_ONE);
     }
     break;
   default:
     MOZ_ASSERT(false, "Unhandled effect type");
     break;
   }
 
   mGLContext->PopScissorRect();
@@ -1291,23 +1421,17 @@ CompositorOGL::EndFrame()
 
   if (sDrawFPS && !mFPS) {
     mFPS = new FPSState();
   } else if (!sDrawFPS && mFPS) {
     mFPS = nullptr;
   }
 
   if (mFPS) {
-    float fillRatio = 0;
-    if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
-      fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
-      if (fillRatio > 999.0f)
-        fillRatio = 999.0f;
-    }
-    mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mGLContext, GetProgram(RGBXLayerProgramType));
+    DrawFPS();
   }
 
   mGLContext->SwapBuffers();
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 }
 
 void
 CompositorOGL::EndFrameForExternalComposition(const gfxMatrix& aTransform)
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -26,16 +26,17 @@
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING
 #include "nsSize.h"                     // for nsIntSize
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType
 #include "nscore.h"                     // for NS_IMETHOD
 #include "VBOArena.h"                   // for gl::VBOArena
+#include <map>
 
 class gfx3DMatrix;
 class nsIWidget;
 struct gfxMatrix;
 
 namespace mozilla {
 class TimeStamp;
 
@@ -49,23 +50,55 @@ class CompositingRenderTarget;
 class CompositingRenderTargetOGL;
 class DataTextureSource;
 class GLManagerCompositor;
 class TextureSource;
 struct Effect;
 struct EffectChain;
 struct FPSState;
 
+class ShaderConfigOGL
+{
+public:
+  ShaderConfigOGL() :
+    mFeatures(0) {}
+
+  void SetRenderColor(bool aEnabled);
+  void SetTextureTarget(GLenum aTarget);
+  void SetRBSwap(bool aEnabled);
+  void SetNoAlpha(bool aEnabled);
+  void SetOpacity(bool aEnabled);
+  void SetYCbCr(bool aEnabled);
+  void SetComponentAlpha(bool aEnabled);
+  void SetColorMatrix(bool aEnabled);
+  void SetBlur(bool aEnabled);
+  void SetMask(bool aEnabled);
+
+  bool operator< (const ShaderConfigOGL& other) const {
+    return mFeatures < other.mFeatures;
+  }
+
+public:
+  void SetFeature(int aBitmask, bool aState) {
+    if (aState)
+      mFeatures |= aBitmask;
+    else
+      mFeatures &= (~aBitmask);
+  }
+
+  int mFeatures;
+};
+
 class CompositorOGL : public Compositor
 {
   typedef mozilla::gl::GLContext GLContext;
-  typedef ShaderProgramType ProgramType;
   
   friend class GLManagerCompositor;
 
+  std::map<ShaderConfigOGL, ShaderProgramOGL*> mPrograms;
 public:
   CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth = -1, int aSurfaceHeight = -1,
                 bool aUseExternalSurfaceSize = false);
 
   virtual ~CompositorOGL();
 
   virtual TemporaryRef<DataTextureSource>
   CreateDataTextureSource(TextureFlags aFlags = 0) MOZ_OVERRIDE;
@@ -145,71 +178,59 @@ public:
   virtual bool Resume() MOZ_OVERRIDE;
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
   virtual const nsIntSize& GetWidgetSize() MOZ_OVERRIDE {
     return mWidgetSize;
   }
 
   GLContext* gl() const { return mGLContext; }
-  ShaderProgramType GetFBOLayerProgramType() const {
-    return mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB ?
-           RGBARectLayerProgramType : RGBALayerProgramType;
-  }
   gfx::SurfaceFormat GetFBOFormat() const {
     return gfx::FORMAT_R8G8B8A8;
   }
 
   virtual void SaveState() MOZ_OVERRIDE;
   virtual void RestoreState() MOZ_OVERRIDE;
 
   /**
    * The compositor provides with temporary textures for use with direct
    * textruing like gralloc texture.
    * Doing so lets us use gralloc the way it has been designed to be used
    * (see https://wiki.mozilla.org/Platform/GFX/Gralloc)
    */
   GLuint GetTemporaryTexture(GLenum aUnit);
+
+  const gfx3DMatrix& GetProjMatrix() const {
+    return mProjMatrix;
+  }
 private:
   /** 
    * Context target, nullptr when drawing directly to our swap chain.
    */
   RefPtr<gfx::DrawTarget> mTarget;
 
   /** Widget associated with this compositor */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
   nsRefPtr<GLContext> mGLContext;
+  gfx3DMatrix mProjMatrix;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
   ScreenPoint mRenderOffset;
 
   /** Helper-class used by Initialize **/
   class ReadDrawFPSPref MOZ_FINAL : public nsRunnable {
   public:
     NS_IMETHOD Run() MOZ_OVERRIDE;
   };
 
   already_AddRefed<mozilla::gl::GLContext> CreateContext();
 
-  /** Shader Programs */
-  struct ShaderProgramVariations {
-    nsAutoTArray<nsAutoPtr<ShaderProgramOGL>, NumMaskTypes> mVariations;
-    ShaderProgramVariations() {
-      MOZ_COUNT_CTOR(ShaderProgramVariations);
-      mVariations.SetLength(NumMaskTypes);
-    }
-    ~ShaderProgramVariations() {
-      MOZ_COUNT_DTOR(ShaderProgramVariations);
-    }
-  };
-  nsTArray<ShaderProgramVariations> mPrograms;
-
   /** Texture target to use for FBOs */
   GLenum mFBOTextureTarget;
 
   /** Currently bound render target */
   RefPtr<CompositingRenderTargetOGL> mCurrentRenderTarget;
 #ifdef DEBUG
   CompositingRenderTargetOGL* mWindowRenderTarget;
 #endif
@@ -243,34 +264,19 @@ private:
    */
   virtual void BeginFrame(const gfx::Rect *aClipRectIn,
                           const gfxMatrix& aTransform,
                           const gfx::Rect& aRenderBounds, 
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE;
 
   ShaderProgramType GetProgramTypeForEffect(Effect* aEffect) const;
-
-  /**
-   * Updates all layer programs with a new projection matrix.
-   */
-  void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);
-
-  /**
-   * Helper method for Initialize, creates all valid variations of a program
-   * and adds them to mPrograms
-   */
-  void AddPrograms(ShaderProgramType aType);
-
-  ShaderProgramOGL* GetProgram(ShaderProgramType aType,
-                               MaskType aMask = MaskNone) {
-    MOZ_ASSERT(ProgramProfileOGL::ProgramExists(aType, aMask),
-               "Invalid program type.");
-    return mPrograms[aType].mVariations[aMask];
-  }
+  ShaderConfigOGL GetShaderConfigFor(GLenum aTarget, gfx::SurfaceFormat aFormat) const;
+  ShaderConfigOGL GetShaderConfigFor(Effect *aEffect, MaskType aMask = MaskNone) const;
+  ShaderProgramOGL* GetShaderProgramFor(const ShaderConfigOGL &aConfig);
 
   /**
    * Create a FBO backed by a texture.
    * Note that the texture target type will be
    * of the type returned by FBOTextureTarget; different
    * shaders are required to sample from the different
    * texture types.
    */
@@ -302,16 +308,18 @@ private:
    * Does not restore the target FBO, so only call from EndFrame.
    */
   void CopyToTarget(gfx::DrawTarget* aTarget, const gfxMatrix& aWorldMatrix);
 
   /**
    * Records the passed frame timestamp and returns the current estimated FPS.
    */
   double AddFrameAndGetFps(const TimeStamp& timestamp);
+  void DrawFPS();
+  GLuint mFPSTexture;
 
   bool mDestroyed;
 
   nsAutoPtr<FPSState> mFPS;
   // Textures used for direct texturing of buffers like gralloc.
   // The index of the texture in this array must correspond to the texture unit.
   nsTArray<GLuint> mTextures;
   static bool sDrawFPS;
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -211,26 +211,26 @@ ContainerLayerOGL::RenderLayer(int aPrev
         } else {
           maskType = Mask2d;
         }
       }
       ShaderProgramOGL *rgb =
         mOGLManager->GetFBOLayerProgram(maskType);
 
       rgb->Activate();
+      rgb->SetProjectionMatrix(mOGLManager->mProjMatrix);
       rgb->SetLayerQuadRect(visibleRect);
       rgb->SetLayerTransform(transform);
       rgb->SetTextureTransform(gfx3DMatrix());
       rgb->SetLayerOpacity(opacity);
       rgb->SetRenderOffset(aOffset);
       rgb->SetTextureUnit(0);
       rgb->LoadMask(GetMaskLayer());
 
-      if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
-        // 2DRect case, get the multiplier right for a sampler2DRect
+      if (rgb->HasTexCoordMultiplier()) {
         rgb->SetTexCoordMultiplier(visibleRect.width, visibleRect.height);
       }
 
       // Drawing is always flipped, but when copying between surfaces we want to avoid
       // this. Pass true for the flip parameter to introduce a second flip
       // that cancels the other one out.
       mOGLManager->BindAndDrawQuad(rgb, true);
 
--- a/gfx/layers/opengl/FPSCounter.h
+++ b/gfx/layers/opengl/FPSCounter.h
@@ -63,24 +63,20 @@ private:
     if (realWindowSecs == 0.0 || numFramesDrawnInWindow == 1) {
       return 0.0;
     }
     return double(numFramesDrawnInWindow - 1) / realWindowSecs;
   }
 };
 
 struct FPSState {
-  GLuint mTexture;
   FPSCounter mCompositionFps;
   FPSCounter mTransactionFps;
-  gl::VBOArena mVBOs;
 
-  FPSState() : mTexture(0) { }
-
-  void DrawFPS(TimeStamp, unsigned, gl::GLContext*, ShaderProgramOGL*);
+  FPSState() { }
 
   void NotifyShadowTreeTransaction() {
     mTransactionFps.AddFrame(TimeStamp::Now());
   }
 };
 
 }
 }
--- a/gfx/layers/opengl/GLManager.cpp
+++ b/gfx/layers/opengl/GLManager.cpp
@@ -18,31 +18,65 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for LayerManager::AddRef, etc
 
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
+inline ShaderProgramType
+GetProgramTypeForSurfaceFormat(GLenum aTarget, gfx::SurfaceFormat aFormat)
+{
+  if (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
+    switch (aFormat) {
+    case gfx::FORMAT_R8G8B8X8:
+    case gfx::FORMAT_R5G6B5:
+      return RGBXRectLayerProgramType;
+    case gfx::FORMAT_R8G8B8A8:
+      return RGBARectLayerProgramType;
+    default:
+      MOZ_CRASH("unhandled program type");
+    }
+  }
+  switch (aFormat) {
+  case gfx::FORMAT_B8G8R8A8:
+    return BGRALayerProgramType;
+  case gfx::FORMAT_B8G8R8X8:
+    return BGRXLayerProgramType;
+  case gfx::FORMAT_R8G8B8X8:
+  case gfx::FORMAT_R5G6B5:
+    return RGBXLayerProgramType;
+  case gfx::FORMAT_R8G8B8A8:
+    return RGBALayerProgramType;
+  default:
+    MOZ_CRASH("unhandled program type");
+  }
+}
+
 class GLManagerLayerManager : public GLManager
 {
 public:
   GLManagerLayerManager(LayerManagerOGL* aManager)
     : mImpl(aManager)
   {}
 
   virtual GLContext* gl() const MOZ_OVERRIDE
   {
     return mImpl->gl();
   }
 
-  virtual ShaderProgramOGL* GetProgram(ShaderProgramType aType) MOZ_OVERRIDE
+  virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) MOZ_OVERRIDE
   {
-    return mImpl->GetProgram(aType);
+    return mImpl->GetProgram(GetProgramTypeForSurfaceFormat(aTarget, aFormat));
+  }
+
+  virtual gfx3DMatrix& GetProjMatrix() const MOZ_OVERRIDE
+  {
+    return mImpl->mProjMatrix;
   }
 
   virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) MOZ_OVERRIDE
   {
     mImpl->BindAndDrawQuad(aProg);
   }
 
 private:
@@ -56,19 +90,25 @@ public:
     : mImpl(aCompositor)
   {}
 
   virtual GLContext* gl() const MOZ_OVERRIDE
   {
     return mImpl->gl();
   }
 
-  virtual ShaderProgramOGL* GetProgram(ShaderProgramType aType) MOZ_OVERRIDE
+  virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) MOZ_OVERRIDE
   {
-    return mImpl->GetProgram(aType);
+    ShaderConfigOGL config = mImpl->GetShaderConfigFor(aTarget, aFormat);
+    return mImpl->GetShaderProgramFor(config);
+  }
+
+  virtual const gfx3DMatrix& GetProjMatrix() const MOZ_OVERRIDE
+  {
+    return mImpl->GetProjMatrix();
   }
 
   virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) MOZ_OVERRIDE
   {
     mImpl->BindAndDrawQuad(aProg);
   }
 
 private:
--- a/gfx/layers/opengl/GLManager.h
+++ b/gfx/layers/opengl/GLManager.h
@@ -26,19 +26,16 @@ class LayerManager;
 class GLManager
 {
 public:
   static GLManager* CreateGLManager(LayerManager* aManager);
 
   virtual ~GLManager() {}
 
   virtual gl::GLContext* gl() const = 0;
-  virtual ShaderProgramOGL* GetProgram(ShaderProgramType aType) = 0;
+  virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) = 0;
+  virtual const gfx3DMatrix& GetProjMatrix() const = 0;
   virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) = 0;
-
-  ShaderProgramOGL* GetProgram(gfx::SurfaceFormat aFormat) {
-    return GetProgram(ShaderProgramFromSurfaceFormat(aFormat));
-  }
 };
 
 }
 }
 #endif
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -256,16 +256,17 @@ ImageLayerOGL::RenderLayer(int,
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTextures[0].GetTextureID());
     gl()->ApplyFilterToBoundTexture(mFilter);
 
     ShaderProgramOGL *program = mOGLManager->GetProgram(YCbCrLayerProgramType,
                                                         GetMaskLayer());
 
     program->Activate();
+    program->SetProjectionMatrix(mOGLManager->mProjMatrix);
     program->SetLayerQuadRect(nsIntRect(0, 0,
                                         yuvImage->GetSize().width,
                                         yuvImage->GetSize().height));
     program->SetLayerTransform(GetEffectiveTransform());
     program->SetTextureTransform(gfx3DMatrix());
     program->SetLayerOpacity(GetEffectiveOpacity());
     program->SetRenderOffset(aOffset);
     program->SetYCbCrTextureUnits(0, 1, 2);
@@ -315,16 +316,17 @@ ImageLayerOGL::RenderLayer(int,
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, data->mTexture.GetTextureID());
 
     ShaderProgramOGL *program = mOGLManager->GetProgram(data->mLayerProgram, GetMaskLayer());
 
     gl()->ApplyFilterToBoundTexture(mFilter);
 
     program->Activate();
+    program->SetProjectionMatrix(mOGLManager->mProjMatrix);
     program->SetLayerQuadRect(nsIntRect(0, 0, 
                                         cairoImage->GetSize().width, 
                                         cairoImage->GetSize().height));
     program->SetLayerTransform(GetEffectiveTransform());
     program->SetTextureTransform(gfx3DMatrix());
     program->SetLayerOpacity(GetEffectiveOpacity());
     program->SetRenderOffset(aOffset);
     program->SetTextureUnit(0);
@@ -342,16 +344,17 @@ ImageLayerOGL::RenderLayer(int,
     }
 
     ShaderProgramType programType =
       ShaderProgramFromTargetAndFormat(handleDetails.mTarget,
                                        handleDetails.mTextureFormat);
     ShaderProgramOGL* program = mOGLManager->GetProgram(programType, GetMaskLayer());
 
     program->Activate();
+    program->SetProjectionMatrix(mOGLManager->mProjMatrix);
     if (programType == RGBARectLayerProgramType) {
       // 2DRect case, get the multiplier right for a sampler2DRect
       program->SetTexCoordMultiplier(data->mSize.width, data->mSize.height);
     }
     program->SetLayerTransform(GetEffectiveTransform());
     program->SetTextureTransform(gfx3DMatrix());
     program->SetLayerOpacity(GetEffectiveOpacity());
     program->SetRenderOffset(aOffset);
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -891,17 +891,19 @@ LayerManagerOGL::Render()
 
   if (sDrawFPS && !mFPS) {
     mFPS = new FPSState();
   } else if (!sDrawFPS && mFPS) {
     mFPS = nullptr;
   }
 
   if (mFPS) {
-    mFPS->DrawFPS(TimeStamp::Now(), 0, mGLContext, GetProgram(Copy2DProgramType));
+    // Disabled due to a refactoring in CompositorOGL.cpp. This file is about to be
+    // deleted anyway.
+    // mFPS->DrawFPS(TimeStamp::Now(), 0, mGLContext, GetProgram(Copy2DProgramType));
   }
 
   if (mGLContext->IsDoubleBuffered()) {
     mGLContext->SwapBuffers();
     LayerManager::PostPresent();
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
     return;
   }
@@ -914,19 +916,20 @@ LayerManagerOGL::Render()
 
   if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
     copyprog = GetProgram(Copy2DRectProgramType);
   }
 
   mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture);
 
   copyprog->Activate();
+  copyprog->SetProjectionMatrix(mProjMatrix);
   copyprog->SetTextureUnit(0);
 
-  if (copyprog->GetTexCoordMultiplierUniformLocation() != -1) {
+  if (copyprog->HasTexCoordMultiplier()) {
     copyprog->SetTexCoordMultiplier(width, height);
   }
 
   // we're going to use client-side vertex arrays for this.
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 
   // "COPY"
   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO,
@@ -1049,17 +1052,17 @@ LayerManagerOGL::SetupPipeline(int aWidt
 
   if (aTransformPolicy == ApplyWorldTransform) {
     viewMatrix = mWorldMatrix * viewMatrix;
   }
 
   gfx3DMatrix matrix3d = gfx3DMatrix::From2D(viewMatrix);
   matrix3d._33 = 0.0f;
 
-  SetLayerProgramProjectionMatrix(matrix3d);
+  mProjMatrix = matrix3d;
 }
 
 void
 LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight)
 {
   if (mGLContext->IsDoubleBuffered()) {
     mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
     return;
@@ -1153,28 +1156,16 @@ LayerManagerOGL::CopyToTarget(gfxContext
 
   gfxContextAutoSaveRestore restore(aTarget);
   aTarget->SetOperator(gfxContext::OPERATOR_SOURCE);
   aTarget->SetMatrix(glToCairoTransform);
   aTarget->SetSource(imageSurface);
   aTarget->Paint();
 }
 
-void
-LayerManagerOGL::SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix)
-{
-  for (unsigned int i = 0; i < mPrograms.Length(); ++i) {
-    for (uint32_t mask = MaskNone; mask < NumMaskTypes; ++mask) {
-      if (mPrograms[i].mVariations[mask]) {
-        mPrograms[i].mVariations[mask]->CheckAndSetProjectionMatrix(aMatrix);
-      }
-    }
-  }
-}
-
 static GLenum
 GetFrameBufferInternalFormat(GLContext* gl,
                              GLuint aCurrentFrameBuffer,
                              nsIWidget* aWidget)
 {
   if (aCurrentFrameBuffer == 0) { // default framebuffer
     return aWidget->GetGLFrameBufferFormat();
   }
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -329,16 +329,18 @@ public:
    * Calculates the 'completeness' of the rendering that intersected with the
    * screen on the last render. This is only useful when progressive tile
    * drawing is enabled, otherwise this will always return 1.0.
    * This function's expense scales with the size of the layer tree and the
    * complexity of individual layers' valid regions.
    */
   float ComputeRenderIntegrity();
 
+  gfx3DMatrix mProjMatrix;
+
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
@@ -407,21 +409,16 @@ private:
   void SetupBackBuffer(int aWidth, int aHeight);
 
   /**
    * Copies the content of our backbuffer to the set transaction target.
    */
   void CopyToTarget(gfxContext *aTarget);
 
   /**
-   * Updates all layer programs with a new projection matrix.
-   */
-  void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);
-
-  /**
    * Helper method for Initialize, creates all valid variations of a program
    * and adds them to mPrograms
    */
   void AddPrograms(ShaderProgramType aType);
 
   /**
    * Recursive helper method for use by ComputeRenderIntegrity. Subtracts
    * any incomplete rendering on aLayer from aScreenRegion. Any low-precision
--- a/gfx/layers/opengl/LayerManagerOGLProgram.cpp
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LayerManagerOGLProgram.h"
 #include <stdint.h>                     // for uint32_t
+#include <sstream>                      // for ostringstream
 #include "gfxMatrix.h"                  // for gfxMatrix
 #include "gfxPoint.h"                   // for gfxIntSize, gfxPoint, etc
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsString.h"                   // for nsAutoCString
 #include "prenv.h"                      // for PR_GetEnv
@@ -17,46 +18,68 @@
 #include "Layers.h"
 #include "GLContext.h"
 
 struct gfxRGBA;
 
 namespace mozilla {
 namespace layers {
 
+using namespace std;
+
 typedef ProgramProfileOGL::Argument Argument;
 
 // helper methods for GetProfileFor
 void
 AddCommonArgs(ProgramProfileOGL& aProfile)
 {
   aProfile.mUniforms.AppendElement(Argument("uLayerTransform"));
   aProfile.mUniforms.AppendElement(Argument("uLayerQuadTransform"));
   aProfile.mUniforms.AppendElement(Argument("uMatrixProj"));
-  aProfile.mHasMatrixProj = true;
   aProfile.mUniforms.AppendElement(Argument("uRenderTargetOffset"));
   aProfile.mAttributes.AppendElement(Argument("aVertexCoord"));
 }
 void
 AddCommonTextureArgs(ProgramProfileOGL& aProfile)
 {
   aProfile.mUniforms.AppendElement(Argument("uLayerOpacity"));
   aProfile.mUniforms.AppendElement(Argument("uTexture"));
   aProfile.mUniforms.AppendElement(Argument("uTextureTransform"));
   aProfile.mAttributes.AppendElement(Argument("aTexCoord"));
 }
 
+void
+AddConfig(ProgramProfileOGL& aProfile, const char *aConfig)
+{
+  aProfile.mDefines.AppendElement(aConfig);
+}
+
 /* static */ ProgramProfileOGL
 ProgramProfileOGL::GetProfileFor(ShaderProgramType aType,
                                  MaskType aMask)
 {
   NS_ASSERTION(ProgramExists(aType, aMask), "Invalid program type.");
   ProgramProfileOGL result;
 
   switch (aType) {
+  case YCbCrLayerProgramType:
+    result.mVertexShaderString = sUnifiedLayerVS;
+    result.mFragmentShaderString = sUnifiedLayerFS;
+    AddCommonArgs(result);
+    AddConfig(result, "#define ENABLE_TEXTURE_YCBCR");
+    if (aMask != MaskNone)
+      AddConfig(result, "#define ENABLE_MASK");
+    result.mUniforms.AppendElement(Argument("uLayerOpacity"));
+    result.mUniforms.AppendElement(Argument("uYTexture"));
+    result.mUniforms.AppendElement(Argument("uCbTexture"));
+    result.mUniforms.AppendElement(Argument("uCrTexture"));
+    result.mUniforms.AppendElement(Argument("uTextureTransform"));
+    result.mAttributes.AppendElement(Argument("aTexCoord"));
+    result.mTextureCount = 3;
+    break;
   case RGBALayerProgramType:
     if (aMask == Mask3d) {
       result.mVertexShaderString = sLayerMask3DVS;
       result.mFragmentShaderString = sRGBATextureLayerMask3DFS;
     } else if (aMask == Mask2d) {
       result.mVertexShaderString = sLayerMaskVS;
       result.mFragmentShaderString = sRGBATextureLayerMaskFS;
     } else {
@@ -111,39 +134,42 @@ ProgramProfileOGL::GetProfileFor(ShaderP
       result.mVertexShaderString = sLayerMaskVS;
       result.mFragmentShaderString = sRGBARectTextureLayerMaskFS;
     } else {
       result.mVertexShaderString = sLayerVS;
       result.mFragmentShaderString = sRGBARectTextureLayerFS;
     }
     AddCommonArgs(result);
     AddCommonTextureArgs(result);
+    result.mUniforms.AppendElement(Argument("uTexCoordMultiplier"));
     result.mTextureCount = 1;
     break;
   case RGBXRectLayerProgramType:
     if (aMask == Mask3d) {
       result.mVertexShaderString = sLayerMask3DVS;
       result.mFragmentShaderString = sRGBXRectTextureLayerMask3DFS;
     } else if (aMask == Mask2d) {
       result.mVertexShaderString = sLayerMaskVS;
       result.mFragmentShaderString = sRGBXRectTextureLayerMaskFS;
     } else {
       result.mVertexShaderString = sLayerVS;
       result.mFragmentShaderString = sRGBXRectTextureLayerFS;
     }
     AddCommonArgs(result);
     AddCommonTextureArgs(result);
+    result.mUniforms.AppendElement(Argument("uTexCoordMultiplier"));
     result.mTextureCount = 1;
     break;
   case BGRARectLayerProgramType:
     MOZ_ASSERT(aMask == MaskNone, "BGRARectLayerProgramType can't handle masks.");
     result.mVertexShaderString = sLayerVS;
     result.mFragmentShaderString = sBGRARectTextureLayerFS;
     AddCommonArgs(result);
     AddCommonTextureArgs(result);
+    result.mUniforms.AppendElement(Argument("uTexCoordMultiplier"));
     result.mTextureCount = 1;
     break;
   case RGBAExternalLayerProgramType:
     if (aMask == Mask3d) {
       result.mVertexShaderString = sLayerMask3DVS;
       result.mFragmentShaderString = sRGBAExternalTextureLayerMask3DFS;
     } else if (aMask == Mask2d) {
       result.mVertexShaderString = sLayerMaskVS;
@@ -162,33 +188,16 @@ ProgramProfileOGL::GetProfileFor(ShaderP
       result.mFragmentShaderString = sSolidColorLayerMaskFS;
     } else {
       result.mVertexShaderString = sLayerVS;
       result.mFragmentShaderString = sSolidColorLayerFS;
     }
     AddCommonArgs(result);
     result.mUniforms.AppendElement(Argument("uRenderColor"));
     break;
-  case YCbCrLayerProgramType:
-    if (aMask == Mask2d) {
-      result.mVertexShaderString = sLayerMaskVS;
-      result.mFragmentShaderString = sYCbCrTextureLayerMaskFS;
-    } else {
-      result.mVertexShaderString = sLayerVS;
-      result.mFragmentShaderString = sYCbCrTextureLayerFS;
-    }
-    AddCommonArgs(result);
-    result.mUniforms.AppendElement(Argument("uLayerOpacity"));
-    result.mUniforms.AppendElement(Argument("uYTexture"));
-    result.mUniforms.AppendElement(Argument("uCbTexture"));
-    result.mUniforms.AppendElement(Argument("uCrTexture"));
-    result.mUniforms.AppendElement(Argument("uTextureTransform"));
-    result.mAttributes.AppendElement(Argument("aTexCoord"));
-    result.mTextureCount = 3;
-    break;
   case ComponentAlphaPass1ProgramType:
     if (aMask == Mask2d) {
       result.mVertexShaderString = sLayerMaskVS;
       result.mFragmentShaderString = sComponentPassMask1FS;
     } else {
       result.mVertexShaderString = sLayerVS;
       result.mFragmentShaderString = sComponentPass1FS;
     }
@@ -259,16 +268,17 @@ ProgramProfileOGL::GetProfileFor(ShaderP
     result.mTextureCount = 1;
     break;
   case Copy2DRectProgramType:
     NS_ASSERTION(!aMask, "Program does not have masked variant.");
     result.mVertexShaderString = sCopyVS;
     result.mFragmentShaderString = sCopy2DRectFS;
     result.mUniforms.AppendElement(Argument("uTexture"));
     result.mUniforms.AppendElement(Argument("uTextureTransform"));
+    result.mUniforms.AppendElement(Argument("uTexCoordMultiplier"));
     result.mAttributes.AppendElement(Argument("aVertexCoord"));
     result.mAttributes.AppendElement(Argument("aTexCoord"));
     result.mTextureCount = 1;
     break;
   default:
     NS_NOTREACHED("Unknown shader program type.");
   }
 
@@ -280,18 +290,17 @@ ProgramProfileOGL::GetProfileFor(ShaderP
 
   return result;
 }
 
 const char* const ShaderProgramOGL::VertexCoordAttrib = "aVertexCoord";
 const char* const ShaderProgramOGL::TexCoordAttrib = "aTexCoord";
 
 ShaderProgramOGL::ShaderProgramOGL(GLContext* aGL, const ProgramProfileOGL& aProfile)
-  : mIsProjectionMatrixStale(false)
-  , mGL(aGL)
+  : mGL(aGL)
   , mProgram(0)
   , mProfile(aProfile)
   , mProgramState(STATE_NEW)
 {}
 
 ShaderProgramOGL::~ShaderProgramOGL()
 {
   if (mProgram <= 0) {
@@ -306,18 +315,25 @@ ShaderProgramOGL::~ShaderProgramOGL()
   ctx->fDeleteProgram(mProgram);
 }
 
 bool
 ShaderProgramOGL::Initialize()
 {
   NS_ASSERTION(mProgramState == STATE_NEW, "Shader program has already been initialised");
 
-  if (!CreateProgram(mProfile.mVertexShaderString,
-                     mProfile.mFragmentShaderString)) {
+  ostringstream vs, fs;
+  for (uint32_t i = 0; i < mProfile.mDefines.Length(); ++i) {
+    vs << mProfile.mDefines[i] << endl;
+    fs << mProfile.mDefines[i] << endl;
+  }
+  vs << mProfile.mVertexShaderString << endl;
+  fs << mProfile.mFragmentShaderString << endl;
+
+  if (!CreateProgram(vs.str().c_str(), fs.str().c_str())) {
     mProgramState = STATE_ERROR;
     return false;
   }
 
   mProgramState = STATE_OK;
 
   for (uint32_t i = 0; i < mProfile.mUniforms.Length(); ++i) {
     mProfile.mUniforms[i].mLocation =
@@ -326,20 +342,16 @@ ShaderProgramOGL::Initialize()
   }
 
   for (uint32_t i = 0; i < mProfile.mAttributes.Length(); ++i) {
     mProfile.mAttributes[i].mLocation =
       mGL->fGetAttribLocation(mProgram, mProfile.mAttributes[i].mName);
     NS_ASSERTION(mProfile.mAttributes[i].mLocation >= 0, "Bad attribute location.");
   }
 
-  // this is a one-off that's present in the 2DRect versions of some shaders.
-  mTexCoordMultiplierUniformLocation =
-    mGL->fGetUniformLocation(mProgram, "uTexCoordMultiplier");
-
   return true;
 }
 
 GLint
 ShaderProgramOGL::CreateShader(GLenum aShaderType, const char *aShaderSource)
 {
   GLint success, len = 0;
 
@@ -482,20 +494,16 @@ ShaderProgramOGL::Activate()
       return;
     }
   }
   NS_ASSERTION(HasInitialized(), "Attempting to activate a program that's not in use!");
   mGL->fUseProgram(mProgram);
 #if CHECK_CURRENT_PROGRAM
   mGL->SetUserData(&sCurrentProgramKey, this);
 #endif
-  // check and set the projection matrix
-  if (mIsProjectionMatrixStale) {
-    SetProjectionMatrix(mProjectionMatrix);
-  }
 }
 
 
 void
 ShaderProgramOGL::SetUniform(GLint aLocation, float aFloatValue)
 {
   ASSERT_THIS_PROGRAM;
   NS_ASSERTION(aLocation >= 0, "Invalid location");
--- a/gfx/layers/opengl/LayerManagerOGLProgram.h
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.h
@@ -26,26 +26,26 @@ namespace mozilla {
 namespace gl {
 class GLContext;
 }
 namespace layers {
 
 class Layer;
 
 enum ShaderProgramType {
+  ColorLayerProgramType,
+  YCbCrLayerProgramType,
   RGBALayerProgramType,
   BGRALayerProgramType,
   RGBXLayerProgramType,
   BGRXLayerProgramType,
   RGBARectLayerProgramType,
   RGBXRectLayerProgramType,
   BGRARectLayerProgramType,
   RGBAExternalLayerProgramType,
-  ColorLayerProgramType,
-  YCbCrLayerProgramType,
   ComponentAlphaPass1ProgramType,
   ComponentAlphaPass1RGBProgramType,
   ComponentAlphaPass2ProgramType,
   ComponentAlphaPass2RGBProgramType,
   Copy2DProgramType,
   Copy2DRectProgramType,
   NumProgramTypes
 };
@@ -181,22 +181,22 @@ struct ProgramProfileOGL
   };
 
   // the source code for the program's shaders
   const char *mVertexShaderString;
   const char *mFragmentShaderString;
 
   nsTArray<Argument> mUniforms;
   nsTArray<Argument> mAttributes;
+  nsTArray<const char *> mDefines;
   uint32_t mTextureCount;
-  bool mHasMatrixProj;
-private:
-  ProgramProfileOGL() :
-    mTextureCount(0),
-    mHasMatrixProj(false) {}
+
+  ProgramProfileOGL(const char *aVS = nullptr, const char *aFS = nullptr) :
+    mVertexShaderString(aVS), mFragmentShaderString(aFS), mTextureCount(0)
+  {}
 };
 
 
 #if defined(DEBUG)
 #define CHECK_CURRENT_PROGRAM 1
 #define ASSERT_THIS_PROGRAM                                             \
   do {                                                                  \
     NS_ASSERTION(mGL->GetUserData(&sCurrentProgramKey) == this, \
@@ -238,20 +238,16 @@ public:
 
   /**
    * Lookup the location of an attribute
    */
   GLint AttribLocation(const char* aName) {
     return mProfile.LookupAttributeLocation(aName);
   }
 
-  GLint GetTexCoordMultiplierUniformLocation() {
-    return mTexCoordMultiplierUniformLocation;
-  }
-
   /**
    * aLayer is the mask layer to use for rendering, or null, if there is no
    * mask layer.
    * If aLayer is non-null, then the result of rendering aLayer is stored as
    * as a texture to be used by the shader. It is stored in the next available
    * texture unit, as determined by the texture unit requirements for the
    * shader.
    * Any other features of the mask layer required by the shader are also
@@ -291,28 +287,18 @@ public:
     gfx3DMatrix m;
     m._11 = aRect.width;
     m._22 = aRect.height;
     m._41 = aRect.x;
     m._42 = aRect.y;
     SetMatrixUniform(mProfile.LookupUniformLocation("uLayerQuadTransform"), m);
   }
 
-  // activates this program and sets its projection matrix, if the program uses one
-  void CheckAndSetProjectionMatrix(const gfx3DMatrix& aMatrix)
-  {
-    if (mProfile.mHasMatrixProj) {
-      mIsProjectionMatrixStale = true;
-      mProjectionMatrix = aMatrix;
-    }
-  }
-
   void SetProjectionMatrix(const gfx3DMatrix& aMatrix) {
     SetMatrixUniform(mProfile.LookupUniformLocation("uMatrixProj"), aMatrix);
-    mIsProjectionMatrixStale = false;
   }
 
   // sets this program's texture transform, if it uses one
   void SetTextureTransform(const gfx3DMatrix& aMatrix) {
     SetMatrixUniform(mProfile.LookupUniformLocation("uTextureTransform"), aMatrix);
   }
 
   void SetTextureTransform(const gfx::Matrix4x4& aMatrix) {
@@ -369,41 +355,47 @@ public:
   void SetRenderColor(const gfxRGBA& aColor) {
     SetUniform(mProfile.LookupUniformLocation("uRenderColor"), aColor);
   }
 
   void SetRenderColor(const gfx::Color& aColor) {
     SetUniform(mProfile.LookupUniformLocation("uRenderColor"), aColor);
   }
 
+  bool HasTexCoordMultiplier() {
+    return mProfile.LookupUniformLocation("uTexCoordMultiplier") != -1;
+  }
+
   void SetTexCoordMultiplier(float aWidth, float aHeight) {
     float f[] = {aWidth, aHeight};
-    SetUniform(mTexCoordMultiplierUniformLocation, 2, f);
+    SetUniform(mProfile.LookupUniformLocation("uTexCoordMultiplier"), 2, f);
+  }
+
+  // Set whether we want the component alpha shader to return the color
+  // vector (pass 1, false) or the alpha vector (pass 2, true). With support
+  // for multiple render targets we wouldn't need two passes here.
+  void SetTexturePass2(bool aFlag) {
+    SetUniform(mProfile.LookupUniformLocation("uTexturePass2"), aFlag ? 1 : 0);
   }
 
   // the names of attributes
   static const char* const VertexCoordAttrib;
   static const char* const TexCoordAttrib;
 
 protected:
-  gfx3DMatrix mProjectionMatrix;
-  // true if the projection matrix needs setting
-  bool mIsProjectionMatrixStale;
-
   RefPtr<GLContext> mGL;
   // the OpenGL id of the program
   GLuint mProgram;
   ProgramProfileOGL mProfile;
   enum {
     STATE_NEW,
     STATE_OK,
     STATE_ERROR
   } mProgramState;
 
-  GLint mTexCoordMultiplierUniformLocation;
 #ifdef CHECK_CURRENT_PROGRAM
   static int sCurrentProgramKey;
 #endif
 
   void SetUniform(GLint aLocation, float aFloatValue);
   void SetUniform(GLint aLocation, const gfxRGBA& aColor);
   void SetUniform(GLint aLocation, int aLength, float *aFloatValues);
   void SetUniform(GLint aLocation, GLint aIntValue);
--- a/gfx/layers/opengl/LayerManagerOGLShaders.h
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.h
@@ -109,19 +109,17 @@ static const char sSolidColorLayerFS[] =
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform vec4 uRenderColor;\n\
 void main()\n\
@@ -138,19 +136,17 @@ static const char sSolidColorLayerMaskFS
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -169,19 +165,17 @@ static const char sRGBATextureLayerFS[] 
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uTexture;\n\
 void main()\n\
@@ -197,19 +191,17 @@ static const char sRGBATextureLayerMaskF
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -228,19 +220,17 @@ static const char sRGBATextureLayerMask3
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec3 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -261,19 +251,17 @@ static const char sRGBARectTextureLayerF
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 /* This should not be used on GL ES */\n\
 #ifndef GL_ES\n\
@@ -299,19 +287,17 @@ static const char sRGBARectTextureLayerM
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -340,19 +326,17 @@ static const char sRGBARectTextureLayerM
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec3 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -382,19 +366,17 @@ static const char sRGBXRectTextureLayerF
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 /* This should not be used on GL ES */\n\
 #ifndef GL_ES\n\
@@ -420,19 +402,17 @@ static const char sRGBXRectTextureLayerM
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -461,19 +441,17 @@ static const char sRGBXRectTextureLayerM
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec3 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -503,19 +481,17 @@ static const char sBGRARectTextureLayerF
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2DRect uTexture;\n\
 uniform vec2 uTexCoordMultiplier;\n\
@@ -531,19 +507,17 @@ static const char sRGBAExternalTextureLa
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform samplerExternalOES uTexture;\n\
 void main()\n\
@@ -560,19 +534,17 @@ static const char sRGBAExternalTextureLa
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -592,19 +564,17 @@ static const char sRGBAExternalTextureLa
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec3 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -624,19 +594,17 @@ static const char sBGRATextureLayerFS[] 
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uTexture;\n\
 void main()\n\
@@ -652,19 +620,17 @@ static const char sBGRATextureLayerMaskF
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -683,19 +649,17 @@ static const char sRGBXTextureLayerFS[] 
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uTexture;\n\
 void main()\n\
@@ -711,19 +675,17 @@ static const char sRGBXTextureLayerMaskF
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -742,19 +704,17 @@ static const char sBGRXTextureLayerFS[] 
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uTexture;\n\
 void main()\n\
@@ -770,19 +730,17 @@ static const char sBGRXTextureLayerMaskF
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -791,120 +749,208 @@ uniform sampler2D uTexture;\n\
 void main()\n\
 {\n\
 float mask = texture2D(uMaskTexture, vMaskCoord).r;\n\
 \n\
 gl_FragColor = vec4(texture2D(uTexture, vTexCoord).bgr, 1.0) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
-static const char sYCbCrTextureLayerFS[] = "/* sYCbCrTextureLayerFS */\n\
-/* Fragment Shader */\n\
-#ifdef GL_ES\n\
-#ifdef MEDIUMP_SHADER\n\
-precision mediump float;\n\
-#else\n\
-precision lowp float;\n\
-#endif\n\
-#endif\n\
-\n\
-#ifndef NO_LAYER_OPACITY\n\
-uniform float uLayerOpacity;\n\
-#endif\n\
+static const char sUnifiedLayerVS[] = "/* sUnifiedLayerVS */\n\
+/* Vertex Shader */\n\
+uniform mat4 uMatrixProj;\n\
+uniform mat4 uLayerQuadTransform;\n\
+uniform mat4 uLayerTransform;\n\
+uniform vec4 uRenderTargetOffset;\n\
+attribute vec4 aVertexCoord;\n\
+#ifndef ENABLE_RENDER_COLOR\n\
+uniform mat4 uTextureTransform;\n\
+attribute vec2 aTexCoord;\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
-\n\
+#endif\n\
+#ifdef ENABLE_MASK\n\
+uniform mat4 uMaskQuadTransform;\n\
+varying vec3 vMaskCoord;\n\
+#endif\n\
+void main()\n\
+{\n\
+vec4 finalPosition = aVertexCoord;\n\
+finalPosition = uLayerQuadTransform * finalPosition;\n\
+finalPosition = uLayerTransform * finalPosition;\n\
+finalPosition.xyz /= finalPosition.w;\n\
+#ifdef ENABLE_MASK\n\
+vMaskCoord.xy = (uMaskQuadTransform * vec4(finalPosition.xyz, 1.0)).xy;\n\
+// correct for perspective correct interpolation, see comment in D3D10 shader\n\
+vMaskCoord.z = 1.0;\n\
+vMaskCoord *= finalPosition.w;\n\
+#endif\n\
+finalPosition = finalPosition - uRenderTargetOffset;\n\
+finalPosition.xyz *= finalPosition.w;\n\
+finalPosition = uMatrixProj * finalPosition;\n\
+#ifndef ENABLE_RENDER_COLOR\n\
+vTexCoord = (uTextureTransform * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;\n\
+#endif\n\
+gl_Position = finalPosition;\n\
+}\n\
+";
+
+static const char sUnifiedLayerFS[] = "/* sUnifiedLayerFS */\n\
 #ifdef GL_ES\n\
-precision mediump float;\n\
+precision lowp float;\n\
+#endif\n\
+#ifdef ENABLE_RENDER_COLOR\n\
+uniform vec4 uRenderColor;\n\
+#else\n\
+#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
+varying mediump vec2 vTexCoord;\n\
+#else\n\
+varying vec2 vTexCoord;\n\
 #endif\n\
+#ifdef ENABLE_OPACITY\n\
+uniform float uLayerOpacity;\n\
+#endif\n\
+#endif\n\
+#ifdef ENABLE_TEXTURE_RECT\n\
+#extension GL_ARB_texture_rectangle : require\n\
+#define sampler2D sampler2DRect\n\
+#define texture2D texture2DRect\n\
+#endif\n\
+#ifdef ENABLE_TEXTURE_EXTERNAL\n\
+#extension GL_OES_EGL_image_external : require\n\
+#define sampler2D samplerExternalOES\n\
+#endif\n\
+#ifdef ENABLE_TEXTURE_YCBCR\n\
 uniform sampler2D uYTexture;\n\
 uniform sampler2D uCbTexture;\n\
 uniform sampler2D uCrTexture;\n\
-void main()\n\
+#else\n\
+#ifdef ENABLE_TEXTURE_COMPONENT_ALPHA\n\
+uniform sampler2D uBlackTexture;\n\
+uniform sampler2D uWhiteTexture;\n\
+uniform bool uTexturePass2;\n\
+#else\n\
+uniform sampler2D uTexture;\n\
+#endif\n\
+#endif\n\
+#ifdef ENABLE_BLUR\n\
+uniform bool uBlurAlpha;\n\
+uniform vec2 uBlurRadius;\n\
+uniform vec2 uBlurOffset;\n\
+#define GAUSSIAN_KERNEL_HALF_WIDTH 11\n\
+#define GAUSSIAN_KERNEL_STEP 0.2\n\
+uniform float uBlurGaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH];\n\
+#endif\n\
+#ifdef ENABLE_COLOR_MATRIX\n\
+uniform mat4 uColorMatrix;\n\
+uniform vec4 uColorMatrixVector;\n\
+#endif\n\
+#ifdef ENABLE_MASK\n\
+varying vec3 vMaskCoord;\n\
+uniform sampler2D uMaskTexture;\n\
+#endif\n\
+vec4 sample(vec2 coord)\n\
 {\n\
 vec4 color;\n\
-float y = texture2D(uYTexture, vTexCoord).r;\n\
-float cb = texture2D(uCbTexture, vTexCoord).r;\n\
-float cr = texture2D(uCrTexture, vTexCoord).r;\n\
+#ifdef ENABLE_TEXTURE_YCBCR\n\
+float y = texture2D(uYTexture, coord).r;\n\
+float cb = texture2D(uCbTexture, coord).r;\n\
+float cr = texture2D(uCrTexture, coord).r;\n\
 y = (y - 0.0625) * 1.164;\n\
 cb = cb - 0.5;\n\
 cr = cr - 0.5;\n\
 color.r = y + cr * 1.596;\n\
 color.g = y - 0.813 * cr - 0.391 * cb;\n\
 color.b = y + cb * 2.018;\n\
 color.a = 1.0;\n\
-float mask = 1.0;\n\
-\n\
-gl_FragColor = color * uLayerOpacity * mask;\n\
-}\n\
-";
-
-static const char sYCbCrTextureLayerMaskFS[] = "/* sYCbCrTextureLayerMaskFS */\n\
-/* Fragment Shader */\n\
-#ifdef GL_ES\n\
-#ifdef MEDIUMP_SHADER\n\
-precision mediump float;\n\
 #else\n\
-precision lowp float;\n\
+#ifdef ENABLE_TEXTURE_COMPONENT_ALPHA\n\
+vec3 onBlack = texture2D(uBlackTexture, coord).rgb;\n\
+vec3 onWhite = texture2D(uWhiteTexture, coord).rgb;\n\
+vec4 alphas = (1.0 - onWhite + onBlack).rgbg;\n\
+if (uTexturePass2)\n\
+color = vec4(onBlack, alphas.a);\n\
+else\n\
+color = alphas;\n\
+#else\n\
+color = texture2D(uTexture, coord);\n\
 #endif\n\
 #endif\n\
-\n\
-#ifndef NO_LAYER_OPACITY\n\
-uniform float uLayerOpacity;\n\
+#ifdef ENABLE_TEXTURE_RB_SWAP\n\
+color = color.bgra;\n\
 #endif\n\
-#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
-varying mediump vec2 vTexCoord;\n\
-#else\n\
-varying vec2 vTexCoord;\n\
+#ifdef ENABLE_TEXTURE_NO_ALPHA\n\
+color = vec4(color.rgb, 1.0);\n\
 #endif\n\
-\n\
-varying vec2 vMaskCoord;\n\
-uniform sampler2D uMaskTexture;\n\
-\n\
-#ifdef GL_ES\n\
-precision mediump float;\n\
+return color;\n\
+}\n\
+#ifdef ENABLE_BLUR\n\
+vec4 sampleAtRadius(vec2 coord, float radius) {\n\
+coord += uBlurOffset;\n\
+coord += radius * uBlurRadius;\n\
+if (coord.x < 0. || coord.y < 0. || coord.x > 1. || coord.y > 1.)\n\
+return vec4(0, 0, 0, 0);\n\
+return sample(coord);\n\
+}\n\
+vec4 blur(vec4 color, vec2 coord) {\n\
+vec4 total = color * uBlurGaussianKernel[0];\n\
+for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; ++i) {\n\
+float r = float(i) * GAUSSIAN_KERNEL_STEP;\n\
+float k = uBlurGaussianKernel[i];\n\
+total += sampleAtRadius(coord, r) * k;\n\
+total += sampleAtRadius(coord, -r) * k;\n\
+}\n\
+if (uBlurAlpha) {\n\
+color *= total.a;\n\
+} else {\n\
+color = total;\n\
+}\n\
+return color;\n\
+}\n\
 #endif\n\
-uniform sampler2D uYTexture;\n\
-uniform sampler2D uCbTexture;\n\
-uniform sampler2D uCrTexture;\n\
 void main()\n\
 {\n\
 vec4 color;\n\
-float y = texture2D(uYTexture, vTexCoord).r;\n\
-float cb = texture2D(uCbTexture, vTexCoord).r;\n\
-float cr = texture2D(uCrTexture, vTexCoord).r;\n\
-y = (y - 0.0625) * 1.164;\n\
-cb = cb - 0.5;\n\
-cr = cr - 0.5;\n\
-color.r = y + cr * 1.596;\n\
-color.g = y - 0.813 * cr - 0.391 * cb;\n\
-color.b = y + cb * 2.018;\n\
-color.a = 1.0;\n\
-float mask = texture2D(uMaskTexture, vMaskCoord).r;\n\
-\n\
-gl_FragColor = color * uLayerOpacity * mask;\n\
+#ifdef ENABLE_RENDER_COLOR\n\
+color = uRenderColor;\n\
+#else\n\
+color = sample(vTexCoord);\n\
+#ifdef ENABLE_BLUR\n\
+color = blur(color, vTexCoord);\n\
+#endif\n\
+#ifdef ENABLE_COLOR_MATRIX\n\
+color = uColorMatrix * vec4(color.rgb / color.a, color.a) + uColorMatrixVector;\n\
+color.rgb *= color.a;\n\
+#endif\n\
+#ifdef ENABLE_OPACITY\n\
+color *= uLayerOpacity;\n\
+#endif\n\
+#endif\n\
+#ifdef ENABLE_MASK\n\
+vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
+color *= texture2D(uMaskTexture, maskCoords).r;\n\
+#endif\n\
+gl_FragColor = color;\n\
 }\n\
 ";
 
 static const char sComponentPass1FS[] = "/* sComponentPass1FS */\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uBlackTexture;\n\
 uniform sampler2D uWhiteTexture;\n\
@@ -924,19 +970,17 @@ static const char sComponentPassMask1FS[
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -959,19 +1003,17 @@ static const char sComponentPass1RGBFS[]
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uBlackTexture;\n\
 uniform sampler2D uWhiteTexture;\n\
@@ -991,19 +1033,17 @@ static const char sComponentPassMask1RGB
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -1026,19 +1066,17 @@ static const char sComponentPass2FS[] = 
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uBlackTexture;\n\
 uniform sampler2D uWhiteTexture;\n\
@@ -1058,19 +1096,17 @@ static const char sComponentPassMask2FS[
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
@@ -1093,19 +1129,17 @@ static const char sComponentPass2RGBFS[]
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 uniform sampler2D uBlackTexture;\n\
 uniform sampler2D uWhiteTexture;\n\
@@ -1125,19 +1159,17 @@ static const char sComponentPassMask2RGB
 #ifdef GL_ES\n\
 #ifdef MEDIUMP_SHADER\n\
 precision mediump float;\n\
 #else\n\
 precision lowp float;\n\
 #endif\n\
 #endif\n\
 \n\
-#ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
-#endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
--- a/gfx/layers/opengl/LayerManagerOGLShaders.txt
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt
@@ -144,19 +144,17 @@ precision lowp float;
 #endif
 #endif
 @end
 
 // fragment shader header for layers
 @define LAYER_FRAGMENT<>
 $FRAGMENT_SHADER_HEADER$
 
-#ifndef NO_LAYER_OPACITY
 uniform float uLayerOpacity;
-#endif
 
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range
 varying mediump vec2 vTexCoord;
 #else
 varying vec2 vTexCoord;
 #endif
 @end
 
@@ -328,52 +326,227 @@ uniform sampler2D uTexture;
 
 void main()
 {
 $FRAGMENT_CALC_MASK<mask>$
   gl_FragColor = vec4(texture2D(uTexture, vTexCoord).bgr, 1.0) * uLayerOpacity * mask;
 }
 @end
 
-// Three textures, representing YCbCr planes of a video image.
+@shader sUnifiedLayerVS
+/* Vertex Shader */
+
+uniform mat4 uMatrixProj;
+uniform mat4 uLayerQuadTransform;
+uniform mat4 uLayerTransform;
+uniform vec4 uRenderTargetOffset;
+
+attribute vec4 aVertexCoord;
+
+#ifndef ENABLE_RENDER_COLOR
+uniform mat4 uTextureTransform;
+attribute vec2 aTexCoord;
+
+#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range
+varying mediump vec2 vTexCoord;
+#else
+varying vec2 vTexCoord;
+#endif
+#endif
+
+#ifdef ENABLE_MASK
+uniform mat4 uMaskQuadTransform;
+varying vec3 vMaskCoord;
+#endif
+
+void main()
+{
+  vec4 finalPosition = aVertexCoord;
+  finalPosition = uLayerQuadTransform * finalPosition;
+  finalPosition = uLayerTransform * finalPosition;
+  finalPosition.xyz /= finalPosition.w;
+
+#ifdef ENABLE_MASK
+  vMaskCoord.xy = (uMaskQuadTransform * vec4(finalPosition.xyz, 1.0)).xy;
+  // correct for perspective correct interpolation, see comment in D3D10 shader
+  vMaskCoord.z = 1.0;
+  vMaskCoord *= finalPosition.w;
+#endif
+
+  finalPosition = finalPosition - uRenderTargetOffset;
+  finalPosition.xyz *= finalPosition.w;
+  finalPosition = uMatrixProj * finalPosition;
+
+#ifndef ENABLE_RENDER_COLOR
+  vTexCoord = (uTextureTransform * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;
+#endif
+
+  gl_Position = finalPosition;
+}
+@end
+
+// Layer fragment shader
 //
 // Some older versions of the Tegra 2 android driver have a bug
 // where arithmetic ops on a texture read are just ignored.  So,
 // if the below was |cb = texture2D(...).r - 0.5|, the "- 0.5" was
 // just being ignored/skipped.  This, of course, lead to crappy
 // rendering -- see bug 765150.  Doing them separately like below
 // makes it all OK.  We don't know if this is special to constants,
 // special to 0.5, special to addition/subtraction, etc.
-@shader sYCbCrTextureLayer<mask:,Mask>FS
-$LAYER_FRAGMENT<mask>$
+@shader sUnifiedLayerFS
 #ifdef GL_ES
-precision mediump float;
+precision lowp float;
+#endif
+
+#ifdef ENABLE_RENDER_COLOR
+uniform vec4 uRenderColor;
+#else
+#ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range
+varying mediump vec2 vTexCoord;
+#else
+varying vec2 vTexCoord;
+#endif
+#ifdef ENABLE_OPACITY
+uniform float uLayerOpacity;
 #endif
+#endif
+
+#ifdef ENABLE_TEXTURE_RECT
+#extension GL_ARB_texture_rectangle : require
+#define sampler2D sampler2DRect
+#define texture2D texture2DRect
+#endif
+
+#ifdef ENABLE_TEXTURE_EXTERNAL
+#extension GL_OES_EGL_image_external : require
+#define sampler2D samplerExternalOES
+#endif
+
+#ifdef ENABLE_TEXTURE_YCBCR
 uniform sampler2D uYTexture;
 uniform sampler2D uCbTexture;
 uniform sampler2D uCrTexture;
+#else
+#ifdef ENABLE_TEXTURE_COMPONENT_ALPHA
+uniform sampler2D uBlackTexture;
+uniform sampler2D uWhiteTexture;
+uniform bool uTexturePass2;
+#else
+uniform sampler2D uTexture;
+#endif
+#endif
 
-void main()
+#ifdef ENABLE_BLUR
+uniform bool uBlurAlpha;
+uniform vec2 uBlurRadius;
+uniform vec2 uBlurOffset;
+#define GAUSSIAN_KERNEL_HALF_WIDTH 11
+#define GAUSSIAN_KERNEL_STEP 0.2
+uniform float uBlurGaussianKernel[GAUSSIAN_KERNEL_HALF_WIDTH];
+#endif
+
+#ifdef ENABLE_COLOR_MATRIX
+uniform mat4 uColorMatrix;
+uniform vec4 uColorMatrixVector;
+#endif
+
+#ifdef ENABLE_MASK
+varying vec3 vMaskCoord;
+uniform sampler2D uMaskTexture;
+#endif
+
+vec4 sample(vec2 coord)
 {
   vec4 color;
 
-  float y = texture2D(uYTexture, vTexCoord).r;
-  float cb = texture2D(uCbTexture, vTexCoord).r;
-  float cr = texture2D(uCrTexture, vTexCoord).r;
+#ifdef ENABLE_TEXTURE_YCBCR
+  float y = texture2D(uYTexture, coord).r;
+  float cb = texture2D(uCbTexture, coord).r;
+  float cr = texture2D(uCrTexture, coord).r;
 
   y = (y - 0.0625) * 1.164;
   cb = cb - 0.5;
   cr = cr - 0.5;
 
   color.r = y + cr * 1.596;
   color.g = y - 0.813 * cr - 0.391 * cb;
   color.b = y + cb * 2.018;
   color.a = 1.0;
-$FRAGMENT_CALC_MASK<mask>$
-  gl_FragColor = color * uLayerOpacity * mask;
+#else
+#ifdef ENABLE_TEXTURE_COMPONENT_ALPHA
+  vec3 onBlack = texture2D(uBlackTexture, coord).rgb;
+  vec3 onWhite = texture2D(uWhiteTexture, coord).rgb;
+  vec4 alphas = (1.0 - onWhite + onBlack).rgbg;
+  if (uTexturePass2)
+    color = vec4(onBlack, alphas.a);
+  else
+    color = alphas;
+#else
+  color = texture2D(uTexture, coord);
+#endif
+#endif
+#ifdef ENABLE_TEXTURE_RB_SWAP
+  color = color.bgra;
+#endif
+#ifdef ENABLE_TEXTURE_NO_ALPHA
+  color = vec4(color.rgb, 1.0);
+#endif
+  return color;
+}
+
+#ifdef ENABLE_BLUR
+vec4 sampleAtRadius(vec2 coord, float radius) {
+  coord += uBlurOffset;
+  coord += radius * uBlurRadius;
+  if (coord.x < 0. || coord.y < 0. || coord.x > 1. || coord.y > 1.)
+    return vec4(0, 0, 0, 0);
+  return sample(coord);
+}
+
+vec4 blur(vec4 color, vec2 coord) {
+  vec4 total = color * uBlurGaussianKernel[0];
+  for (int i = 1; i < GAUSSIAN_KERNEL_HALF_WIDTH; ++i) {
+    float r = float(i) * GAUSSIAN_KERNEL_STEP;
+    float k = uBlurGaussianKernel[i];
+    total += sampleAtRadius(coord, r) * k;
+    total += sampleAtRadius(coord, -r) * k;
+  }
+  if (uBlurAlpha) {
+    color *= total.a;
+  } else {
+    color = total;
+  }
+  return color;
+}
+#endif
+
+void main()
+{
+  vec4 color;
+#ifdef ENABLE_RENDER_COLOR
+  color = uRenderColor;
+#else
+  color = sample(vTexCoord);
+#ifdef ENABLE_BLUR
+  color = blur(color, vTexCoord);
+#endif
+#ifdef ENABLE_COLOR_MATRIX
+  color = uColorMatrix * vec4(color.rgb / color.a, color.a) + uColorMatrixVector;
+  color.rgb *= color.a;
+#endif
+#ifdef ENABLE_OPACITY
+  color *= uLayerOpacity;
+#endif
+#endif
+#ifdef ENABLE_MASK
+  vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;
+  color *= texture2D(uMaskTexture, maskCoords).r;
+#endif
+  gl_FragColor = color;
 }
 @end
 
 // Two textures and two passes for component alpha rendering
 @shader sComponentPass<mask:,Mask>1FS
 
 $LAYER_FRAGMENT<mask>$
 uniform sampler2D uBlackTexture;
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -92,39 +92,16 @@ protected:
  * released. At the moment the teardown sequence happens in the middle of
  * the nsBaseWidget's destructor, meaning that at a given moment we must be
  * able to easily find and release all the GL resources.
  * The point is: be careful about the ownership model and limit the number
  * of objects sharing references to GL resources to make the tear down
  * sequence as simple as possible.
  */
 
-inline ShaderProgramType
-GetProgramTypeForSurfaceFormat(gfx::SurfaceFormat aFormat)
- {
-  switch (aFormat) {
-  case gfx::FORMAT_B8G8R8A8:
-    return BGRALayerProgramType;;
-  case gfx::FORMAT_B8G8R8X8:
-    return BGRXLayerProgramType;;
-  case gfx::FORMAT_R8G8B8X8:
-    return RGBXLayerProgramType;;
-  case gfx::FORMAT_R8G8B8A8:
-    return RGBALayerProgramType;;
-  default:
-    MOZ_CRASH("unhandled program type");
-  }
-}
-
-inline ShaderProgramType
-GetProgramTypeForTexture(const DeprecatedTextureHost *aDeprecatedTextureHost)
-{
-  return GetProgramTypeForSurfaceFormat(aDeprecatedTextureHost->GetFormat());
-}
-
 /**
  * TextureSourceOGL provides the necessary API for CompositorOGL to composite
  * a TextureSource.
  */
 class TextureSourceOGL
 {
 public:
   virtual bool IsValid() const = 0;
@@ -139,16 +116,24 @@ public:
 
   virtual gfx::SurfaceFormat GetFormat() const = 0;
 
   virtual GLenum GetWrapMode() const = 0;
 
   virtual gfx3DMatrix GetTextureTransform() { return gfx3DMatrix(); }
 
   virtual TextureImageDeprecatedTextureHostOGL* AsTextureImageDeprecatedTextureHost() { return nullptr; }
+
+  // Return the effective texture transform, compensating for the fact that
+  // IOSurface uses 0,0...w,h coordinate rather then 0,0..1,1.
+  const gfx3DMatrix GetEffectiveTextureTransform() {
+    if (GetTextureTarget() == LOCAL_GL_TEXTURE_RECTANGLE_ARB)
+      return GetTextureTransform() * gfx3DMatrix::ScalingMatrix(GetSize().width, GetSize().height, 1.0f);
+    return GetTextureTransform();
+  }
 };
 
 /**
  * A TextureSource backed by a TextureImage.
  *
  * Depending on the underlying TextureImage, may support texture tiling, so
  * make sure to check AsTileIterator() and use the texture accordingly.
  *
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -192,27 +192,29 @@ ThebesLayerBufferOGL::RenderTo(const nsI
                                  ComponentAlphaPass2RGBProgramType :
                                  ComponentAlphaPass2ProgramType;
         alphaProgram = aManager->GetProgram(type, mLayer->GetMaskLayer());
         gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
       }
 
       alphaProgram->Activate();
+      alphaProgram->SetProjectionMatrix(aManager->mProjMatrix);
       alphaProgram->SetBlackTextureUnit(0);
       alphaProgram->SetWhiteTextureUnit(1);
       program = alphaProgram;
     } else {
       // Note BGR: Cairo's image surfaces are always in what
       // OpenGL and our shaders consider BGR format.
       ShaderProgramOGL* basicProgram =
         aManager->GetProgram(ShaderProgramFromSurfaceFormat(mTexImage->GetTextureFormat()),
                              mLayer->GetMaskLayer());
 
       basicProgram->Activate();
+      basicProgram->SetProjectionMatrix(aManager->mProjMatrix);
       basicProgram->SetTextureUnit(0);
       program = basicProgram;
     }
 
     program->SetLayerOpacity(mLayer->GetEffectiveOpacity());
     program->SetLayerTransform(mLayer->GetEffectiveTransform());
     program->SetTextureTransform(gfx3DMatrix());
     program->SetRenderOffset(aOffset);
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -333,35 +333,41 @@ public:
     nsRefPtr<GLContext> context = gl::GLContextProvider::CreateForWindow(aWindow);
     return context ? new GLPresenter(context) : nullptr;
   }
 
   GLPresenter(GLContext* aContext);
   virtual ~GLPresenter();
 
   virtual GLContext* gl() const MOZ_OVERRIDE { return mGLContext; }
-  virtual ShaderProgramOGL* GetProgram(ShaderProgramType aType) MOZ_OVERRIDE
+  virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) MOZ_OVERRIDE
   {
-    MOZ_ASSERT(aType == RGBARectLayerProgramType, "unexpected program type");
+    MOZ_ASSERT(aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+    MOZ_ASSERT(aFormat == gfx::FORMAT_R8G8B8A8);
     return mRGBARectProgram;
   }
+  virtual const gfx3DMatrix& GetProjMatrix() const MOZ_OVERRIDE
+  {
+    return mProjMatrix;
+  }
   virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) MOZ_OVERRIDE;
 
   void BeginFrame(nsIntSize aRenderSize);
   void EndFrame();
 
   NSOpenGLContext* GetNSOpenGLContext()
   {
     return static_cast<NSOpenGLContext*>(
       mGLContext->GetNativeData(GLContext::NativeGLContext));
   }
 
 protected:
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
   nsAutoPtr<mozilla::layers::ShaderProgramOGL> mRGBARectProgram;
+  gfx3DMatrix mProjMatrix;
   GLuint mQuadVBO;
 };
 
 } // unnamed namespace
 
 #pragma mark -
 
 nsChildView::nsChildView() : nsBaseWidget()
@@ -2612,27 +2618,30 @@ RectTextureImage::UpdateFromDrawTarget(c
   mUpdateDrawTarget = nullptr;
 }
 
 void
 RectTextureImage::Draw(GLManager* aManager,
                        const nsIntPoint& aLocation,
                        const gfx3DMatrix& aTransform)
 {
-  ShaderProgramOGL* program = aManager->GetProgram(RGBARectLayerProgramType);
+  ShaderProgramOGL* program = aManager->GetProgram(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+                                                   gfx::FORMAT_R8G8B8A8);
 
   aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture);
 
   program->Activate();
+  program->SetProjectionMatrix(aManager->GetProjMatrix());
   program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mUsedSize));
   program->SetLayerTransform(aTransform * gfx3DMatrix::Translation(aLocation.x, aLocation.y, 0));
-  program->SetTextureTransform(gfx3DMatrix());
-  program->SetLayerOpacity(1.0);
+  program->SetTextureTransform(gfx3DMatrix::ScalingMatrix(mUsedSize.width, mUsedSize.height, 1.0f));
   program->SetRenderOffset(nsIntPoint(0, 0));
-  program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height);
+  if (program->HasTexCoordMultiplier()) {
+    program->SetTexCoordMultiplier(1.0f, 1.0f);
+  }
   program->SetTextureUnit(0);
 
   aManager->BindAndDrawQuad(program);
 
   aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
 }
 
 // GLPresenter implementation
@@ -2664,17 +2673,17 @@ GLPresenter::~GLPresenter()
   if (mQuadVBO) {
     mGLContext->MakeCurrent();
     mGLContext->fDeleteBuffers(1, &mQuadVBO);
     mQuadVBO = 0;
   }
 }
 
 void
-GLPresenter::BindAndDrawQuad(ShaderProgramOGL* aProgram)
+GLPresenter::BindAndDrawQuad(ShaderProgramOGL *aProgram)
 {
   mGLContext->MakeCurrent();
 
   GLuint vertAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
   GLuint texCoordAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
 
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
   mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
@@ -2702,17 +2711,17 @@ GLPresenter::BeginFrame(nsIntSize aRende
   gfxMatrix viewMatrix;
   viewMatrix.Translate(-gfxPoint(1.0, -1.0));
   viewMatrix.Scale(2.0f / float(aRenderSize.width), 2.0f / float(aRenderSize.height));
   viewMatrix.Scale(1.0f, -1.0f);
 
   gfx3DMatrix matrix3d = gfx3DMatrix::From2D(viewMatrix);
   matrix3d._33 = 0.0f;
 
-  mRGBARectProgram->CheckAndSetProjectionMatrix(matrix3d);
+  mProjMatrix = matrix3d;
 
   // Default blend function implements "OVER"
   mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                  LOCAL_GL_ONE, LOCAL_GL_ONE);
   mGLContext->fEnable(LOCAL_GL_BLEND);
 
   mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
   mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);