b=567626; fix up opengl layers; r=bas
authorVladimir Vukicevic <vladimir@pobox.com>
Mon, 24 May 2010 23:35:35 -0700
changeset 42791 683e229680747c5344e3abfdc46af35e40c2cf3c
parent 42790 7536d09c992205cb75e5c7235c79b75907cc77bf
child 42792 ec3dafe67d2b8f1b9de7c0daa523d1e0b5ac6dcf
push idunknown
push userunknown
push dateunknown
reviewersbas
bugs567626
milestone1.9.3a5pre
b=567626; fix up opengl layers; r=bas
gfx/layers/Makefile.in
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/CanvasLayerOGL.h
gfx/layers/opengl/ColorLayerOGL.cpp
gfx/layers/opengl/ColorLayerOGL.h
gfx/layers/opengl/ContainerLayerOGL.cpp
gfx/layers/opengl/ContainerLayerOGL.h
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.h
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
gfx/layers/opengl/LayerManagerOGLProgram.h
gfx/layers/opengl/LayerManagerOGLShaders.h
gfx/layers/opengl/LayerManagerOGLShaders.txt
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.h
gfx/layers/opengl/genshaders.py
gfx/thebes/public/GLContext.h
gfx/thebes/public/gfx3DMatrix.h
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -57,16 +57,17 @@ ifdef MOZ_DEBUG
 DEFINES += -DD3D_DEBUG_INFO
 endif
 
 EXPORTS = \
         BasicLayers.h \
         ImageLayers.h \
         Layers.h \
         LayerManagerOGL.h \
+        LayerManagerOGLProgram.h \
         $(NULL)
 
 CPPSRCS = \
         BasicImages.cpp \
         BasicLayers.cpp \
         LayerManagerOGL.cpp \
         ColorLayerOGL.cpp \
         ThebesLayerOGL.cpp \
@@ -85,11 +86,26 @@ CPPSRCS += \
         ContainerLayerD3D9.cpp \
         ImageLayerD3D9.cpp \
         ColorLayerD3D9.cpp \
         CanvasLayerD3D9.cpp \
         $(NULL)
 endif
 endif
 
+# Enable GLES2.0 under maemo
+ifdef MOZ_X11
+ifdef MOZ_PLATFORM_MAEMO
+DEFINES += -DUSE_GLES2
+endif
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
+
+LayerManagerOGLShaders.h: LayerManagerOGLShaders.txt genshaders.py
+	$(PYTHON) $(srcdir)/opengl/genshaders.py $< $@
+
+LayerManagerOGL.$(OBJ_SUFFIX): LayerManagerOGLShaders.h
+
+GARBAGE += LayerManagerOGLShaders.h
+
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-/
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -50,214 +50,202 @@
 #endif
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::gl;
 
 CanvasLayerOGL::~CanvasLayerOGL()
 {
-  LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
-  GLContext *gl = glManager->gl();
-  glManager->MakeCurrent();
+  mOGLManager->MakeCurrent();
 
-  if (mTexture) {
-    gl->fDeleteTextures(1, &mTexture);
-  }
+  if (mTexture)
+    gl()->fDeleteTextures(1, &mTexture);
 }
 
 void
 CanvasLayerOGL::Initialize(const Data& aData)
 {
-  NS_ASSERTION(mSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
+  NS_ASSERTION(mCanvasSurface == nsnull, "BasicCanvasLayer::Initialize called twice!");
 
   if (aData.mSurface) {
-    mSurface = aData.mSurface;
+    mCanvasSurface = aData.mSurface;
     NS_ASSERTION(aData.mGLContext == nsnull,
                  "CanvasLayerOGL can't have both surface and GLContext");
-    mNeedsYFlip = PR_TRUE;
+    mNeedsYFlip = PR_FALSE;
   } else if (aData.mGLContext) {
     // this must be a pbuffer context
     void *pbuffer = aData.mGLContext->GetNativeData(GLContext::NativePBuffer);
     if (!pbuffer) {
       NS_WARNING("CanvasLayerOGL with GL context without NativePBuffer");
       return;
     }
 
-    mGLContext = aData.mGLContext;
+    mCanvasGLContext = aData.mGLContext;
     mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied;
-    mNeedsYFlip = PR_FALSE;
+    mNeedsYFlip = PR_TRUE;
   } else {
     NS_WARNING("CanvasLayerOGL::Initialize called without surface or GL context!");
     return;
   }
 
   mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
 }
 
 void
 CanvasLayerOGL::Updated(const nsIntRect& aRect)
 {
-  LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
-  GLContext *gl = glManager->gl();
-  glManager->MakeCurrent();
+  NS_ASSERTION(mUpdatedRect.IsEmpty(),
+               "CanvasLayer::Updated called more than once during a transaction!");
 
-  NS_ASSERTION(mUpdatedRect.IsEmpty(), "CanvasLayer::Updated called more than once during a transaction!");
+  mOGLManager->MakeCurrent();
 
   mUpdatedRect.UnionRect(mUpdatedRect, aRect);
 
-  if (mSurface) {
+  if (mCanvasSurface) {
     if (mTexture == 0) {
-      gl->fGenTextures(1, (GLuint*)&mTexture);
+      gl()->fGenTextures(1, &mTexture);
 
-      gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+      gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+      gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
 
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
       mUpdatedRect = mBounds;
     } else {
-      gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+      gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
     }
 
     nsRefPtr<gfxImageSurface> updatedAreaImageSurface;
-    nsRefPtr<gfxASurface> sourceSurface = mSurface;
+    nsRefPtr<gfxASurface> sourceSurface = mCanvasSurface;
 
 #ifdef XP_WIN
     if (sourceSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
       sourceSurface = static_cast<gfxWindowsSurface*>(sourceSurface.get())->GetImageSurface();
       if (!sourceSurface)
-        sourceSurface = mSurface;
+        sourceSurface = mCanvasSurface;
     }
 #endif
 
 #if 0
     // XXX don't copy, blah.
     // but need to deal with stride on the gl side; do this later.
-    if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) {
-      gfxImageSurface *s = static_cast<gfxImageSurface*>(mSurface.get());
+    if (mCanvasSurface->GetType() == gfxASurface::SurfaceTypeImage) {
+      gfxImageSurface *s = static_cast<gfxImageSurface*>(mCanvasSurface.get());
       if (s->Format() == gfxASurface::ImageFormatARGB32 ||
           s->Format() == gfxASurface::ImageFormatRGB24)
       {
         updatedAreaImageSurface = ...;
       } else {
         NS_WARNING("surface with format that we can't handle");
         return;
       }
     } else
 #endif
     {
-      updatedAreaImageSurface = new gfxImageSurface(gfxIntSize(mUpdatedRect.width, mUpdatedRect.height),
-                                                    gfxASurface::ImageFormatARGB32);
+      updatedAreaImageSurface =
+        new gfxImageSurface(gfxIntSize(mUpdatedRect.width, mUpdatedRect.height),
+                            gfxASurface::ImageFormatARGB32);
       nsRefPtr<gfxContext> ctx = new gfxContext(updatedAreaImageSurface);
       ctx->Translate(gfxPoint(-mUpdatedRect.x, -mUpdatedRect.y));
       ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
       ctx->SetSource(sourceSurface);
       ctx->Paint();
     }
 
     if (mUpdatedRect == mBounds) {
-      gl->fTexImage2D(LOCAL_GL_TEXTURE_2D,
-                      0,
-                      LOCAL_GL_RGBA,
-                      mUpdatedRect.width,
-                      mUpdatedRect.height,
-                      0,
-                      LOCAL_GL_BGRA,
-                      LOCAL_GL_UNSIGNED_BYTE,
-                      updatedAreaImageSurface->Data());
+      gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D,
+                        0,
+                        LOCAL_GL_RGBA,
+                        mUpdatedRect.width,
+                        mUpdatedRect.height,
+                        0,
+                        LOCAL_GL_RGBA,
+                        LOCAL_GL_UNSIGNED_BYTE,
+                        updatedAreaImageSurface->Data());
     } else {
-      gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
-                         0,
-                         mUpdatedRect.x,
-                         mUpdatedRect.y,
-                         mUpdatedRect.width,
-                         mUpdatedRect.height,
-                         LOCAL_GL_BGRA,
-                         LOCAL_GL_UNSIGNED_BYTE,
-                         updatedAreaImageSurface->Data());
+      gl()->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
+                           0,
+                           mUpdatedRect.x,
+                           mUpdatedRect.y,
+                           mUpdatedRect.width,
+                           mUpdatedRect.height,
+                           LOCAL_GL_RGBA,
+                           LOCAL_GL_UNSIGNED_BYTE,
+                           updatedAreaImageSurface->Data());
     }
-  } else if (mGLContext) {
+  } else if (mCanvasGLContext) {
     // we just need to create a texture that we'll use, the first time through
     if (mTexture == 0) {
-      gl->fGenTextures(1, (GLuint*)&mTexture);
+      gl()->fGenTextures(1, (GLuint*)&mTexture);
 
-      gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+      gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
 
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
-      gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+      gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
       mUpdatedRect = mBounds;
     }
   }
 
   // sanity
-  NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect), "CanvasLayer: Updated rect bigger than bounds!");
+  NS_ASSERTION(mUpdatedRect.IsEmpty() || mBounds.Contains(mUpdatedRect),
+               "CanvasLayer: Updated rect bigger than bounds!");
 }
 
 void
 CanvasLayerOGL::RenderLayer(int aPreviousDestination,
-                            DrawThebesLayerCallback aCallback,
-                            void* aCallbackData)
+                            const nsIntPoint& aOffset)
 {
-  LayerManagerOGL *glManager = static_cast<LayerManagerOGL*>(mManager);
-  GLContext *gl = glManager->gl();
-  glManager->MakeCurrent();
-
-  float quadTransform[4][4];
-  // Transform the quad to the size of the canvas.
-  memset(&quadTransform, 0, sizeof(quadTransform));
-  quadTransform[0][0] = (float)mBounds.width;
-  quadTransform[1][1] = (float)mBounds.height;
-  quadTransform[2][2] = 1.0f;
-  quadTransform[3][3] = 1.0f;
+  mOGLManager->MakeCurrent();
 
   // XXX We're going to need a different program depending on if
   // mGLBufferIsPremultiplied is TRUE or not.  The RGBLayerProgram
   // assumes that it's true.
 
-  // XXX this function needs to handle both mNeedsYFlip -- right now,
-  // as written, PBuffer canvas layers will be drawn upside-down.
-
-  RGBLayerProgram *program = glManager->GetRGBLayerProgram();
-
-  program->Activate();
+  ColorTextureLayerProgram *program = nsnull;
 
-  program->SetLayerQuadTransform(&quadTransform[0][0]);
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+  gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
 
-  gl->fActiveTexture(LOCAL_GL_TEXTURE0);
-  gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-
-  if (mGLContext) {
+  if (mCanvasGLContext) {
 #if defined(XP_MACOSX)
     CGLError err;
-    err = CGLTexImagePBuffer((CGLContextObj) gl->GetNativeData(GLContext::NativeCGLContext),
-                             (CGLPBufferObj) mGLContext->GetNativeData(GLContext::NativePBuffer),
+    err = CGLTexImagePBuffer((CGLContextObj) mCanvasGLContext->GetNativeData(GLContext::NativeCGLContext),
+                             (CGLPBufferObj) mCanvasGLContext->GetNativeData(GLContext::NativePBuffer),
                              LOCAL_GL_BACK);
 #elif defined(XP_WIN)
-    if (!sWGLLibrary.fBindTexImage((HANDLE) mGLContext->GetNativeData(GLContext::NativePBuffer),
+    if (!sWGLLibrary.fBindTexImage((HANDLE) mCanvasGLContext->GetNativeData(GLContext::NativePBuffer),
                                    LOCAL_WGL_FRONT_LEFT_ARB))
     {
       NS_WARNING("CanvasLayerOGL::RenderLayer wglBindTexImageARB failed");
       return;
     }
 #else
     NS_WARNING("CanvasLayerOGL::RenderLayer with GL context, but I don't know how to render on this platform!");
 #endif
+
+    program = mOGLManager->GetRGBALayerProgram();
+  } else {
+    program = mOGLManager->GetBGRALayerProgram();
   }
 
+  program->Activate();
+  program->SetLayerQuadRect(mBounds);
+  program->SetLayerTransform(mTransform);
   program->SetLayerOpacity(GetOpacity());
-  program->SetLayerTransform(&mTransform._11);
-  program->Apply();
+  program->SetRenderOffset(aOffset);
+  program->SetTextureUnit(0);
 
-  gl->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+  mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false);
 
-  if (mGLContext) {
+  if (mCanvasGLContext) {
 #if defined(XP_WIN)
-    sWGLLibrary.fReleaseTexImage((HANDLE) mGLContext->GetNativeData(GLContext::NativePBuffer),
+    sWGLLibrary.fReleaseTexImage((HANDLE) mCanvasGLContext->GetNativeData(GLContext::NativePBuffer),
                                  LOCAL_WGL_FRONT_LEFT_ARB);
 #endif
   }
 }
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -61,25 +61,24 @@ public:
 
   // CanvasLayer implementation
   virtual void Initialize(const Data& aData);
   virtual void Updated(const nsIntRect& aRect);
 
   // LayerOGL implementation
   virtual LayerType GetType() { return TYPE_CANVAS; }
   virtual Layer* GetLayer() { return this; }
-  virtual void RenderLayer(int aPreviousDestination,
-                           DrawThebesLayerCallback aCallback,
-                           void* aCallbackData);
+  virtual void RenderLayer(int aPreviousFrameBuffer,
+                           const nsIntPoint& aOffset);
 
 protected:
-  nsRefPtr<gfxASurface> mSurface;
-  nsRefPtr<GLContext> mGLContext;
+  nsRefPtr<gfxASurface> mCanvasSurface;
+  nsRefPtr<GLContext> mCanvasGLContext;
 
-  unsigned int mTexture;
+  GLuint mTexture;
 
   nsIntRect mBounds;
   nsIntRect mUpdatedRect;
 
   PRPackedBool mGLBufferIsPremultiplied;
   PRPackedBool mNeedsYFlip;
 };
 
--- a/gfx/layers/opengl/ColorLayerOGL.cpp
+++ b/gfx/layers/opengl/ColorLayerOGL.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -15,16 +15,17 @@
  * The Original Code is Mozilla Corporation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Robert O'Callahan <robert@ocallahan.org>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -48,47 +49,43 @@ ColorLayerOGL::GetType()
 
 Layer*
 ColorLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
-ColorLayerOGL::RenderLayer(int, DrawThebesLayerCallback, void*)
+ColorLayerOGL::RenderLayer(int,
+                           const nsIntPoint& aOffset)
 {
-  static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
+  mOGLManager->MakeCurrent();
 
   // XXX we might be able to improve performance by using glClear
 
-  float quadTransform[4][4];
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
-  // Transform the quad to the size of the visible area.
-  memset(&quadTransform, 0, sizeof(quadTransform));
-  quadTransform[0][0] = (float)visibleRect.width;
-  quadTransform[1][1] = (float)visibleRect.height;
-  quadTransform[2][2] = 1.0f;
-  quadTransform[3][0] = (float)visibleRect.x;
-  quadTransform[3][1] = (float)visibleRect.y;
-  quadTransform[3][3] = 1.0f;
   
-  ColorLayerProgram *program =
-    static_cast<LayerManagerOGL*>(mManager)->GetColorLayerProgram();
+  /* 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.
+   */
+  float opacity = GetOpacity();
+  gfxRGBA color(mColor);
+  color.r *= opacity;
+  color.g *= opacity;
+  color.b *= opacity;
+  color.a *= opacity;
 
+  SolidColorLayerProgram *program = mOGLManager->GetColorLayerProgram();
   program->Activate();
-
-  program->SetLayerQuadTransform(&quadTransform[0][0]);
+  program->SetLayerQuadRect(visibleRect);
+  program->SetLayerTransform(mTransform);
+  program->SetRenderOffset(aOffset);
+  program->SetRenderColor(color);
 
-  gfxRGBA color = mColor;
-  // color is premultiplied, so we need to adjust all channels
-  color.r *= GetOpacity();
-  color.g *= GetOpacity();
-  color.b *= GetOpacity();
-  color.a *= GetOpacity();
-  program->SetLayerColor(color);
-  program->SetLayerTransform(&mTransform._11);
-  program->Apply();
+  mOGLManager->BindAndDrawQuad(program);
 
-  gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+  DEBUG_GL_ERROR_CHECK(gl());
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ColorLayerOGL.h
+++ b/gfx/layers/opengl/ColorLayerOGL.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-/
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -56,19 +56,18 @@ public:
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion) { mVisibleRegion = aRegion; }
 
   // LayerOGL Implementation
   virtual LayerType GetType();
 
   virtual Layer* GetLayer();
 
-  virtual void RenderLayer(int aPreviousDestination,
-                           DrawThebesLayerCallback aCallback,
-                           void* aCallbackData);
+  virtual void RenderLayer(int aPreviousFrameBuffer,
+                           const nsIntPoint& aOffset);
 
 protected:
   nsIntRegion mVisibleRegion;
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_COLORLAYEROGL_H */
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp
+++ b/gfx/layers/opengl/ContainerLayerOGL.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -134,139 +134,91 @@ ContainerLayerOGL::GetFirstChildOGL()
   if (!mFirstChild) {
     return nsnull;
   }
   return static_cast<LayerOGL*>(mFirstChild->ImplData());
 }
 
 void
 ContainerLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                               DrawThebesLayerCallback aCallback,
-                               void* aCallbackData)
+                               const nsIntPoint& aOffset)
 {
   /**
    * Setup our temporary texture for rendering the contents of this container.
    */
   GLuint containerSurface;
   GLuint frameBuffer;
-  RGBLayerProgram *rgbProgram =
-    static_cast<LayerManagerOGL*>(mManager)->GetRGBLayerProgram();
-  ColorLayerProgram *colorProgram =
-    static_cast<LayerManagerOGL*>(mManager)->GetColorLayerProgram();
-  YCbCrLayerProgram *yCbCrProgram =
-    static_cast<LayerManagerOGL*>(mManager)->GetYCbCrLayerProgram();
+
+  nsIntPoint childOffset(aOffset);
+  bool needsFramebuffer = false;
 
   float opacity = GetOpacity();
   if (opacity != 1.0) {
-    gl()->fGenTextures(1, &containerSurface);
-    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, containerSurface);
-    gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D,
-			    0,
-			    LOCAL_GL_RGBA,
-			    mVisibleRect.width,
-			    mVisibleRect.height,
-			    0,
-			    LOCAL_GL_BGRA,
-			    LOCAL_GL_UNSIGNED_BYTE,
-			    NULL);
-    gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
-    gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
-
-    /**
-     * Create the framebuffer and bind it to make our content render into our
-     * framebuffer.
-     */
-    gl()->fGenFramebuffers(1, &frameBuffer);
-    gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, frameBuffer);
-    gl()->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
-                              LOCAL_GL_COLOR_ATTACHMENT0,
-                              LOCAL_GL_TEXTURE_2D,
-                              containerSurface,
-                              0);
-
-    NS_ASSERTION(
-	  gl()->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
-	    LOCAL_GL_FRAMEBUFFER_COMPLETE, "Error setting up framebuffer.");
-
-    /**
-     * Store old shader program variables and set the ones used for rendering
-     * this container's content.
-     */
-    
-    rgbProgram->Activate();
-    rgbProgram->PushRenderTargetOffset((GLfloat)GetVisibleRect().x, (GLfloat)GetVisibleRect().y);
-
-    colorProgram->Activate();
-    colorProgram->PushRenderTargetOffset((GLfloat)GetVisibleRect().x, (GLfloat)GetVisibleRect().y);
-
-    yCbCrProgram->Activate();
-    yCbCrProgram->PushRenderTargetOffset((GLfloat)GetVisibleRect().x, (GLfloat)GetVisibleRect().y);
+    mOGLManager->CreateFBOWithTexture(mVisibleRect.width,
+                                      mVisibleRect.height,
+                                      &frameBuffer,
+                                      &containerSurface);
+    childOffset.x = mVisibleRect.x;
+    childOffset.y = mVisibleRect.y;
   } else {
     frameBuffer = aPreviousFrameBuffer;
   }
-  
+
   /**
    * Render this container's contents.
    */
   LayerOGL *layerToRender = GetFirstChildOGL();
   while (layerToRender) {
     const nsIntRect *clipRect = layerToRender->GetLayer()->GetClipRect();
     if (clipRect) {
-      gl()->fScissor(clipRect->x - GetVisibleRect().x,
-                   clipRect->y - GetVisibleRect().y,
-                   clipRect->width,
-                   clipRect->height);
+      gl()->fScissor(clipRect->x - mVisibleRect.x,
+                     clipRect->y - mVisibleRect.y,
+                     clipRect->width,
+                     clipRect->height);
     } else {
-      gl()->fScissor(0, 0, GetVisibleRect().width, GetVisibleRect().height);
+      gl()->fScissor(0, 0, mVisibleRect.width, mVisibleRect.height);
     }
 
-    layerToRender->RenderLayer(frameBuffer, aCallback, aCallbackData);
+    layerToRender->RenderLayer(frameBuffer, childOffset);
+
     layerToRender = layerToRender->GetNextSibling();
   }
 
   if (opacity != 1.0) {
     // Unbind the current framebuffer and rebind the previous one.
     gl()->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, aPreviousFrameBuffer);
     gl()->fDeleteFramebuffers(1, &frameBuffer);
 
-    // Restore old shader program variables.
-    yCbCrProgram->Activate();
-    yCbCrProgram->PopRenderTargetOffset();
+    gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+
+    gl()->fBindTexture(mOGLManager->FBOTextureTarget(), containerSurface);
+
+    ColorTextureLayerProgram *rgb = mOGLManager->GetFBOLayerProgram();
 
-    colorProgram->Activate();
-    colorProgram->PopRenderTargetOffset();
-
-    rgbProgram->Activate();
-    rgbProgram->PopRenderTargetOffset();
+    rgb->Activate();
+    rgb->SetLayerQuadRect(mVisibleRect);
+    rgb->SetLayerTransform(mTransform);
+    rgb->SetLayerOpacity(opacity);
+    rgb->SetRenderOffset(aOffset);
+    rgb->SetTextureUnit(0);
 
-    /**
-     * Render the contents of this container to our destination.
-     */
-    float quadTransform[4][4];
-    /*
-     * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position
-     * and size.
-     */
-    memset(&quadTransform, 0, sizeof(quadTransform));
-    quadTransform[0][0] = (float)GetVisibleRect().width;
-    quadTransform[1][1] = (float)GetVisibleRect().height;
-    quadTransform[2][2] = 1.0f;
-    quadTransform[3][0] = (float)GetVisibleRect().x;
-    quadTransform[3][1] = (float)GetVisibleRect().y;
-    quadTransform[3][3] = 1.0f;
+    if (rgb->GetTexCoordMultiplierUniformLocation() != -1) {
+      // 2DRect case, get the multiplier right for a sampler2DRect
+      float f[] = { float(mVisibleRect.width), float(mVisibleRect.height) };
+      rgb->SetUniform(rgb->GetTexCoordMultiplierUniformLocation(),
+                      2, f);
+    }
+
+    DEBUG_GL_ERROR_CHECK(gl());
 
-    rgbProgram->SetLayerQuadTransform(&quadTransform[0][0]);
+    mOGLManager->BindAndDrawQuad(rgb);
 
-    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, containerSurface);
+    DEBUG_GL_ERROR_CHECK(gl());
 
-    rgbProgram->SetLayerOpacity(opacity);
-    rgbProgram->SetLayerTransform(&mTransform._11);
-    rgbProgram->Apply();
+    // Clean up resources.  This also unbinds the texture.
+    gl()->fDeleteTextures(1, &containerSurface);
 
-    gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
-
-    // Clean up resources.
-    gl()->fDeleteTextures(1, &containerSurface);
+    DEBUG_GL_ERROR_CHECK(gl());
   }
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ContainerLayerOGL.h
+++ b/gfx/layers/opengl/ContainerLayerOGL.h
@@ -64,19 +64,18 @@ public:
   LayerType GetType();
 
   Layer* GetLayer();
 
   LayerOGL* GetFirstChildOGL();
 
   PRBool IsEmpty();
 
-  void RenderLayer(int aPreviousFrameBuffer,
-                   DrawThebesLayerCallback aCallback,
-                   void* aCallbackData);
+  virtual void RenderLayer(int aPreviousFrameBuffer,
+                           const nsIntPoint& aOffset);
 private:
   nsIntRect mVisibleRect;
 
   GLuint mTexture;
 };
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -15,16 +15,17 @@
  * The Original Code is Mozilla Corporation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Bas Schouten <bschouten@mozilla.org>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -264,95 +265,83 @@ ImageLayerOGL::GetType()
 
 Layer*
 ImageLayerOGL::GetLayer()
 {
   return this;
 }
 
 void
-ImageLayerOGL::RenderLayer(int, DrawThebesLayerCallback aCallback,
-                           void* aCallbackData)
+ImageLayerOGL::RenderLayer(int,
+                           const nsIntPoint& aOffset)
 {
-  if (!GetContainer()) {
+  if (!GetContainer())
     return;
-  }
 
-  LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(mManager);
-  manager->MakeCurrent();
+  mOGLManager->MakeCurrent();
 
   nsRefPtr<Image> image = GetContainer()->GetCurrentImage();
 
   if (image->GetFormat() == Image::PLANAR_YCBCR) {
     PlanarYCbCrImageOGL *yuvImage =
       static_cast<PlanarYCbCrImageOGL*>(image.get());
 
-    if (!yuvImage->HasData()) {
+    if (!yuvImage->HasData())
       return;
-    }
-
-    if (!yuvImage->HasTextures()) {
-      yuvImage->AllocateTextures(manager);
-    }
 
-    float quadTransform[4][4];
-    // Transform the quad to the size of the video.
-    memset(&quadTransform, 0, sizeof(quadTransform));
-    quadTransform[0][0] = (float)yuvImage->mSize.width;
-    quadTransform[1][1] = (float)yuvImage->mSize.height;
-    quadTransform[2][2] = 1.0f;
-    quadTransform[3][3] = 1.0f;
+    if (!yuvImage->HasTextures())
+      yuvImage->AllocateTextures(mOGLManager);
 
-    YCbCrLayerProgram *program = manager->GetYCbCrLayerProgram();
-
-    program->Activate();
-
-    program->SetLayerQuadTransform(&quadTransform[0][0]);
-  
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[0].GetTextureID());
     gl()->fActiveTexture(LOCAL_GL_TEXTURE1);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[1].GetTextureID());
     gl()->fActiveTexture(LOCAL_GL_TEXTURE2);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[2].GetTextureID());
 
-    program->SetLayerOpacity(GetOpacity());
-    program->SetLayerTransform(&mTransform._11);
-    program->Apply();
+    YCbCrTextureLayerProgram *program = mOGLManager->GetYCbCrLayerProgram();
 
-    gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+    program->Activate();
+    program->SetLayerQuadRect(nsIntRect(0, 0,
+                                        yuvImage->mSize.width,
+                                        yuvImage->mSize.height));
+    program->SetLayerTransform(mTransform);
+    program->SetLayerOpacity(GetOpacity());
+    program->SetRenderOffset(aOffset);
+    program->SetYCbCrTextureUnits(0, 1, 2);
 
+    DEBUG_GL_ERROR_CHECK(gl());
+
+    mOGLManager->BindAndDrawQuad(program);
+
+    // We shouldn't need to do this, but do it anyway just in case
+    // someone else forgets.
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-
   } else if (image->GetFormat() == Image::CAIRO_SURFACE) {
     CairoImageOGL *cairoImage =
       static_cast<CairoImageOGL*>(image.get());
 
-    float quadTransform[4][4];
-    // Transform the quad to the size of the video.
-    memset(&quadTransform, 0, sizeof(quadTransform));
-    quadTransform[0][0] = (float)cairoImage->mSize.width;
-    quadTransform[1][1] = (float)cairoImage->mSize.height;
-    quadTransform[2][2] = 1.0f;
-    quadTransform[3][3] = 1.0f;
+    gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, cairoImage->mTexture.GetTextureID());
   
-    RGBLayerProgram *program = manager->GetRGBLayerProgram();
+    ColorTextureLayerProgram *program = mOGLManager->GetBGRALayerProgram();
 
     program->Activate();
-
-    program->SetLayerQuadTransform(&quadTransform[0][0]);
-
-    gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, cairoImage->mTexture.GetTextureID());
+    program->SetLayerQuadRect(nsIntRect(0, 0,
+                                        cairoImage->mSize.width,
+                                        cairoImage->mSize.height));
+    program->SetLayerTransform(mTransform);
     program->SetLayerOpacity(GetOpacity());
-    program->SetLayerTransform(&mTransform._11);
-    program->Apply();
+    program->SetRenderOffset(aOffset);
+    program->SetTextureUnit(0);
 
-    gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+    mOGLManager->BindAndDrawQuad(program);
   }
+
+  DEBUG_GL_ERROR_CHECK(gl());
 }
 
 PlanarYCbCrImageOGL::PlanarYCbCrImageOGL(RecycleBin *aRecycleBin)
   : PlanarYCbCrImage(nsnull), mRecycleBin(aRecycleBin), mHasData(PR_FALSE)
 {
 }
 
 PlanarYCbCrImageOGL::~PlanarYCbCrImageOGL()
@@ -547,35 +536,38 @@ CairoImageOGL::SetData(const CairoImage:
 
   mozilla::gl::GLContext *gl = mTexture.GetGLContext();
   gl->MakeCurrent();
 
   mSize = aData.mSize;
 
   // XXX This could be a lot more efficient if we already have an image-compatible
   // surface
+  // XXX if we ever create an ImageFormatRGB24 surface, make sure that we use
+  // a BGRX program in that case (instead of BGRA)
   nsRefPtr<gfxImageSurface> imageSurface =
     new gfxImageSurface(aData.mSize, gfxASurface::ImageFormatARGB32);
   nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
 
   context->SetSource(aData.mSurface);
   context->Paint();
 
+  gl->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture.GetTextureID());
 
   gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
   gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
   gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
   gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
   gl->fTexImage2D(LOCAL_GL_TEXTURE_2D,
                   0,
                   LOCAL_GL_RGBA,
                   mSize.width,
                   mSize.height,
                   0,
-                  LOCAL_GL_BGRA,
+                  LOCAL_GL_RGBA,
                   LOCAL_GL_UNSIGNED_BYTE,
                   imageSurface->Data());
 }
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -170,19 +170,18 @@ public:
     mImplData = static_cast<LayerOGL*>(this);
   }
 
   // LayerOGL Implementation
   virtual LayerType GetType();
 
   virtual Layer* GetLayer();
 
-  virtual void RenderLayer(int aPreviousDestination,
-                           DrawThebesLayerCallback aCallback,
-                           void* aCallbackData);
+  virtual void RenderLayer(int aPreviousFrameBuffer,
+                           const nsIntPoint& aOffset);
 };
 
 class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage
 {
   typedef mozilla::gl::GLContext GLContext;
 
 public:
   PlanarYCbCrImageOGL(RecycleBin *aRecycleBin);
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -15,16 +15,18 @@
  * The Original Code is Mozilla Corporation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Bas Schouten <bschouten@mozilla.org>
+ *   Frederic Plourde <frederic.plourde@collabora.co.uk>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -48,256 +50,283 @@
 #include "nsIWidget.h"
 
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
 #include "nsIServiceManager.h"
 #include "nsIConsoleService.h"
 
-static const GLint VERTEX_ATTRIB_LOCATION = 0;
-
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gl;
 
+int LayerManagerOGLProgram::sCurrentProgramKey = 0;
+
+static void
+DumpLayerAndChildren(LayerOGL *l, int advance = 0)
+{
+  for (int i = 0; i < advance; i++)
+    fprintf(stderr, "  ");
+
+  fprintf(stderr, "%p: Layer type %d\n", l, l->GetType());
+
+  l = l->GetFirstChildOGL();
+  while (l) {
+    DumpLayerAndChildren(l, advance+1);
+    l = l->GetNextSibling();
+  }
+}
+
 /**
  * LayerManagerOGL
  */
 LayerManagerOGL::LayerManagerOGL(nsIWidget *aWidget) 
   : mWidget(aWidget)
-  , mBackBuffer(0)
-  , mFrameBuffer(0)
-  , mRGBLayerProgram(NULL)
-  , mYCbCrLayerProgram(NULL)
-  , mVertexShader(0)
-  , mRGBShader(0)
-  , mYUVShader(0)
+  , mBackBufferFBO(0)
+  , mBackBufferTexture(0)
+  , mHasBGRA(0)
 {
 }
 
 LayerManagerOGL::~LayerManagerOGL()
 {
-  mGLContext->MakeCurrent();
-  delete mRGBLayerProgram;
-  delete mColorLayerProgram;
-  delete mYCbCrLayerProgram;
+  if (mGLContext)
+    mGLContext->MakeCurrent();
+
+  for (unsigned int i = 0; i < mPrograms.Length(); ++i)
+    delete mPrograms[i];
+
+  mPrograms.Clear();
 }
 
 PRBool
 LayerManagerOGL::Initialize()
 {
   mGLContext = sGLContextProvider.CreateForWindow(mWidget);
 
   if (!mGLContext) {
+    NS_WARNING("Failed to create LayerManagerOGL context");
     return PR_FALSE;
   }
 
   MakeCurrent();
 
-  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, LOCAL_GL_ONE, LOCAL_GL_ONE);
-  mGLContext->fEnable(LOCAL_GL_BLEND);
-  mGLContext->fEnable(LOCAL_GL_TEXTURE_2D);
-  mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
+  DEBUG_GL_ERROR_CHECK(mGLContext);
+
+  const char *extensionStr =
+    (const char*) mGLContext->fGetString(LOCAL_GL_EXTENSIONS);
 
-  mVertexShader = mGLContext->fCreateShader(LOCAL_GL_VERTEX_SHADER);
-  mRGBShader = mGLContext->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
-  mColorShader = mGLContext->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
-  mYUVShader = mGLContext->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
+  mHasBGRA = (strstr(extensionStr, "EXT_bgra") != nsnull);
+
+  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+                                 LOCAL_GL_ONE, LOCAL_GL_ONE);
+  mGLContext->fEnable(LOCAL_GL_BLEND);
 
-  mGLContext->fShaderSource(mVertexShader, 1, (const GLchar**)&sVertexShader, NULL);
-  mGLContext->fShaderSource(mRGBShader, 1, (const GLchar**)&sRGBLayerPS, NULL);
-  mGLContext->fShaderSource(mColorShader, 1, (const GLchar**)&sColorLayerPS, NULL);
-  mGLContext->fShaderSource(mYUVShader, 1, (const GLchar**)&sYUVLayerPS, NULL);
+  // We unfortunately can't do generic initialization here, since the
+  // concrete type actually matters.  This macro generates the
+  // initialization using a concrete type and index.
+#define SHADER_PROGRAM(penum, ptype, vsstr, fsstr) do {                 \
+    NS_ASSERTION(programIndex++ == penum, "out of order shader initialization!"); \
+    ptype *p = new ptype(mGLContext);                                   \
+    if (!p->Initialize(vsstr, fsstr))                                   \
+      return PR_FALSE;                                                  \
+    mPrograms.AppendElement(p);                                         \
+  } while (0)
 
-  mGLContext->fCompileShader(mVertexShader);
-  mGLContext->fCompileShader(mRGBShader);
-  mGLContext->fCompileShader(mColorShader);
-  mGLContext->fCompileShader(mYUVShader);
 
-  GLint status;
-  mGLContext->fGetShaderiv(mVertexShader, LOCAL_GL_COMPILE_STATUS, &status);
-  if (!status) {
-    return false;
-  }
+  // NOTE: Order matters here, and should be in the same order as the
+  // ProgramType enum!
+  GLint programIndex = 0;
 
-  mGLContext->fGetShaderiv(mRGBShader, LOCAL_GL_COMPILE_STATUS, &status);
-  if (!status) {
-    return false;
-  }
+  /* Layer programs */
+  SHADER_PROGRAM(RGBALayerProgramType, ColorTextureLayerProgram,
+                 sLayerVS, sRGBATextureLayerFS);
+  SHADER_PROGRAM(BGRALayerProgramType, ColorTextureLayerProgram,
+                 sLayerVS, sBGRATextureLayerFS);
+  SHADER_PROGRAM(RGBXLayerProgramType, ColorTextureLayerProgram,
+                 sLayerVS, sRGBXTextureLayerFS);
+  SHADER_PROGRAM(BGRXLayerProgramType, ColorTextureLayerProgram,
+                 sLayerVS, sBGRXTextureLayerFS);
+  SHADER_PROGRAM(RGBARectLayerProgramType, ColorTextureLayerProgram,
+                 sLayerVS, sRGBARectTextureLayerFS);
+  SHADER_PROGRAM(ColorLayerProgramType, SolidColorLayerProgram,
+                 sLayerVS, sSolidColorLayerFS);
+  SHADER_PROGRAM(YCbCrLayerProgramType, YCbCrTextureLayerProgram,
+                 sLayerVS, sYCbCrTextureLayerFS);
+  /* Copy programs (used for final framebuffer blit) */
+  SHADER_PROGRAM(Copy2DProgramType, CopyProgram,
+                 sCopyVS, sCopy2DFS);
+  SHADER_PROGRAM(Copy2DRectProgramType, CopyProgram,
+                 sCopyVS, sCopy2DRectFS);
 
-  mGLContext->fGetShaderiv(mColorShader, LOCAL_GL_COMPILE_STATUS, &status);
-  if (!status) {
-    return false;
-  }
+#undef SHADER_PROGRAM
 
-  mGLContext->fGetShaderiv(mYUVShader, LOCAL_GL_COMPILE_STATUS, &status);
-  if (!status) {
-    return false;
-  }
+  NS_ASSERTION(programIndex == NumProgramTypes,
+               "not all programs were initialized!");
 
   /**
    * We'll test the ability here to bind NPOT textures to a framebuffer, if
-   * this fails we'll try EXT_texture_rectangle.
+   * this fails we'll try ARB_texture_rectangle.
    */
-  mGLContext->fGenFramebuffers(1, &mFrameBuffer);
+  mGLContext->fGenFramebuffers(1, &mBackBufferFBO);
 
-  GLenum textureTargets[] = { LOCAL_GL_TEXTURE_2D,
-                              LOCAL_GL_TEXTURE_RECTANGLE_EXT };
-  mFBOTextureTarget = 0;
+  GLenum textureTargets[] = {
+    LOCAL_GL_TEXTURE_2D,
+#ifndef USE_GLES2
+    LOCAL_GL_TEXTURE_RECTANGLE_ARB
+#endif
+  };
+
+  mFBOTextureTarget = LOCAL_GL_NONE;
 
   for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(textureTargets); i++) {
-    mGLContext->fGenTextures(1, &mBackBuffer);
-    mGLContext->fBindTexture(textureTargets[i], mBackBuffer);
-    mGLContext->fTexParameteri(textureTargets[i],
+    GLenum target = textureTargets[i];
+    mGLContext->fGenTextures(1, &mBackBufferTexture);
+    mGLContext->fBindTexture(target, mBackBufferTexture);
+    mGLContext->fTexParameteri(target,
                                LOCAL_GL_TEXTURE_MIN_FILTER,
                                LOCAL_GL_NEAREST);
-    mGLContext->fTexParameteri(textureTargets[i],
+    mGLContext->fTexParameteri(target,
                                LOCAL_GL_TEXTURE_MAG_FILTER,
                                LOCAL_GL_NEAREST);
-    mGLContext->fTexImage2D(textureTargets[i],
+    mGLContext->fTexImage2D(target,
                             0,
                             LOCAL_GL_RGBA,
-                            200,
-                            100,
+                            5, 3, /* sufficiently NPOT */
                             0,
                             LOCAL_GL_RGBA,
                             LOCAL_GL_UNSIGNED_BYTE,
                             NULL);
 
-    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFrameBuffer);
+    // unbind this texture, in preparation for binding it to the FBO
+    mGLContext->fBindTexture(target, 0);
+
+    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
     mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
                                       LOCAL_GL_COLOR_ATTACHMENT0,
-                                      textureTargets[i],
-                                      mBackBuffer,
+                                      target,
+                                      mBackBufferTexture,
                                       0);
 
     if (mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
-        LOCAL_GL_FRAMEBUFFER_COMPLETE) {
-          mFBOTextureTarget = textureTargets[i];
-          break;
+        LOCAL_GL_FRAMEBUFFER_COMPLETE)
+    {
+      mFBOTextureTarget = target;
+      break;
     }
 
-    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
-    mGLContext->fBindTexture(textureTargets[i], 0);
-    /**
-     * We need to delete this texture since we can't bind a texture multiple
-     * time to different textures.
-     */
-    mGLContext->fDeleteTextures(1, &mBackBuffer);
+    // We weren't succesful with this texture, so we don't need it
+    // any more.
+    mGLContext->fDeleteTextures(1, &mBackBufferTexture);
   }
-  if (mFBOTextureTarget == 0) {
+
+  if (mFBOTextureTarget == LOCAL_GL_NONE) {
     /* Unable to find a texture target that works with FBOs and NPOT textures */
     return false;
   }
 
-  mRGBLayerProgram = new RGBLayerProgram();
-  if (!mRGBLayerProgram->Initialize(mVertexShader, mRGBShader, mGLContext)) {
-    return false;
-  }
-  mColorLayerProgram = new ColorLayerProgram();
-  if (!mColorLayerProgram->Initialize(mVertexShader, mColorShader, mGLContext)) {
-    return false;
-  }
-  mYCbCrLayerProgram = new YCbCrLayerProgram();
-  if (!mYCbCrLayerProgram->Initialize(mVertexShader, mYUVShader, mGLContext)) {
-    return false;
+  if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
+    /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
+     * extension -- the EXT variant does not provide support for
+     * texture rectangle access inside GLSL (sampler2DRect,
+     * texture2DRect).
+     */
+    if (strstr(extensionStr, "ARB_texture_rectangle") == NULL)
+      return false;
   }
 
-  mRGBLayerProgram->UpdateLocations();
-  mColorLayerProgram->UpdateLocations();
-  mYCbCrLayerProgram->UpdateLocations();
+  // back to default framebuffer, to avoid confusion
+  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+  DEBUG_GL_ERROR_CHECK(mGLContext);
+
+  /* Create a simple quad VBO */
 
-  mGLContext->fGenBuffers(1, &mVBO);
-  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mVBO);
-  mGLContext->fEnableClientState(LOCAL_GL_VERTEX_ARRAY);
-  mGLContext->fEnableVertexAttribArray(VERTEX_ATTRIB_LOCATION);
+  mGLContext->fGenBuffers(1, &mQuadVBO);
+  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
 
-  GLfloat vertices[] = { 0, 0, 1.0f, 0, 0, 1.0f, 1.0f, 1.0f };
+  GLfloat vertices[] = {
+    /* First quad vertices */
+    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+    /* Then quad texcoords */
+    0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+    /* Then flipped quad texcoords */
+    0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+  };
   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW);
 
-  mRGBLayerProgram->Activate();
-  mGLContext->fVertexAttribPointer(VERTEX_ATTRIB_LOCATION,
-                        2,
-                        LOCAL_GL_FLOAT,
-                        LOCAL_GL_FALSE,
-                        0,
-                        0);
-  mColorLayerProgram->Activate();
-  mGLContext->fVertexAttribPointer(VERTEX_ATTRIB_LOCATION,
-                        2,
-                        LOCAL_GL_FLOAT,
-                        LOCAL_GL_FALSE,
-                        0,
-                        0);
-  mYCbCrLayerProgram->Activate();
-  mGLContext->fVertexAttribPointer(VERTEX_ATTRIB_LOCATION,
-                        2,
-                        LOCAL_GL_FLOAT,
-                        LOCAL_GL_FALSE,
-                        0,
-                        0);
-
-  mRGBLayerProgram->SetLayerTexture(0);
-
-  mYCbCrLayerProgram->SetYTexture(0);
-  mYCbCrLayerProgram->SetCbTexture(1);
-  mYCbCrLayerProgram->SetCrTexture(2);
+  DEBUG_GL_ERROR_CHECK(mGLContext);
 
   nsCOMPtr<nsIConsoleService> 
     console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
 
   if (console) {
     nsString msg;
     msg +=
       NS_LITERAL_STRING("OpenGL LayerManager Initialized Succesfully.\nVersion: ");
     msg += NS_ConvertUTF8toUTF16(
       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VERSION)));
     msg += NS_LITERAL_STRING("\nVendor: ");
     msg += NS_ConvertUTF8toUTF16(
       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_VENDOR)));
     msg += NS_LITERAL_STRING("\nRenderer: ");
     msg += NS_ConvertUTF8toUTF16(
       nsDependentCString((const char*)mGLContext->fGetString(LOCAL_GL_RENDERER)));
+    msg += NS_LITERAL_STRING("\nFBO Texture Target: ");
+    if (mFBOTextureTarget == LOCAL_GL_TEXTURE_2D)
+      msg += NS_LITERAL_STRING("TEXTURE_2D");
+    else
+      msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
     console->LogStringMessage(msg.get());
   }
 
+  DEBUG_GL_ERROR_CHECK(mGLContext);
+
   return true;
 }
 
 void
 LayerManagerOGL::SetClippingRegion(const nsIntRegion& aClippingRegion)
 {
   mClippingRegion = aClippingRegion;
 }
 
 void
 LayerManagerOGL::BeginTransaction()
 {
+  NS_ASSERTION(mRootLayer, "Root not set");
 }
 
 void
 LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget)
 {
   mTarget = aTarget;
 }
 
 void
 LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback,
                                 void* aCallbackData)
 {
-  Render(aCallback, aCallbackData);
+  mThebesLayerCallback = aCallback;
+  mThebesLayerCallbackData = aCallbackData;
+
+  Render();
+
+  mThebesLayerCallback = nsnull;
+  mThebesLayerCallbackData = nsnull;
+
   mTarget = NULL;
 }
 
 void
 LayerManagerOGL::SetRoot(Layer *aLayer)
 {
-  mRootLayer =  static_cast<LayerOGL*>(aLayer->ImplData());;
+  mRootLayer = static_cast<LayerOGL*>(aLayer->ImplData());;
 }
 
 already_AddRefed<ThebesLayer>
 LayerManagerOGL::CreateThebesLayer()
 {
   nsRefPtr<ThebesLayer> layer = new ThebesLayerOGL(this);
   return layer.forget();
 }
@@ -333,400 +362,338 @@ LayerManagerOGL::CreateColorLayer()
 already_AddRefed<CanvasLayer>
 LayerManagerOGL::CreateCanvasLayer()
 {
   nsRefPtr<CanvasLayer> layer = new CanvasLayerOGL(this);
   return layer.forget();
 }
 
 void
-LayerManagerOGL::SetClippingEnabled(PRBool aEnabled)
+LayerManagerOGL::MakeCurrent()
 {
-  if (aEnabled) {
-    mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
-  } else {
-    mGLContext->fDisable(LOCAL_GL_SCISSOR_TEST);
-  }
+  mGLContext->MakeCurrent();
 }
 
 void
-LayerManagerOGL::MakeCurrent()
+LayerManagerOGL::Render()
 {
-    mGLContext->MakeCurrent();
-}
+  static int rcount = 0;
 
-void
-LayerManagerOGL::Render(DrawThebesLayerCallback aCallback,
-                        void* aCallbackData)
-{
+  //DumpLayerAndChildren(mRootLayer);
+
   nsIntRect rect;
   mWidget->GetBounds(rect);
   GLint width = rect.width;
   GLint height = rect.height;
 
   MakeCurrent();
-  SetupBackBuffer();
+
+  DEBUG_GL_ERROR_CHECK(mGLContext);
+
+  SetupBackBuffer(width, height);
+  SetupPipeline(width, height);
+
+  // Default blend function implements "OVER"
+  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
+                                 LOCAL_GL_ONE, LOCAL_GL_ONE);
 
-  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFrameBuffer);
-  mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, LOCAL_GL_ONE, LOCAL_GL_ONE);
-  mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0);
-  mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
+  DEBUG_GL_ERROR_CHECK(mGLContext);
 
-  SetupPipeline();
-  SetClippingEnabled(PR_FALSE);
+#if 0
+  // XXX for whatever reason, scissor is not working -- even with no
+  // cliprect set, so we go through the 0,0,w,h path, any updates
+  // after the initial render end up failing the scissor rectangle.  I
+  // have no idea why.  We disable it for now, because it's not actually
+  // helping us with anything -- we draw to a specific location in the
+  // front buffer as it is.
 
-  if (mRootLayer) {
-    const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect();
-    if (clipRect) {
-      mGLContext->fScissor(clipRect->x, clipRect->y, clipRect->width, clipRect->height);
-    } else {
-      mGLContext->fScissor(0, 0, width, height);
-    }
+  const nsIntRect *clipRect = mRootLayer->GetLayer()->GetClipRect();
+
+  if (clipRect) {
+    mGLContext->fScissor(clipRect->x, clipRect->y,
+                         clipRect->width, clipRect->height);
+  } else {
+    mGLContext->fScissor(0, 0, width, height);
+  }
 
-    mRootLayer->RenderLayer(mFrameBuffer, aCallback, aCallbackData);
-  }
+  mGLContext->fEnable(LOCAL_GL_SCISSOR_TEST);
+#else
+  mGLContext->fDisable(LOCAL_GL_SCISSOR_TEST);
+#endif
+
+  DEBUG_GL_ERROR_CHECK(mGLContext);
+
+  // Render our layers.
+  mRootLayer->RenderLayer(mBackBufferFBO, nsIntPoint(0, 0));
+
+  DEBUG_GL_ERROR_CHECK(mGLContext);
 
   if (mTarget) {
     CopyToTarget();
-  } else {
-    /**
-     * Draw our backbuffer to the screen without using vertex or fragment
-     * shaders. We're fine with just calculating the viewport coordinates
-     * in software. And nothing special is required for the texture sampling.
-     */
-    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
-    mGLContext->fUseProgram(0);
-    if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_EXT) {
-      mGLContext->fEnable(LOCAL_GL_TEXTURE_RECTANGLE_EXT);
-    }
-    mGLContext->fDisableVertexAttribArray(VERTEX_ATTRIB_LOCATION);
-    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
-    mGLContext->fEnableClientState(LOCAL_GL_VERTEX_ARRAY);
-    mGLContext->fEnableClientState(LOCAL_GL_TEXTURE_COORD_ARRAY);
-    mGLContext->fBindTexture(mFBOTextureTarget, mBackBuffer);
+    return;
+  }
 
-    const nsIntRect *r;
-    for (nsIntRegionRectIterator iter(mClippingRegion);
-         (r = iter.Next()) != nsnull;) {
-      mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO, LOCAL_GL_ONE, LOCAL_GL_ZERO);
-      float left = (GLfloat)r->x / width;
-      float right = (GLfloat)r->XMost() / width;
-      float top = (GLfloat)r->y / height;
-      float bottom = (GLfloat)r->YMost() / height;
+  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
+  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+
+  CopyProgram *copyprog = GetCopy2DProgram();
 
-      float vertices[] = { left * 2.0f - 1.0f,
-                           -(top * 2.0f - 1.0f),
-                           right * 2.0f - 1.0f,
-                           -(top * 2.0f - 1.0f),
-                           left * 2.0f - 1.0f,
-                           -(bottom * 2.0f - 1.0f),
-                           right * 2.0f - 1.0f,
-                           -(bottom * 2.0f - 1.0f) };
+  if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
+    copyprog = GetCopy2DRectProgram();
+  }
+
+  mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture);
 
-      float coords[8];
-      if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_EXT) {
-        /* These are in non-normalized texture coords */
-        coords[0] = (GLfloat)r->x; coords[1] = (GLfloat)r->y;
-        coords[2] = (GLfloat)r->XMost(); coords[3] = (GLfloat)r->y;
-        coords[4] = (GLfloat)r->x; coords[5] = (GLfloat)r->YMost();
-        coords[6] = (GLfloat)r->XMost(); coords[7] = (GLfloat)r->YMost();
-      } else {
-        coords[0] = left; coords[1] = top;
-        coords[2] = right; coords[3] = top;
-        coords[4] = left; coords[5] = bottom;
-        coords[6] = right; coords[7] = bottom;
-      }
+  copyprog->Activate();
+  copyprog->SetTextureUnit(0);
 
-      mGLContext->fVertexPointer(2, LOCAL_GL_FLOAT, 0, vertices);
-      mGLContext->fTexCoordPointer(2, LOCAL_GL_FLOAT, 0, coords);
-      mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
-    }
-    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mVBO);
-    mGLContext->fEnableVertexAttribArray(VERTEX_ATTRIB_LOCATION);
-    mGLContext->fDisableClientState(LOCAL_GL_TEXTURE_COORD_ARRAY);
-    if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_EXT) {
-      mGLContext->fDisable(LOCAL_GL_TEXTURE_RECTANGLE_EXT);
-    }
+  if (copyprog->GetTexCoordMultiplierUniformLocation() != -1) {
+    float f[] = { float(width), float(height) };
+    copyprog->SetUniform(copyprog->GetTexCoordMultiplierUniformLocation(),
+                         2, f);
   }
 
+  DEBUG_GL_ERROR_CHECK(mGLContext);
+
+  // 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,
+                                 LOCAL_GL_ONE, LOCAL_GL_ZERO);
+
+  // enable our vertex attribs; we'll call glVertexPointer below
+  // to fill with the correct data.
+  GLint vcattr = copyprog->AttribLocation(CopyProgram::VertexCoordAttrib);
+  GLint tcattr = copyprog->AttribLocation(CopyProgram::TexCoordAttrib);
+
+  mGLContext->fEnableVertexAttribArray(vcattr);
+  mGLContext->fEnableVertexAttribArray(tcattr);
+
+  const nsIntRect *r;
+  nsIntRegionRectIterator iter(mClippingRegion);
+
+  while ((r = iter.Next()) != nsnull) {
+    float left = (GLfloat)r->x / width;
+    float right = (GLfloat)r->XMost() / width;
+    float top = (GLfloat)r->y / height;
+    float bottom = (GLfloat)r->YMost() / height;
+
+    float vertices[] = { left * 2.0f - 1.0f,
+                         -(top * 2.0f - 1.0f),
+                         right * 2.0f - 1.0f,
+                         -(top * 2.0f - 1.0f),
+                         left * 2.0f - 1.0f,
+                         -(bottom * 2.0f - 1.0f),
+                         right * 2.0f - 1.0f,
+                         -(bottom * 2.0f - 1.0f) };
+
+    float coords[] = { left, top,
+                       right, top,
+                       left, bottom,
+                       right, bottom };
+
+    mGLContext->fVertexAttribPointer(vcattr,
+                                     2, LOCAL_GL_FLOAT,
+                                     LOCAL_GL_FALSE,
+                                     0, vertices);
+
+    mGLContext->fVertexAttribPointer(tcattr,
+                                     2, LOCAL_GL_FLOAT,
+                                     LOCAL_GL_FALSE,
+                                     0, coords);
+
+    mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+    DEBUG_GL_ERROR_CHECK(mGLContext);
+  }
+
+  mGLContext->fDisableVertexAttribArray(vcattr);
+  mGLContext->fDisableVertexAttribArray(tcattr);
+
+  DEBUG_GL_ERROR_CHECK(mGLContext);
+
   mGLContext->fFinish();
+
+  DEBUG_GL_ERROR_CHECK(mGLContext);
 }
 
 void
-LayerManagerOGL::SetupPipeline()
+LayerManagerOGL::SetupPipeline(int aWidth, int aHeight)
 {
-  nsIntRect rect;
-  mWidget->GetBounds(rect);
-
-  mGLContext->fViewport(0, 0, rect.width, rect.height);
+  // Set the viewport correctly
+  mGLContext->fViewport(0, 0, aWidth, aHeight);
 
-  float viewMatrix[4][4];
-  /**
-   * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, 
-   * <1.0, -1.0> bottomright)
-   */
-  memset(&viewMatrix, 0, sizeof(viewMatrix));
-  viewMatrix[0][0] = 2.0f / rect.width;
-  viewMatrix[1][1] = 2.0f / rect.height;
-  viewMatrix[2][2] = 1.0f;
-  viewMatrix[3][0] = -1.0f;
-  viewMatrix[3][1] = -1.0f;
-  viewMatrix[3][3] = 1.0f;
-  
-  mRGBLayerProgram->Activate();
-  mRGBLayerProgram->SetMatrixProj(&viewMatrix[0][0]);
+  // Matrix to transform to viewport space ( <-1.0, 1.0> topleft, 
+  // <1.0, -1.0> bottomright)
+  gfx3DMatrix viewMatrix;
+  viewMatrix._11 = 2.0f / float(aWidth);
+  viewMatrix._22 = 2.0f / float(aHeight);
+  viewMatrix._41 = -1.0f;
+  viewMatrix._42 = -1.0f;
 
-  mColorLayerProgram->Activate();
-  mColorLayerProgram->SetMatrixProj(&viewMatrix[0][0]);
-
-  mYCbCrLayerProgram->Activate();
-  mYCbCrLayerProgram->SetMatrixProj(&viewMatrix[0][0]);
+  SetLayerProgramProjectionMatrix(viewMatrix);
 }
 
-PRBool
-LayerManagerOGL::SetupBackBuffer()
+void
+LayerManagerOGL::SetupBackBuffer(int aWidth, int aHeight)
 {
-  nsIntRect rect;
-  mWidget->GetBounds(rect);
-  GLint width = rect.width;
-  GLint height = rect.height;
-
-  if (width == mBackBufferSize.width && height == mBackBufferSize.height) {
-    return PR_TRUE;
+  // Do we have a FBO of the right size already?
+  if (mBackBufferSize.width == aWidth &&
+      mBackBufferSize.height == aHeight)
+  {
+    mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
+    return;
   }
 
-  /**
-   * Setup the texture used as the backbuffer. We use a texture as our
-   * backbuffer since we can rely on both GLES and OGL 2.1 to support this
-   * method.
-   */
-  mGLContext->fBindTexture(mFBOTextureTarget, mBackBuffer);
-  mGLContext->fTexEnvf(LOCAL_GL_TEXTURE_ENV, LOCAL_GL_TEXTURE_ENV_MODE, LOCAL_GL_MODULATE);
-  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
-  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
+  // we already have a FBO, but we need to resize its texture.
+  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+  mGLContext->fBindTexture(mFBOTextureTarget, mBackBufferTexture);
   mGLContext->fTexImage2D(mFBOTextureTarget,
-                        0,
-                        LOCAL_GL_RGBA,
-                        width,
-                        height,
-                        0,
-                        LOCAL_GL_RGBA,
-                        LOCAL_GL_UNSIGNED_BYTE,
-                        NULL);
+                          0,
+                          LOCAL_GL_RGBA,
+                          aWidth, aHeight,
+                          0,
+                          LOCAL_GL_RGBA,
+                          LOCAL_GL_UNSIGNED_BYTE,
+                          NULL);
+  mGLContext->fBindTexture(mFBOTextureTarget, 0);
 
-  /* Bind our framebuffer to make our content render into our backbuffer. */
-  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mFrameBuffer);
+  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
   mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
-                                   LOCAL_GL_COLOR_ATTACHMENT0,
-                                   mFBOTextureTarget,
-                                   mBackBuffer,
-                                   0);
+                                    LOCAL_GL_COLOR_ATTACHMENT0,
+                                    mFBOTextureTarget,
+                                    mBackBufferTexture,
+                                    0);
 
-  return PR_TRUE;
+  mBackBufferSize.width = aWidth;
+  mBackBufferSize.height = aHeight;
 }
 
 void
 LayerManagerOGL::CopyToTarget()
 {
   nsIntRect rect;
   mWidget->GetBounds(rect);
   GLint width = rect.width;
   GLint height = rect.height;
 
-  if ((PRInt64)width * (PRInt64)height > PR_INT32_MAX) {
+  if ((PRInt64(width) * PRInt64(height) * PRInt64(4)) > PR_INT32_MAX) {
     NS_ERROR("Widget size too big - integer overflow!");
     return;
   }
 
   nsRefPtr<gfxImageSurface> imageSurface =
     new gfxImageSurface(gfxIntSize(width, height),
                         gfxASurface::ImageFormatARGB32);
 
+#ifdef USE_GLES2
+  // GLES2 promises that binding to any custom FBO will attach 
+  // to GL_COLOR_ATTACHMENT0 attachment point.
+  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mBackBufferFBO);
+#else
   mGLContext->fReadBuffer(LOCAL_GL_COLOR_ATTACHMENT0);
-
-  if (imageSurface->Stride() != width * 4) {
-    char *tmpData = new char[width * height * 4];
+#endif
 
-    mGLContext->fReadPixels(0,
-                          0,
-                          width,
-                          height,
-                          LOCAL_GL_BGRA,
-                          LOCAL_GL_UNSIGNED_BYTE,
-                          tmpData);
-    mGLContext->fFinish();
+  GLenum format = LOCAL_GL_RGBA;
+  if (mHasBGRA)
+    format = LOCAL_GL_BGRA;
 
-    for (int y = 0; y < height; y++) {
-      memcpy(imageSurface->Data() + imageSurface->Stride() * y,
-             tmpData + width * 4 * y,
-             width * 4);
-    }
-    delete [] tmpData;
-  } else {
-    mGLContext->fReadPixels(0,
-                          0,
-                          width,
-                          height,
-                          LOCAL_GL_BGRA,
+  NS_ASSERTION(imageSurface->Stride() == width * 4,
+               "Image Surfaces being created with weird stride!");
+
+  mGLContext->fReadPixels(0, 0,
+                          width, height,
+                          format,
                           LOCAL_GL_UNSIGNED_BYTE,
                           imageSurface->Data());
-    mGLContext->fFinish();
-  }                          
+
+  if (!mHasBGRA) {
+    // need to swap B and R bytes
+    for (int j = 0; j < height; ++j) {
+      PRUint32 *row = (PRUint32*) (imageSurface->Data() + imageSurface->Stride() * j);
+      for (int i = 0; i < width; ++i) {
+        *row = (*row & 0xff00ff00) | ((*row & 0xff) << 16) | ((*row & 0xff0000) >> 16);
+        row++;
+      }
+    }
+  }
 
   mTarget->SetOperator(gfxContext::OPERATOR_OVER);
   mTarget->SetSource(imageSurface);
   mTarget->Paint();
 }
 
-LayerOGL::LayerOGL(LayerManagerOGL *aManager)
-  : mOGLManager(aManager)
-  , mNextSibling(NULL)
-{
-}
+LayerManagerOGL::ProgramType LayerManagerOGL::sLayerProgramTypes[] = {
+  LayerManagerOGL::RGBALayerProgramType,
+  LayerManagerOGL::BGRALayerProgramType,
+  LayerManagerOGL::RGBXLayerProgramType,
+  LayerManagerOGL::BGRXLayerProgramType,
+  LayerManagerOGL::RGBARectLayerProgramType,
+  LayerManagerOGL::ColorLayerProgramType,
+  LayerManagerOGL::YCbCrLayerProgramType
+};
 
-LayerOGL*
-LayerOGL::GetNextSibling()
-{
-  return mNextSibling;
-}
+#define FOR_EACH_LAYER_PROGRAM(vname)                       \
+  for (int lpindex = 0;                                     \
+       lpindex < sizeof(sLayerProgramTypes)/sizeof(int);    \
+       ++lpindex)                                           \
+  {                                                         \
+    LayerProgram *vname = static_cast<LayerProgram*>        \
+      (mPrograms[sLayerProgramTypes[lpindex]]);             \
+    do
+
+#define FOR_EACH_LAYER_PROGRAM_END              \
+    while (0);                                  \
+  }                                             \
 
 void
-LayerOGL::SetNextSibling(LayerOGL *aNextSibling)
-{
-  mNextSibling = aNextSibling;
-}
-
-/**
- * LayerProgram Helpers
- */
-LayerProgram::LayerProgram()
-  : mGLContext(NULL)
-  , mProgram(0)
-{
-}
-
-LayerProgram::~LayerProgram()
-{
-  mGLContext->fDeleteProgram(mProgram);
-}
-
-PRBool
-LayerProgram::Initialize(GLuint aVertexShader,
-                         GLuint aFragmentShader,
-                         mozilla::gl::GLContext *aContext)
+LayerManagerOGL::SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix)
 {
-  mGLContext = aContext;
-
-  mProgram = mGLContext->fCreateProgram();
-  mGLContext->fAttachShader(mProgram, aVertexShader);
-  mGLContext->fAttachShader(mProgram, aFragmentShader);
-
-  mGLContext->fBindAttribLocation(mProgram, VERTEX_ATTRIB_LOCATION, "aVertex");
-  
-  mGLContext->fLinkProgram(mProgram);
-
-  GLint status;
-  mGLContext->fGetProgramiv(mProgram, LOCAL_GL_LINK_STATUS, &status);
-
-  if (!status) {
-    return false;
-  }
-  return true;
-}
-
-void
-LayerProgram::Activate()
-{
-  mGLContext->fUseProgram(mProgram);
-}
-
-void
-LayerProgram::UpdateLocations()
-{
-  mMatrixProjLocation = mGLContext->fGetUniformLocation(mProgram, "uMatrixProj");
-  mLayerQuadTransformLocation =
-    mGLContext->fGetUniformLocation(mProgram, "uLayerQuadTransform");
-  mLayerTransformLocation = mGLContext->fGetUniformLocation(mProgram, "uLayerTransform");
-  mRenderTargetOffsetLocation =
-    mGLContext->fGetUniformLocation(mProgram, "uRenderTargetOffset");
-  mLayerOpacityLocation = mGLContext->fGetUniformLocation(mProgram, "uLayerOpacity");
+  FOR_EACH_LAYER_PROGRAM(lp) {
+    lp->Activate();
+    lp->SetProjectionMatrix(aMatrix);
+  } FOR_EACH_LAYER_PROGRAM_END
 }
 
 void
-LayerProgram::SetMatrixUniform(GLint aLocation, const GLfloat *aValue)
-{
-  mGLContext->fUniformMatrix4fv(aLocation, 1, false, aValue);
-}
-
-void
-LayerProgram::SetInt(GLint aLocation, GLint aValue)
+LayerManagerOGL::CreateFBOWithTexture(int aWidth, int aHeight,
+                                      GLuint *aFBO, GLuint *aTexture)
 {
-  mGLContext->fUniform1i(aLocation, aValue);
-}
-
-void
-LayerProgram::SetColor(GLint aLocation, const gfxRGBA& aColor)
-{
-  mGLContext->fUniform4f(aLocation, aColor.r, aColor.g, aColor.b, aColor.a);
-}
+  GLuint tex, fbo;
 
-void
-LayerProgram::SetLayerOpacity(GLfloat aValue)
-{
-  mGLContext->fUniform1f(mLayerOpacityLocation, aValue);
-}
+  mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+  mGLContext->fGenTextures(1, &tex);
+  mGLContext->fBindTexture(mFBOTextureTarget, tex);
+  mGLContext->fTexImage2D(mFBOTextureTarget,
+                          0,
+                          LOCAL_GL_RGBA,
+                          aWidth, aHeight,
+                          0,
+                          LOCAL_GL_RGBA,
+                          LOCAL_GL_UNSIGNED_BYTE,
+                          NULL);
+  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MIN_FILTER,
+                             LOCAL_GL_LINEAR);
+  mGLContext->fTexParameteri(mFBOTextureTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
+                             LOCAL_GL_LINEAR);
+  mGLContext->fBindTexture(mFBOTextureTarget, 0);
 
-void
-LayerProgram::PushRenderTargetOffset(GLfloat aValueX, GLfloat aValueY)
-{
-  GLvec2 vector;
-  vector.mX = aValueX;
-  vector.mY = aValueY;
-  mRenderTargetOffsetStack.AppendElement(vector);
-}
+  mGLContext->fGenFramebuffers(1, &fbo);
+  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fbo);
+  mGLContext->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+                                    LOCAL_GL_COLOR_ATTACHMENT0,
+                                    mFBOTextureTarget,
+                                    tex,
+                                    0);
 
-void
-LayerProgram::PopRenderTargetOffset()
-{
-  NS_ASSERTION(mRenderTargetOffsetStack.Length(), "Unbalanced push/pops");
-  mRenderTargetOffsetStack.RemoveElementAt(mRenderTargetOffsetStack.Length() - 1);
+  NS_ASSERTION(mGLContext->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
+               LOCAL_GL_FRAMEBUFFER_COMPLETE, "Error setting up framebuffer.");
+
+  *aFBO = fbo;
+  *aTexture = tex;
+
+  DEBUG_GL_ERROR_CHECK(gl());
 }
 
-void
-LayerProgram::Apply()
-{
-  if (!mRenderTargetOffsetStack.Length()) {
-    mGLContext->fUniform4f(mRenderTargetOffsetLocation, 0, 0, 0, 0);
-  } else {
-    GLvec2 vector =
-      mRenderTargetOffsetStack[mRenderTargetOffsetStack.Length() - 1];
-    mGLContext->fUniform4f(mRenderTargetOffsetLocation, vector.mX, vector.mY, 0, 0);
-  }
-}
-
-void
-RGBLayerProgram::UpdateLocations()
-{
-  LayerProgram::UpdateLocations();
-
-  mLayerTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uLayerTexture");
-}
-
-void
-ColorLayerProgram::UpdateLocations()
-{
-  LayerProgram::UpdateLocations();
-
-  mRenderColorLocation = mGLContext->fGetUniformLocation(mProgram, "uRenderColor");
-}
-
-void
-YCbCrLayerProgram::UpdateLocations()
-{
-  LayerProgram::UpdateLocations();
-
-  mYTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uYTexture");
-  mCbTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uCbTexture");
-  mCrTextureLocation = mGLContext->fGetUniformLocation(mProgram, "uCrTexture");
-}
-
+                                     
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -15,16 +15,18 @@
  * The Original Code is Mozilla Corporation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Bas Schouten <bschouten@mozilla.org>
+ *   Frederic Plourde <frederic.plourde@collabora.co.uk>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -52,145 +54,36 @@ typedef unsigned int GLenum;
 typedef unsigned int GLbitfield;
 typedef unsigned int GLuint;
 typedef int GLint;
 typedef int GLsizei;
 
 #define BUFFER_OFFSET(i) ((char *)NULL + (i))
 
 #include "gfxContext.h"
+#include "gfx3DMatrix.h"
 #include "nsIWidget.h"
 #include "GLContext.h"
 
+#include "LayerManagerOGLProgram.h"
+
 namespace mozilla {
 namespace layers {
 
 class LayerOGL;
 
-struct GLvec2
-{
-  GLfloat mX;
-  GLfloat mY;
-};
-
-/**
- * Helper class for Layer Programs.
- */
-class LayerProgram
-{
-public:
-  LayerProgram();
-  virtual ~LayerProgram();
-
-  PRBool Initialize(GLuint aVertexShader,
-                    GLuint aFragmentShader,
-                    mozilla::gl::GLContext *aContext);
-
-  virtual void UpdateLocations();
-
-  void Activate();
-
-  void SetMatrixUniform(GLint aLocation, const GLfloat *aValue);
-  void SetInt(GLint aLocation, GLint aValue);
-  void SetColor(GLint aLocation, const gfxRGBA& aColor);
-
-  void SetMatrixProj(GLfloat *aValue)
-  {
-    SetMatrixUniform(mMatrixProjLocation, aValue);
-  }
-
-  void SetLayerQuadTransform(GLfloat *aValue)
-  {
-    SetMatrixUniform(mLayerQuadTransformLocation, aValue);
-  }
-
-  void SetLayerTransform(const GLfloat *aValue)
-  {
-    SetMatrixUniform(mLayerTransformLocation, aValue);
-  }
-
-  void SetLayerOpacity(GLfloat aValue);
-
-  void PushRenderTargetOffset(GLfloat aValueX, GLfloat aValueY);
-  void PopRenderTargetOffset();
-
-  void Apply();
-
-protected:
-  mozilla::gl::GLContext *mGLContext;
-
-  GLuint mProgram;
-  GLint mMatrixProjLocation;
-  GLint mLayerQuadTransformLocation;
-  GLint mLayerTransformLocation;
-  GLint mRenderTargetOffsetLocation;
-  GLint mLayerOpacityLocation;
-
-  nsTArray<GLvec2> mRenderTargetOffsetStack;
-};
-
-class RGBLayerProgram : public LayerProgram
-{
-public:
-  void UpdateLocations();
-
-  void SetLayerTexture(GLint aValue)
-  {
-    SetInt(mLayerTextureLocation, aValue);
-  }
-protected:
-  GLint mLayerTextureLocation;
-};
-
-class ColorLayerProgram : public LayerProgram
-{
-public:
-  void UpdateLocations();
-
-  void SetLayerColor(const gfxRGBA& aColor)
-  {
-    SetColor(mRenderColorLocation, aColor);
-  }
-
-protected:
-  GLint mRenderColorLocation;
-};
-
-class YCbCrLayerProgram : public LayerProgram
-{
-public:
-  void UpdateLocations();
-
-  void SetYTexture(GLint aValue)
-  {
-    SetInt(mYTextureLocation, aValue);
-  }
-  void SetCbTexture(GLint aValue)
-  {
-    SetInt(mCbTextureLocation, aValue);
-  }
-  void SetCrTexture(GLint aValue)
-  {
-    SetInt(mCrTextureLocation, aValue);
-  }
-protected:
-  GLint mYTextureLocation;
-  GLint mCbTextureLocation;
-  GLint mCrTextureLocation;
-};
-
 /**
  * This is the LayerManager used for OpenGL 2.1. For now this will render on
  * the main thread.
  */
 class THEBES_API LayerManagerOGL : public LayerManager {
 public:
   LayerManagerOGL(nsIWidget *aWidget);
   virtual ~LayerManagerOGL();
-
+  
   /**
    * Initializes the layer manager, this is when the layer manager will
    * actually access the device and attempt to create the swap chain used
    * to draw to the window. If this method fails the device cannot be used.
    * This function is not threadsafe.
    *
    * \return True is initialization was succesful, false when it was not.
    */
@@ -233,125 +126,281 @@ public:
 
   virtual already_AddRefed<ImageContainer> CreateImageContainer();
 
   virtual LayersBackend GetBackendType() { return LAYERS_OPENGL; }
 
   /**
    * Helper methods.
    */
-  void SetClippingEnabled(PRBool aEnabled);
-
   void MakeCurrent();
 
-  RGBLayerProgram *GetRGBLayerProgram() { return mRGBLayerProgram; }
-  ColorLayerProgram *GetColorLayerProgram() { return mColorLayerProgram; }
-  YCbCrLayerProgram *GetYCbCrLayerProgram() { return mYCbCrLayerProgram; }
+  ColorTextureLayerProgram *GetRGBALayerProgram() {
+    return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBALayerProgramType]);
+  }
+  ColorTextureLayerProgram *GetBGRALayerProgram() {
+    return static_cast<ColorTextureLayerProgram*>(mPrograms[BGRALayerProgramType]);
+  }
+  ColorTextureLayerProgram *GetRGBXLayerProgram() {
+    return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBXLayerProgramType]);
+  }
+  ColorTextureLayerProgram *GetBGRXLayerProgram() {
+    return static_cast<ColorTextureLayerProgram*>(mPrograms[BGRXLayerProgramType]);
+  }
+  ColorTextureLayerProgram *GetRGBARectLayerProgram() {
+    return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBARectLayerProgramType]);
+  }
+  SolidColorLayerProgram *GetColorLayerProgram() {
+    return static_cast<SolidColorLayerProgram*>(mPrograms[ColorLayerProgramType]);
+  }
+  YCbCrTextureLayerProgram *GetYCbCrLayerProgram() {
+    return static_cast<YCbCrTextureLayerProgram*>(mPrograms[YCbCrLayerProgramType]);
+  }
+  CopyProgram *GetCopy2DProgram() {
+    return static_cast<CopyProgram*>(mPrograms[Copy2DProgramType]);
+  }
+  CopyProgram *GetCopy2DRectProgram() {
+    return static_cast<CopyProgram*>(mPrograms[Copy2DRectProgramType]);
+  }
+
+  ColorTextureLayerProgram *GetFBOLayerProgram() {
+    if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB)
+      return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBARectLayerProgramType]);
+    return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBALayerProgramType]);
+  }
 
   typedef mozilla::gl::GLContext GLContext;
 
   GLContext *gl() const { return mGLContext; }
 
+  /*
+   * Helper functions for our layers
+   */
+  void CallThebesLayerDrawCallback(ThebesLayer* aLayer,
+                                   gfxContext* aContext,
+                                   const nsIntRegion& aRegionToDraw)
+  {
+    NS_ASSERTION(mThebesLayerCallback,
+                 "CallThebesLayerDrawCallback without callback!");
+    mThebesLayerCallback(aLayer, aContext,
+                         aRegionToDraw, mThebesLayerCallbackData);
+  }
+
+  GLenum FBOTextureTarget() { return mFBOTextureTarget; }
+
+  /* Create a FBO backed by a texture; will leave the FBO
+   * bound.  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.
+   */
+  void CreateFBOWithTexture(int aWidth, int aHeight,
+                            GLuint *aFBO, GLuint *aTexture);
+
+  GLuint QuadVBO() { return mQuadVBO; }
+  GLintptr QuadVBOVertexOffset() { return 0; }
+  GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
+  GLintptr QuadVBOFlippedTexCoordOffset() { return sizeof(float)*8*2; }
+
+  void BindQuadVBO() {
+    mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
+  }
+
+  void QuadVBOVerticesAttrib(GLuint aAttribIndex) {
+    mGLContext->fVertexAttribPointer(aAttribIndex, 2,
+                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+                                     (GLvoid*) QuadVBOVertexOffset());
+  }
+
+  void QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
+    mGLContext->fVertexAttribPointer(aAttribIndex, 2,
+                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+                                     (GLvoid*) QuadVBOTexCoordOffset());
+  }
+
+  void QuadVBOFlippedTexCoordsAttrib(GLuint aAttribIndex) {
+    mGLContext->fVertexAttribPointer(aAttribIndex, 2,
+                                     LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+                                     (GLvoid*) QuadVBOFlippedTexCoordOffset());
+  }
+
+  // Super common
+
+  void BindAndDrawQuad(GLuint aVertAttribIndex,
+                       GLuint aTexCoordAttribIndex,
+                       bool aFlipped = false)
+  {
+    BindQuadVBO();
+    QuadVBOVerticesAttrib(aVertAttribIndex);
+
+    if (aTexCoordAttribIndex != -1) {
+      if (aFlipped)
+        QuadVBOFlippedTexCoordsAttrib(aTexCoordAttribIndex);
+      else
+        QuadVBOTexCoordsAttrib(aTexCoordAttribIndex);
+
+      mGLContext->fEnableVertexAttribArray(aTexCoordAttribIndex);
+    }
+
+    mGLContext->fEnableVertexAttribArray(aVertAttribIndex);
+
+    mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+
+    mGLContext->fDisableVertexAttribArray(aVertAttribIndex);
+
+    if (aTexCoordAttribIndex != -1) {
+      mGLContext->fDisableVertexAttribArray(aTexCoordAttribIndex);
+    }
+  }
+
+  void BindAndDrawQuad(LayerProgram *aProg,
+                       bool aFlipped = false)
+  {
+    BindAndDrawQuad(aProg->AttribLocation(LayerProgram::VertexAttrib),
+                    aProg->AttribLocation(LayerProgram::TexCoordAttrib),
+                    aFlipped);
+  }
+
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   /** 
    * Context target, NULL when drawing directly to our swap chain.
    */
   nsRefPtr<gfxContext> mTarget;
 
   nsRefPtr<GLContext> mGLContext;
 
-  /** Backbuffer */
-  GLuint mBackBuffer;
-  /** Backbuffer size */
-  nsIntSize mBackBufferSize;
-  /** Framebuffer */
-  GLuint mFrameBuffer;
-  /** RGB Layer Program */
-  RGBLayerProgram *mRGBLayerProgram;
-  /** Color Layer Program */
-  ColorLayerProgram *mColorLayerProgram;
-  /** YUV Layer Program */
-  YCbCrLayerProgram *mYCbCrLayerProgram;
-  /** Vertex Shader */
-  GLuint mVertexShader;
-  /** RGB fragment shader */
-  GLuint mRGBShader;
-  /** Solid color shader */
-  GLuint mColorShader;
-  /** YUV fragment shader */
-  GLuint mYUVShader;
+  enum ProgramType {
+    RGBALayerProgramType,
+    BGRALayerProgramType,
+    RGBXLayerProgramType,
+    BGRXLayerProgramType,
+    RGBARectLayerProgramType,
+    ColorLayerProgramType,
+    YCbCrLayerProgramType,
+    Copy2DProgramType,
+    Copy2DRectProgramType,
+    NumProgramTypes
+  };
+
+  static ProgramType sLayerProgramTypes[];
+
   /** Current root layer. */
   LayerOGL *mRootLayer;
-  /** Vertex buffer */
-  GLuint mVBO;
+
+  /** Backbuffer */
+  GLuint mBackBufferFBO;
+  GLuint mBackBufferTexture;
+  nsIntSize mBackBufferSize;
+
+  /** Shader Programs */
+  nsTArray<LayerManagerOGLProgram*> mPrograms;
+
   /** Texture target to use for FBOs */
   GLenum mFBOTextureTarget;
 
-  /**
-   * Region we're clipping our current drawing to.
-   */
+  /** VBO that has some basics in it for a textured quad,
+   *  including vertex coords and texcoords for both
+   *  flipped and unflipped textures */
+  GLuint mQuadVBO;
+
+  /** Region we're clipping our current drawing to. */
   nsIntRegion mClippingRegion;
+
+  /** Misc */
+  PRPackedBool mHasBGRA;
+
   /**
    * Render the current layer tree to the active target.
    */
-  void Render(DrawThebesLayerCallback aCallback,
-              void* aCallbackData);
+  void Render();
   /**
-   * Setup the pipeline.
+   * Setup the viewport and projection matrix for rendering
+   * to a window of the given dimensions.
    */
-  void SetupPipeline();
+  void SetupPipeline(int aWidth, int aHeight);
   /**
-   * Setup the backbuffer.
-   *
-   * \return PR_TRUE if setup was succesful
+   * Setup a backbuffer of the given dimensions.
    */
-  PRBool SetupBackBuffer();
+  void SetupBackBuffer(int aWidth, int aHeight);
   /**
    * Copies the content of our backbuffer to the set transaction target.
    */
   void CopyToTarget();
+
+  /**
+   * Updates all layer programs with a new projection matrix.
+   *
+   * XXX we need a way to be able to delay setting this until
+   * the program is actually used.  Maybe a DelayedSetUniform
+   * on Program, that will delay the set until the next Activate?
+   *
+   * XXX this is only called once per frame, so it's not awful.
+   * If we have any more similar updates, then we should delay.
+   */
+  void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);
+
+  /* Thebes layer callbacks; valid at the end of a transaciton,
+   * while rendering */
+  DrawThebesLayerCallback mThebesLayerCallback;
+  void *mThebesLayerCallbackData;
 };
 
 /**
  * General information and tree management for OGL layers.
  */
 class LayerOGL
 {
 public:
-  typedef LayerManager::DrawThebesLayerCallback DrawThebesLayerCallback;
-
-  LayerOGL(LayerManagerOGL *aManager);
+  LayerOGL(LayerManagerOGL *aManager)
+    : mOGLManager(aManager), mNextSibling(nsnull)
+  { }
 
   enum LayerType {
     TYPE_THEBES,
     TYPE_CONTAINER,
     TYPE_IMAGE,
     TYPE_COLOR,
     TYPE_CANVAS
   };
   
   virtual LayerType GetType() = 0;
 
-  LayerOGL *GetNextSibling();
-  virtual LayerOGL *GetFirstChildOGL() { return nsnull; }
+  LayerOGL *GetNextSibling() {
+    return mNextSibling;
+  }
 
-  void SetNextSibling(LayerOGL *aParent);
-  void SetFirstChild(LayerOGL *aParent);
+  void SetNextSibling(LayerOGL *aSibling) {
+    mNextSibling = aSibling;
+  }
+
+  virtual LayerOGL *GetFirstChildOGL() {
+    return nsnull;
+  }
 
   virtual Layer* GetLayer() = 0;
 
-  virtual void RenderLayer(int aPreviousFrameBuffer, DrawThebesLayerCallback aCallback,
-                           void* aCallbackData) = 0;
+  virtual void RenderLayer(int aPreviousFrameBuffer,
+                           const nsIntPoint& aOffset) = 0;
 
   typedef mozilla::gl::GLContext GLContext;
 
   GLContext *gl() const { return mOGLManager->gl(); }
 protected:
   LayerManagerOGL *mOGLManager;
   LayerOGL *mNextSibling;
 };
 
+#ifdef DEBUG
+#define DEBUG_GL_ERROR_CHECK(cx) do {           \
+    /*fprintf (stderr, "trace %s %d\n", __FILE__, __LINE__);*/          \
+    GLenum err = (cx)->fGetError();             \
+    if (err) { fprintf (stderr, "GL ERROR: 0x%04x at %s:%d\n", err, __FILE__, __LINE__); } \
+  } while (0)
+#else
+#define DEBUG_GL_ERROR_CHECK(cx) do { } while (0)
+#endif
+
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_LAYERMANAGEROGL_H */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/LayerManagerOGLProgram.h
@@ -0,0 +1,764 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_LAYERMANAGEROGLPROGRAM_H
+#define GFX_LAYERMANAGEROGLPROGRAM_H
+
+#include <string.h>
+
+#include "prenv.h"
+
+#include "nsString.h"
+#include "GLContext.h"
+
+namespace mozilla {
+namespace layers {
+
+#define ASSERT_THIS_PROGRAM                                             \
+  do {                                                                  \
+    NS_ASSERTION(mGL->GetUserData(&sCurrentProgramKey) == this, \
+                 "SetUniform with wrong program active!");              \
+  } while (0)
+
+struct UniformValue {
+  UniformValue() {
+    memset(this, 0, sizeof(UniformValue));
+  }
+
+  void setInt(const int i) {
+    value.i[0] = i;
+  }
+
+  void setFloat(const float f) {
+    value.f[0] = f;
+  }
+
+  void setFloatN(const float *f, const int n) {
+    memcpy(value.f, f, sizeof(float)*n);
+  }
+
+  void setColor(const gfxRGBA& c) {
+    value.f[0] = float(c.r);
+    value.f[1] = float(c.g);
+    value.f[2] = float(c.b);
+    value.f[3] = float(c.a);
+  }
+
+  bool equalsInt(const int i) {
+    return i == value.i[0];
+  }
+
+  bool equalsFloat(const float f) {
+    return f == value.f[0];
+  }
+
+  bool equalsFloatN(const float *f, const int n) {
+    return memcmp(f, value.f, sizeof(float)*n) == 0;
+  }
+
+  bool equalsColor(const gfxRGBA& c) {
+    return value.f[0] == float(c.r) &&
+      value.f[1] == float(c.g) &&
+      value.f[2] == float(c.b) &&
+      value.f[3] == float(c.a);
+  }
+
+  union {
+    int i[1];
+    float f[16];
+  } value;
+};
+
+class LayerManagerOGLProgram {
+protected:
+  static int sCurrentProgramKey;
+
+public:
+  typedef mozilla::gl::GLContext GLContext;
+
+  // common attrib locations
+  enum {
+    VertexAttrib = 0,
+    TexCoordAttrib = 1
+  };
+
+  LayerManagerOGLProgram(GLContext *aGL)
+    : mGL(aGL), mProgram(0)
+  { }
+
+  virtual ~LayerManagerOGLProgram() { }
+
+  void Activate() {
+    NS_ASSERTION(mProgram != 0, "Attempting to activate a program that's not in use!");
+    mGL->fUseProgram(mProgram);
+    mGL->SetUserData(&sCurrentProgramKey, this);
+  }
+
+  void SetUniform(GLuint aUniform, float aFloatValue) {
+    ASSERT_THIS_PROGRAM;
+
+    if (aUniform == -1)
+      return;
+
+    if (!mUniformValues[aUniform].equalsFloat(aFloatValue)) {
+      mGL->fUniform1f(aUniform, aFloatValue);
+      mUniformValues[aUniform].setFloat(aFloatValue);
+    }
+  }
+
+  void SetUniform(GLuint aUniform, const gfxRGBA& aColor) {
+    ASSERT_THIS_PROGRAM;
+
+    if (aUniform == -1)
+      return;
+
+    if (!mUniformValues[aUniform].equalsColor(aColor)) {
+      mGL->fUniform4f(aUniform, float(aColor.r), float(aColor.g), float(aColor.b), float(aColor.a));
+      mUniformValues[aUniform].setColor(aColor);
+    }
+  }
+
+  void SetUniform(GLuint aUniform, int aLength, float *aFloatValues) {
+    ASSERT_THIS_PROGRAM;
+
+    if (aUniform == -1)
+      return;
+
+    if (!mUniformValues[aUniform].equalsFloatN(aFloatValues, aLength)) {
+      if (aLength == 1) {
+        mGL->fUniform1fv(aUniform, 1, aFloatValues);
+      } else if (aLength == 2) {
+        mGL->fUniform2fv(aUniform, 1, aFloatValues);
+      } else if (aLength == 3) {
+        mGL->fUniform3fv(aUniform, 1, aFloatValues);
+      } else if (aLength == 4) {
+        mGL->fUniform4fv(aUniform, 1, aFloatValues);
+      } else {
+        NS_NOTREACHED("Bogus aLength param");
+      }
+      mUniformValues[aUniform].setFloatN(aFloatValues, aLength);
+    }
+  }
+
+  void SetUniform(GLuint aUniform, GLint aIntValue) {
+    ASSERT_THIS_PROGRAM;
+
+    if (aUniform == -1)
+      return;
+
+    if (!mUniformValues[aUniform].equalsInt(aIntValue)) {
+      mGL->fUniform1i(aUniform, aIntValue);
+      mUniformValues[aUniform].setInt(aIntValue);
+    }
+  }
+
+  void SetMatrixUniform(GLuint aUniform, const float *aFloatValues) {
+    ASSERT_THIS_PROGRAM;
+
+    if (aUniform == -1)
+      return;
+
+    if (!mUniformValues[aUniform].equalsFloatN(aFloatValues, 16)) {
+      mGL->fUniformMatrix4fv(aUniform, 1, false, aFloatValues);
+      mUniformValues[aUniform].setFloatN(aFloatValues, 16);
+    }
+  }
+
+protected:
+  GLContext *mGL;
+
+  GLuint mProgram;
+  GLuint mFragmentShader;
+  GLuint mVertexShader;
+
+  nsTArray<UniformValue> mUniformValues;
+
+  GLint CreateShader(GLenum aShaderType,
+                     const char *aShaderSource)
+  {
+    GLint success, len = 0;
+
+    GLint sh = mGL->fCreateShader(aShaderType);
+    mGL->fShaderSource(sh, 1, (const GLchar**)&aShaderSource, NULL);
+    mGL->fCompileShader(sh);
+    mGL->fGetShaderiv(sh, LOCAL_GL_COMPILE_STATUS, &success);
+    mGL->fGetShaderiv(sh, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
+    /* Even if compiling is successful, there may still be warnings.  Print them
+     * in a debug build.  The > 10 is to catch silly compilers that might put
+     * some whitespace in the log but otherwise leave it empty.
+     */
+    if (!success
+#ifdef DEBUG
+        || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS"))
+#endif
+        )
+    {
+      nsCAutoString log;
+      log.SetCapacity(len);
+      mGL->fGetShaderInfoLog(sh, len, (GLint*) &len, (char*) log.BeginWriting());
+      log.SetLength(len);
+
+      if (!success) {
+        fprintf (stderr, "=== SHADER COMPILATION FAILED ===\n");
+      } else {
+        fprintf (stderr, "=== SHADER COMPILATION WARNINGS ===\n");
+      }
+
+        fprintf (stderr, "=== Source:\n%s\n", aShaderSource);
+        fprintf (stderr, "=== Log:\n%s\n", nsPromiseFlatCString(log).get());
+        fprintf (stderr, "============\n");
+
+      if (!success) {
+        mGL->fDeleteShader(sh);
+        return 0;
+      }
+    }
+
+    return sh;
+  }
+
+  bool CreateProgram(const char *aVertexShaderString,
+                     const char *aFragmentShaderString)
+  {
+    mVertexShader = CreateShader(LOCAL_GL_VERTEX_SHADER, aVertexShaderString);
+    mFragmentShader = CreateShader(LOCAL_GL_FRAGMENT_SHADER, aFragmentShaderString);
+
+    if (!mVertexShader || !mFragmentShader)
+      return false;
+
+    mProgram = mGL->fCreateProgram();
+    mGL->fAttachShader(mProgram, mVertexShader);
+    mGL->fAttachShader(mProgram, mFragmentShader);
+
+    // bind common attribs to consistent indices
+    mGL->fBindAttribLocation(mProgram, VertexAttrib, "aVertex");
+    mGL->fBindAttribLocation(mProgram, TexCoordAttrib, "aTexCoord");
+
+    mGL->fLinkProgram(mProgram);
+
+    GLint success, len;
+    mGL->fGetProgramiv(mProgram, LOCAL_GL_LINK_STATUS, &success);
+    mGL->fGetProgramiv(mProgram, LOCAL_GL_INFO_LOG_LENGTH, (GLint*) &len);
+    /* Even if linking is successful, there may still be warnings.  Print them
+     * in a debug build.  The > 10 is to catch silly compilers that might put
+     * some whitespace in the log but otherwise leave it empty.
+     */
+    if (!success
+#ifdef DEBUG
+        || (len > 10 && PR_GetEnv("MOZ_DEBUG_SHADERS"))
+#endif
+        )
+    {
+      nsCAutoString log;
+      log.SetCapacity(len);
+      mGL->fGetProgramInfoLog(mProgram, len, (GLint*) &len, (char*) log.BeginWriting());
+      log.SetLength(len);
+
+      if (!success) {
+        fprintf (stderr, "=== PROGRAM LINKING FAILED ===\n");
+      } else {
+        fprintf (stderr, "=== PROGRAM LINKING WARNINGS ===\n");
+      }
+      fprintf (stderr, "=== Log:\n%s\n", nsPromiseFlatCString(log).get());
+      fprintf (stderr, "============\n");
+
+      if (!success) {
+        mGL->fDeleteProgram(mProgram);
+        mGL->fDeleteShader(mVertexShader);
+        mGL->fDeleteShader(mFragmentShader);
+
+        mProgram = 0;
+
+        return false;
+      }
+    }
+
+    // Now query uniforms, so that we can initialize mUniformValues
+    // note that for simplicity, mUniformLocations is indexed by the
+    // uniform -location-, and not the uniform -index-.  This means
+    // that it might have a bunch of unused space as locations dense
+    // like indices are; however, there are unlikely to be enough for
+    // our shaders for this to become a significant memory issue.
+    GLint count, maxnamelen;
+    nsCAutoString uname;
+    GLint maxloc = 0;
+    mGL->fGetProgramiv(mProgram, LOCAL_GL_ACTIVE_UNIFORMS, &count);
+    mGL->fGetProgramiv(mProgram, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxnamelen);
+    uname.SetCapacity(maxnamelen);
+    for (int i = 0; i < count; ++i) {
+      GLsizei namelen;
+      GLint usize;
+      GLenum utype;
+
+      mGL->fGetActiveUniform(mProgram, i, maxnamelen, &namelen, &usize, &utype, uname.BeginWriting());
+      uname.SetLength(namelen);
+      GLint uloc = mGL->fGetUniformLocation(mProgram, uname.BeginReading());
+      if (maxloc < uloc)
+        maxloc = uloc;
+    }
+
+    // Note +1: the last valid index needs to be 'maxloc', so we need
+    // to set the array length to 1 more than that.
+    mUniformValues.SetLength(maxloc+1);
+    
+    return true;
+  }
+
+  void GetAttribLocations(const char **aAttribNames,
+                          GLint *aAttribLocations)
+  {
+    NS_ASSERTION(mProgram != 0, "GetAttribLocations called with no program!");
+
+    for (int i = 0; aAttribNames[i] != nsnull; ++i) {
+      aAttribLocations[i] = mGL->fGetAttribLocation(mProgram, aAttribNames[i]);
+    }
+  }
+
+  void GetUniformLocations(const char **aUniformNames,
+                           GLint *aUniformLocations)
+  {
+    NS_ASSERTION(mProgram != 0, "GetUniformLocations called with no program!");
+
+    for (int i = 0; aUniformNames[i] != nsnull; ++i) {
+      aUniformLocations[i] = mGL->fGetUniformLocation(mProgram, aUniformNames[i]);
+    }
+  }
+};
+
+/*
+ * A LayerProgram is the base of all further LayerPrograms.
+ *
+ * It has a number of attributes and uniforms common to all layer programs.
+ *
+ * Attribute inputs:
+ *   aVertexCoord  - vertex coordinate
+ *
+ * Uniforms:
+ *   uTransformMatrix - a transform matrix
+ *   uQuadTransform
+ *   uProjMatrix      - projection matrix
+ *   uOffset          - a vec4 offset to apply to the transformed coordinates
+ *   uLayerOpacity    - a float, the layer opacity (final colors will be multiplied by this)
+ */
+
+class LayerProgram  :
+  public LayerManagerOGLProgram
+{
+public:
+  enum {
+    TransformMatrixUniform = 0,
+    QuadTransformUniform,
+    ProjectionMatrixUniform,
+    OffsetUniform,
+    LayerOpacityUniform,
+    NumLayerUniforms
+  };
+
+  enum {
+    VertexCoordAttrib = 0,
+    NumLayerAttribs
+  };
+
+  LayerProgram(GLContext *aGL)
+    : LayerManagerOGLProgram(aGL)
+  { }
+
+  bool Initialize(const char *aVertexShaderString,
+                  const char *aFragmentShaderString)
+  {
+    if (!CreateProgram(aVertexShaderString, aFragmentShaderString))
+      return false;
+
+    const char *uniformNames[] = {
+      "uLayerTransform",
+      "uLayerQuadTransform",
+      "uMatrixProj",
+      "uRenderTargetOffset",
+      "uLayerOpacity",
+      NULL
+    };
+
+    mUniformLocations.SetLength(NumLayerUniforms);
+    GetUniformLocations(uniformNames, &mUniformLocations[0]);
+
+    const char *attribNames[] = {
+      "aVertexCoord",
+      NULL
+    };
+
+    mAttribLocations.SetLength(NumLayerAttribs);
+    GetAttribLocations(attribNames, &mAttribLocations[0]);
+
+    return true;
+  }
+
+  GLint AttribLocation(int aWhich) {
+    if (aWhich < 0 || aWhich >= int(mAttribLocations.Length()))
+      return -1;
+    return mAttribLocations[aWhich];
+  }
+
+  void SetLayerTransform(const gfx3DMatrix& aMatrix) {
+    SetLayerTransform(&aMatrix._11);
+  }
+
+  void SetLayerTransform(const float *aMatrix) {
+    SetMatrixUniform(mUniformLocations[TransformMatrixUniform], aMatrix);
+  }
+
+  void SetLayerQuadRect(const nsIntRect& aRect) {
+    gfx3DMatrix m;
+    m._11 = float(aRect.width);
+    m._22 = float(aRect.height);
+    m._41 = float(aRect.x);
+    m._42 = float(aRect.y);
+    SetMatrixUniform(mUniformLocations[QuadTransformUniform], &m._11);
+  }
+
+  void SetProjectionMatrix(const gfx3DMatrix& aMatrix) {
+    SetProjectionMatrix(&aMatrix._11);
+  }
+
+  void SetProjectionMatrix(const float *aMatrix) {
+    SetMatrixUniform(mUniformLocations[ProjectionMatrixUniform], aMatrix);
+  }
+
+  void SetRenderOffset(const nsIntPoint& aOffset) {
+    float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f };
+    SetUniform(mUniformLocations[OffsetUniform], 4, vals);
+  }
+
+  void SetRenderOffset(float aX, float aY) {
+    float vals[4] = { aX, aY, 0.0f, 0.0f };
+    SetUniform(mUniformLocations[OffsetUniform], 4, vals);
+  }
+
+  void SetLayerOpacity(float aOpacity) {
+    SetUniform(mUniformLocations[LayerOpacityUniform], aOpacity);
+  }
+
+protected:
+  nsTArray<GLint> mUniformLocations;
+  nsTArray<GLint> mAttribLocations;
+};
+
+/*
+ * A ColorTextureLayerProgram is a LayerProgram that renders
+ * a single texture.  It adds the following attributes and uniforms:
+ *
+ * Attribute inputs:
+ *   aTexCoord     - texture coordinate
+ *
+ * Uniforms:
+ *   uTexture         - 2D texture unit which to sample
+ */
+
+class ColorTextureLayerProgram :
+  public LayerProgram
+{
+public:
+  enum {
+    TextureUniform = NumLayerUniforms,
+    NumUniforms
+  };
+
+  enum {
+    TexCoordAttrib = NumLayerAttribs,
+    NumAttribs
+  };
+
+  ColorTextureLayerProgram(GLContext *aGL)
+    : LayerProgram(aGL)
+  { }
+
+  bool Initialize(const char *aVertexShaderString,
+                  const char *aFragmentShaderString)
+  {
+    if (!LayerProgram::Initialize(aVertexShaderString, aFragmentShaderString))
+      return false;
+
+    const char *uniformNames[] = {
+      "uTexture",
+      NULL
+    };
+
+    mUniformLocations.SetLength(NumUniforms);
+    GetUniformLocations(uniformNames, &mUniformLocations[NumLayerUniforms]);
+
+    const char *attribNames[] = {
+      "aTexCoord",
+      NULL
+    };
+
+    mAttribLocations.SetLength(NumAttribs);
+    GetAttribLocations(attribNames, &mAttribLocations[NumLayerAttribs]);
+
+    // this is a one-off that's present in the 2DRect versions of some shaders.
+    mTexCoordMultiplierUniformLocation =
+      mGL->fGetUniformLocation(mProgram, "uTexCoordMultiplier");
+
+    return true;
+  }
+
+  void SetTextureUnit(GLint aUnit) {
+    SetUniform(mUniformLocations[TextureUniform], aUnit);
+  }
+
+  GLint GetTexCoordMultiplierUniformLocation() {
+    return mTexCoordMultiplierUniformLocation;
+  }
+
+protected:
+  GLint mTexCoordMultiplierUniformLocation;
+};
+
+/*
+ * A YCbCrTextureLayerProgram is a LayerProgram that renders a YCbCr
+ * image, reading from three texture units.  The textures are assumed
+ * to be single-channel textures.
+ *
+ * Attribute inputs:
+ *   aTexCoord     - texture coordinate
+ *
+ * Uniforms:
+ *   uYTexture     - 2D texture unit which to sample Y
+ *   uCbTexture    - 2D texture unit which to sample Cb
+ *   uCrTexture    - 2D texture unit which to sample Cr
+ */
+
+class YCbCrTextureLayerProgram :
+  public LayerProgram
+{
+public:
+  enum {
+    YTextureUniform = NumLayerUniforms,
+    CbTextureUniform,
+    CrTextureUniform,
+    NumUniforms
+  };
+
+  enum {
+    TexCoordAttrib = NumLayerAttribs,
+    NumAttribs
+  };
+
+  YCbCrTextureLayerProgram(GLContext *aGL)
+    : LayerProgram(aGL)
+  { }
+
+  bool Initialize(const char *aVertexShaderString,
+                  const char *aFragmentShaderString)
+  {
+    if (!LayerProgram::Initialize(aVertexShaderString, aFragmentShaderString))
+      return false;
+
+    const char *uniformNames[] = {
+      "uYTexture",
+      "uCbTexture",
+      "uCrTexture",
+      NULL
+    };
+
+    mUniformLocations.SetLength(NumUniforms);
+    GetUniformLocations(uniformNames, &mUniformLocations[NumLayerUniforms]);
+
+    const char *attribNames[] = {
+      "aTexCoord",
+      NULL
+    };
+
+    mAttribLocations.SetLength(NumAttribs);
+    GetAttribLocations(attribNames, &mAttribLocations[NumLayerAttribs]);
+
+    return true;
+  }
+
+  void SetYTextureUnit(GLint aUnit) {
+    SetUniform(mUniformLocations[YTextureUniform], aUnit);
+  }
+
+  void SetCbTextureUnit(GLint aUnit) {
+    SetUniform(mUniformLocations[CbTextureUniform], aUnit);
+  }
+
+  void SetCrTextureUnit(GLint aUnit) {
+    SetUniform(mUniformLocations[CrTextureUniform], aUnit);
+  }
+
+  void SetYCbCrTextureUnits(GLint aYUnit, GLint aCbUnit, GLint aCrUnit) {
+    SetUniform(mUniformLocations[YTextureUniform], aYUnit);
+    SetUniform(mUniformLocations[CbTextureUniform], aCbUnit);
+    SetUniform(mUniformLocations[CrTextureUniform], aCrUnit);
+  }
+};
+
+/*
+ * A SolidColorLayerProgram is a LayerProgram that renders
+ * a solid color.  It adds the following attributes and uniforms:
+ *
+ * Uniforms:
+ *   uRenderColor      - solid color to render;
+ *      This should be with premultiplied opacity, as it's written
+ *      to the color buffer directly.  Layer Opacity is ignored.
+ */
+
+class SolidColorLayerProgram :
+  public LayerProgram
+{
+public:
+  enum {
+    RenderColorUniform = NumLayerUniforms,
+    NumUniforms
+  };
+
+  enum {
+    NumAttribs = NumLayerAttribs
+  };
+
+  SolidColorLayerProgram(GLContext *aGL)
+    : LayerProgram(aGL)
+  { }
+
+  bool Initialize(const char *aVertexShaderString,
+                  const char *aFragmentShaderString)
+  {
+    if (!LayerProgram::Initialize(aVertexShaderString, aFragmentShaderString))
+      return false;
+
+    const char *uniformNames[] = {
+      "uRenderColor",
+      NULL
+    };
+
+    mUniformLocations.SetLength(NumUniforms);
+    GetUniformLocations(uniformNames, &mUniformLocations[NumLayerUniforms]);
+
+    return true;
+  }
+
+  void SetRenderColor(const gfxRGBA& aColor) {
+    SetUniform(mUniformLocations[RenderColorUniform], aColor);
+  }
+};
+
+/*
+ * A CopyProgram is an OpenGL program that copies a 4-channel texture
+ * to the destination, making no attempt to transform any incoming
+ * vertices.  It has the following attributes and uniforms:
+ *
+ * Attribute inputs:
+ *   aVertex       - vertex coordinate
+ *   aTexCoord     - texture coordinate
+ *
+ * Uniforms:
+ *   uTexture      - 2D texture unit which to sample
+ */
+
+class CopyProgram :
+  public LayerManagerOGLProgram
+{
+public:
+  enum {
+    TextureUniform = 0,
+    NumUniforms
+  };
+
+  enum {
+    VertexCoordAttrib = 0,
+    TexCoordAttrib,
+    NumAttribs
+  };
+
+  CopyProgram(GLContext *aGL)
+    : LayerManagerOGLProgram(aGL)
+  { }
+
+  bool Initialize(const char *aVertexShaderString,
+                  const char *aFragmentShaderString)
+  {
+    if (!CreateProgram(aVertexShaderString, aFragmentShaderString))
+      return false;
+
+    const char *uniformNames[] = {
+      "uTexture",
+      NULL
+    };
+
+    mUniformLocations.SetLength(NumUniforms);
+    GetUniformLocations(uniformNames, &mUniformLocations[0]);
+
+    const char *attribNames[] = {
+      "aVertexCoord",
+      "aTexCoord",
+      NULL
+    };
+
+    mAttribLocations.SetLength(NumAttribs);
+    GetAttribLocations(attribNames, &mAttribLocations[0]);
+
+    // this is a one-off that's present in the 2DRect versions of some shaders.
+    mTexCoordMultiplierUniformLocation =
+      mGL->fGetUniformLocation(mProgram, "uTexCoordMultiplier");
+
+    return true;
+  }
+
+  GLint AttribLocation(int aWhich) {
+    if (aWhich < 0 || aWhich >= int(mAttribLocations.Length()))
+      return -1;
+    return mAttribLocations[aWhich];
+  }
+
+  void SetTextureUnit(GLint aUnit) {
+    SetUniform(mUniformLocations[TextureUniform], aUnit);
+  }
+
+  GLint GetTexCoordMultiplierUniformLocation() {
+    return mTexCoordMultiplierUniformLocation;
+  }
+
+protected:
+  nsTArray<GLint> mUniformLocations;
+  nsTArray<GLint> mAttribLocations;
+
+  GLint mTexCoordMultiplierUniformLocation;
+};
+
+} /* layers */
+} /* mozilla */
+
+#endif /* GFX_LAYERMANAGEROGLPROGRAM_H */
deleted file mode 100644
--- a/gfx/layers/opengl/LayerManagerOGLShaders.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#define SHADER_GLOBAL_VARS "uniform mat4 uMatrixProj; \
-uniform mat4 uLayerQuadTransform; \
-uniform mat4 uLayerTransform; \
-uniform vec4 uRenderTargetOffset; \
-uniform vec4 uRenderColor; \
-uniform float uLayerOpacity; \
-\
-uniform sampler2D uLayerTexture; \
-uniform sampler2D uYTexture; \
-uniform sampler2D uCbTexture; \
-uniform sampler2D uCrTexture; \
-varying vec2 vTextureCoordinate;"
-
-static const GLchar *sVertexShader = SHADER_GLOBAL_VARS "attribute vec4 aVertex; \
-void main() \
-{ \
-    vec4 finalPosition = aVertex; \
-    finalPosition = uLayerQuadTransform * finalPosition; \
-    finalPosition = uLayerTransform * finalPosition; \
-    finalPosition = finalPosition - uRenderTargetOffset; \
-    finalPosition = uMatrixProj * finalPosition; \
-    gl_Position = finalPosition; \
-    vTextureCoordinate = vec2(aVertex); \
-    }";
-
-static const GLchar *sRGBLayerPS = SHADER_GLOBAL_VARS "void main() \
-{ \
-gl_FragColor = texture2D(uLayerTexture, vTextureCoordinate) * uLayerOpacity; \
-}";
-
-static const GLchar *sColorLayerPS = SHADER_GLOBAL_VARS "void main() \
-{ \
-gl_FragColor = uRenderColor; \
-}";
-
-static const GLchar *sYUVLayerPS = SHADER_GLOBAL_VARS "void main() \
-{ \
-    vec4 yuv; \
-    vec4 color; \
-    yuv.r = texture2D(uCrTexture, vTextureCoordinate).r - 0.5; \
-    yuv.g = texture2D(uYTexture, vTextureCoordinate).r - 0.0625; \
-    yuv.b = texture2D(uCbTexture, vTextureCoordinate).r - 0.5; \
-    color.r = yuv.g * 1.164 + yuv.r * 1.596; \
-    color.g = yuv.g * 1.164 - 0.813 * yuv.r - 0.391 * yuv.b; \
-    color.b = yuv.g * 1.164 + yuv.b * 2.018; \
-    color.a = 1.0; \
-    gl_FragColor = color * uLayerOpacity; \
-}";
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt
@@ -0,0 +1,279 @@
+// -*- Mode: glsl; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40; -*-
+// ***** BEGIN LICENSE BLOCK *****
+// Version: MPL 1.1/GPL 2.0/LGPL 2.1
+//
+// The contents of this file are subject to the Mozilla Public License Version
+// 1.1 (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+// http://www.mozilla.org/MPL/
+//
+// Software distributed under the License is distributed on an "AS IS" basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+// for the specific language governing rights and limitations under the
+// License.
+//
+// The Original Code is Mozilla Foundation code.
+//
+// The Initial Developer of the Original Code is
+//   Mozilla Foundation.
+// Portions created by the Initial Developer are Copyright (C) 2010
+// the Initial Developer. All Rights Reserved.
+//
+// Contributor(s):
+//   Bas Schouten <bschouten@mozilla.org>
+//   Vladimir Vukicevic <vladimir@pobox.com>
+//
+// Alternatively, the contents of this file may be used under the terms of
+// either the GNU General Public License Version 2 or later (the "GPL"), or
+// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+// in which case the provisions of the GPL or the LGPL are applicable instead
+// of those above. If you wish to allow use of your version of this file only
+// under the terms of either the GPL or the LGPL, and not to allow others to
+// use your version of this file under the terms of the MPL, indicate your
+// decision by deleting the provisions above and replace them with the notice
+// and other provisions required by the GPL or the LGPL. If you do not delete
+// the provisions above, a recipient may use your version of this file under
+// the terms of any one of the MPL, the GPL or the LGPL.
+//
+// ***** END LICENSE BLOCK *****
+
+//
+// Syntax:
+//
+// // comments (only at the start of a line)
+//
+// (@ is used because # is valid inside GLSL)
+//
+// multi-line:
+// @define FOO
+// ...
+// @end
+//
+// single:
+// @define FOO 123
+//
+// $FOO$ to paste
+//
+// To generate a constant string named ShaderName:
+// @shader ShaderName
+// ...
+// @end
+//
+// 
+
+@define VERTEX_SHADER_HEADER
+/* Vertex Shader */
+@end
+
+@define FRAGMENT_SHADER_HEADER
+/* Fragment Shader */
+#ifdef GL_ES
+precision mediump float;
+#endif
+@end
+
+// fragment shader header for all layers
+@define LAYER_FRAGMENT
+$FRAGMENT_SHADER_HEADER$
+
+#ifndef NO_LAYER_OPACITY
+uniform float uLayerOpacity;
+#endif
+
+varying vec2 vTexCoord;
+@end
+
+// This is a basic Layer vertex shader.  It's used for all
+// the Layer programs.
+
+@shader sLayerVS
+$VERTEX_SHADER_HEADER$
+
+uniform mat4 uMatrixProj;
+uniform mat4 uLayerQuadTransform;
+uniform mat4 uLayerTransform;
+uniform vec4 uRenderTargetOffset;
+
+attribute vec4 aVertexCoord;
+attribute vec2 aTexCoord;
+
+varying vec2 vTexCoord;
+
+void main()
+{
+  vec4 finalPosition = aVertexCoord;
+  finalPosition = uLayerQuadTransform * finalPosition;
+  finalPosition = uLayerTransform * finalPosition;
+  finalPosition = finalPosition - uRenderTargetOffset;
+  finalPosition = uMatrixProj * finalPosition;
+
+  vTexCoord = aTexCoord;
+  gl_Position = finalPosition;
+}
+@end
+
+// Solid color rendering.
+// texcoords are ignored (no texture to sample).
+// The layer opacity is baked in to the color.
+@shader sSolidColorLayerFS
+#define NO_LAYER_OPACITY 1
+$LAYER_FRAGMENT$
+uniform vec4 uRenderColor;
+
+void main()
+{
+  gl_FragColor = uRenderColor;
+}
+@end
+
+// Single texture in RGBA format
+@shader sRGBATextureLayerFS
+$LAYER_FRAGMENT$
+uniform sampler2D uTexture;
+
+void main()
+{
+  gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity;
+}
+@end
+
+// Single texture in RGBA format, but with a Rect texture.
+// Container layer needs this to render a FBO group.
+@shader sRGBARectTextureLayerFS
+#extension GL_ARB_texture_rectangle : enable
+
+$LAYER_FRAGMENT$
+
+/* This should not be used on GL ES */
+#ifndef GL_ES
+uniform sampler2DRect uTexture;
+uniform vec2 uTexCoordMultiplier;
+void main()
+{
+  gl_FragColor = texture2DRect(uTexture, vec2(vTexCoord * uTexCoordMultiplier)) * uLayerOpacity;
+}
+#else
+void main()
+{
+  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+}
+#endif
+@end
+
+// Single texture in BGRA format (via swizzle)
+@shader sBGRATextureLayerFS
+$LAYER_FRAGMENT$
+uniform sampler2D uTexture;
+
+void main()
+{
+  gl_FragColor = texture2D(uTexture, vTexCoord).bgra * uLayerOpacity;
+}
+@end
+
+// Single texture in RGBX format
+@shader sRGBXTextureLayerFS
+$LAYER_FRAGMENT$
+uniform sampler2D uTexture;
+
+void main()
+{
+  gl_FragColor = vec4(texture2D(uTexture, vTexCoord).rgb, 1.0) * uLayerOpacity;
+}
+@end
+
+// Single texture in BGRX format (via swizzle)
+@shader sBGRXTextureLayerFS
+$LAYER_FRAGMENT$
+uniform sampler2D uTexture;
+
+void main()
+{
+  gl_FragColor = vec4(texture2D(uTexture, vTexCoord).bgr, 1.0) * uLayerOpacity;
+}
+@end
+
+// Three textures, representing YCbCr planes of a video image
+@shader sYCbCrTextureLayerFS
+$LAYER_FRAGMENT$
+uniform sampler2D uYTexture;
+uniform sampler2D uCbTexture;
+uniform sampler2D uCrTexture;
+
+void main()
+{
+  vec4 yuv;
+  vec4 color;
+  yuv.r = texture2D(uCrTexture, vTexCoord).r - 0.5;
+  yuv.g = texture2D(uYTexture, vTexCoord).r - 0.0625;
+  yuv.b = texture2D(uCbTexture, vTexCoord).r - 0.5;
+  color.r = yuv.g * 1.164 + yuv.r * 1.596;
+  color.g = yuv.g * 1.164 - 0.813 * yuv.r - 0.391 * yuv.b;
+  color.b = yuv.g * 1.164 + yuv.b * 2.018;
+  color.a = 1.0;
+  gl_FragColor = color * uLayerOpacity;
+}
+@end
+
+//
+// The "Copy" program is used for blitting a texture to a destination
+// with no transforms or any other manipulation.  They're used for
+// blitting the contents of a FBO-rendered texture to a destination.
+//
+// There are two variants of the fragment shader: one that uses 2D
+// textures and one that uses 2DRect textures (for when
+// EXT_TEXTURE_RECTANGLE is used for FBOs).
+//
+// On GL ES, EXT_TEXTURE_RECTANGLE isn't available, so we still
+// compile the shader but have it render pure red.  It should never
+// be used.
+//
+
+@shader sCopyVS
+$VERTEX_SHADER_HEADER$
+
+attribute vec4 aVertexCoord;
+attribute vec2 aTexCoord;
+
+varying vec2 vTexCoord;
+
+void main()
+{
+  gl_Position = aVertexCoord;
+  vTexCoord = aTexCoord;
+}
+@end
+
+@shader sCopy2DFS
+$FRAGMENT_SHADER_HEADER$
+
+varying vec2 vTexCoord;
+
+uniform sampler2D uTexture;
+void main()
+{
+  gl_FragColor = texture2D(uTexture, vTexCoord);
+}
+@end
+
+@shader sCopy2DRectFS
+#extension GL_ARB_texture_rectangle : enable
+
+$FRAGMENT_SHADER_HEADER$
+
+varying vec2 vTexCoord;
+uniform vec2 uTexCoordMultiplier;
+
+#ifndef GL_ES
+uniform sampler2DRect uTexture;
+void main()
+{
+  gl_FragColor = texture2DRect(uTexture, vTexCoord * uTexCoordMultiplier);
+}
+#else
+void main()
+{
+  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+}
+#endif
+@end
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -15,16 +15,17 @@
  * The Original Code is Mozilla Corporation code.
  *
  * The Initial Developer of the Original Code is Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Bas Schouten <bschouten@mozilla.org>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -74,54 +75,54 @@ ThebesLayerOGL::ThebesLayerOGL(LayerMana
   , LayerOGL(aManager)
   , mTexture(0)
 {
   mImplData = static_cast<LayerOGL*>(this);
 }
 
 ThebesLayerOGL::~ThebesLayerOGL()
 {
-  static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
+  mOGLManager->MakeCurrent();
   if (mTexture) {
     gl()->fDeleteTextures(1, &mTexture);
   }
 }
 
 void
 ThebesLayerOGL::SetVisibleRegion(const nsIntRegion &aRegion)
 {
-  if (aRegion.GetBounds() == mVisibleRect) {
+  if (aRegion.GetBounds() == mVisibleRect)
     return;
-  }
-  mVisibleRect = aRegion.GetBounds();
 
-  static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
-
-  if (!mTexture) {
-    gl()->fGenTextures(1, &mTexture);
-  }
-
+  mVisibleRect = aRegion.GetBounds();
   mInvalidatedRect = mVisibleRect;
 
+  mOGLManager->MakeCurrent();
+
+  if (!mTexture)
+    gl()->fGenTextures(1, &mTexture);
+
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
   gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
   gl()->fTexImage2D(LOCAL_GL_TEXTURE_2D,
-                  0,
-                  LOCAL_GL_RGBA,
-                  mVisibleRect.width,
-                  mVisibleRect.height,
-                  0,
-                  LOCAL_GL_BGRA,
-                  LOCAL_GL_UNSIGNED_BYTE,
-                  NULL);
+                    0,
+                    LOCAL_GL_RGBA,
+                    mVisibleRect.width,
+                    mVisibleRect.height,
+                    0,
+                    LOCAL_GL_RGBA,
+                    LOCAL_GL_UNSIGNED_BYTE,
+                    NULL);
+
+  DEBUG_GL_ERROR_CHECK(gl());
 }
 
 void
 ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion)
 {
   nsIntRegion invalidatedRegion;
   invalidatedRegion.Or(aRegion, mInvalidatedRect);
   invalidatedRegion.And(invalidatedRegion, mVisibleRect);
@@ -137,22 +138,25 @@ ThebesLayerOGL::GetType()
 const nsIntRect&
 ThebesLayerOGL::GetVisibleRect()
 {
   return mVisibleRect;
 }
 
 void
 ThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
-                            DrawThebesLayerCallback aCallback,
-                            void* aCallbackData)
+                            const nsIntPoint& aOffset)
 {
-  if (!mTexture) {
+  if (!mTexture)
     return;
-  }
+
+  mOGLManager->MakeCurrent();
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+
+  bool needsTextureBind = true;
 
   if (!mInvalidatedRect.IsEmpty()) {
     gfxASurface::gfxImageFormat imageFormat;
 
     if (UseOpaqueSurface(this)) {
       imageFormat = gfxASurface::ImageFormatRGB24;
     } else {
       imageFormat = gfxASurface::ImageFormatARGB32;
@@ -161,20 +165,22 @@ ThebesLayerOGL::RenderLayer(int aPreviou
     nsRefPtr<gfxASurface> surface =
       gfxPlatform::GetPlatform()->
         CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
                                           mInvalidatedRect.height),
                                imageFormat);
 
     nsRefPtr<gfxContext> ctx = new gfxContext(surface);
     ctx->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
-    aCallback(this, ctx, mInvalidatedRect, aCallbackData);
 
-    static_cast<LayerManagerOGL*>(mManager)->MakeCurrent();
+    /* Call the thebes layer callback */
+    mOGLManager->CallThebesLayerDrawCallback(this, ctx, mInvalidatedRect);
 
+    /* Then take its results and put it in an image surface,
+     * in preparation for a texture upload */
     nsRefPtr<gfxImageSurface> imageSurface;
 
     switch (surface->GetType()) {
       case gfxASurface::SurfaceTypeImage:
         imageSurface = static_cast<gfxImageSurface*>(surface.get());
         break;
 #ifdef XP_WIN
       case gfxASurface::SurfaceTypeWin32:
@@ -202,46 +208,43 @@ ThebesLayerOGL::RenderLayer(int aPreviou
 
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
     gl()->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
                          0,
                          mInvalidatedRect.x - mVisibleRect.x,
                          mInvalidatedRect.y - mVisibleRect.y,
                          mInvalidatedRect.width,
                          mInvalidatedRect.height,
-                         LOCAL_GL_BGRA,
+                         LOCAL_GL_RGBA,
                          LOCAL_GL_UNSIGNED_BYTE,
                          imageSurface->Data());
+
+    needsTextureBind = false;
   }
 
-  float quadTransform[4][4];
-  /*
-   * Matrix to transform the <0.0,0.0>, <1.0,1.0> quad to the correct position
-   * and size.
-   */
-  memset(&quadTransform, 0, sizeof(quadTransform));
-  quadTransform[0][0] = (float)GetVisibleRect().width;
-  quadTransform[1][1] = (float)GetVisibleRect().height;
-  quadTransform[2][2] = 1.0f;
-  quadTransform[3][0] = (float)GetVisibleRect().x;
-  quadTransform[3][1] = (float)GetVisibleRect().y;
-  quadTransform[3][3] = 1.0f;
+  if (needsTextureBind)
+    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
 
-  RGBLayerProgram *program = 
-    static_cast<LayerManagerOGL*>(mManager)->GetRGBLayerProgram();
+  // Note BGR: Cairo's image surfaces are always in what
+  // OpenGL and our shaders consider BGR format.
+  ColorTextureLayerProgram *program =
+    UseOpaqueSurface(this)
+    ? mOGLManager->GetBGRXLayerProgram()
+    : mOGLManager->GetBGRALayerProgram();
 
   program->Activate();
-  program->SetLayerQuadTransform(&quadTransform[0][0]);
+  program->SetLayerQuadRect(mVisibleRect);
   program->SetLayerOpacity(GetOpacity());
-  program->SetLayerTransform(&mTransform._11);
-  program->Apply();
+  program->SetLayerTransform(mTransform);
+  program->SetRenderOffset(aOffset);
+  program->SetTextureUnit(0);
 
-  gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+  mOGLManager->BindAndDrawQuad(program);
 
-  gl()->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+  DEBUG_GL_ERROR_CHECK(gl());
 }
 
 const nsIntRect&
 ThebesLayerOGL::GetInvalidatedRect()
 {
   return mInvalidatedRect;
 }
 
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-/
+/* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -59,18 +59,17 @@ public:
   /** ThebesLayer implementation */
   void InvalidateRegion(const nsIntRegion& aRegion);
 
   /** LayerOGL implementation */
   LayerType GetType();
   Layer* GetLayer();
   virtual PRBool IsEmpty();
   virtual void RenderLayer(int aPreviousFrameBuffer,
-                           DrawThebesLayerCallback aCallback,
-                           void* aCallbackData);
+                           const nsIntPoint& aOffset);
 
   /** ThebesLayerOGL */
   const nsIntRect &GetVisibleRect();
   const nsIntRect &GetInvalidatedRect();
 
 private:
   /** 
    * Visible rectangle, this is used to know the size and position of the quad
@@ -81,14 +80,13 @@ private:
    * Currently invalidated rectangular area.
    */
   nsIntRect mInvalidatedRect;
 
   /**
    * OpenGL Texture
    */
   GLuint mTexture;
-
 };
 
 } /* layers */
 } /* mozilla */
 #endif /* GFX_THEBESLAYEROGL_H */
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/genshaders.py
@@ -0,0 +1,140 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Foundation code.
+#
+# The Initial Developer of the Original Code is
+#   Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Vladimir Vukicevic <vladimir@pobox.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+
+import sys
+import re
+import string
+
+defines = dict()
+
+def emitShader(fp, shadername, shaderlines):
+    eolContinue = "\\n\\\n";
+    fp.write("const char %s[] = \"/* %s */%s" % (shadername,shadername,eolContinue))
+    for line in shaderlines:
+        line.replace("\\", "\\\\")
+        while line.find('$') != -1:
+            expansions = re.findall('\$\S+\$', line)
+            for m in expansions:
+                mkey = m[1:-1]
+                if not defines.has_key(mkey):
+                    print "Error: Undefined expansion used: '%s'" % (m,)
+                    sys.exit(1)
+                mval = defines[mkey]
+                if type(mval) == str:
+                    line = line.replace(m, mval)
+                elif type(mval) == list:
+                    line = line.replace(m, eolContinue.join(mval) + eolContinue);
+                else:
+                    print "Internal Error: Unknown type in defines array: '%s'" % (str(type(mval)),)
+
+        fp.write("%s%s" % (line,eolContinue))
+    fp.write("\";\n\n");
+
+def genShaders(infile, outfile):
+    source = open(infile, "r").readlines()
+    desthdr = open(outfile, "w+")
+
+    desthdr.write("/* AUTOMATICALLY GENERATED */\n");
+    desthdr.write("/* DO NOT EDIT! */\n\n");
+
+    global defines
+
+    indefine = None
+    inshader = None
+
+    inblock = False
+    linebuffer = []
+
+    for line in source:
+        # strip comments, if not inblock
+        if not inblock and line.startswith("//"):
+            continue
+        line = string.strip(line)
+
+        if len(line) == 0:
+            continue
+
+        if line[0] == '@':
+            cmd = line
+            rest = ''
+
+            if line.find(' ') != -1:
+                cmd = line[0:line.find(' ')]
+                rest = string.strip(line[len(cmd) + 1:])
+                
+            if cmd == "@define":
+                if inblock:
+                    raise Exception("@define inside a block!")
+                space = rest.find(' ')
+                if space != -1:
+                    defines[rest[0:space]] = rest[space+1:]
+                else:
+                    indefine = rest
+                    inblock = True
+            elif cmd == "@shader":
+                if inblock:
+                    raise Exception("@shader inside a block!")
+                if len(rest) == 0:
+                    raise Exception("@shader without a name!")
+                inshader = rest
+                inblock = True
+            elif cmd == "@end":
+                if indefine is not None:
+                    if type(linebuffer) == list:
+                        for i in range(len(linebuffer)):
+                            linebuffer[i] = linebuffer[i].replace("\\", "\\\\")
+                    defines[indefine] = linebuffer
+                elif inshader is not None:
+                    emitShader(desthdr, inshader, linebuffer)
+                else:
+                    raise Exception("@end outside of a block!")
+                indefine = None
+                inshader = None
+                inblock = None
+                linebuffer = []
+            else:
+                raise Exception("Unknown command: %s" % (cmd,))
+        else:
+            if inblock:
+                linebuffer.append(line)
+
+if (len(sys.argv) != 3):
+    print "Usage: %s infile.txt outfile.h" % (sys.argv[0],)
+    sys.exit(1)
+
+genShaders(sys.argv[1], sys.argv[2])
--- a/gfx/thebes/public/GLContext.h
+++ b/gfx/thebes/public/GLContext.h
@@ -44,16 +44,19 @@
 #include <windows.h>
 #endif
 
 #include "GLDefs.h"
 #include "gfxTypes.h"
 #include "nsISupportsImpl.h"
 #include "prlink.h"
 
+#include "nsDataHashtable.h"
+#include "nsHashKeys.h"
+
 #ifndef GLAPIENTRY
 #ifdef XP_WIN
 #define GLAPIENTRY __stdcall
 #else
 #define GLAPIENTRY
 #endif
 #define GLAPI
 #endif
@@ -105,44 +108,60 @@ protected:
 };
 
 
 class GLContext
     : public LibrarySymbolLoader
 {
     THEBES_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext)
 public:
-    GLContext() : mInitialized(PR_FALSE) { }
+    GLContext()
+      : mInitialized(PR_FALSE)
+    {
+        mUserData.Init();
+    }
 
     virtual ~GLContext() { }
 
     virtual PRBool MakeCurrent() = 0;
     virtual PRBool SetupLookupFunction() = 0;
 
+    void *GetUserData(void *aKey) {
+	void *result = nsnull;
+	mUserData.Get(aKey, &result);
+	return result;
+    }
+
+    void SetUserData(void *aKey, void *aValue) {
+	mUserData.Put(aKey, aValue);
+    }
+
     enum NativeDataType {
       NativeGLContext,
       NativeCGLContext,
       NativePBuffer,
       NativeImageSurface,
       NativeDataTypeMax
     };
 
     virtual void *GetNativeData(NativeDataType aType) { return NULL; }
 protected:
 
     PRBool mInitialized;
+    nsDataHashtable<nsVoidPtrHashKey, void*> mUserData;
 
     PRBool InitWithPrefix(const char *prefix, PRBool trygl);
 
     //
     // the wrapped functions
     //
 public:
-    /* One would think that this would live in some nice perl-or-python-or-js script somewhere and would be autogenerated;
-     * one would be wrong.
+    /* One would think that this would live in some nice
+     * perl-or-python-or-js script somewhere and would be
+     * autogenerated; one would be wrong.
      */
     typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREPROC) (GLenum texture);
     PFNGLACTIVETEXTUREPROC fActiveTexture;
     typedef void (GLAPIENTRY * PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
     PFNGLATTACHSHADERPROC fAttachShader;
     typedef void (GLAPIENTRY * PFNGLBINDATTRIBLOCATIONPROC) (GLuint program, GLuint index, const GLchar* name);
     PFNGLBINDATTRIBLOCATIONPROC fBindAttribLocation;
     typedef void (GLAPIENTRY * PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
--- a/gfx/thebes/public/gfx3DMatrix.h
+++ b/gfx/thebes/public/gfx3DMatrix.h
@@ -101,16 +101,21 @@ public:
 
   /**
    * Create a scale matrix. Scales uniformly along all axes.
    *
    * \param aScale Scale factor
    */
   static inline gfx3DMatrix Scale(float aFactor);
 
+  /**
+   * Create a scale matrix.
+   */
+  static inline gfx3DMatrix Scale(float aX, float aY, float aZ);
+
   /** Matrix elements */
   float _11, _12, _13, _14;
   float _21, _22, _23, _24;
   float _31, _32, _33, _34;
   float _41, _42, _43, _44;
 };
 
 inline
@@ -185,9 +190,21 @@ inline gfx3DMatrix
 gfx3DMatrix::Scale(float aFactor)
 {
   gfx3DMatrix matrix;
 
   matrix._11 = matrix._22 = matrix._33 = aFactor;
   return matrix;
 }
 
+inline gfx3DMatrix
+gfx3DMatrix::Scale(float aX, float aY, float aZ)
+{
+  gfx3DMatrix matrix;
+
+  matrix._11 = aX;
+  matrix._22 = aY;
+  matrix._33 = aZ;
+
+  return matrix;
+}
+
 #endif /* GFX_3DMATRIX_H */