Bug 728625 - Add support for vertically flipping textured quads generated with RectTriangles and DecomposeIntoNoRepeatTriangles. r=bjacob,gw280
authorJoe Drew <joe@drew.ca>
Wed, 29 Feb 2012 14:15:12 -0800
changeset 89306 92afa414d2621670e6ab1a55d3af5ae7a6582283
parent 89305 aa51129a3495ee690917aa66f967fdef23d9402e
child 89307 d1837ca496be192d091574c83ba41d09b537b5d6
push id7119
push usereakhgari@mozilla.com
push dateWed, 14 Mar 2012 17:40:57 +0000
treeherdermozilla-inbound@10d7baa4aff0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob, gw280
bugs728625
milestone13.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 728625 - Add support for vertically flipping textured quads generated with RectTriangles and DecomposeIntoNoRepeatTriangles. r=bjacob,gw280
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/layers/opengl/LayerManagerOGL.h
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -2450,47 +2450,65 @@ GLContext::TexSubImage2DWithoutUnpackSub
                     type,
                     newPixels);
     delete [] newPixels;
     fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
 }
 
 void
 GLContext::RectTriangles::addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
-                                  GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1)
+                                  GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
+                                  bool flip_y /* = false */)
 {
     vert_coord v;
     v.x = x0; v.y = y0;
     vertexCoords.AppendElement(v);
     v.x = x1; v.y = y0;
     vertexCoords.AppendElement(v);
     v.x = x0; v.y = y1;
     vertexCoords.AppendElement(v);
 
     v.x = x0; v.y = y1;
     vertexCoords.AppendElement(v);
     v.x = x1; v.y = y0;
     vertexCoords.AppendElement(v);
     v.x = x1; v.y = y1;
     vertexCoords.AppendElement(v);
 
-    tex_coord t;
-    t.u = tx0; t.v = ty0;
-    texCoords.AppendElement(t);
-    t.u = tx1; t.v = ty0;
-    texCoords.AppendElement(t);
-    t.u = tx0; t.v = ty1;
-    texCoords.AppendElement(t);
-
-    t.u = tx0; t.v = ty1;
-    texCoords.AppendElement(t);
-    t.u = tx1; t.v = ty0;
-    texCoords.AppendElement(t);
-    t.u = tx1; t.v = ty1;
-    texCoords.AppendElement(t);
+    if (flip_y) {
+        tex_coord t;
+        t.u = tx0; t.v = ty1;
+        texCoords.AppendElement(t);
+        t.u = tx1; t.v = ty1;
+        texCoords.AppendElement(t);
+        t.u = tx0; t.v = ty0;
+        texCoords.AppendElement(t);
+
+        t.u = tx0; t.v = ty0;
+        texCoords.AppendElement(t);
+        t.u = tx1; t.v = ty1;
+        texCoords.AppendElement(t);
+        t.u = tx1; t.v = ty0;
+        texCoords.AppendElement(t);
+    } else {
+        tex_coord t;
+        t.u = tx0; t.v = ty0;
+        texCoords.AppendElement(t);
+        t.u = tx1; t.v = ty0;
+        texCoords.AppendElement(t);
+        t.u = tx0; t.v = ty1;
+        texCoords.AppendElement(t);
+
+        t.u = tx0; t.v = ty1;
+        texCoords.AppendElement(t);
+        t.u = tx1; t.v = ty0;
+        texCoords.AppendElement(t);
+        t.u = tx1; t.v = ty1;
+        texCoords.AppendElement(t);
+    }
 }
 
 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,
@@ -2500,17 +2518,18 @@ WrapTexCoord(GLfloat v)
     }
 
     return fmodf(v, 1.0f);
 }
 
 void
 GLContext::DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect,
                                           const nsIntSize& aTexSize,
-                                          RectTriangles& aRects)
+                                          RectTriangles& aRects,
+                                          bool aFlipY /* = false */)
 {
     // normalize this
     nsIntRect tcr(aTexCoordRect);
     while (tcr.x >= aTexSize.width)
         tcr.x -= aTexSize.width;
     while (tcr.y >= aTexSize.height)
         tcr.y -= aTexSize.height;
 
@@ -2569,56 +2588,65 @@ GLContext::DecomposeIntoNoRepeatTriangle
     NS_ASSERTION(!ywrap || ylen > 0.0f, "ylen isn't > 0, what's going on?");
     NS_ASSERTION(aTexCoordRect.width <= aTexSize.width &&
                  aTexCoordRect.height <= aTexSize.height, "tex coord rect would cause tiling!");
 
     if (!xwrap && !ywrap) {
         aRects.addRect(0.0f, 0.0f,
                        1.0f, 1.0f,
                        tl[0], tl[1],
-                       br[0], br[1]);
+                       br[0], br[1],
+                       aFlipY);
     } else if (!xwrap && ywrap) {
         GLfloat ymid = (1.0f - tl[1]) / ylen;
         aRects.addRect(0.0f, 0.0f,
                        1.0f, ymid,
                        tl[0], tl[1],
-                       br[0], 1.0f);
+                       br[0], 1.0f,
+                       aFlipY);
         aRects.addRect(0.0f, ymid,
                        1.0f, 1.0f,
                        tl[0], 0.0f,
-                       br[0], br[1]);
+                       br[0], br[1],
+                       aFlipY);
     } else if (xwrap && !ywrap) {
         GLfloat xmid = (1.0f - tl[0]) / xlen;
         aRects.addRect(0.0f, 0.0f,
                        xmid, 1.0f,
                        tl[0], tl[1],
-                       1.0f, br[1]);
+                       1.0f, br[1],
+                       aFlipY);
         aRects.addRect(xmid, 0.0f,
                        1.0f, 1.0f,
                        0.0f, tl[1],
-                       br[0], br[1]);
+                       br[0], br[1],
+                       aFlipY);
     } else {
         GLfloat xmid = (1.0f - tl[0]) / xlen;
         GLfloat ymid = (1.0f - tl[1]) / ylen;
         aRects.addRect(0.0f, 0.0f,
                        xmid, ymid,
                        tl[0], tl[1],
-                       1.0f, 1.0f);
+                       1.0f, 1.0f,
+                       aFlipY);
         aRects.addRect(xmid, 0.0f,
                        1.0f, ymid,
                        0.0f, tl[1],
-                       br[0], 1.0f);
+                       br[0], 1.0f,
+                       aFlipY);
         aRects.addRect(0.0f, ymid,
                        xmid, 1.0f,
                        tl[0], 0.0f,
-                       1.0f, br[1]);
+                       1.0f, br[1],
+                       aFlipY);
         aRects.addRect(xmid, ymid,
                        1.0f, 1.0f,
                        0.0f, 0.0f,
-                       br[0], br[1]);
+                       br[0], br[1],
+                       aFlipY);
     }
 }
 
 void
 GLContext::UseBlitProgram()
 {
     if (mBlitProgram) {
         fUseProgram(mBlitProgram);
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -1340,18 +1340,22 @@ public:
                                             GLenum format, GLenum type,
                                             const GLvoid* pixels);
 
     /** Helper for DecomposeIntoNoRepeatTriangles
      */
     struct RectTriangles {
         RectTriangles() { }
 
+        // 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);
+                     GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
+                     bool flip_y = false);
 
         /**
          * these return a float pointer to the start of each array respectively.
          * Use it for glVertexAttribPointer calls.
          * We can return NULL if we choose to use Vertex Buffer Objects here.
          */
         float* vertexPointer() {
             return &vertexCoords[0].x;
@@ -1372,28 +1376,30 @@ public:
         nsAutoTArray<vert_coord, 6> vertexCoords;
         nsAutoTArray<tex_coord, 6>  texCoords;
     };
 
     /**
      * Decompose drawing the possibly-wrapped aTexCoordRect rectangle
      * of a texture of aTexSize into one or more rectangles (represented
      * as 2 triangles) and associated tex coordinates, such that
-     * we don't have to use the REPEAT wrap mode.
+     * we don't have to use the REPEAT wrap mode. If aFlipY is true, the
+     * texture coordinates will be specified vertically flipped.
      *
      * The resulting triangle vertex coordinates will be in the space of
      * (0.0, 0.0) to (1.0, 1.0) -- transform the coordinates appropriately
      * if you need a different space.
      *
      * The resulting vertex coordinates should be drawn using GL_TRIANGLES,
      * and rects.numRects * 3 * 6
      */
     static void DecomposeIntoNoRepeatTriangles(const nsIntRect& aTexCoordRect,
                                                const nsIntSize& aTexSize,
-                                               RectTriangles& aRects);
+                                               RectTriangles& aRects,
+                                               bool aFlipY = false);
 
     /**
      * Known GL extensions that can be queried by
      * IsExtensionSupported.  The results of this are cached, and as
      * such it's safe to use this even in performance critical code.
      * If you add to this array, remember to add to the string names
      * in GLContext.cpp.
      */
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -432,17 +432,19 @@ ShadowCanvasLayerOGL::RenderLayer(int aP
       // We can't use BindAndDrawQuad because that always uploads the whole texture from 0.0f -> 1.0f
       // in x and y. We use BindAndDrawQuadWithTextureRect to actually draw a subrect of the texture
       // We need to reset the origin to 0,0 from the tile rect because the tile originates at 0,0 in the
       // actual texture, even though its origin in the composed (tiled) texture is not 0,0
       // FIXME: we need to handle mNeedsYFlip, Bug #728625
       mOGLManager->BindAndDrawQuadWithTextureRect(program,
                                                   nsIntRect(0, 0, mTexImage->GetTileRect().width,
                                                                   mTexImage->GetTileRect().height),
-                                                  mTexImage->GetTileRect().Size());
+                                                  mTexImage->GetTileRect().Size(),
+                                                  mTexImage->GetWrapMode(),
+                                                  mNeedsYFlip);
     } while (mTexImage->NextTile());
   }
 }
 
 void
 ShadowCanvasLayerOGL::CleanupResources()
 {
   DestroyFrontBuffer();
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -669,17 +669,18 @@ LayerManagerOGL::FPSState::DrawFPS(GLCon
 // square from 0,0 to 1,1.
 //
 // |aTexSize| is the actual size of the texture, as it can be larger
 // than the rectangle given by |aTexCoordRect|.
 void 
 LayerManagerOGL::BindAndDrawQuadWithTextureRect(LayerProgram *aProg,
                                                 const nsIntRect& aTexCoordRect,
                                                 const nsIntSize& aTexSize,
-                                                GLenum aWrapMode)
+                                                GLenum aWrapMode /* = LOCAL_GL_REPEAT */,
+                                                bool aFlipped /* = false */)
 {
   GLuint vertAttribIndex =
     aProg->AttribLocation(LayerProgram::VertexAttrib);
   GLuint texCoordAttribIndex =
     aProg->AttribLocation(LayerProgram::TexCoordAttrib);
   NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?");
 
   // clear any bound VBO so that glVertexAttribPointer() goes back to
@@ -703,19 +704,21 @@ LayerManagerOGL::BindAndDrawQuadWithText
 
   if (aWrapMode == LOCAL_GL_REPEAT) {
     rects.addRect(/* dest rectangle */
                   0.0f, 0.0f, 1.0f, 1.0f,
                   /* tex coords */
                   aTexCoordRect.x / GLfloat(realTexSize.width),
                   aTexCoordRect.y / GLfloat(realTexSize.height),
                   aTexCoordRect.XMost() / GLfloat(realTexSize.width),
-                  aTexCoordRect.YMost() / GLfloat(realTexSize.height));
+                  aTexCoordRect.YMost() / GLfloat(realTexSize.height),
+                  aFlipped);
   } else {
-    GLContext::DecomposeIntoNoRepeatTriangles(aTexCoordRect, realTexSize, rects);
+    GLContext::DecomposeIntoNoRepeatTriangles(aTexCoordRect, realTexSize,
+                                              rects, aFlipped);
   }
 
   mGLContext->fVertexAttribPointer(vertAttribIndex, 2,
                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
                                    rects.vertexPointer());
 
   mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2,
                                    LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0,
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -361,18 +361,19 @@ public:
     BindAndDrawQuad(aProg->AttribLocation(LayerProgram::VertexAttrib),
                     aProg->AttribLocation(LayerProgram::TexCoordAttrib),
                     aFlipped);
   }
 
   void BindAndDrawQuadWithTextureRect(LayerProgram *aProg,
                                       const nsIntRect& aTexCoordRect,
                                       const nsIntSize& aTexSize,
-                                      GLenum aWrapMode = LOCAL_GL_REPEAT);
-                                      
+                                      GLenum aWrapMode = LOCAL_GL_REPEAT,
+                                      bool aFlipped = false);
+
 
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() const { return "OGL"; }
 #endif // MOZ_LAYERS_HAVE_LOG
 
   const nsIntSize& GetWigetSize() {
     return mWidgetSize;
   }