Bug 607687 - Fennec should take care about Texture MAX size HW limitation r=jmuizelaar
authorFlorian Haenel <florian.haenel@heeen.de>
Wed, 06 Jul 2011 11:00:47 -0700
changeset 72417 709b5696199b5c146f81f7a981598ad2d93cf0df
parent 72416 eb4d059af819237e9d02da62dd2f013a6c6be773
child 72418 ea752bcac5c5af2f6cef891e63baf020857b3463
push id20715
push userromaxa@gmail.com
push dateWed, 06 Jul 2011 18:14:21 +0000
treeherdermozilla-central@709b5696199b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar
bugs607687
milestone8.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 607687 - Fennec should take care about Texture MAX size HW limitation r=jmuizelaar
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/thebes/GLContext.cpp
gfx/thebes/GLContext.h
gfx/thebes/GLContextProviderEGL.cpp
gfx/thebes/GLContextProviderGLX.cpp
widget/src/cocoa/nsChildView.mm
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -361,24 +361,26 @@ ShadowCanvasLayerOGL::GetLayer()
 }
 
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
   mOGLManager->MakeCurrent();
 
-  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-  gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   ColorTextureLayerProgram *program =
     mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
 
   ApplyFilter(mFilter);
 
   program->Activate();
-  program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
   program->SetLayerTransform(GetEffectiveTransform());
   program->SetLayerOpacity(GetEffectiveOpacity());
   program->SetRenderOffset(aOffset);
   program->SetTextureUnit(0);
 
-  mOGLManager->BindAndDrawQuad(program, mNeedsYFlip ? true : false);
+  mTexImage->BeginTileIteration();
+  do {
+    TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
+    program->SetLayerQuadRect(mTexImage->GetTileRect());
+    mOGLManager->BindAndDrawQuad(program, mNeedsYFlip); // FIXME flip order of tiles?
+  } while (mTexImage->NextTile());
 }
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -933,63 +933,53 @@ ShadowImageLayerOGL::GetLayer()
 }
 
 void
 ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                  const nsIntPoint& aOffset)
 {
   mOGLManager->MakeCurrent();
 
-  LayerProgram* program;
-
   if (mTexImage) {
-    gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
     ColorTextureLayerProgram *colorProgram =
       mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
 
-    ApplyFilter(mFilter);
-
     colorProgram->Activate();
     colorProgram->SetTextureUnit(0);
-    colorProgram->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
-    program = colorProgram;
+
+    mTexImage->BeginTileIteration();
+    do {
+      TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
+      ApplyFilter(mFilter);
+      colorProgram->SetLayerQuadRect(mTexImage->GetTileRect());
+      mOGLManager->BindAndDrawQuad(colorProgram);
+    } while (mTexImage->NextTile());
   } else {
     gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[0].GetTextureID());
     ApplyFilter(mFilter);
     gl()->fActiveTexture(LOCAL_GL_TEXTURE1);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[1].GetTextureID());
     ApplyFilter(mFilter);
     gl()->fActiveTexture(LOCAL_GL_TEXTURE2);
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mYUVTexture[2].GetTextureID());
     ApplyFilter(mFilter);
-    
+
     YCbCrTextureLayerProgram *yuvProgram = mOGLManager->GetYCbCrLayerProgram();
 
     yuvProgram->Activate();
     yuvProgram->SetLayerQuadRect(nsIntRect(0, 0,
                                            mPictureRect.width,
                                            mPictureRect.height));
     yuvProgram->SetYCbCrTextureUnits(0, 1, 2);
+    yuvProgram->SetLayerTransform(GetEffectiveTransform());
+    yuvProgram->SetLayerOpacity(GetEffectiveOpacity());
+    yuvProgram->SetRenderOffset(aOffset);
 
-    program = yuvProgram;
-    program->SetLayerTransform(GetEffectiveTransform());
-    program->SetLayerOpacity(GetEffectiveOpacity());
-    program->SetRenderOffset(aOffset);
-
-    mOGLManager->BindAndDrawQuadWithTextureRect(program,
+    mOGLManager->BindAndDrawQuadWithTextureRect(yuvProgram,
                                                 mPictureRect,
                                                 nsIntSize(mSize.width, mSize.height));
-
-    return;
-  }
-
-  program->SetLayerTransform(GetEffectiveTransform());
-  program->SetLayerOpacity(GetEffectiveOpacity());
-  program->SetRenderOffset(aOffset);
-
-  mOGLManager->BindAndDrawQuad(program);
+ }
 }
 
 
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -136,20 +136,16 @@ ThebesLayerBufferOGL::RenderTo(const nsI
   if (mTexImage->InUpdate()) {
     mTexImage->EndUpdate();
   }
 
   if (mTexImageOnWhite && mTexImageOnWhite->InUpdate()) {
     mTexImageOnWhite->EndUpdate();
   }
 
-  // Bind textures.
-  TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
-  TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1);
-
   PRInt32 passes = mTexImageOnWhite ? 2 : 1;
   for (PRInt32 pass = 1; pass <= passes; ++pass) {
     LayerProgram *program;
 
     if (passes == 2) {
       ComponentAlphaTextureLayerProgram *alphaProgram;
       NS_ASSERTION(!mTexImage->IsRGB() && !mTexImageOnWhite->IsRGB(),
                    "Only BGR image surported with component alpha (currently!)");
@@ -189,27 +185,52 @@ ThebesLayerBufferOGL::RenderTo(const nsI
       // If we're resampling, then the texture image will contain exactly the
       // entire visible region's bounds, and we should draw it all in one quad
       // to avoid unexpected aliasing.
       tmpRegion = visibleRegion.GetBounds();
       renderRegion = &tmpRegion;
     } else {
       renderRegion = &visibleRegion;
     }
-    nsIntRegionRectIterator iter(*renderRegion);
-    while (const nsIntRect *iterRect = iter.Next()) {
-      nsIntRect quadRect = *iterRect;
-      program->SetLayerQuadRect(quadRect);
+
+    mTexImage->BeginTileIteration();
+    if (mTexImageOnWhite) {
+      mTexImageOnWhite->BeginTileIteration();
+      NS_ASSERTION(mTexImageOnWhite->GetTileRect() == mTexImage->GetTileRect(), "component alpha textures should be the same size.");
+    }
+    nsIntRegion region(*renderRegion);
+    nsIntPoint origin = GetOriginOffset();
+    region.MoveBy(-origin);           // translate into TexImage space, buffer origin might not be at texture (0,0)
 
-      quadRect.MoveBy(-GetOriginOffset());
+    do {
+      nsIntRect textureRect = mTexImage->GetTileRect();
+      textureRect.MoveBy(region.GetBounds().x, region.GetBounds().y);
+      nsIntRegion subregion(region);
+      subregion.And(region, textureRect); // region this texture is visible in
+      if (subregion.IsEmpty()) {
+        continue;
+      }
+      // Bind textures.
+      TextureImage::ScopedBindTexture texBind(mTexImage, LOCAL_GL_TEXTURE0);
+      TextureImage::ScopedBindTexture texOnWhiteBind(mTexImageOnWhite, LOCAL_GL_TEXTURE1);
 
-      aManager->BindAndDrawQuadWithTextureRect(program, quadRect,
-                                               mTexImage->GetSize(),
-                                               mTexImage->GetWrapMode());
-    }
+      nsIntRegionRectIterator iter(subregion);
+      while (const nsIntRect *iterRect = iter.Next()) {
+        nsIntRect regionRect = *iterRect;  // one rectangle of this texture's region
+        // translate into the correct place for this texture sub-region
+        nsIntRect screenRect = regionRect;
+        screenRect.MoveBy(origin);
+        program->SetLayerQuadRect(screenRect);
+
+        regionRect.MoveBy(-mTexImage->GetTileRect().TopLeft()); // get region of tile
+        aManager->BindAndDrawQuadWithTextureRect(program, regionRect,
+                                                 textureRect.Size(),
+                                                 mTexImage->GetWrapMode());
+      }
+    } while (mTexImage->NextTile());
   }
 
   if (mTexImageOnWhite) {
     // Restore defaults
     gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                              LOCAL_GL_ONE, LOCAL_GL_ONE);
   }
 }
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -47,16 +47,17 @@
 
 #include "nsThreadUtils.h"
 
 #include "gfxPlatform.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
 #include "gfxCrashReporterUtils.h"
+#include "gfxUtils.h"
 
 #include "mozilla/Util.h" // for DebugOnly
 
 namespace mozilla {
 namespace gl {
 
 #ifdef DEBUG
 // see comment near declaration in GLContext.h. Should be thread-local.
@@ -631,17 +632,17 @@ BasicTextureImage::EndUpdate()
     mUpdateSurface = nsnull;
     mTextureState = Valid;
 }
 
 void
 BasicTextureImage::BindTexture(GLenum aTextureUnit)
 {
     mGLContext->fActiveTexture(aTextureUnit);
-    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture());
+    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
     mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
 }
 
 already_AddRefed<gfxASurface>
 BasicTextureImage::GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
 {
     return gfxPlatform::GetPlatform()->
         CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
@@ -654,33 +655,33 @@ BasicTextureImage::FinishedSurfaceUpdate
 }
 
 void
 BasicTextureImage::FinishedSurfaceUpload()
 {
 }
 
 bool 
-BasicTextureImage::DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion)
+BasicTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
 {
     nsIntRect bounds = aRegion.GetBounds();
     nsIntRegion region;
     if (mTextureState != Valid) {
         bounds = nsIntRect(0, 0, mSize.width, mSize.height);
         region = nsIntRegion(bounds);
     } else {
         region = aRegion;
     }
 
     mShaderType =
         mGLContext->UploadSurfaceToTexture(aSurf,
                                            region,
                                            mTexture,
                                            mTextureState == Created,
-                                           bounds.TopLeft(),
+                                           bounds.TopLeft() + aFrom,
                                            PR_FALSE);
     mTextureState = Valid;
     return true;
 }
 
 void
 BasicTextureImage::Resize(const nsIntSize& aSize)
 {
@@ -697,16 +698,212 @@ BasicTextureImage::Resize(const nsIntSiz
                             LOCAL_GL_RGBA,
                             LOCAL_GL_UNSIGNED_BYTE,
                             NULL);
 
     mTextureState = Allocated;
     mSize = aSize;
 }
 
+TiledTextureImage::TiledTextureImage(GLContext* aGL,
+                                     nsIntSize aSize,
+                                     TextureImage::ContentType aContentType,
+                                     PRBool aUseNearestFilter)
+    : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aUseNearestFilter)
+    , mCurrentImage(0)
+    , mInUpdate(PR_FALSE)
+    , mGL(aGL)
+    , mUseNearestFilter(aUseNearestFilter)
+    , mTextureState(Created)
+{
+    mTileSize = mGL->GetMaxTextureSize();
+    if (aSize != nsIntSize(0,0)) {
+        Resize(aSize);
+    }
+}
+
+TiledTextureImage::~TiledTextureImage()
+{
+}
+
+bool 
+TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
+{
+    nsIntRect bounds = aRegion.GetBounds();
+    nsIntRegion region;
+    if (mTextureState != Valid) {
+        bounds = nsIntRect(0, 0, mSize.width, mSize.height);
+        region = nsIntRegion(bounds);
+    } else {
+        region = aRegion;
+    }
+
+    PRBool result = PR_TRUE;
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        unsigned int xPos = (i % mColumns) * mTileSize;
+        unsigned int yPos = (i / mColumns) * mTileSize;
+        nsIntRegion tileRegion;
+        tileRegion.And(region, nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize())); // intersect with tile
+        if (tileRegion.IsEmpty())
+            continue;
+        tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
+        result &= mImages[i]->DirectUpdate(aSurf,
+                                           tileRegion,
+                                           aFrom + nsIntPoint(xPos, yPos));
+    }
+    mShaderType = mImages[0]->GetShaderProgramType();
+    mIsRGBFormat = mImages[0]->IsRGB();
+    mTextureState = Valid;
+    return result;
+}
+
+gfxASurface*
+TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
+{
+    NS_ASSERTION(!mInUpdate, "nested update");
+    mInUpdate = PR_TRUE;
+
+    if (mTextureState != Valid)
+    {
+        // if the texture hasn't been initialized yet, or something important
+        // changed, we need to recreate our backing surface and force the
+        // client to paint everything
+        mUpdateRegion = nsIntRect(nsIntPoint(0, 0), mSize);
+    } else {
+        mUpdateRegion = aRegion;
+    }
+
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        unsigned int xPos = (i % mColumns) * mTileSize;
+        unsigned int yPos = (i / mColumns) * mTileSize;
+        nsIntRegion imageRegion = nsIntRegion(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
+
+        // a single Image can handle this update request
+        if (imageRegion.Contains(aRegion)) {
+            // adjust for tile offset
+            aRegion.MoveBy(-xPos, -yPos);
+            // forward the actual call
+            nsRefPtr<gfxASurface> surface = mImages[i]->BeginUpdate(aRegion);
+            // caller expects container space
+            aRegion.MoveBy(xPos, yPos);
+            // we don't have a temp surface
+            mUpdateSurface = nsnull;
+            // remember which image to EndUpdate
+            mCurrentImage = i;
+            return surface.get();
+        }
+    }
+    // update covers multiple Images - create a temp surface to paint in
+    gfxASurface::gfxImageFormat format =
+        (GetContentType() == gfxASurface::CONTENT_COLOR) ?
+        gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
+
+    nsIntRect bounds = aRegion.GetBounds();
+    mUpdateSurface = gfxPlatform::GetPlatform()->
+        CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), gfxASurface::ContentFromFormat(format));
+    mUpdateSurface->SetDeviceOffset(gfxPoint(-bounds.x, -bounds.y));
+    return mUpdateSurface;
+}
+
+void
+TiledTextureImage::EndUpdate()
+{
+    NS_ASSERTION(mInUpdate, "EndUpdate not in update");
+    if (!mUpdateSurface) { // update was to a single TextureImage
+        mImages[mCurrentImage]->EndUpdate();
+        mInUpdate = PR_FALSE;
+        mTextureState = Valid;
+        mShaderType = mImages[mCurrentImage]->GetShaderProgramType();
+        mIsRGBFormat = mImages[mCurrentImage]->IsRGB();
+        return;
+    }
+
+    // upload tiles from temp surface
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        unsigned int xPos = (i % mColumns) * mTileSize;
+        unsigned int yPos = (i / mColumns) * mTileSize;
+        nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize());
+        nsIntRegion subregion;
+        subregion.And(mUpdateRegion, imageRect);
+        if (subregion.IsEmpty())
+            continue;
+        subregion.MoveBy(-xPos, -yPos); // Tile-local space
+        // copy tile from temp surface
+        gfxASurface* surf = mImages[i]->BeginUpdate(subregion);
+        nsRefPtr<gfxContext> ctx = new gfxContext(surf);
+        gfxUtils::ClipToRegion(ctx, subregion);
+        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+        ctx->SetSource(mUpdateSurface, gfxPoint(-xPos, -yPos));
+        ctx->Paint();
+        mImages[i]->EndUpdate();
+    }
+
+    mUpdateSurface = nsnull;
+    mInUpdate = PR_FALSE;
+    mShaderType = mImages[0]->GetShaderProgramType();
+    mIsRGBFormat = mImages[0]->IsRGB();
+}
+
+void TiledTextureImage::BeginTileIteration()
+{
+    mCurrentImage = 0;
+}
+
+PRBool TiledTextureImage::NextTile()
+{
+    if (mCurrentImage + 1 < mImages.Length()) {
+        mCurrentImage++;
+        return PR_TRUE;
+    }
+    return PR_FALSE;
+}
+
+nsIntRect TiledTextureImage::GetTileRect()
+{
+    nsIntRect rect = mImages[mCurrentImage]->GetTileRect();
+    unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
+    unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
+    rect.MoveTo(xPos, yPos);
+    return rect;
+}
+
+void
+TiledTextureImage::BindTexture(GLenum aTextureUnit)
+{
+    mImages[mCurrentImage]->BindTexture(aTextureUnit);
+}
+
+/*
+ * simple resize, just discards everything. we can be more clever just
+ * adding or discarding tiles, but do we want this?
+ */
+void TiledTextureImage::Resize(const nsIntSize& aSize)
+{
+    if (mSize == aSize && mTextureState != Created) {
+        return;
+    }
+    mSize = aSize;
+    mImages.Clear();
+    // calculate rows and columns, rounding up
+    mColumns = (aSize.width  + mTileSize - 1) / mTileSize;
+    mRows    = (aSize.height + mTileSize - 1) / mTileSize;
+
+    for (unsigned int row = 0; row < mRows; row++) {
+      for (unsigned int col = 0; col < mColumns; col++) {
+          nsIntSize size( // use tilesize first, then the remainder
+                  (col+1) * mTileSize > (unsigned int)aSize.width  ? aSize.width  % mTileSize : mTileSize,
+                  (row+1) * mTileSize > (unsigned int)aSize.height ? aSize.height % mTileSize : mTileSize);
+          nsRefPtr<TextureImage> teximg =
+                  mGL->TileGenFunc(size, mContentType, mUseNearestFilter);
+          mImages.AppendElement(teximg.forget());
+      }
+    }
+    mTextureState = Allocated;
+}
+
 PRBool
 GLContext::ResizeOffscreenFBO(const gfxIntSize& aSize)
 {
     if (!IsOffscreenSizeAllowed(aSize))
         return PR_FALSE;
 
     MakeCurrent();
 
@@ -1240,77 +1437,137 @@ GLContext::ReadPixelsIntoImageSurface(GL
 
 void
 GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
                             TextureImage *aDst, const nsIntRect& aDstRect)
 {
     NS_ASSERTION(!aSrc->InUpdate(), "Source texture is in update!");
     NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!");
 
+    if (aSrcRect.IsEmpty() || aDstRect.IsEmpty())
+        return;
+
     // only save/restore this stuff on Qualcomm Adreno, to work
     // around an apparent bug
     int savedFb = 0;
     if (mVendor == VendorQualcomm) {
         fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb);
     }
 
     fDisable(LOCAL_GL_SCISSOR_TEST);
     fDisable(LOCAL_GL_BLEND);
 
-    SetBlitFramebufferForDestTexture(aDst->Texture());
-
-    UseBlitProgram();
+    // 2.0 means scale up by two
+    float blitScaleX = float(aDstRect.width) / float(aSrcRect.width);
+    float blitScaleY = float(aDstRect.height) / float(aSrcRect.height);
 
-    nsIntSize srcSize = aSrc->GetSize();
-    nsIntSize dstSize = aDst->GetSize();
+    // We start iterating over all destination tiles
+    aDst->BeginTileIteration();
+    do {
+        // calculate portion of the tile that is going to be painted to
+        nsIntRect dstSubRect;
+        nsIntRect dstTextureRect = aDst->GetTileRect();
+        dstSubRect.IntersectRect(aDstRect, dstTextureRect);
 
-    PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height));
+        // this tile is not part of the destination rectangle aDstRect
+        if (dstSubRect.IsEmpty())
+            continue;
 
-    float dx0 = 2.0 * float(aDstRect.x) / float(dstSize.width) - 1.0;
-    float dy0 = 2.0 * float(aDstRect.y) / float(dstSize.height) - 1.0;
-    float dx1 = 2.0 * float(aDstRect.x + aDstRect.width) / float(dstSize.width) - 1.0;
-    float dy1 = 2.0 * float(aDstRect.y + aDstRect.height) / float(dstSize.height) - 1.0;
+        // (*) transform the rect of this tile into the rectangle defined by aSrcRect...
+        nsIntRect dstInSrcRect(dstSubRect);
+        dstInSrcRect.MoveBy(-aDstRect.TopLeft());
+        // ...which might be of different size, hence scale accordingly
+        dstInSrcRect.ScaleRoundOut(1.0f / blitScaleX, 1.0f / blitScaleY);
+        dstInSrcRect.MoveBy(aSrcRect.TopLeft());
 
-    RectTriangles rects;
-    if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
-        rects.addRect(/* dest rectangle */
-                      dx0, dy0, dx1, dy1,
-                      /* tex coords */
-                      aSrcRect.x / float(srcSize.width),
-                      aSrcRect.y / float(srcSize.height),
-                      aSrcRect.XMost() / float(srcSize.width),
-                      aSrcRect.YMost() / float(srcSize.height));
-    } else {
-        DecomposeIntoNoRepeatTriangles(aSrcRect, srcSize, rects);
+        SetBlitFramebufferForDestTexture(aDst->GetTextureID());
+        UseBlitProgram();
+
+        aSrc->BeginTileIteration();
+        // now iterate over all tiles in the source Image...
+        do {
+            // calculate portion of the source tile that is in the source rect
+            nsIntRect srcSubRect;
+            nsIntRect srcTextureRect = aSrc->GetTileRect();
+            srcSubRect.IntersectRect(aSrcRect, srcTextureRect);
 
-        // now put the coords into the d[xy]0 .. d[xy]1 coordinate space
-        // from the 0..1 that it comes out of decompose
-        RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer();
-        for (int i = 0; i < rects.elements(); ++i) {
-            v[i].x = (v[i].x * (dx1 - dx0)) + dx0;
-            v[i].y = (v[i].y * (dy1 - dy0)) + dy0;
-        }
-    }
+            // this tile is not part of the source rect
+            if (srcSubRect.IsEmpty()) {
+                continue;
+            }
+            // calculate intersection of source rect with destination rect
+            srcSubRect.IntersectRect(srcSubRect, dstInSrcRect);
+            // this tile does not overlap the current destination tile
+            if (srcSubRect.IsEmpty()) {
+                continue;
+            }
+            // We now have the intersection of 
+            //     the current source tile 
+            // and the desired source rectangle
+            // and the destination tile
+            // and the desired destination rectange
+            // in destination space.
+            // We need to transform this back into destination space, inverting the transform from (*)
+            nsIntRect srcSubInDstRect(srcSubRect);
+            srcSubInDstRect.MoveBy(-aSrcRect.TopLeft());
+            srcSubInDstRect.ScaleRoundOut(blitScaleX, blitScaleY);
+            srcSubInDstRect.MoveBy(aDstRect.TopLeft());
 
+            // we transform these rectangles to be relative to the current src and dst tiles, respectively
+            nsIntSize srcSize = srcTextureRect.Size();
+            nsIntSize dstSize = dstTextureRect.Size();
+            srcSubRect.MoveBy(-srcTextureRect.x, -srcTextureRect.y);
+            srcSubInDstRect.MoveBy(-dstTextureRect.x, -dstTextureRect.y);
 
-    fActiveTexture(LOCAL_GL_TEXTURE0);
-    fBindTexture(LOCAL_GL_TEXTURE_2D, aSrc->Texture());
+            float dx0 = 2.0 * float(srcSubInDstRect.x) / float(dstSize.width) - 1.0;
+            float dy0 = 2.0 * float(srcSubInDstRect.y) / float(dstSize.height) - 1.0;
+            float dx1 = 2.0 * float(srcSubInDstRect.x + srcSubInDstRect.width) / float(dstSize.width) - 1.0;
+            float dy1 = 2.0 * float(srcSubInDstRect.y + srcSubInDstRect.height) / float(dstSize.height) - 1.0;
+            PushViewportRect(nsIntRect(0, 0, dstSize.width, dstSize.height));
 
-    fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+            RectTriangles rects;
+            if (aSrc->GetWrapMode() == LOCAL_GL_REPEAT) {
+                rects.addRect(/* dest rectangle */
+                        dx0, dy0, dx1, dy1,
+                        /* tex coords */
+                        srcSubRect.x / float(srcSize.width),
+                        srcSubRect.y / float(srcSize.height),
+                        srcSubRect.XMost() / float(srcSize.width),
+                        srcSubRect.YMost() / float(srcSize.height));
+            } else {
+                DecomposeIntoNoRepeatTriangles(srcSubRect, srcSize, rects);
 
-    fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer());
-    fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer());
+                // now put the coords into the d[xy]0 .. d[xy]1 coordinate space
+                // from the 0..1 that it comes out of decompose
+                RectTriangles::vert_coord* v = (RectTriangles::vert_coord*)rects.vertexPointer();
 
-    fEnableVertexAttribArray(0);
-    fEnableVertexAttribArray(1);
+                for (unsigned int i = 0; i < rects.elements(); ++i) {
+                    v[i].x = (v[i].x * (dx1 - dx0)) + dx0;
+                    v[i].y = (v[i].y * (dy1 - dy0)) + dy0;
+                }
+            }
+
+            TextureImage::ScopedBindTexture texBind(aSrc, LOCAL_GL_TEXTURE0);
+
+            fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
 
-    fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
+            fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.vertexPointer());
+            fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, rects.texCoordPointer());
+
+            fEnableVertexAttribArray(0);
+            fEnableVertexAttribArray(1);
 
-    fDisableVertexAttribArray(0);
-    fDisableVertexAttribArray(1);
+            fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements());
+
+            fDisableVertexAttribArray(0);
+            fDisableVertexAttribArray(1);
+
+            PopViewportRect();
+        } while (aSrc->NextTile());
+    } while (aDst->NextTile());
 
     fVertexAttribPointer(0, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL);
     fVertexAttribPointer(1, 2, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, NULL);
 
     // unbind the previous texture from the framebuffer
     SetBlitFramebufferForDestTexture(0);
 
     // then put back the previous framebuffer, and don't
@@ -1320,18 +1577,16 @@ GLContext::BlitTextureImage(TextureImage
     // (which it will be, once we assign texture 0 to the color
     // attachment)
     if (mVendor == VendorQualcomm) {
         fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
     }
 
     fEnable(LOCAL_GL_SCISSOR_TEST);
     fEnable(LOCAL_GL_BLEND);
-
-    PopViewportRect();
 }
 
 static unsigned int 
 DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
 {
   unsigned int data = aPoint.y * aSurf->Stride();
   data += aPoint.x * gfxASurface::BytePerPixelFromFormat(aSurf->Format());
   return data;
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -70,18 +70,22 @@
 #define USE_GLES2 1
 #endif
 
 typedef char realGLboolean;
 
 #include "GLContextSymbols.h"
 
 namespace mozilla {
+  namespace layers {
+    class LayerManagerOGL;
+    class ColorTextureLayerProgram;
+  };
+
 namespace gl {
-
 class GLContext;
 
 class LibrarySymbolLoader
 {
 public:
     PRBool OpenLibrary(const char *library);
 
     typedef PRFuncPtr (GLAPIENTRY * PlatformLookupFunction) (const char *);
@@ -151,16 +155,23 @@ enum ShaderProgramType {
  *  (2) efficient manager of texture memory; e.g. by having clients draw
  *      into a scratch buffer which is then uploaded with
  *      glTexSubImage2D().
  */
 class TextureImage
 {
     NS_INLINE_DECL_REFCOUNTING(TextureImage)
 public:
+    enum TextureState
+    {
+      Created, // Texture created, but has not had glTexImage called to initialize it.
+      Allocated,  // Texture memory exists, but contents are invalid.
+      Valid  // Texture fully ready to use.
+    };
+
     typedef gfxASurface::gfxContentType ContentType;
 
     virtual ~TextureImage() {}
 
     /**
      * Returns a gfxASurface for updating |aRegion| of the client's
      * image if successul, NULL if not.  |aRegion|'s bounds must fit
      * within Size(); its coordinate space (if any) is ignored.  If
@@ -187,31 +198,52 @@ public:
      * necessary.
      *
      * BeginUpdate() must have been called exactly once before
      * EndUpdate().
      */
     virtual void EndUpdate() = 0;
 
     /**
+     * The Image may contain several textures for different regions (tiles).
+     * These functions iterate over each sub texture image tile.
+     */
+    virtual void BeginTileIteration() {
+    };
+
+    virtual PRBool NextTile() {
+        return PR_FALSE;
+    };
+
+    virtual nsIntRect GetTileRect() {
+        return nsIntRect(nsIntPoint(0,0), mSize);
+    };
+
+    virtual GLuint GetTextureID() = 0;
+    /**
      * Set this TextureImage's size, and ensure a texture has been
      * allocated.  Must not be called between BeginUpdate and EndUpdate.
      * After a resize, the contents are undefined.
      *
      * If this isn't implemented by a subclass, it will just perform
      * a dummy BeginUpdate/EndUpdate pair.
      */
     virtual void Resize(const nsIntSize& aSize) {
         mSize = aSize;
         nsIntRegion r(nsIntRect(0, 0, aSize.width, aSize.height));
         BeginUpdate(r);
         EndUpdate();
     }
 
-    virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion) =0;
+    /**
+     * aSurf - the source surface to update from
+     * aRegion - the region in this image to update
+     * aFrom - offset in the source to update from
+     */
+    virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0)) = 0;
 
     virtual void BindTexture(GLenum aTextureUnit) = 0;
     virtual void ReleaseTexture() {};
 
     class ScopedBindTexture
     {
     public:
         ScopedBindTexture(TextureImage *aTexture, GLenum aTextureUnit) :
@@ -228,26 +260,16 @@ public:
                 mTexture->ReleaseTexture();
             }       
         }
 
     private:
         TextureImage *mTexture;
     };
 
-    /**
-     * Return this TextureImage's texture ID for use with GL APIs.
-     * Callers are responsible for properly binding the texture etc.
-     *
-     * The texture is only texture complete after either Resize
-     * or a matching pair of BeginUpdate/EndUpdate have been called.
-     * Otherwise, a texture ID may be returned, but the texture
-     * may not be texture complete.
-     */
-    GLuint Texture() { return mTexture; }
 
     /**
      * Returns the shader program type that should be used to render
      * this texture. Only valid after a matching BeginUpdate/EndUpdate
      * pair have been called.
      */
     virtual ShaderProgramType GetShaderProgramType()
     {
@@ -274,27 +296,25 @@ protected:
     friend class GLContext;
 
     /**
      * After the ctor, the TextureImage is invalid.  Implementations
      * must allocate resources successfully before returning the new
      * TextureImage from GLContext::CreateTextureImage().  That is,
      * clients must not be given partially-constructed TextureImages.
      */
-    TextureImage(GLuint aTexture, const nsIntSize& aSize,
+    TextureImage(const nsIntSize& aSize,
                  GLenum aWrapMode, ContentType aContentType,
                  PRBool aIsRGB = PR_FALSE)
-        : mTexture(aTexture)
-        , mSize(aSize)
+        : mSize(aSize)
         , mWrapMode(aWrapMode)
         , mContentType(aContentType)
         , mIsRGBFormat(aIsRGB)
     {}
 
-    GLuint mTexture;
     nsIntSize mSize;
     GLenum mWrapMode;
     ContentType mContentType;
     PRPackedBool mIsRGBFormat;
     ShaderProgramType mShaderType;
 };
 
 /**
@@ -313,35 +333,29 @@ public:
     typedef gfxASurface::gfxImageFormat ImageFormat;
     virtual ~BasicTextureImage();
 
     BasicTextureImage(GLuint aTexture,
                       const nsIntSize& aSize,
                       GLenum aWrapMode,
                       ContentType aContentType,
                       GLContext* aContext)
-        : TextureImage(aTexture, aSize, aWrapMode, aContentType)
+        : TextureImage(aSize, aWrapMode, aContentType)
+        , mTexture(aTexture)
         , mTextureState(Created)
         , mGLContext(aContext)
         , mUpdateOffset(0, 0)
     {}
 
-    enum TextureState
-    {
-      Created, // Texture created, but has not had glTexImage called to initialize it.
-      Allocated,  // Texture memory exists, but contents are invalid.
-      Valid  // Texture fully ready to use.
-    };
-    
     virtual void BindTexture(GLenum aTextureUnit);
 
     virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
     virtual void EndUpdate();
-    virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion);
-
+    virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0));
+    virtual GLuint GetTextureID() { return mTexture; };
     // Returns a surface to draw into
     virtual already_AddRefed<gfxASurface>
       GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt);
 
     // Call when drawing into the update surface is complete.
     // Returns true if textures should be upload with a relative 
     // offset - See UploadSurfaceToTexture.
     virtual bool FinishedSurfaceUpdate();
@@ -349,25 +363,67 @@ public:
     // Call after surface data has been uploaded to a texture.
     virtual void FinishedSurfaceUpload();
 
     virtual PRBool InUpdate() const { return !!mUpdateSurface; }
 
     virtual void Resize(const nsIntSize& aSize);
 protected:
 
+    GLuint mTexture;
     TextureState mTextureState;
     GLContext* mGLContext;
     nsRefPtr<gfxASurface> mUpdateSurface;
     nsIntRegion mUpdateRegion;
 
     // The offset into the update surface at which the update rect is located.
     nsIntPoint mUpdateOffset;
 };
 
+/**
+ * A container class that complements many sub TextureImages into a big TextureImage.
+ * Aims to behave just like the real thing.
+ */
+
+class TiledTextureImage
+    : public TextureImage
+{
+public:
+    TiledTextureImage(GLContext* aGL, nsIntSize aSize,
+        TextureImage::ContentType aContentType, PRBool aUseNearestFilter = PR_FALSE);
+    ~TiledTextureImage();
+    void DumpDiv();
+    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
+    virtual void EndUpdate();
+    virtual void Resize(const nsIntSize& aSize);
+    virtual void BeginTileIteration();
+    virtual PRBool NextTile();
+    virtual nsIntRect GetTileRect();
+    virtual GLuint GetTextureID() {
+        return mImages[mCurrentImage]->GetTextureID();
+    };
+    virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom = nsIntPoint(0,0));
+    virtual PRBool InUpdate() const { return mInUpdate; };
+    virtual void BindTexture(GLenum);
+protected:
+    unsigned int mCurrentImage;
+    nsTArray< nsRefPtr<TextureImage> > mImages;
+    bool mInUpdate;
+    nsIntSize mSize;
+    unsigned int mTileSize;
+    unsigned int mRows, mColumns;
+    GLContext* mGL;
+    PRBool mUseNearestFilter;
+    // A temporary surface to faciliate cross-tile updates.
+    nsRefPtr<gfxASurface> mUpdateSurface;
+    // The region of update requested
+    nsIntRegion mUpdateRegion;
+    TextureState mTextureState;
+};
+
 struct THEBES_API ContextFormat
 {
     static const ContextFormat BasicRGBA32Format;
 
     enum StandardContextFormat {
         Empty,
         BasicRGBA32,
         StrictBasicRGBA32,
@@ -702,16 +758,31 @@ public:
      */
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
                        PRBool aUseNearestFilter=PR_FALSE);
 
     /**
+     * In EGL we want to use Tiled Texture Images, which we return
+     * from CreateTextureImage above.
+     * Inside TiledTextureImage we need to create actual images and to
+     * prevent infinite recursion we need to differentiate the two
+     * functions.
+     **/
+    virtual already_AddRefed<TextureImage>
+    TileGenFunc(const nsIntSize& aSize,
+                TextureImage::ContentType aContentType,
+                PRBool aUseNearestFilter = PR_FALSE)
+    {
+        return nsnull;
+    };
+
+    /**
      * Read the image data contained in aTexture, and return it as an ImageSurface.
      * If GL_RGBA is given as the format, a ImageFormatARGB32 surface is returned.
      * Not implemented yet:
      * If GL_RGB is given as the format, a ImageFormatRGB24 surface is returned.
      * If GL_LUMINANCE is given as the format, a ImageFormatA8 surface is returned.
      *
      * THIS IS EXPENSIVE.  It is ridiculously expensive.  Only do this
      * if you absolutely positively must, and never in any performance
--- a/gfx/thebes/GLContextProviderEGL.cpp
+++ b/gfx/thebes/GLContextProviderEGL.cpp
@@ -816,23 +816,28 @@ public:
             return nsnull;
         }
     }
 
     PRBool SwapBuffers()
     {
         return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
     }
-
+    // GLContext interface - returns Tiled Texture Image in our case
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
                        PRBool aUseNearestFilter=PR_FALSE);
 
+    // a function to generate Tiles for Tiled Texture Image
+    virtual already_AddRefed<TextureImage>
+    TileGenFunc(const nsIntSize& aSize,
+                TextureImage::ContentType aContentType,
+                PRBool aUseNearestFilter = PR_FALSE);
     // hold a reference to the given surface
     // for the lifetime of this context.
     void HoldSurface(gfxASurface *aSurf) {
         mThebesSurface = aSurf;
     }
 
     void SetQtGLWidget(void *widget) {
         mGLWidget = widget;
@@ -1103,17 +1108,18 @@ class TextureImageEGL
     : public TextureImage
 {
 public:
     TextureImageEGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
                     GLContext* aContext)
-        : TextureImage(aTexture, aSize, aWrapMode, aContentType)
+        : TextureImage(aSize, aWrapMode, aContentType)
+        , mTexture(aTexture)
         , mGLContext(aContext)
         , mUpdateFormat(gfxASurface::ImageFormatUnknown)
         , mSurface(nsnull)
         , mConfig(nsnull)
         , mImageKHR(nsnull)
         , mCreated(PR_FALSE)
         , mBound(PR_FALSE)
         , mIsLocked(PR_FALSE)
@@ -1297,60 +1303,64 @@ public:
                                        GLTypeForImage(uploadImage->Format()),
                                        uploadImage->Data());
         }
 
         mUpdateSurface = nsnull;
         return;         // mTexture is bound
     }
 
-    virtual bool DirectUpdate(gfxASurface *aSurf, const nsIntRegion& aRegion)
+    virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
     {
         nsIntRect bounds = aRegion.GetBounds();
-  
+
         nsIntRegion region;
         if (!mCreated) {
             bounds = nsIntRect(0, 0, mSize.width, mSize.height);
             region = nsIntRegion(bounds);
         } else {
             region = aRegion;
         }
 
         if (mBackingSurface && sEGLLibrary.HasKHRLockSurface()) {
             mUpdateSurface = GetLockSurface();
             if (mUpdateSurface) {
                 nsRefPtr<gfxContext> ctx = new gfxContext(mUpdateSurface);
                 gfxUtils::ClipToRegion(ctx, aRegion);
-                ctx->SetSource(aSurf);
+                ctx->SetSource(aSurf, gfxPoint(-aFrom.x, -aFrom.y));
                 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
                 ctx->Paint();
                 mUpdateSurface = nsnull;
                 UnlockSurface();
             }
         } else {
             mShaderType =
               mGLContext->UploadSurfaceToTexture(aSurf,
                                                  region,
                                                  mTexture,
                                                  !mCreated,
-                                                 bounds.TopLeft(),
+                                                 bounds.TopLeft() + aFrom,
                                                  PR_FALSE);
         }
 
         mCreated = PR_TRUE;
         return true;
     }
 
     virtual void BindTexture(GLenum aTextureUnit)
     {
         mGLContext->fActiveTexture(aTextureUnit);
-        mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture());
+        mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
         mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
     }
 
+    virtual GLuint GetTextureID() {
+        return mTexture;
+    };
+
     virtual PRBool InUpdate() const { return !!mUpdateSurface; }
 
     virtual void Resize(const nsIntSize& aSize)
     {
         NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
 
         if (mSize == aSize && mCreated)
             return;
@@ -1571,45 +1581,55 @@ protected:
     GLContext* mGLContext;
 
     nsIntRect mUpdateRect;
     ImageFormat mUpdateFormat;
     nsRefPtr<gfxASurface> mBackingSurface;
     nsRefPtr<gfxASurface> mUpdateSurface;
     EGLSurface mSurface;
     EGLConfig mConfig;
+    GLuint mTexture;
     EGLImageKHR mImageKHR;
 
     PRPackedBool mCreated;
     PRPackedBool mBound;
     PRPackedBool mIsLocked;
 };
 
 already_AddRefed<TextureImage>
 GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
                                  PRBool aUseNearestFilter)
 {
+    nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType);
+    return t.forget();
+};
+
+already_AddRefed<TextureImage>
+GLContextEGL::TileGenFunc(const nsIntSize& aSize,
+                                 TextureImage::ContentType aContentType,
+                                 PRBool aUseNearestFilter)
+{
   MakeCurrent();
 
   GLuint texture;
   fGenTextures(1, &texture);
 
   fActiveTexture(LOCAL_GL_TEXTURE0);
   fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
 
   nsRefPtr<TextureImageEGL> teximage =
-      new TextureImageEGL(texture, aSize, aWrapMode, aContentType, this);
+      new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this);
 
   GLint texfilter = aUseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
   fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
   fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
-  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
-  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
+  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+  fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
   return teximage.forget();
 }
 
 static ContextFormat
 DepthToGLFormat(int aDepth)
 {
     switch (aDepth) {
--- a/gfx/thebes/GLContextProviderGLX.cpp
+++ b/gfx/thebes/GLContextProviderGLX.cpp
@@ -547,30 +547,31 @@ public:
         return mUpdateSurface;
     }
 
     virtual void EndUpdate()
     {
         mInUpdate = PR_FALSE;
     }
 
-    virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion)
+
+    virtual bool DirectUpdate(gfxASurface* aSurface, const nsIntRegion& aRegion, const nsIntPoint& aFrom)
     {
         nsRefPtr<gfxContext> ctx = new gfxContext(mUpdateSurface);
         gfxUtils::ClipToRegion(ctx, aRegion);
-        ctx->SetSource(aSurface);
+        ctx->SetSource(aSurface, aFrom);
         ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
         ctx->Paint();
         return true;
     }
 
     virtual void BindTexture(GLenum aTextureUnit)
     {
         mGLContext->fActiveTexture(aTextureUnit);
-        mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, Texture());
+        mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
         sGLXLibrary.BindTexImage(mPixmap);
         mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
     }
 
     virtual void ReleaseTexture()
     {
         sGLXLibrary.ReleaseTexImage(mPixmap);
     }
@@ -578,41 +579,47 @@ public:
     virtual already_AddRefed<gfxASurface> GetBackingSurface()
     {
         NS_ADDREF(mUpdateSurface);
         return mUpdateSurface.get();
     }
 
     virtual PRBool InUpdate() const { return mInUpdate; }
 
+    virtual GLuint GetTextureID() {
+        return mTexture;
+    };
+
 private:
    TextureImageGLX(GLuint aTexture,
                    const nsIntSize& aSize,
                    GLenum aWrapMode,
                    ContentType aContentType,
                    GLContext* aContext,
                    gfxASurface* aSurface,
                    GLXPixmap aPixmap)
-        : TextureImage(aTexture, aSize, aWrapMode, aContentType)
+        : TextureImage(aSize, aWrapMode, aContentType)
         , mGLContext(aContext)
         , mUpdateSurface(aSurface)
         , mPixmap(aPixmap)
         , mInUpdate(PR_FALSE)
+        , mTexture(aTexture)
     {
         if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA) {
             mShaderType = gl::RGBALayerProgramType;
         } else {
             mShaderType = gl::RGBXLayerProgramType;
         }
     }
 
     GLContext* mGLContext;
     nsRefPtr<gfxASurface> mUpdateSurface;
     GLXPixmap mPixmap;
     PRPackedBool mInUpdate;
+    GLuint mTexture;
 };
 
 already_AddRefed<TextureImage>
 GLContextGLX::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
                                  PRBool aUseNearestFilter)
 {
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -2068,18 +2068,17 @@ nsChildView::DrawOver(LayerManager* aMan
     mResizerImage->EndUpdate();
   }
 
   NS_ABORT_IF_FALSE(mResizerImage, "Must have a texture allocated by now!");
 
   float bottomX = aRect.x + aRect.width;
   float bottomY = aRect.y + aRect.height;
 
-  manager->gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
-  manager->gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mResizerImage->Texture());
+  TextureImage::ScopedBindTexture texBind(mResizerImage, LOCAL_GL_TEXTURE0);
 
   ColorTextureLayerProgram *program =
     manager->GetColorTextureLayerProgram(mResizerImage->GetShaderProgramType());
   program->Activate();
   program->SetLayerQuadRect(nsIntRect(bottomX - 15,
                                       bottomY - 15,
                                       15,
                                       15));