Backed out 4 changesets (bug 1012407) for b2g reftest5 orange on an otherwise CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 21 May 2014 18:05:15 -0700
changeset 184310 3d4e5e80de4ad0ebd30617f58eace3d08e4af3c6
parent 184309 94b9062d46291a061201c3064c0e5f942362d1ed
child 184327 4505506929eab5a6fc498aafba49c37d863cd7d9
child 184337 344f0e4b126cb3846bc6945d6ee5b1dbe18970ea
push id26816
push userkwierso@gmail.com
push dateThu, 22 May 2014 03:15:39 +0000
treeherderautoland@3d4e5e80de4a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1012407
milestone32.0a1
backs out08e17f48aed12c1eef3accfaf4b037c8e648ed4f
b17b7b59cf8868e82fb9112dd9cbcdf6e0a73b7f
1c692df3f0803ea533c4970188832b0e75b22946
560bd45d52deeec730708146cec365d3ed7137a6
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 4 changesets (bug 1012407) for b2g reftest5 orange on an otherwise CLOSED TREE Backed out changeset 08e17f48aed1 (bug 1012407) Backed out changeset b17b7b59cf88 (bug 1012407) Backed out changeset 1c692df3f080 (bug 1012407) Backed out changeset 560bd45d52de (bug 1012407)
gfx/gl/DecomposeIntoNoRepeatTriangles.cpp
gfx/gl/DecomposeIntoNoRepeatTriangles.h
gfx/gl/VBOArena.cpp
gfx/gl/VBOArena.h
gfx/gl/moz.build
gfx/layers/composite/FPSCounter.h
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/GLManager.cpp
gfx/layers/opengl/GLManager.h
gfx/layers/opengl/OGLShaderProgram.cpp
gfx/layers/opengl/OGLShaderProgram.h
widget/cocoa/nsChildView.mm
--- a/gfx/gl/DecomposeIntoNoRepeatTriangles.cpp
+++ b/gfx/gl/DecomposeIntoNoRepeatTriangles.cpp
@@ -32,16 +32,35 @@ RectTriangles::addRect(GLfloat x0, GLflo
 {
     if (flip_y) {
         std::swap(ty0, ty1);
     }
     AppendRectToCoordArray(mVertexCoords, x0, y0, x1, y1);
     AppendRectToCoordArray(mTexCoords, tx0, ty0, tx1, ty1);
 }
 
+bool
+RectTriangles::isSimpleQuad(gfx3DMatrix& aOutTextureTransform) const
+{
+    if (mVertexCoords.Length() == 6 &&
+        mVertexCoords[0].x == 0.0f &&
+        mVertexCoords[0].y == 0.0f &&
+        mVertexCoords[5].x == 1.0f &&
+        mVertexCoords[5].y == 1.0f)
+    {
+        GLfloat tx0 = mTexCoords[0].x;
+        GLfloat ty0 = mTexCoords[0].y;
+        GLfloat tx1 = mTexCoords[5].x;
+        GLfloat ty1 = mTexCoords[5].y;
+        aOutTextureTransform = gfx3DMatrix::From2D(gfxMatrix(tx1 - tx0, 0, 0, ty1 - ty0, tx0, ty0));
+        return true;
+    }
+    return false;
+}
+
 static GLfloat
 WrapTexCoord(GLfloat v)
 {
     // fmodf gives negative results for negative numbers;
     // that is, fmodf(0.75, 1.0) == 0.75, but
     // fmodf(-0.75, 1.0) == -0.75.  For the negative case,
     // the result we need is 0.25, so we add 1.0f.
     if (v < 0.0f) {
--- a/gfx/gl/DecomposeIntoNoRepeatTriangles.h
+++ b/gfx/gl/DecomposeIntoNoRepeatTriangles.h
@@ -23,16 +23,23 @@ public:
 
     // Always pass texture coordinates upright. If you want to flip the
     // texture coordinates emitted to the tex_coords array, set flip_y to
     // true.
     void addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
                  GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
                  bool flip_y = false);
 
+    // Returns whether this object is made of only one rect that can be drawn
+    // with a pre-buffered unity quad which has 0,0,1,1 as both vertex
+    // positions and texture coordinates.
+    // aOutTextureTransform returns the transform that maps 0,0,1,1 texture
+    // coordinates to the correct ones.
+    bool isSimpleQuad(gfx3DMatrix& aOutTextureTransform) const;
+
     /**
       * these return a float pointer to the start of each array respectively.
       * Use it for glVertexAttribPointer calls.
       * We can return nullptr if we choose to use Vertex Buffer Objects here.
       */
     InfallibleTArray<coord>& vertCoords() {
         return mVertexCoords;
     }
new file mode 100644
--- /dev/null
+++ b/gfx/gl/VBOArena.cpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "VBOArena.h"
+#include "GLContext.h"
+
+using namespace mozilla::gl;
+
+GLuint VBOArena::Allocate(GLContext *aGLContext)
+{
+    if (!mAvailableVBOs.size()) {
+        GLuint vbo;
+        aGLContext->fGenBuffers(1, &vbo);
+        mAllocatedVBOs.push_back(vbo);
+        return vbo;
+    }
+    GLuint vbo = mAvailableVBOs.back();
+    mAvailableVBOs.pop_back();
+    return vbo;
+}
+
+void VBOArena::Reset()
+{
+    mAvailableVBOs = mAllocatedVBOs;
+}
+
+void VBOArena::Flush(GLContext *aGLContext)
+{
+    if (mAvailableVBOs.size()) {
+#ifdef DEBUG
+        printf_stderr("VBOArena::Flush for %u VBOs\n", mAvailableVBOs.size());
+#endif
+        aGLContext->fDeleteBuffers(mAvailableVBOs.size(), &mAvailableVBOs[0]);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/gl/VBOArena.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef VBOARENA_H_
+#define VBOARENA_H_
+
+#include "GLTypes.h"
+#include <vector>
+
+namespace mozilla {
+namespace gl {
+
+class GLContext;
+
+class VBOArena {
+public:
+    // Allocate a new VBO.
+    GLuint Allocate(GLContext *aGLContext);
+
+    // Re-use previously allocated VBOs.
+    void Reset();
+
+    // Throw away all allocated VBOs.
+    void Flush(GLContext *aGLContext);
+private:
+    std::vector<GLuint> mAllocatedVBOs;
+    std::vector<GLuint> mAvailableVBOs;
+};
+
+}
+}
+
+#endif
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -50,16 +50,17 @@ EXPORTS += [
     'ScopedGLHelpers.h',
     'SharedSurface.h',
     'SharedSurfaceEGL.h',
     'SharedSurfaceGL.h',
     'SurfaceFactory.h',
     'SurfaceStream.h',
     'SurfaceTypes.h',
     'TextureGarbageBin.h',
+    'VBOArena.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS += [
         'GLContextGLX.h',
         'GLXLibrary.h',
     ]
 
@@ -134,16 +135,17 @@ UNIFIED_SOURCES += [
     'SharedSurface.cpp',
     'SharedSurfaceEGL.cpp',
     'SharedSurfaceGL.cpp',
     'SurfaceFactory.cpp',
     'SurfaceStream.cpp',
     'SurfaceTypes.cpp',
     'TextureGarbageBin.cpp',
     'TextureImageEGL.cpp',
+    'VBOArena.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 MSVC_ENABLE_PGO = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/gfx/layers/composite/FPSCounter.h
+++ b/gfx/layers/composite/FPSCounter.h
@@ -8,16 +8,17 @@
 
 #include <algorithm>                    // for min
 #include <stddef.h>                     // for size_t
 #include <map>                          // for std::map
 #include "GLDefs.h"                     // for GLuint
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/TimeStamp.h"          // for TimeStamp, TimeDuration
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray_Impl, etc
+#include "VBOArena.h"                   // for gl::VBOArena
 #include "prio.h"                       // for NSPR file i/o
 
 namespace mozilla {
 namespace gl {
 class GLContext;
 }
 namespace layers {
 
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -35,16 +35,17 @@
 #include "nsAString.h"
 #include "nsIConsoleService.h"          // for nsIConsoleService, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsLiteralString.h"            // for NS_LITERAL_STRING
 #include "nsMathUtils.h"                // for NS_roundf
 #include "nsRect.h"                     // for nsIntRect
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"                   // for nsString, nsAutoCString, etc
+#include "DecomposeIntoNoRepeatTriangles.h"
 #include "ScopedGLHelpers.h"
 #include "GLReadTexImageHelper.h"
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "HeapCopyOfStackArray.h"
 
 #if MOZ_ANDROID_OMTC
 #include "TexturePoolOGL.h"
 #endif
@@ -76,16 +77,75 @@ BindMaskForProgram(ShaderProgramOGL* aPr
                    GLenum aTexUnit, const gfx::Matrix4x4& aTransform)
 {
   MOZ_ASSERT(LOCAL_GL_TEXTURE0 <= aTexUnit && aTexUnit <= LOCAL_GL_TEXTURE31);
   aSourceMask->BindTexture(aTexUnit, gfx::Filter::LINEAR);
   aProgram->SetMaskTextureUnit(aTexUnit - LOCAL_GL_TEXTURE0);
   aProgram->SetMaskLayerTransform(aTransform);
 }
 
+// Draw the given quads with the already selected shader. Texture coordinates
+// are supplied if the shader requires them.
+static void
+DrawQuads(GLContext *aGLContext,
+          VBOArena &aVBOs,
+          ShaderProgramOGL *aProg,
+          GLenum aMode,
+          RectTriangles &aRects)
+{
+  NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
+  GLuint vertAttribIndex =
+    aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
+  GLuint texCoordAttribIndex =
+    aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
+  bool texCoords = (texCoordAttribIndex != GLuint(-1));
+
+  GLsizei bytes = aRects.elements() * 2 * sizeof(GLfloat);
+
+  GLsizei total = bytes;
+  if (texCoords) {
+    total *= 2;
+  }
+
+  aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER,
+                          aVBOs.Allocate(aGLContext));
+  aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
+                          total,
+                          nullptr,
+                          LOCAL_GL_STREAM_DRAW);
+
+  aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
+                             0,
+                             bytes,
+                             aRects.vertCoords().Elements());
+  aGLContext->fEnableVertexAttribArray(vertAttribIndex);
+  aGLContext->fVertexAttribPointer(vertAttribIndex,
+                                   2, LOCAL_GL_FLOAT,
+                                   LOCAL_GL_FALSE,
+                                   0, BUFFER_OFFSET(0));
+
+  if (texCoords) {
+    aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER,
+                               bytes,
+                               bytes,
+                               aRects.texCoords().Elements());
+    aGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
+    aGLContext->fVertexAttribPointer(texCoordAttribIndex,
+                                     2, LOCAL_GL_FLOAT,
+                                     LOCAL_GL_FALSE,
+                                     0, BUFFER_OFFSET(bytes));
+  } else {
+    aGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
+  }
+
+  aGLContext->fDrawArrays(aMode, 0, aRects.elements());
+
+  aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+}
+
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
@@ -122,16 +182,20 @@ CompositorOGL::CreateContext()
   }
 
   return context.forget();
 }
 
 void
 CompositorOGL::Destroy()
 {
+  if (gl() && gl()->MakeCurrent()) {
+    mVBOs.Flush(gl());
+  }
+
   if (mTexturePool) {
     mTexturePool->Clear();
     mTexturePool = nullptr;
   }
 
   if (!mDestroyed) {
     mDestroyed = true;
     CleanupResources();
@@ -298,34 +362,21 @@ CompositorOGL::Initialize()
       return false;
   }
 
   /* Create a simple quad VBO */
 
   mGLContext->fGenBuffers(1, &mQuadVBO);
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
 
-  // 4 quads, with the number of the quad (vertexID) encoded in w.
   GLfloat vertices[] = {
-    0.0f, 0.0f, 0.0f, 0.0f,
-    1.0f, 0.0f, 0.0f, 0.0f,
-    0.0f, 1.0f, 0.0f, 0.0f,
-    1.0f, 1.0f, 0.0f, 0.0f,
-    0.0f, 0.0f, 0.0f, 1.0f,
-    1.0f, 0.0f, 0.0f, 1.0f,
-    0.0f, 1.0f, 0.0f, 1.0f,
-    1.0f, 1.0f, 0.0f, 1.0f,
-    0.0f, 0.0f, 0.0f, 2.0f,
-    1.0f, 0.0f, 0.0f, 2.0f,
-    0.0f, 1.0f, 0.0f, 2.0f,
-    1.0f, 1.0f, 0.0f, 2.0f,
-    0.0f, 0.0f, 0.0f, 3.0f,
-    1.0f, 0.0f, 0.0f, 3.0f,
-    0.0f, 1.0f, 0.0f, 3.0f,
-    1.0f, 1.0f, 0.0f, 3.0f,
+    /* 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,
   };
   HeapCopyOfStackArray<GLfloat> verticesOnHeap(vertices);
   mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER,
                           verticesOnHeap.ByteLength(),
                           verticesOnHeap.Data(),
                           LOCAL_GL_STATIC_DRAW);
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 
@@ -351,186 +402,99 @@ CompositorOGL::Initialize()
       msg += NS_LITERAL_STRING("TEXTURE_RECTANGLE");
     console->LogStringMessage(msg.get());
   }
 
   reporter.SetSuccessful();
   return true;
 }
 
-static GLfloat
-WrapTexCoord(GLfloat v)
+// |aTextureTransform| is the texture transform that will be set on
+// aProg, possibly multiplied with another texture transform of our
+// own.
+// |aTexCoordRect| is the rectangle from the texture that we want to
+// draw using the given program.  The program already has a necessary
+// offset and scale, so the geometry that needs to be drawn is a unit
+// square from 0,0 to 1,1.
+//
+// |aTexture| is the texture we are drawing. Its actual size can be
+// larger than the rectangle given by |aTexCoordRect|.
+void
+CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
+                                              const Rect& aRect,
+                                              const gfx3DMatrix& aTextureTransform,
+                                              const Rect& aTexCoordRect,
+                                              TextureSource *aTexture)
 {
-    // fmodf gives negative results for negative numbers;
-    // that is, fmodf(0.75, 1.0) == 0.75, but
-    // fmodf(-0.75, 1.0) == -0.75.  For the negative case,
-    // the result we need is 0.25, so we add 1.0f.
-    if (v < 0.0f) {
-        return 1.0f + fmodf(v, 1.0f);
-    }
-
-    return fmodf(v, 1.0f);
-}
+  // Given what we know about these textures and coordinates, we can
+  // compute fmod(t, 1.0f) to get the same texture coordinate out.  If
+  // the texCoordRect dimension is < 0 or > width/height, then we have
+  // wraparound that we need to deal with by drawing multiple quads,
+  // because we can't rely on full non-power-of-two texture support
+  // (which is required for the REPEAT wrap mode).
 
-static void
-SetRects(int n,
-         Rect* aLayerRects,
-         Rect* aTextureRects,
-         GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
-         GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
-         bool flip_y /* = false */)
-{
-  if (flip_y) {
-    std::swap(ty0, ty1);
+  RectTriangles rects;
+
+  GLenum wrapMode = aTexture->AsSourceOGL()->GetWrapMode();
+
+  IntSize realTexSize = aTexture->GetSize();
+  if (!CanUploadNonPowerOfTwo(mGLContext)) {
+    realTexSize = IntSize(NextPowerOfTwo(realTexSize.width),
+                          NextPowerOfTwo(realTexSize.height));
   }
-  aLayerRects[n] = Rect(x0, y0, x1 - x0, y1 - y0);
-  aTextureRects[n] = Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
-}
 
-static int
-DecomposeIntoNoRepeatRects(const Rect& aRect,
-                           const Rect& aTexCoordRect,
-                           Rect* aLayerRects,
-                           Rect* aTextureRects)
-{
-  Rect texCoordRect = aTexCoordRect;
+  // We need to convert back to actual texels here to get proper behaviour with
+  // our GL helper functions. Should fix this sometime.
+  // I want to vomit.
+  IntRect texCoordRect = IntRect(NS_roundf(aTexCoordRect.x * aTexture->GetSize().width),
+                                 NS_roundf(aTexCoordRect.y * aTexture->GetSize().height),
+                                 NS_roundf(aTexCoordRect.width * aTexture->GetSize().width),
+                                 NS_roundf(aTexCoordRect.height * aTexture->GetSize().height));
 
-  // If the texture should be flipped, it will have negative height. Detect that
-  // here and compensate for it. We will flip each rect as we emit it.
+  // This is fairly disgusting - if the texture should be flipped it will have a
+  // negative height, in which case we un-invert the texture coords and pass the
+  // flipped 'flag' to the functions below. We can't just use the inverted coords
+  // because our GL funtions use an explicit flag.
   bool flipped = false;
   if (texCoordRect.height < 0) {
     flipped = true;
     texCoordRect.y = texCoordRect.YMost();
     texCoordRect.height = -texCoordRect.height;
   }
 
-  Point tl = texCoordRect.TopLeft();
-  Point br = texCoordRect.BottomRight();
-
-  // Chen check if we wrap in either the x or y axis; if we do,
-  // then also use fmod to figure out the "true" non-wrapping
-  // texture coordinates.
-  bool xwrap = false, ywrap = false;
-
-  if (texCoordRect.x < 0 ||
-      texCoordRect.x > 1.0f ||
-      texCoordRect.XMost() < 0 ||
-      texCoordRect.XMost() > 1.0f) {
-    xwrap = true;
-    tl = Point(WrapTexCoord(tl.x), tl.y);
-    br = Point(WrapTexCoord(br.x), br.y);
-  }
-
-  if (texCoordRect.y < 0 ||
-      texCoordRect.y > 1.0f ||
-      texCoordRect.YMost() < 0 ||
-      texCoordRect.YMost() > 1.0f) {
-    ywrap = true;
-    tl = Point(tl.x, WrapTexCoord(tl.y));
-    br = Point(br.x, WrapTexCoord(br.y));
-  }
-
-  NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f &&
-               tl.y >= 0.0f && tl.y <= 1.0f &&
-               br.x >= 0.0f && br.x <= 1.0f &&
-               br.y >= 0.0f && br.y <= 1.0f,
-               "Somehow generated invalid texture coordinates");
-
-  // If xwrap is false, the texture will be sampled from tl.x
-  // .. br.x.  If xwrap is true, then it will be split into tl.x
-  // .. 1.0, and 0.0 .. br.x.  Same for the Y axis.  The
-  // destination rectangle is also split appropriately, according
-  // to the calculated xmid/ymid values.
-
-  // There isn't a 1:1 mapping between tex coords and destination coords;
-  // when computing midpoints, we have to take that into account.  We
-  // need to map the texture coords, which are (in the wrap case):
-  // |tl->1| and |0->br| to the |0->1| range of the vertex coords.  So
-  // we have the length (1-tl)+(br) that needs to map into 0->1.
-  // These are only valid if there is wrap involved, they won't be used
-  // otherwise.
-  GLfloat xlen = (1.0f - tl.x) + br.x;
-  GLfloat ylen = (1.0f - tl.y) + br.y;
-
-  NS_ASSERTION(!xwrap || xlen > 0.0f, "xlen isn't > 0, what's going on?");
-  NS_ASSERTION(!ywrap || ylen > 0.0f, "ylen isn't > 0, what's going on?");
-
-  if (!xwrap && !ywrap) {
-    SetRects(0, aLayerRects, aTextureRects,
-             aRect.x, aRect.y, aRect.XMost(), aRect.YMost(),
-             tl.x, tl.y, br.x, br.y,
-             flipped);
-    return 1;
+  if (wrapMode == LOCAL_GL_REPEAT) {
+    rects.addRect(/* dest rectangle */
+                  0.0f, 0.0f, 1.0f, 1.0f,
+                  /* tex coords */
+                  texCoordRect.x / GLfloat(realTexSize.width),
+                  texCoordRect.y / GLfloat(realTexSize.height),
+                  texCoordRect.XMost() / GLfloat(realTexSize.width),
+                  texCoordRect.YMost() / GLfloat(realTexSize.height),
+                  flipped);
+  } else {
+    nsIntRect tcRect(texCoordRect.x, texCoordRect.y,
+                     texCoordRect.width, texCoordRect.height);
+    DecomposeIntoNoRepeatTriangles(tcRect,
+                                   nsIntSize(realTexSize.width, realTexSize.height),
+                                   rects, flipped);
   }
 
-  GLfloat xmid = aRect.x + (1.0f - tl.x) / xlen * aRect.width;
-  GLfloat ymid = aRect.y + (1.0f - tl.y) / ylen * aRect.height;
-
-  if (!xwrap && ywrap) {
-    SetRects(0, aLayerRects, aTextureRects,
-             aRect.x, aRect.y, aRect.XMost(), ymid,
-             tl.x, tl.y, br.x, 1.0f,
-             flipped);
-    SetRects(1, aLayerRects, aTextureRects,
-             aRect.x, ymid, aRect.XMost(), aRect.YMost(),
-             tl.x, 0.0f, br.x, br.y,
-             flipped);
-    return 2;
-  }
-
-  if (xwrap && !ywrap) {
-    SetRects(0, aLayerRects, aTextureRects,
-             aRect.x, aRect.y, xmid, aRect.YMost(),
-             tl.x, tl.y, 1.0f, br.y,
-             flipped);
-    SetRects(1, aLayerRects, aTextureRects,
-             xmid, aRect.y, aRect.XMost(), aRect.YMost(),
-             0.0f, tl.y, br.x, br.y,
-             flipped);
-    return 2;
+  gfx3DMatrix textureTransform;
+  if (rects.isSimpleQuad(textureTransform)) {
+    Matrix4x4 transform;
+    ToMatrix4x4(aTextureTransform * textureTransform, transform);
+    aProg->SetTextureTransform(transform);
+    BindAndDrawQuad(aProg, aRect);
+  } else {
+    Matrix4x4 transform;
+    ToMatrix4x4(aTextureTransform, transform);
+    aProg->SetTextureTransform(transform);
+    aProg->SetLayerQuadRect(aRect);
+    DrawQuads(mGLContext, mVBOs, aProg, LOCAL_GL_TRIANGLES, rects);
   }
-
-  SetRects(0, aLayerRects, aTextureRects,
-           aRect.x, aRect.y, xmid, ymid,
-           tl.x, tl.y, 1.0f, 1.0f,
-           flipped);
-  SetRects(1, aLayerRects, aTextureRects,
-           xmid, aRect.y, aRect.XMost(), ymid,
-           0.0f, tl.y, br.x, 1.0f,
-           flipped);
-  SetRects(2, aLayerRects, aTextureRects,
-           aRect.x, ymid, xmid, aRect.YMost(),
-           tl.x, 0.0f, 1.0f, br.y,
-           flipped);
-  SetRects(3, aLayerRects, aTextureRects,
-           xmid, ymid, aRect.XMost(), aRect.YMost(),
-           0.0f, 0.0f, br.x, br.y,
-           flipped);
-  return 4;
-}
-
-// |aRect| is the rectangle we want to draw to. We will draw it with
-// up to 4 draw commands if necessary to avoid wrapping.
-// |aTexCoordRect| is the rectangle from the texture that we want to
-// draw using the given program.
-// |aTexture| is the texture we are drawing. Its actual size can be
-// larger than the rectangle given by |texCoordRect|.
-void
-CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
-                                              const Rect& aRect,
-                                              const Rect& aTexCoordRect,
-                                              TextureSource *aTexture)
-{
-  Rect layerRects[4];
-  Rect textureRects[4];
-  int rects = DecomposeIntoNoRepeatRects(aRect,
-                                         aTexCoordRect,
-                                         layerRects,
-                                         textureRects);
-  BindAndDrawQuads(aProg, rects, layerRects, textureRects);
 }
 
 void
 CompositorOGL::PrepareViewport(const gfx::IntSize& aSize,
                                const Matrix& aWorldTransform)
 {
   // Set the viewport correctly.
   mGLContext->fViewport(0, 0, aSize.width, aSize.height);
@@ -665,16 +629,18 @@ CompositorOGL::BeginFrame(const nsIntReg
                           Rect *aClipRectOut,
                           Rect *aRenderBoundsOut)
 {
   PROFILER_LABEL("CompositorOGL", "BeginFrame");
   MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
 
   LayerScope::BeginFrame(mGLContext, PR_Now());
 
+  mVBOs.Reset();
+
   mFrameInProgress = true;
   gfx::Rect rect;
   if (mUseExternalSurfaceSize) {
     rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
   } else {
     rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
     // If render bounds is not updated explicitly, try to infer it from widget
     if (rect.width == 0 || rect.height == 0) {
@@ -1084,25 +1050,23 @@ CompositorOGL::DrawQuad(const Rect& aRec
         // pixel-aligned compositing operations. This works around them. This
         // code should not be needed!
         filter = gfx::Filter::POINT;
       }
 #endif
       source->AsSourceOGL()->BindTexture(LOCAL_GL_TEXTURE0, filter);
 
       program->SetTextureUnit(0);
-      Matrix4x4 transform;
-      ToMatrix4x4(textureTransform, transform);
-      program->SetTextureTransform(transform);
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE1, maskQuadTransform);
       }
 
-      BindAndDrawQuadWithTextureRect(program, aRect, texturedEffect->mTextureCoords, source);
+      BindAndDrawQuadWithTextureRect(program, aRect, textureTransform,
+                                     texturedEffect->mTextureCoords, source);
     }
     break;
   case EffectTypes::YCBCR: {
       EffectYCbCr* effectYCbCr =
         static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
       TextureSource* sourceYCbCr = effectYCbCr->mTexture;
       const int Y = 0, Cb = 1, Cr = 2;
       TextureSourceOGL* sourceY =  sourceYCbCr->GetSubSource(Y)->AsSourceOGL();
@@ -1114,24 +1078,24 @@ CompositorOGL::DrawQuad(const Rect& aRec
         return;
       }
 
       sourceY->BindTexture(LOCAL_GL_TEXTURE0, effectYCbCr->mFilter);
       sourceCb->BindTexture(LOCAL_GL_TEXTURE1, effectYCbCr->mFilter);
       sourceCr->BindTexture(LOCAL_GL_TEXTURE2, effectYCbCr->mFilter);
 
       program->SetYCbCrTextureUnits(Y, Cb, Cr);
-      program->SetTextureTransform(Matrix4x4());
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE3, maskQuadTransform);
       }
       didSetBlendMode = SetBlendMode(gl(), blendMode);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
+                                     gfx3DMatrix(),
                                      effectYCbCr->mTextureCoords,
                                      sourceYCbCr->GetSubSource(Y));
     }
     break;
   case EffectTypes::RENDER_TARGET: {
       EffectRenderTarget* effectRenderTarget =
         static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
       RefPtr<CompositingRenderTargetOGL> surface
@@ -1179,36 +1143,38 @@ CompositorOGL::DrawQuad(const Rect& aRec
         return;
       }
 
       sourceOnBlack->BindTexture(LOCAL_GL_TEXTURE0, effectComponentAlpha->mFilter);
       sourceOnWhite->BindTexture(LOCAL_GL_TEXTURE1, effectComponentAlpha->mFilter);
 
       program->SetBlackTextureUnit(0);
       program->SetWhiteTextureUnit(1);
-      program->SetTextureTransform(Matrix4x4());
+      program->SetTextureTransform(gfx::Matrix4x4());
 
       if (maskType != MaskType::MaskNone) {
         BindMaskForProgram(program, sourceMask, LOCAL_GL_TEXTURE2, maskQuadTransform);
       }
       // Pass 1.
       gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
                                LOCAL_GL_ONE, LOCAL_GL_ONE);
       program->SetTexturePass2(false);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
+                                     gfx3DMatrix(),
                                      effectComponentAlpha->mTextureCoords,
                                      effectComponentAlpha->mOnBlack);
 
       // Pass 2.
       gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
                                LOCAL_GL_ONE, LOCAL_GL_ONE);
       program->SetTexturePass2(true);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
+                                     gfx3DMatrix(),
                                      effectComponentAlpha->mTextureCoords,
                                      effectComponentAlpha->mOnBlack);
 
       mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                      LOCAL_GL_ONE, LOCAL_GL_ONE);
     }
     break;
   default:
@@ -1482,53 +1448,48 @@ CompositorOGL::MakeCurrent(MakeCurrentFl
 
 void
 CompositorOGL::BindQuadVBO() {
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
 }
 
 void
 CompositorOGL::QuadVBOVerticesAttrib(GLuint aAttribIndex) {
-  mGLContext->fVertexAttribPointer(aAttribIndex, 4,
-                                   LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
-                                   (GLvoid*) 0);
+  mGLContext->fVertexAttribPointer(aAttribIndex, 2,
+                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+                                    (GLvoid*) QuadVBOVertexOffset());
 }
 
 void
 CompositorOGL::QuadVBOTexCoordsAttrib(GLuint aAttribIndex) {
-  mGLContext->fVertexAttribPointer(aAttribIndex, 4,
-                                   LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
-                                   (GLvoid*) 0);
+  mGLContext->fVertexAttribPointer(aAttribIndex, 2,
+                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
+                                    (GLvoid*) QuadVBOTexCoordOffset());
 }
 
 void
-CompositorOGL::BindAndDrawQuads(ShaderProgramOGL *aProg,
-                                int aQuads,
-                                const Rect* aLayerRects,
-                                const Rect* aTextureRects)
+CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg, const Rect& aRect)
 {
   NS_ASSERTION(aProg->HasInitialized(), "Shader program not correctly initialized");
 
-  aProg->SetLayerRects(aLayerRects);
+  aProg->SetLayerQuadRect(aRect);
 
   GLuint vertAttribIndex = aProg->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
   GLuint texCoordAttribIndex = aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
 
   BindQuadVBO();
   QuadVBOVerticesAttrib(vertAttribIndex);
 
   if (texCoordAttribIndex != GLuint(-1)) {
     QuadVBOTexCoordsAttrib(texCoordAttribIndex);
     mGLContext->fEnableVertexAttribArray(texCoordAttribIndex);
-
-    aProg->SetTextureRects(aTextureRects);
   }
 
   mGLContext->fEnableVertexAttribArray(vertAttribIndex);
-  mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4 * aQuads);
+  mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
 }
 
 GLuint
 CompositorOGL::GetTemporaryTexture(GLenum aTarget, GLenum aUnit)
 {
   if (!mTexturePool) {
 #ifdef MOZ_WIDGET_GONK
     mTexturePool = new PerFrameTexturePoolOGL(gl());
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -26,16 +26,17 @@
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType
 #include "nscore.h"                     // for NS_IMETHOD
+#include "VBOArena.h"                   // for gl::VBOArena
 #ifdef MOZ_WIDGET_GONK
 #include <ui/GraphicBuffer.h>
 #endif
 
 class gfx3DMatrix;
 class nsIWidget;
 
 namespace mozilla {
@@ -306,16 +307,21 @@ private:
 #endif
 
   /**
    * VBO that has some basics in it for a textured quad, including vertex
    * coords and texcoords.
    */
   GLuint mQuadVBO;
 
+  /**
+   * When we can't use mQuadVBO, we allocate VBOs from this arena instead.
+   */
+  gl::VBOArena mVBOs;
+
   bool mHasBGRA;
 
   /**
    * When rendering to some EGL surfaces (e.g. on Android), we rely on being told
    * about size changes (via SetSurfaceSize) rather than pulling this information
    * from the widget.
    */
   bool mUseExternalSurfaceSize;
@@ -351,34 +357,27 @@ private:
    * of the type returned by FBOTextureTarget; different
    * shaders are required to sample from the different
    * texture types.
    */
   void CreateFBOWithTexture(const gfx::IntRect& aRect, bool aCopyFromSource,
                             GLuint aSourceFrameBuffer,
                             GLuint *aFBO, GLuint *aTexture);
 
+  GLintptr QuadVBOVertexOffset() { return 0; }
+  GLintptr QuadVBOTexCoordOffset() { return sizeof(float)*4*2; }
+
   void BindQuadVBO();
   void QuadVBOVerticesAttrib(GLuint aAttribIndex);
   void QuadVBOTexCoordsAttrib(GLuint aAttribIndex);
-  void BindAndDrawQuads(ShaderProgramOGL *aProg,
-                        int aQuads,
-                        const gfx::Rect* aLayerRect,
-                        const gfx::Rect* aTextureRect);
   void BindAndDrawQuad(ShaderProgramOGL *aProg,
-                       const gfx::Rect& aLayerRect,
-                       const gfx::Rect& aTextureRect = gfx::Rect(0.0f, 0.0f, 1.0f, 1.0f)) {
-    gfx::Rect layerRects[4];
-    gfx::Rect textureRects[4];
-    layerRects[0] = aLayerRect;
-    textureRects[0] = aTextureRect;
-    BindAndDrawQuads(aProg, 1, layerRects, textureRects);
-  }
+                       const gfx::Rect& aRect);
   void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                       const gfx::Rect& aRect,
+                                      const gfx3DMatrix& aTextureTransform,
                                       const gfx::Rect& aTexCoordRect,
                                       TextureSource *aTexture);
 
   void CleanupResources();
 
   /**
    * Copies the content of our backbuffer to the set transaction target.
    * Does not restore the target FBO, so only call from EndFrame.
--- a/gfx/layers/opengl/GLManager.cpp
+++ b/gfx/layers/opengl/GLManager.cpp
@@ -38,21 +38,19 @@ public:
     return mImpl->GetShaderProgramFor(config);
   }
 
   virtual const gfx::Matrix4x4& GetProjMatrix() const MOZ_OVERRIDE
   {
     return mImpl->GetProjMatrix();
   }
 
-  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg,
-                               const gfx::Rect& aLayerRect,
-                               const gfx::Rect& aTextureRect) MOZ_OVERRIDE
+  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aRect) MOZ_OVERRIDE
   {
-    mImpl->BindAndDrawQuad(aProg, aLayerRect, aTextureRect);
+    mImpl->BindAndDrawQuad(aProg, aRect);
   }
 
 private:
   RefPtr<CompositorOGL> mImpl;
 };
 
 /* static */ GLManager*
 GLManager::CreateGLManager(LayerManagerComposite* aManager)
--- a/gfx/layers/opengl/GLManager.h
+++ b/gfx/layers/opengl/GLManager.h
@@ -28,15 +28,14 @@ class GLManager
 public:
   static GLManager* CreateGLManager(LayerManagerComposite* aManager);
 
   virtual ~GLManager() {}
 
   virtual gl::GLContext* gl() const = 0;
   virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) = 0;
   virtual const gfx::Matrix4x4& GetProjMatrix() const = 0;
-  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aLayerRect,
-                               const gfx::Rect& aTextureRect) = 0;
+  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aRect) = 0;
 };
 
 }
 }
 #endif
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -26,21 +26,20 @@ typedef ProgramProfileOGL::Argument Argu
 #define GAUSSIAN_KERNEL_HALF_WIDTH 11
 #define GAUSSIAN_KERNEL_STEP 0.2
 
 void
 AddUniforms(ProgramProfileOGL& aProfile)
 {
     static const char *sKnownUniformNames[] = {
         "uLayerTransform",
-        "uMaskTransform",
-        "uLayerRects",
+        "uMaskQuadTransform",
+        "uLayerQuadRect",
         "uMatrixProj",
         "uTextureTransform",
-        "uTextureRects",
         "uRenderTargetOffset",
         "uLayerOpacity",
         "uTexture",
         "uYTexture",
         "uCbTexture",
         "uCrTexture",
         "uBlackTexture",
         "uWhiteTexture",
@@ -141,59 +140,54 @@ ShaderConfigOGL::SetPremultiply(bool aEn
 ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
 {
   ProgramProfileOGL result;
   ostringstream fs, vs;
 
   AddUniforms(result);
 
   vs << "uniform mat4 uMatrixProj;" << endl;
-  vs << "uniform vec4 uLayerRects[4];" << endl;
+  vs << "uniform vec4 uLayerQuadRect;" << endl;
   vs << "uniform mat4 uLayerTransform;" << endl;
   vs << "uniform vec4 uRenderTargetOffset;" << endl;
 
   vs << "attribute vec4 aVertexCoord;" << endl;
 
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
     vs << "uniform mat4 uTextureTransform;" << endl;
-    vs << "uniform vec4 uTextureRects[4];" << endl;
-    vs << "attribute vec4 aTexCoord;" << endl;
+    vs << "attribute vec2 aTexCoord;" << endl;
     vs << "varying vec2 vTexCoord;" << endl;
   }
 
   if (aConfig.mFeatures & ENABLE_MASK_2D ||
       aConfig.mFeatures & ENABLE_MASK_3D) {
-    vs << "uniform mat4 uMaskTransform;" << endl;
+    vs << "uniform mat4 uMaskQuadTransform;" << endl;
     vs << "varying vec3 vMaskCoord;" << endl;
   }
 
   vs << "void main() {" << endl;
-  vs << "  int vertexID = int(aVertexCoord.w);" << endl;
-  vs << "  vec4 layerRect = uLayerRects[vertexID];" << endl;
-  vs << "  vec4 finalPosition = vec4(aVertexCoord.xy * layerRect.zw + layerRect.xy, 0.0, 1.0);" << endl;
+  vs << "  vec4 finalPosition = vec4(aVertexCoord.xy * uLayerQuadRect.zw + uLayerQuadRect.xy, 0.0, 1.0);" << endl;
   vs << "  finalPosition = uLayerTransform * finalPosition;" << endl;
   vs << "  finalPosition.xyz /= finalPosition.w;" << endl;
 
   if (aConfig.mFeatures & ENABLE_MASK_3D) {
-    vs << "  vMaskCoord.xy = (uMaskTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl;
+    vs << "  vMaskCoord.xy = (uMaskQuadTransform * vec4(finalPosition.xyz, 1.0)).xy;" << endl;
     // correct for perspective correct interpolation, see comment in D3D10 shader
     vs << "  vMaskCoord.z = 1.0;" << endl;
     vs << "  vMaskCoord *= finalPosition.w;" << endl;
   } else if (aConfig.mFeatures & ENABLE_MASK_2D) {
-    vs << "  vMaskCoord.xy = (uMaskTransform * finalPosition).xy;" << endl;
+    vs << "  vMaskCoord.xy = (uMaskQuadTransform * finalPosition).xy;" << endl;
   }
 
   vs << "  finalPosition = finalPosition - uRenderTargetOffset;" << endl;
   vs << "  finalPosition.xyz *= finalPosition.w;" << endl;
   vs << "  finalPosition = uMatrixProj * finalPosition;" << endl;
 
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
-    vs << "  vec4 textureRect = uTextureRects[vertexID];" << endl;
-    vs << "  vec2 texCoord = aTexCoord.xy * textureRect.zw + textureRect.xy;" << endl;
-    vs << "  vTexCoord = (uTextureTransform * vec4(texCoord, 0.0, 1.0)).xy;" << endl;
+    vs << "  vTexCoord = (uTextureTransform * vec4(aTexCoord.x, aTexCoord.y, 0.0, 1.0)).xy;" << endl;
   }
 
   vs << "  gl_Position = finalPosition;" << endl;
   vs << "}" << endl;
 
   if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
     fs << "#extension GL_ARB_texture_rectangle : require" << endl;
   }
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -46,21 +46,20 @@ enum ShaderFeatures {
 };
 
 class KnownUniform {
 public:
   enum KnownUniformName {
     NotAKnownUniform = -1,
 
     LayerTransform = 0,
-    MaskTransform,
-    LayerRects,
+    MaskQuadTransform,
+    LayerQuadRect,
     MatrixProj,
     TextureTransform,
-    TextureRects,
     RenderTargetOffset,
     LayerOpacity,
     Texture,
     YTexture,
     CbTexture,
     CrTexture,
     BlackTexture,
     WhiteTexture,
@@ -314,44 +313,33 @@ public:
    * Not all uniforms may be set for all programs, and such uses will throw
    * an assertion.
    */
   void SetLayerTransform(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::LayerTransform, aMatrix);
   }
 
   void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) {
-    SetMatrixUniform(KnownUniform::MaskTransform, aMatrix);
+    SetMatrixUniform(KnownUniform::MaskQuadTransform, aMatrix);
   }
 
-  void SetLayerRects(const gfx::Rect* aRects) {
-    float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
-                       aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
-                       aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
-                       aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
-    SetUniform(KnownUniform::LayerRects, 16, vals);
+  void SetLayerQuadRect(const gfx::Rect& aRect) {
+    float vals[4] = { float(aRect.x), float(aRect.y), float(aRect.width), float(aRect.height) };
+    SetUniform(KnownUniform::LayerQuadRect, 4, vals);
   }
 
   void SetProjectionMatrix(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::MatrixProj, aMatrix);
   }
 
   // sets this program's texture transform, if it uses one
   void SetTextureTransform(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::TextureTransform, aMatrix);
   }
 
-  void SetTextureRects(const gfx::Rect* aRects) {
-    float vals[16] = { aRects[0].x, aRects[0].y, aRects[0].width, aRects[0].height,
-                       aRects[1].x, aRects[1].y, aRects[1].width, aRects[1].height,
-                       aRects[2].x, aRects[2].y, aRects[2].width, aRects[2].height,
-                       aRects[3].x, aRects[3].y, aRects[3].width, aRects[3].height };
-    SetUniform(KnownUniform::TextureRects, 16, vals);
-  }
-
   void SetRenderOffset(const nsIntPoint& aOffset) {
     float vals[4] = { float(aOffset.x), float(aOffset.y), 0.0f, 0.0f };
     SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
   }
 
   void SetRenderOffset(float aX, float aY) {
     float vals[4] = { aX, aY, 0.0f, 0.0f };
     SetUniform(KnownUniform::RenderTargetOffset, 4, vals);
@@ -472,17 +460,16 @@ protected:
 
     KnownUniform& ku(mProfile.mUniforms[aKnownUniform]);
     if (ku.UpdateUniform(aLength, aFloatValues)) {
       switch (aLength) {
       case 1: mGL->fUniform1fv(ku.mLocation, 1, ku.mValue.f16v); break;
       case 2: mGL->fUniform2fv(ku.mLocation, 1, ku.mValue.f16v); break;
       case 3: mGL->fUniform3fv(ku.mLocation, 1, ku.mValue.f16v); break;
       case 4: mGL->fUniform4fv(ku.mLocation, 1, ku.mValue.f16v); break;
-      case 16: mGL->fUniform4fv(ku.mLocation, 4, ku.mValue.f16v); break;
       default:
         NS_NOTREACHED("Bogus aLength param");
       }
     }
   }
 
   void SetUniform(KnownUniform::KnownUniformName aKnownUniform, GLint aIntValue) {
     ASSERT_THIS_PROGRAM;
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -340,19 +340,17 @@ public:
     MOZ_ASSERT(aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB);
     MOZ_ASSERT(aFormat == gfx::SurfaceFormat::R8G8B8A8);
     return mRGBARectProgram;
   }
   virtual const gfx::Matrix4x4& GetProjMatrix() const MOZ_OVERRIDE
   {
     return mProjMatrix;
   }
-  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg,
-                               const gfx::Rect& aLayerRect,
-                               const gfx::Rect& aTextureRect) MOZ_OVERRIDE;
+  virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aRect) MOZ_OVERRIDE;
 
   void BeginFrame(nsIntSize aRenderSize);
   void EndFrame();
 
   NSOpenGLContext* GetNSOpenGLContext()
   {
     return GLContextCGL::Cast(mGLContext)->GetNSOpenGLContext();
   }
@@ -2757,19 +2755,17 @@ RectTextureImage::Draw(GLManager* aManag
   gfx::Matrix4x4 transform;
   gfx::ToMatrix4x4(aTransform, transform);
   program->SetLayerTransform(transform * gfx::Matrix4x4().Translate(aLocation.x, aLocation.y, 0));
   program->SetTextureTransform(gfx::Matrix4x4());
   program->SetRenderOffset(nsIntPoint(0, 0));
   program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height);
   program->SetTextureUnit(0);
 
-  aManager->BindAndDrawQuad(program,
-                            gfx::Rect(0.0, 0.0, mUsedSize.width, mUsedSize.height),
-                            gfx::Rect(0.0, 0.0, 1.0f, 1.0f));
+  aManager->BindAndDrawQuad(program, gfx::Rect(0, 0, mUsedSize.width, mUsedSize.height));
 
   aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0);
 }
 
 // GLPresenter implementation
 
 GLPresenter::GLPresenter(GLContext* aContext)
  : mGLContext(aContext)
@@ -2799,30 +2795,21 @@ GLPresenter::~GLPresenter()
   if (mQuadVBO) {
     mGLContext->MakeCurrent();
     mGLContext->fDeleteBuffers(1, &mQuadVBO);
     mQuadVBO = 0;
   }
 }
 
 void
-GLPresenter::BindAndDrawQuad(ShaderProgramOGL *aProgram,
-                             const gfx::Rect& aLayerRect,
-                             const gfx::Rect& aTextureRect)
+GLPresenter::BindAndDrawQuad(ShaderProgramOGL *aProgram, const gfx::Rect& aRect)
 {
   mGLContext->MakeCurrent();
 
-  gfx::Rect layerRects[4];
-  gfx::Rect textureRects[4];
-
-  layerRects[0] = aLayerRect;
-  textureRects[0] = aTextureRect;
-
-  aProgram->SetLayerRects(layerRects);
-  aProgram->SetTextureRects(textureRects);
+  aProgram->SetLayerQuadRect(aRect);
 
   GLuint vertAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::VertexCoordAttrib);
   GLuint texCoordAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::TexCoordAttrib);
 
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
   mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
                                    (GLvoid*)0);