Bug 811958 - Move TextureImage to its own files - r=bgirard
☠☠ backed out by 7ca16b44a6db ☠ ☠
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 26 Nov 2012 12:51:58 -0800
changeset 114140 807f2c3df974408ecc0819219a4626ab04efb303
parent 114139 1637c39b4ed69b9bc07b8146e1e83d090b0fe545
child 114141 23582327333e1fbcd2d1196abc9e937ee53226fb
push id23907
push useremorley@mozilla.com
push dateTue, 27 Nov 2012 14:15:28 +0000
treeherdermozilla-central@532d0832c09d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbgirard
bugs811958
milestone20.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 811958 - Move TextureImage to its own files - r=bgirard
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLTextureImage.cpp
gfx/gl/GLTextureImage.h
gfx/gl/Makefile.in
widget/cocoa/nsChildView.mm
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -18,16 +18,18 @@
 #include "GLContextProvider.h"
 
 #include "gfxCrashReporterUtils.h"
 #include "gfxUtils.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Util.h" // for DebugOnly
 
+#include "GLTextureImage.h"
+
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace gl {
 
 #ifdef DEBUG
 unsigned GLContext::sCurrentGLContextTLS = -1;
 #endif
@@ -733,16 +735,29 @@ GLContext::CreateTextureImage(const nsIn
     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);
 
     return CreateBasicTextureImage(texture, aSize, aWrapMode, aContentType, this, aFlags);
 }
 
+already_AddRefed<TextureImage>
+GLContext::CreateBasicTextureImage(GLuint aTexture,
+                        const nsIntSize& aSize,
+                        GLenum aWrapMode,
+                        TextureImage::ContentType aContentType,
+                        GLContext* aContext,
+                        TextureImage::Flags aFlags)
+{
+    nsRefPtr<BasicTextureImage> teximage(
+        new BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags));
+    return teximage.forget();
+}
+
 void GLContext::ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter)
 {
     ApplyFilterToBoundTexture(LOCAL_GL_TEXTURE_2D, aFilter);
 }
 
 void GLContext::ApplyFilterToBoundTexture(GLuint aTarget,
                                           gfxPattern::GraphicsFilter aFilter)
 {
@@ -750,556 +765,16 @@ void GLContext::ApplyFilterToBoundTextur
         fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
         fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
     } else {
         fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
         fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
     }
 }
 
-BasicTextureImage::~BasicTextureImage()
-{
-    GLContext *ctx = mGLContext;
-    if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
-        ctx = ctx->GetSharedContext();
-    }
-
-    // If we have a context, then we need to delete the texture;
-    // if we don't have a context (either real or shared),
-    // then they went away when the contex was deleted, because it
-    // was the only one that had access to it.
-    if (ctx && !ctx->IsDestroyed()) {
-        mGLContext->MakeCurrent();
-        mGLContext->fDeleteTextures(1, &mTexture);
-    }
-}
-
-gfxASurface*
-BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
-{
-    NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
-
-    // determine the region the client will need to repaint
-    if (mGLContext->CanUploadSubTextures()) {
-        GetUpdateRegion(aRegion);
-    } else {
-        aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
-    }
-
-    mUpdateRegion = aRegion;
-
-    nsIntRect rgnSize = mUpdateRegion.GetBounds();
-    if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) {
-        NS_ERROR("update outside of image");
-        return NULL;
-    }
-
-    ImageFormat format =
-        (GetContentType() == gfxASurface::CONTENT_COLOR) ?
-        gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
-    mUpdateSurface =
-        GetSurfaceForUpdate(gfxIntSize(rgnSize.width, rgnSize.height), format);
-
-    if (!mUpdateSurface || mUpdateSurface->CairoStatus()) {
-        mUpdateSurface = NULL;
-        return NULL;
-    }
-
-    mUpdateSurface->SetDeviceOffset(gfxPoint(-rgnSize.x, -rgnSize.y));
-
-    return mUpdateSurface;
-}
-
-void
-BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
-{
-  // 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
-  if (mTextureState != Valid)
-      aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
-}
-
-void
-BasicTextureImage::EndUpdate()
-{
-    NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?");
-
-    // FIXME: this is the slow boat.  Make me fast (with GLXPixmap?).
-
-    // Undo the device offset that BeginUpdate set; doesn't much matter for us here,
-    // but important if we ever do anything directly with the surface.
-    mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0));
-
-    bool relative = FinishedSurfaceUpdate();
-
-    mShaderType =
-        mGLContext->UploadSurfaceToTexture(mUpdateSurface,
-                                           mUpdateRegion,
-                                           mTexture,
-                                           mTextureState == Created,
-                                           mUpdateOffset,
-                                           relative);
-    FinishedSurfaceUpload();
-
-    mUpdateSurface = nullptr;
-    mTextureState = Valid;
-}
-
-void
-BasicTextureImage::BindTexture(GLenum aTextureUnit)
-{
-    mGLContext->fActiveTexture(aTextureUnit);
-    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-    mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
-}
-
-void
-BasicTextureImage::ApplyFilter()
-{
-  mGLContext->ApplyFilterToBoundTexture(mFilter);
-}
-
-
-already_AddRefed<gfxASurface>
-BasicTextureImage::GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
-{
-    return gfxPlatform::GetPlatform()->
-        CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
-}
-
-bool
-BasicTextureImage::FinishedSurfaceUpdate()
-{
-    return false;
-}
-
-void
-BasicTextureImage::FinishedSurfaceUpload()
-{
-}
-
-bool 
-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() + aFrom,
-                                           false);
-    mTextureState = Valid;
-    return true;
-}
-
-void
-BasicTextureImage::Resize(const nsIntSize& aSize)
-{
-    NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
-
-    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-
-    mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
-                            0,
-                            LOCAL_GL_RGBA,
-                            aSize.width,
-                            aSize.height,
-                            0,
-                            LOCAL_GL_RGBA,
-                            LOCAL_GL_UNSIGNED_BYTE,
-                            NULL);
-
-    mTextureState = Allocated;
-    mSize = aSize;
-}
-
-TiledTextureImage::TiledTextureImage(GLContext* aGL,
-                                     nsIntSize aSize,
-                                     TextureImage::ContentType aContentType,
-                                     TextureImage::Flags aFlags)
-    : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
-    , mCurrentImage(0)
-    , mIterationCallback(nullptr)
-    , mInUpdate(false)
-    , mRows(0)
-    , mColumns(0)
-    , mGL(aGL)
-    , mTextureState(Created)
-{
-    mTileSize = (!(aFlags & TextureImage::ForceSingleTile) && mGL->WantsSmallTiles())
-        ? 256 : 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) */)
-{
-    nsIntRegion region;
-
-    if (mTextureState != Valid) {
-        nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
-        region = nsIntRegion(bounds);
-    } else {
-        region = aRegion;
-    }
-
-    bool result = true;
-    int oldCurrentImage = mCurrentImage;
-    BeginTileIteration();
-    do {
-        nsIntRect tileRect = GetSrcTileRect();
-        int xPos = tileRect.x;
-        int yPos = tileRect.y;
-
-        nsIntRegion tileRegion;
-        tileRegion.And(region, tileRect); // intersect with tile
-
-        if (tileRegion.IsEmpty())
-            continue;
-
-        if (mGL->CanUploadSubTextures()) {
-          tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
-        } else {
-          // If sub-textures are unsupported, expand to tile boundaries
-          tileRect.x = tileRect.y = 0;
-          tileRegion = nsIntRegion(tileRect);
-        }
-
-        result &= mImages[mCurrentImage]->
-          DirectUpdate(aSurf, tileRegion, aFrom + nsIntPoint(xPos, yPos));
-
-        if (mCurrentImage == mImages.Length() - 1) {
-            // We know we're done, but we still need to ensure that the callback
-            // gets called (e.g. to update the uploaded region).
-            NextTile();
-            break;
-        }
-        // Override a callback cancelling iteration if the texture wasn't valid.
-        // We need to force the update in that situation, or we may end up
-        // showing invalid/out-of-date texture data.
-    } while (NextTile() || (mTextureState != Valid));
-    mCurrentImage = oldCurrentImage;
-
-    mShaderType = mImages[0]->GetShaderProgramType();
-    mTextureState = Valid;
-    return result;
-}
-
-void
-TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
-{
-    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
-        aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
-        return;
-    }
-
-    nsIntRegion newRegion;
-
-    // We need to query each texture with the region it will be drawing and
-    // set aForRegion to be the combination of all of these regions
-    for (unsigned i = 0; i < mImages.Length(); i++) {
-        int xPos = (i % mColumns) * mTileSize;
-        int yPos = (i / mColumns) * mTileSize;
-        nsIntRect imageRect = nsIntRect(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
-
-        if (aForRegion.Intersects(imageRect)) {
-            // Make a copy of the region
-            nsIntRegion subRegion;
-            subRegion.And(aForRegion, imageRect);
-            // Translate it into tile-space
-            subRegion.MoveBy(-xPos, -yPos);
-            // Query region
-            mImages[i]->GetUpdateRegion(subRegion);
-            // Translate back
-            subRegion.MoveBy(xPos, yPos);
-            // Add to the accumulated region
-            newRegion.Or(newRegion, subRegion);
-        }
-    }
-
-    aForRegion = newRegion;
-}
-
-gfxASurface*
-TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
-{
-    NS_ASSERTION(!mInUpdate, "nested update");
-    mInUpdate = true;
-
-    // Note, we don't call GetUpdateRegion here as if the updated region is
-    // fully contained in a single tile, we get to avoid iterating through
-    // the tiles again (and a little copying).
-    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
-        aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
-    }
-
-    nsIntRect bounds = aRegion.GetBounds();
-
-    for (unsigned i = 0; i < mImages.Length(); i++) {
-        int xPos = (i % mColumns) * mTileSize;
-        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);
-            // Correct the device offset
-            gfxPoint offset = surface->GetDeviceOffset();
-            surface->SetDeviceOffset(gfxPoint(offset.x - xPos,
-                                              offset.y - yPos));
-            // we don't have a temp surface
-            mUpdateSurface = nullptr;
-            // remember which image to EndUpdate
-            mCurrentImage = i;
-            return surface.get();
-        }
-    }
-
-    // Get the real updated region, taking into account the capabilities of
-    // each TextureImage tile
-    GetUpdateRegion(aRegion);
-    mUpdateRegion = aRegion;
-    bounds = aRegion.GetBounds();
-
-    // update covers multiple Images - create a temp surface to paint in
-    gfxASurface::gfxImageFormat format =
-        (GetContentType() == gfxASurface::CONTENT_COLOR) ?
-        gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
-    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 = false;
-        mTextureState = Valid;
-        mShaderType = mImages[mCurrentImage]->GetShaderProgramType();
-        return;
-    }
-
-    // upload tiles from temp surface
-    for (unsigned i = 0; i < mImages.Length(); i++) {
-        int xPos = (i % mColumns) * mTileSize;
-        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 = nullptr;
-    mInUpdate = false;
-    mShaderType = mImages[0]->GetShaderProgramType();
-    mTextureState = Valid;
-}
-
-void TiledTextureImage::BeginTileIteration()
-{
-    mCurrentImage = 0;
-}
-
-bool TiledTextureImage::NextTile()
-{
-    bool continueIteration = true;
-
-    if (mIterationCallback)
-        continueIteration = mIterationCallback(this, mCurrentImage,
-                                               mIterationCallbackData);
-
-    if (mCurrentImage + 1 < mImages.Length()) {
-        mCurrentImage++;
-        return continueIteration;
-    }
-    return false;
-}
-
-void TiledTextureImage::SetIterationCallback(TileIterationCallback aCallback,
-                                             void* aCallbackData)
-{
-    mIterationCallback = aCallback;
-    mIterationCallbackData = aCallbackData;
-}
-
-nsIntRect TiledTextureImage::GetTileRect()
-{
-    nsIntRect rect = mImages[mCurrentImage]->GetTileRect();
-    unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
-    unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
-    rect.MoveBy(xPos, yPos);
-    return rect;
-}
-
-nsIntRect TiledTextureImage::GetSrcTileRect()
-{
-    nsIntRect rect = GetTileRect();
-    unsigned int srcY = mFlags & NeedsYFlip
-                        ? mSize.height - rect.height - rect.y
-                        : rect.y;
-    return nsIntRect(rect.x, srcY, rect.width, rect.height);
-}
-
-void
-TiledTextureImage::BindTexture(GLenum aTextureUnit)
-{
-    mImages[mCurrentImage]->BindTexture(aTextureUnit);
-}
-
-void
-TiledTextureImage::ApplyFilter()
-{
-   mGL->ApplyFilterToBoundTexture(mFilter);
-}
-
-/*
- * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per
- * column. A tile on a column is reused if it hasn't changed size, otherwise it
- * is discarded/replaced. Extra tiles on a column are pruned after iterating
- * each column, and extra rows are pruned after iteration over the entire image
- * finishes.
- */
-void TiledTextureImage::Resize(const nsIntSize& aSize)
-{
-    if (mSize == aSize && mTextureState != Created) {
-        return;
-    }
-
-    // calculate rows and columns, rounding up
-    unsigned int columns = (aSize.width  + mTileSize - 1) / mTileSize;
-    unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize;
-
-    // Iterate over old tile-store and insert/remove tiles as necessary
-    int row;
-    unsigned int i = 0;
-    for (row = 0; row < (int)rows; row++) {
-        // If we've gone beyond how many rows there were before, set mColumns to
-        // zero so that we only create new tiles.
-        if (row >= (int)mRows)
-            mColumns = 0;
-
-        // Similarly, if we're on the last row of old tiles and the height has
-        // changed, discard all tiles in that row.
-        // This will cause the pruning of columns not to work, but we don't need
-        // to worry about that, as no more tiles will be reused past this point
-        // anyway.
-        if ((row == (int)mRows - 1) && (aSize.height != mSize.height))
-            mColumns = 0;
-
-        int col;
-        for (col = 0; col < (int)columns; 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);
-
-            bool replace = false;
-
-            // Check if we can re-use old tiles.
-            if (col < (int)mColumns) {
-                // Reuse an existing tile. If the tile is an end-tile and the
-                // width differs, replace it instead.
-                if (mSize.width != aSize.width) {
-                    if (col == (int)mColumns - 1) {
-                        // Tile at the end of the old column, replace it with
-                        // a new one.
-                        replace = true;
-                    } else if (col == (int)columns - 1) {
-                        // Tile at the end of the new column, create a new one.
-                    } else {
-                        // Before the last column on both the old and new sizes,
-                        // reuse existing tile.
-                        i++;
-                        continue;
-                    }
-                } else {
-                    // Width hasn't changed, reuse existing tile.
-                    i++;
-                    continue;
-                }
-            }
-
-            // Create a new tile.
-            nsRefPtr<TextureImage> teximg =
-                    mGL->TileGenFunc(size, mContentType, mFlags);
-            if (replace)
-                mImages.ReplaceElementAt(i, teximg.forget());
-            else
-                mImages.InsertElementAt(i, teximg.forget());
-            i++;
-        }
-
-        // Prune any unused tiles on the end of the column.
-        if (row < (int)mRows) {
-            for (col = (int)mColumns - col; col > 0; col--) {
-                mImages.RemoveElementAt(i);
-            }
-        }
-    }
-
-    // Prune any unused tiles at the end of the store.
-    unsigned int length = mImages.Length();
-    for (; i < length; i++)
-      mImages.RemoveElementAt(mImages.Length()-1);
-
-    // Reset tile-store properties.
-    mRows = rows;
-    mColumns = columns;
-    mSize = aSize;
-    mTextureState = Allocated;
-    mCurrentImage = 0;
-}
-
-uint32_t TiledTextureImage::GetTileCount()
-{
-    return mImages.Length();
-}
 
 GLContext::GLFormats
 GLContext::ChooseGLFormats(ContextFormat& aCF, ColorByteOrder aByteOrder)
 {
     GLFormats formats;
 
     // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less
     // OR we don't support full 8-bit color, return a 4444 or 565 format.
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -28,16 +28,17 @@
 #include "prlink.h"
 
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsRegion.h"
 #include "nsAutoPtr.h"
 #include "nsThreadUtils.h"
 #include "GLContextTypes.h"
+#include "GLTextureImage.h"
 
 typedef char realGLboolean;
 
 #include "GLContextSymbols.h"
 
 #include "mozilla/mozalloc.h"
 #include "mozilla/Preferences.h"
 
@@ -51,378 +52,16 @@ namespace mozilla {
     class ColorTextureLayerProgram;
   }
 
 namespace gl {
 class GLContext;
 
 typedef uintptr_t SharedTextureHandle;
 
-/**
- * A TextureImage encapsulates a surface that can be drawn to by a
- * Thebes gfxContext and (hopefully efficiently!) synchronized to a
- * texture in the server.  TextureImages are associated with one and
- * only one GLContext.
- *
- * Implementation note: TextureImages attempt to unify two categories
- * of backends
- *
- *  (1) proxy to server-side object that can be bound to a texture;
- *      e.g. Pixmap on X11.
- *
- *  (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.
-    };
-
-    enum Flags {
-        NoFlags          = 0x0,
-        UseNearestFilter = 0x1,
-        NeedsYFlip       = 0x2,
-        ForceSingleTile  = 0x4
-    };
-
-    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
-     * the update begins successfully, the returned gfxASurface is
-     * owned by this.  Otherwise, NULL is returned.
-     *
-     * |aRegion| is an inout param: the returned region is what the
-     * client must repaint.  Category (1) regions above can
-     * efficiently handle repaints to "scattered" regions, while (2)
-     * can only efficiently handle repaints to rects.
-     *
-     * Painting the returned surface outside of |aRegion| results 
-     * in undefined behavior.
-     *
-     * BeginUpdate() calls cannot be "nested", and each successful
-     * BeginUpdate() must be followed by exactly one EndUpdate() (see
-     * below).  Failure to do so can leave this in a possibly
-     * inconsistent state.  Unsuccessful BeginUpdate()s must not be
-     * followed by EndUpdate().
-     */
-    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion) = 0;
-    /**
-     * Retrieves the region that will require updating, given a
-     * region that needs to be updated. This can be used for
-     * making decisions about updating before calling BeginUpdate().
-     *
-     * |aRegion| is an inout param.
-     */
-    virtual void GetUpdateRegion(nsIntRegion& aForRegion) {
-    }
-    /**
-     * Finish the active update and synchronize with the server, if
-     * 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 bool NextTile() {
-        return false;
-    }
-
-    // Function prototype for a tile iteration callback. Returning false will
-    // cause iteration to be interrupted (i.e. the corresponding NextTile call
-    // will return false).
-    typedef bool (* TileIterationCallback)(TextureImage* aImage,
-                                           int aTileNumber,
-                                           void* aCallbackData);
-
-    // Sets a callback to be called every time NextTile is called.
-    virtual void SetIterationCallback(TileIterationCallback aCallback,
-                                      void* aCallbackData) {
-    }
-
-    virtual nsIntRect GetTileRect() {
-        return nsIntRect(nsIntPoint(0,0), mSize);
-    }
-
-    virtual GLuint GetTextureID() = 0;
-
-    virtual uint32_t GetTileCount() {
-        return 1;
-    }
-
-    /**
-     * 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();
-    }
-
-    /**
-     * Mark this texture as having valid contents. Call this after modifying
-     * the texture contents externally.
-     */
-    virtual void MarkValid() {}
-
-    /**
-     * 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() {}
-
-    void BindTextureAndApplyFilter(GLenum aTextureUnit) {
-        BindTexture(aTextureUnit);
-        ApplyFilter();
-    }
-
-    class ScopedBindTexture
-    {
-    public:
-        ScopedBindTexture(TextureImage *aTexture, GLenum aTextureUnit) :
-          mTexture(aTexture)
-        {
-            if (mTexture) {
-                mTexture->BindTexture(aTextureUnit);
-            }
-        }
-
-        ~ScopedBindTexture()
-        {
-            if (mTexture) {
-                mTexture->ReleaseTexture();
-            }       
-        }
-
-    protected:
-        TextureImage *mTexture;
-    };
-
-    class ScopedBindTextureAndApplyFilter
-        : public ScopedBindTexture
-    {
-    public:
-        ScopedBindTextureAndApplyFilter(TextureImage *aTexture, GLenum aTextureUnit) :
-          ScopedBindTexture(aTexture, aTextureUnit)
-        {
-            if (mTexture) {
-                mTexture->ApplyFilter();
-            }
-        }
-    };
-
-    /**
-     * 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()
-    {
-         return mShaderType;
-    }
-
-    /** Can be called safely at any time. */
-
-    /**
-     * If this TextureImage has a permanent gfxASurface backing,
-     * return it.  Otherwise return NULL.
-     */
-    virtual already_AddRefed<gfxASurface> GetBackingSurface()
-    { return NULL; }
-
-    const nsIntSize& GetSize() const { return mSize; }
-    ContentType GetContentType() const { return mContentType; }
-    virtual bool InUpdate() const = 0;
-    GLenum GetWrapMode() const { return mWrapMode; }
-
-    void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
-
-    /**
-     * Applies this TextureImage's filter, assuming that its texture is
-     * the currently bound texture.
-     */
-    virtual void ApplyFilter() = 0;
-
-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(const nsIntSize& aSize,
-                 GLenum aWrapMode, ContentType aContentType,
-                 Flags aFlags = NoFlags)
-        : mSize(aSize)
-        , mWrapMode(aWrapMode)
-        , mContentType(aContentType)
-        , mFilter(gfxPattern::FILTER_GOOD)
-        , mFlags(aFlags)
-    {}
-
-    virtual nsIntRect GetSrcTileRect() {
-        return nsIntRect(nsIntPoint(0,0), mSize);
-    }
-
-    nsIntSize mSize;
-    GLenum mWrapMode;
-    ContentType mContentType;
-    ShaderProgramType mShaderType;
-    gfxPattern::GraphicsFilter mFilter;
-    Flags mFlags;
-};
-
-/**
- * BasicTextureImage is the baseline TextureImage implementation ---
- * it updates its texture by allocating a scratch buffer for the
- * client to draw into, then using glTexSubImage2D() to upload the new
- * pixels.  Platforms must provide the code to create a new surface
- * into which the updated pixels will be drawn, and the code to
- * convert the update surface's pixels into an image on which we can
- * glTexSubImage2D().
- */
-class BasicTextureImage
-    : public TextureImage
-{
-public:
-    typedef gfxASurface::gfxImageFormat ImageFormat;
-    virtual ~BasicTextureImage();
-
-    BasicTextureImage(GLuint aTexture,
-                      const nsIntSize& aSize,
-                      GLenum aWrapMode,
-                      ContentType aContentType,
-                      GLContext* aContext,
-                      TextureImage::Flags aFlags = TextureImage::NoFlags)
-        : TextureImage(aSize, aWrapMode, aContentType, aFlags)
-        , mTexture(aTexture)
-        , mTextureState(Created)
-        , mGLContext(aContext)
-        , mUpdateOffset(0, 0)
-    {}
-
-    virtual void BindTexture(GLenum aTextureUnit);
-
-    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
-    virtual void GetUpdateRegion(nsIntRegion& aForRegion);
-    virtual void EndUpdate();
-    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);
-
-    virtual void MarkValid() { mTextureState = Valid; }
-
-    // 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();
-
-    // Call after surface data has been uploaded to a texture.
-    virtual void FinishedSurfaceUpload();
-
-    virtual bool InUpdate() const { return !!mUpdateSurface; }
-
-    virtual void Resize(const nsIntSize& aSize);
-
-    virtual void ApplyFilter();
-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, TextureImage::Flags aFlags = TextureImage::NoFlags);
-    ~TiledTextureImage();
-    void DumpDiv();
-    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
-    virtual void GetUpdateRegion(nsIntRegion& aForRegion);
-    virtual void EndUpdate();
-    virtual void Resize(const nsIntSize& aSize);
-    virtual uint32_t GetTileCount();
-    virtual void BeginTileIteration();
-    virtual bool NextTile();
-    virtual void SetIterationCallback(TileIterationCallback aCallback,
-                                      void* aCallbackData);
-    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 bool InUpdate() const { return mInUpdate; }
-    virtual void BindTexture(GLenum);
-    virtual void ApplyFilter();
-
-protected:
-    virtual nsIntRect GetSrcTileRect();
-
-    unsigned int mCurrentImage;
-    TileIterationCallback mIterationCallback;
-    void* mIterationCallbackData;
-    nsTArray< nsRefPtr<TextureImage> > mImages;
-    bool mInUpdate;
-    nsIntSize mSize;
-    unsigned int mTileSize;
-    unsigned int mRows, mColumns;
-    GLContext* mGL;
-    // 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,
@@ -1922,22 +1561,17 @@ protected:
     void InitExtensions();
 
     virtual already_AddRefed<TextureImage>
     CreateBasicTextureImage(GLuint aTexture,
                             const nsIntSize& aSize,
                             GLenum aWrapMode,
                             TextureImage::ContentType aContentType,
                             GLContext* aContext,
-                            TextureImage::Flags aFlags = TextureImage::NoFlags)
-    {
-        nsRefPtr<BasicTextureImage> teximage(
-            new BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags));
-        return teximage.forget();
-    }
+                            TextureImage::Flags aFlags = TextureImage::NoFlags);
 
     bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const {
         int32_t biggerDimension = NS_MAX(aSize.width, aSize.height);
         int32_t maxAllowed = NS_MIN(mMaxRenderbufferSize, mMaxTextureSize);
         return biggerDimension <= maxAllowed;
     }
 
     nsTArray<nsIntRect> mViewportStack;
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -1067,16 +1067,17 @@ bool GLContextEGL::AttachSharedHandle(Sh
     default:
         NS_ERROR("Unknown shared handle type");
         return false;
     }
 
     return true;
 }
 
+
 bool
 GLContextEGL::BindTex2DOffscreen(GLContext *aOffscreen)
 {
     if (aOffscreen->GetContextType() != ContextTypeEGL) {
         NS_WARNING("non-EGL context");
         return false;
     }
 
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLTextureImage.cpp
@@ -0,0 +1,573 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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 "GLTextureImage.h"
+#include "GLContext.h"
+#include "gfxContext.h"
+#include "gfxPlatform.h"
+#include "gfxUtils.h"
+
+using namespace mozilla::gl;
+
+already_AddRefed<TextureImage>
+TextureImage::Create(GLContext* gl,
+                     const nsIntSize& size,
+                     TextureImage::ContentType contentType,
+                     GLenum wrapMode,
+                     TextureImage::Flags flags)
+{
+    return gl->CreateTextureImage(size, contentType, wrapMode, flags);
+}
+
+BasicTextureImage::~BasicTextureImage()
+{
+    GLContext *ctx = mGLContext;
+    if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
+        ctx = ctx->GetSharedContext();
+    }
+
+    // If we have a context, then we need to delete the texture;
+    // if we don't have a context (either real or shared),
+    // then they went away when the contex was deleted, because it
+    // was the only one that had access to it.
+    if (ctx && !ctx->IsDestroyed()) {
+        mGLContext->MakeCurrent();
+        mGLContext->fDeleteTextures(1, &mTexture);
+    }
+}
+
+gfxASurface*
+BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
+{
+    NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
+
+    // determine the region the client will need to repaint
+    if (mGLContext->CanUploadSubTextures()) {
+        GetUpdateRegion(aRegion);
+    } else {
+        aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
+    }
+
+    mUpdateRegion = aRegion;
+
+    nsIntRect rgnSize = mUpdateRegion.GetBounds();
+    if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) {
+        NS_ERROR("update outside of image");
+        return NULL;
+    }
+
+    ImageFormat format =
+        (GetContentType() == gfxASurface::CONTENT_COLOR) ?
+        gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
+    mUpdateSurface =
+        GetSurfaceForUpdate(gfxIntSize(rgnSize.width, rgnSize.height), format);
+
+    if (!mUpdateSurface || mUpdateSurface->CairoStatus()) {
+        mUpdateSurface = NULL;
+        return NULL;
+    }
+
+    mUpdateSurface->SetDeviceOffset(gfxPoint(-rgnSize.x, -rgnSize.y));
+
+    return mUpdateSurface;
+}
+
+void
+BasicTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
+{
+  // 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
+  if (mTextureState != Valid)
+      aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
+}
+
+void
+BasicTextureImage::EndUpdate()
+{
+    NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?");
+
+    // FIXME: this is the slow boat.  Make me fast (with GLXPixmap?).
+
+    // Undo the device offset that BeginUpdate set; doesn't much matter for us here,
+    // but important if we ever do anything directly with the surface.
+    mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0));
+
+    bool relative = FinishedSurfaceUpdate();
+
+    mShaderType =
+        mGLContext->UploadSurfaceToTexture(mUpdateSurface,
+                                           mUpdateRegion,
+                                           mTexture,
+                                           mTextureState == Created,
+                                           mUpdateOffset,
+                                           relative);
+    FinishedSurfaceUpload();
+
+    mUpdateSurface = nullptr;
+    mTextureState = Valid;
+}
+
+void
+BasicTextureImage::BindTexture(GLenum aTextureUnit)
+{
+    mGLContext->fActiveTexture(aTextureUnit);
+    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+    mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
+}
+
+void
+BasicTextureImage::ApplyFilter()
+{
+  mGLContext->ApplyFilterToBoundTexture(mFilter);
+}
+
+
+already_AddRefed<gfxASurface>
+BasicTextureImage::GetSurfaceForUpdate(const gfxIntSize& aSize, ImageFormat aFmt)
+{
+    return gfxPlatform::GetPlatform()->
+        CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
+}
+
+bool
+BasicTextureImage::FinishedSurfaceUpdate()
+{
+    return false;
+}
+
+void
+BasicTextureImage::FinishedSurfaceUpload()
+{
+}
+
+bool
+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() + aFrom,
+                                           false);
+    mTextureState = Valid;
+    return true;
+}
+
+void
+BasicTextureImage::Resize(const nsIntSize& aSize)
+{
+    NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
+
+    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
+
+    mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
+                            0,
+                            LOCAL_GL_RGBA,
+                            aSize.width,
+                            aSize.height,
+                            0,
+                            LOCAL_GL_RGBA,
+                            LOCAL_GL_UNSIGNED_BYTE,
+                            NULL);
+
+    mTextureState = Allocated;
+    mSize = aSize;
+}
+
+TiledTextureImage::TiledTextureImage(GLContext* aGL,
+                                     nsIntSize aSize,
+                                     TextureImage::ContentType aContentType,
+                                     TextureImage::Flags aFlags)
+    : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
+    , mCurrentImage(0)
+    , mIterationCallback(nullptr)
+    , mInUpdate(false)
+    , mRows(0)
+    , mColumns(0)
+    , mGL(aGL)
+    , mTextureState(Created)
+{
+    mTileSize = (!(aFlags & TextureImage::ForceSingleTile) && mGL->WantsSmallTiles())
+        ? 256 : 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) */)
+{
+    nsIntRegion region;
+
+    if (mTextureState != Valid) {
+        nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
+        region = nsIntRegion(bounds);
+    } else {
+        region = aRegion;
+    }
+
+    bool result = true;
+    int oldCurrentImage = mCurrentImage;
+    BeginTileIteration();
+    do {
+        nsIntRect tileRect = GetSrcTileRect();
+        int xPos = tileRect.x;
+        int yPos = tileRect.y;
+
+        nsIntRegion tileRegion;
+        tileRegion.And(region, tileRect); // intersect with tile
+
+        if (tileRegion.IsEmpty())
+            continue;
+
+        if (mGL->CanUploadSubTextures()) {
+          tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space
+        } else {
+          // If sub-textures are unsupported, expand to tile boundaries
+          tileRect.x = tileRect.y = 0;
+          tileRegion = nsIntRegion(tileRect);
+        }
+
+        result &= mImages[mCurrentImage]->
+          DirectUpdate(aSurf, tileRegion, aFrom + nsIntPoint(xPos, yPos));
+
+        if (mCurrentImage == mImages.Length() - 1) {
+            // We know we're done, but we still need to ensure that the callback
+            // gets called (e.g. to update the uploaded region).
+            NextTile();
+            break;
+        }
+        // Override a callback cancelling iteration if the texture wasn't valid.
+        // We need to force the update in that situation, or we may end up
+        // showing invalid/out-of-date texture data.
+    } while (NextTile() || (mTextureState != Valid));
+    mCurrentImage = oldCurrentImage;
+
+    mShaderType = mImages[0]->GetShaderProgramType();
+    mTextureState = Valid;
+    return result;
+}
+
+void
+TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion)
+{
+    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
+        aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
+        return;
+    }
+
+    nsIntRegion newRegion;
+
+    // We need to query each texture with the region it will be drawing and
+    // set aForRegion to be the combination of all of these regions
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        int xPos = (i % mColumns) * mTileSize;
+        int yPos = (i / mColumns) * mTileSize;
+        nsIntRect imageRect = nsIntRect(nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()));
+
+        if (aForRegion.Intersects(imageRect)) {
+            // Make a copy of the region
+            nsIntRegion subRegion;
+            subRegion.And(aForRegion, imageRect);
+            // Translate it into tile-space
+            subRegion.MoveBy(-xPos, -yPos);
+            // Query region
+            mImages[i]->GetUpdateRegion(subRegion);
+            // Translate back
+            subRegion.MoveBy(xPos, yPos);
+            // Add to the accumulated region
+            newRegion.Or(newRegion, subRegion);
+        }
+    }
+
+    aForRegion = newRegion;
+}
+
+gfxASurface*
+TiledTextureImage::BeginUpdate(nsIntRegion& aRegion)
+{
+    NS_ASSERTION(!mInUpdate, "nested update");
+    mInUpdate = true;
+
+    // Note, we don't call GetUpdateRegion here as if the updated region is
+    // fully contained in a single tile, we get to avoid iterating through
+    // the tiles again (and a little copying).
+    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
+        aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
+    }
+
+    nsIntRect bounds = aRegion.GetBounds();
+
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        int xPos = (i % mColumns) * mTileSize;
+        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);
+            // Correct the device offset
+            gfxPoint offset = surface->GetDeviceOffset();
+            surface->SetDeviceOffset(gfxPoint(offset.x - xPos,
+                                              offset.y - yPos));
+            // we don't have a temp surface
+            mUpdateSurface = nullptr;
+            // remember which image to EndUpdate
+            mCurrentImage = i;
+            return surface.get();
+        }
+    }
+
+    // Get the real updated region, taking into account the capabilities of
+    // each TextureImage tile
+    GetUpdateRegion(aRegion);
+    mUpdateRegion = aRegion;
+    bounds = aRegion.GetBounds();
+
+    // update covers multiple Images - create a temp surface to paint in
+    gfxASurface::gfxImageFormat format =
+        (GetContentType() == gfxASurface::CONTENT_COLOR) ?
+        gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
+    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 = false;
+        mTextureState = Valid;
+        mShaderType = mImages[mCurrentImage]->GetShaderProgramType();
+        return;
+    }
+
+    // upload tiles from temp surface
+    for (unsigned i = 0; i < mImages.Length(); i++) {
+        int xPos = (i % mColumns) * mTileSize;
+        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 = nullptr;
+    mInUpdate = false;
+    mShaderType = mImages[0]->GetShaderProgramType();
+    mTextureState = Valid;
+}
+
+void TiledTextureImage::BeginTileIteration()
+{
+    mCurrentImage = 0;
+}
+
+bool TiledTextureImage::NextTile()
+{
+    bool continueIteration = true;
+
+    if (mIterationCallback)
+        continueIteration = mIterationCallback(this, mCurrentImage,
+                                               mIterationCallbackData);
+
+    if (mCurrentImage + 1 < mImages.Length()) {
+        mCurrentImage++;
+        return continueIteration;
+    }
+    return false;
+}
+
+void TiledTextureImage::SetIterationCallback(TileIterationCallback aCallback,
+                                             void* aCallbackData)
+{
+    mIterationCallback = aCallback;
+    mIterationCallbackData = aCallbackData;
+}
+
+nsIntRect TiledTextureImage::GetTileRect()
+{
+    nsIntRect rect = mImages[mCurrentImage]->GetTileRect();
+    unsigned int xPos = (mCurrentImage % mColumns) * mTileSize;
+    unsigned int yPos = (mCurrentImage / mColumns) * mTileSize;
+    rect.MoveBy(xPos, yPos);
+    return rect;
+}
+
+nsIntRect TiledTextureImage::GetSrcTileRect()
+{
+    nsIntRect rect = GetTileRect();
+    unsigned int srcY = mFlags & NeedsYFlip
+                        ? mSize.height - rect.height - rect.y
+                        : rect.y;
+    return nsIntRect(rect.x, srcY, rect.width, rect.height);
+}
+
+void
+TiledTextureImage::BindTexture(GLenum aTextureUnit)
+{
+    mImages[mCurrentImage]->BindTexture(aTextureUnit);
+}
+
+void
+TiledTextureImage::ApplyFilter()
+{
+   mGL->ApplyFilterToBoundTexture(mFilter);
+}
+
+/*
+ * Resize, trying to reuse tiles. The reuse strategy is to decide on reuse per
+ * column. A tile on a column is reused if it hasn't changed size, otherwise it
+ * is discarded/replaced. Extra tiles on a column are pruned after iterating
+ * each column, and extra rows are pruned after iteration over the entire image
+ * finishes.
+ */
+void TiledTextureImage::Resize(const nsIntSize& aSize)
+{
+    if (mSize == aSize && mTextureState != Created) {
+        return;
+    }
+
+    // calculate rows and columns, rounding up
+    unsigned int columns = (aSize.width  + mTileSize - 1) / mTileSize;
+    unsigned int rows = (aSize.height + mTileSize - 1) / mTileSize;
+
+    // Iterate over old tile-store and insert/remove tiles as necessary
+    int row;
+    unsigned int i = 0;
+    for (row = 0; row < (int)rows; row++) {
+        // If we've gone beyond how many rows there were before, set mColumns to
+        // zero so that we only create new tiles.
+        if (row >= (int)mRows)
+            mColumns = 0;
+
+        // Similarly, if we're on the last row of old tiles and the height has
+        // changed, discard all tiles in that row.
+        // This will cause the pruning of columns not to work, but we don't need
+        // to worry about that, as no more tiles will be reused past this point
+        // anyway.
+        if ((row == (int)mRows - 1) && (aSize.height != mSize.height))
+            mColumns = 0;
+
+        int col;
+        for (col = 0; col < (int)columns; 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);
+
+            bool replace = false;
+
+            // Check if we can re-use old tiles.
+            if (col < (int)mColumns) {
+                // Reuse an existing tile. If the tile is an end-tile and the
+                // width differs, replace it instead.
+                if (mSize.width != aSize.width) {
+                    if (col == (int)mColumns - 1) {
+                        // Tile at the end of the old column, replace it with
+                        // a new one.
+                        replace = true;
+                    } else if (col == (int)columns - 1) {
+                        // Tile at the end of the new column, create a new one.
+                    } else {
+                        // Before the last column on both the old and new sizes,
+                        // reuse existing tile.
+                        i++;
+                        continue;
+                    }
+                } else {
+                    // Width hasn't changed, reuse existing tile.
+                    i++;
+                    continue;
+                }
+            }
+
+            // Create a new tile.
+            nsRefPtr<TextureImage> teximg =
+                    mGL->TileGenFunc(size, mContentType, mFlags);
+            if (replace)
+                mImages.ReplaceElementAt(i, teximg.forget());
+            else
+                mImages.InsertElementAt(i, teximg.forget());
+            i++;
+        }
+
+        // Prune any unused tiles on the end of the column.
+        if (row < (int)mRows) {
+            for (col = (int)mColumns - col; col > 0; col--) {
+                mImages.RemoveElementAt(i);
+            }
+        }
+    }
+
+    // Prune any unused tiles at the end of the store.
+    unsigned int length = mImages.Length();
+    for (; i < length; i++)
+      mImages.RemoveElementAt(mImages.Length()-1);
+
+    // Reset tile-store properties.
+    mRows = rows;
+    mColumns = columns;
+    mSize = aSize;
+    mTextureState = Allocated;
+    mCurrentImage = 0;
+}
+
+uint32_t TiledTextureImage::GetTileCount()
+{
+    return mImages.Length();
+}
+
+TextureImage::ScopedBindTexture::ScopedBindTexture(TextureImage* aTexture,
+                                                   GLenum aTextureUnit)
+    : mTexture(aTexture)
+{
+    if (mTexture) {
+        MOZ_ASSERT(aTextureUnit >= LOCAL_GL_TEXTURE0);
+        mTexture->BindTexture(aTextureUnit);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/gl/GLTextureImage.h
@@ -0,0 +1,385 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* 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 GLTEXTUREIMAGE_H_
+#define GLTEXTUREIMAGE_H_
+
+#include "nsAutoPtr.h"
+#include "nsRegion.h"
+#include "gfxASurface.h"
+#include "GLContextTypes.h"
+#include "gfxPattern.h"
+
+namespace mozilla {
+namespace gl {
+class GLContext;
+
+/**
+ * A TextureImage encapsulates a surface that can be drawn to by a
+ * Thebes gfxContext and (hopefully efficiently!) synchronized to a
+ * texture in the server.  TextureImages are associated with one and
+ * only one GLContext.
+ *
+ * Implementation note: TextureImages attempt to unify two categories
+ * of backends
+ *
+ *  (1) proxy to server-side object that can be bound to a texture;
+ *      e.g. Pixmap on X11.
+ *
+ *  (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.
+    };
+
+    enum Flags {
+        NoFlags          = 0x0,
+        UseNearestFilter = 0x1,
+        NeedsYFlip       = 0x2,
+        ForceSingleTile  = 0x4
+    };
+
+    typedef gfxASurface::gfxContentType ContentType;
+
+    static already_AddRefed<TextureImage> Create(
+                       GLContext* gl,
+                       const nsIntSize& aSize,
+                       TextureImage::ContentType aContentType,
+                       GLenum aWrapMode,
+                       TextureImage::Flags aFlags = TextureImage::NoFlags);
+
+    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
+     * the update begins successfully, the returned gfxASurface is
+     * owned by this.  Otherwise, NULL is returned.
+     *
+     * |aRegion| is an inout param: the returned region is what the
+     * client must repaint.  Category (1) regions above can
+     * efficiently handle repaints to "scattered" regions, while (2)
+     * can only efficiently handle repaints to rects.
+     *
+     * Painting the returned surface outside of |aRegion| results
+     * in undefined behavior.
+     *
+     * BeginUpdate() calls cannot be "nested", and each successful
+     * BeginUpdate() must be followed by exactly one EndUpdate() (see
+     * below).  Failure to do so can leave this in a possibly
+     * inconsistent state.  Unsuccessful BeginUpdate()s must not be
+     * followed by EndUpdate().
+     */
+    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion) = 0;
+    /**
+     * Retrieves the region that will require updating, given a
+     * region that needs to be updated. This can be used for
+     * making decisions about updating before calling BeginUpdate().
+     *
+     * |aRegion| is an inout param.
+     */
+    virtual void GetUpdateRegion(nsIntRegion& aForRegion) {
+    }
+    /**
+     * Finish the active update and synchronize with the server, if
+     * 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 bool NextTile() {
+        return false;
+    }
+
+    // Function prototype for a tile iteration callback. Returning false will
+    // cause iteration to be interrupted (i.e. the corresponding NextTile call
+    // will return false).
+    typedef bool (* TileIterationCallback)(TextureImage* aImage,
+                                           int aTileNumber,
+                                           void* aCallbackData);
+
+    // Sets a callback to be called every time NextTile is called.
+    virtual void SetIterationCallback(TileIterationCallback aCallback,
+                                      void* aCallbackData) {
+    }
+
+    virtual nsIntRect GetTileRect() {
+        return nsIntRect(nsIntPoint(0,0), mSize);
+    }
+
+    virtual GLuint GetTextureID() = 0;
+
+    virtual uint32_t GetTileCount() {
+        return 1;
+    }
+
+    /**
+     * 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();
+    }
+
+    /**
+     * Mark this texture as having valid contents. Call this after modifying
+     * the texture contents externally.
+     */
+    virtual void MarkValid() {}
+
+    /**
+     * 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() {}
+
+    void BindTextureAndApplyFilter(GLenum aTextureUnit) {
+        BindTexture(aTextureUnit);
+        ApplyFilter();
+    }
+
+    class ScopedBindTexture
+    {
+    public:
+        ScopedBindTexture(TextureImage *aTexture, GLenum aTextureUnit);
+
+        ~ScopedBindTexture()
+        {
+            if (mTexture) {
+                mTexture->ReleaseTexture();
+            }
+        }
+
+    protected:
+        TextureImage *mTexture;
+    };
+
+    class ScopedBindTextureAndApplyFilter
+        : public ScopedBindTexture
+    {
+    public:
+        ScopedBindTextureAndApplyFilter(TextureImage *aTexture, GLenum aTextureUnit) :
+          ScopedBindTexture(aTexture, aTextureUnit)
+        {
+            if (mTexture) {
+                mTexture->ApplyFilter();
+            }
+        }
+    };
+
+    /**
+     * 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()
+    {
+         return mShaderType;
+    }
+
+    /** Can be called safely at any time. */
+
+    /**
+     * If this TextureImage has a permanent gfxASurface backing,
+     * return it.  Otherwise return NULL.
+     */
+    virtual already_AddRefed<gfxASurface> GetBackingSurface()
+    { return NULL; }
+
+    const nsIntSize& GetSize() const { return mSize; }
+    ContentType GetContentType() const { return mContentType; }
+    virtual bool InUpdate() const = 0;
+    GLenum GetWrapMode() const { return mWrapMode; }
+
+    void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
+
+    /**
+     * Applies this TextureImage's filter, assuming that its texture is
+     * the currently bound texture.
+     */
+    virtual void ApplyFilter() = 0;
+
+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(const nsIntSize& aSize,
+                 GLenum aWrapMode, ContentType aContentType,
+                 Flags aFlags = NoFlags)
+        : mSize(aSize)
+        , mWrapMode(aWrapMode)
+        , mContentType(aContentType)
+        , mFilter(gfxPattern::FILTER_GOOD)
+        , mFlags(aFlags)
+    {}
+
+    virtual nsIntRect GetSrcTileRect() {
+        return nsIntRect(nsIntPoint(0,0), mSize);
+    }
+
+    nsIntSize mSize;
+    GLenum mWrapMode;
+    ContentType mContentType;
+    ShaderProgramType mShaderType;
+    gfxPattern::GraphicsFilter mFilter;
+    Flags mFlags;
+};
+
+/**
+ * BasicTextureImage is the baseline TextureImage implementation ---
+ * it updates its texture by allocating a scratch buffer for the
+ * client to draw into, then using glTexSubImage2D() to upload the new
+ * pixels.  Platforms must provide the code to create a new surface
+ * into which the updated pixels will be drawn, and the code to
+ * convert the update surface's pixels into an image on which we can
+ * glTexSubImage2D().
+ */
+class BasicTextureImage
+    : public TextureImage
+{
+public:
+    typedef gfxASurface::gfxImageFormat ImageFormat;
+    virtual ~BasicTextureImage();
+
+    BasicTextureImage(GLuint aTexture,
+                      const nsIntSize& aSize,
+                      GLenum aWrapMode,
+                      ContentType aContentType,
+                      GLContext* aContext,
+                      TextureImage::Flags aFlags = TextureImage::NoFlags)
+        : TextureImage(aSize, aWrapMode, aContentType, aFlags)
+        , mTexture(aTexture)
+        , mTextureState(Created)
+        , mGLContext(aContext)
+        , mUpdateOffset(0, 0)
+    {}
+
+    virtual void BindTexture(GLenum aTextureUnit);
+
+    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
+    virtual void GetUpdateRegion(nsIntRegion& aForRegion);
+    virtual void EndUpdate();
+    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);
+
+    virtual void MarkValid() { mTextureState = Valid; }
+
+    // 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();
+
+    // Call after surface data has been uploaded to a texture.
+    virtual void FinishedSurfaceUpload();
+
+    virtual bool InUpdate() const { return !!mUpdateSurface; }
+
+    virtual void Resize(const nsIntSize& aSize);
+
+    virtual void ApplyFilter();
+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, TextureImage::Flags aFlags = TextureImage::NoFlags);
+    ~TiledTextureImage();
+    void DumpDiv();
+    virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion);
+    virtual void GetUpdateRegion(nsIntRegion& aForRegion);
+    virtual void EndUpdate();
+    virtual void Resize(const nsIntSize& aSize);
+    virtual uint32_t GetTileCount();
+    virtual void BeginTileIteration();
+    virtual bool NextTile();
+    virtual void SetIterationCallback(TileIterationCallback aCallback,
+                                      void* aCallbackData);
+    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 bool InUpdate() const { return mInUpdate; }
+    virtual void BindTexture(GLenum);
+    virtual void ApplyFilter();
+
+protected:
+    virtual nsIntRect GetSrcTileRect();
+
+    unsigned int mCurrentImage;
+    TileIterationCallback mIterationCallback;
+    void* mIterationCallbackData;
+    nsTArray< nsRefPtr<TextureImage> > mImages;
+    bool mInUpdate;
+    nsIntSize mSize;
+    unsigned int mTileSize;
+    unsigned int mRows, mColumns;
+    GLContext* mGL;
+    // A temporary surface to faciliate cross-tile updates.
+    nsRefPtr<gfxASurface> mUpdateSurface;
+    // The region of update requested
+    nsIntRegion mUpdateRegion;
+    TextureState mTextureState;
+};
+
+} // namespace gl
+} // namespace mozilla
+
+#endif /* GLTEXTUREIMAGE_H_ */
--- a/gfx/gl/Makefile.in
+++ b/gfx/gl/Makefile.in
@@ -19,16 +19,17 @@ EXPORTS	= \
 	GLDefs.h \
 	GLContext.h \
 	GLContextTypes.h \
 	GLContextSymbols.h \
 	GLContextProvider.h \
 	GLContextProviderImpl.h \
 	GLLibraryLoader.h \
 	ForceDiscreteGPUHelperCGL.h \
+	GLTextureImage.h \
 	$(NULL)
 
 ifdef MOZ_X11
 EXPORTS += \
 	GLXLibrary.h \
 	$(NULL)
 endif
 
@@ -43,16 +44,17 @@ DEFINES += -DMOZ_D3DX9_DLL=$(MOZ_D3DX9_D
 DEFINES += -DMOZ_D3DCOMPILER_DLL=$(MOZ_D3DCOMPILER_DLL)
 endif
 endif
 
 CPPSRCS	= \
 	GLContext.cpp \
 	GLContextUtils.cpp \
 	GLLibraryLoader.cpp \
+	GLTextureImage.cpp \
 	$(NULL)
 
 GL_PROVIDER = Null
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 GL_PROVIDER = WGL
 endif
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -46,16 +46,17 @@
 #include "ComplexTextInputPanel.h"
 #endif
 
 #include "gfxContext.h"
 #include "gfxQuartzSurface.h"
 #include "nsRegion.h"
 #include "Layers.h"
 #include "LayerManagerOGL.h"
+#include "GLTextureImage.h"
 #include "mozilla/layers/CompositorCocoaWidgetHelper.h"
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 #include "mozilla/Preferences.h"
 
 #include <dlfcn.h>
@@ -1753,20 +1754,21 @@ nsChildView::DrawWindowOverlay(LayerMana
   }
 
   nsRefPtr<LayerManagerOGL> manager(static_cast<LayerManagerOGL*>(aManager));
   if (!manager) {
     return;
   }
 
   if (!mResizerImage) {
-    mResizerImage = manager->gl()->CreateTextureImage(nsIntSize(15, 15),
-                                                      gfxASurface::CONTENT_COLOR_ALPHA,
-                                                      LOCAL_GL_CLAMP_TO_EDGE,
-                                                      TextureImage::UseNearestFilter);
+    mResizerImage = TextureImage::Create(manager->gl(),
+                                         nsIntSize(15, 15),
+                                         gfxASurface::CONTENT_COLOR_ALPHA,
+                                         LOCAL_GL_CLAMP_TO_EDGE,
+                                         TextureImage::UseNearestFilter);
 
     // Creation of texture images can fail.
     if (!mResizerImage)
       return;
 
     nsIntRegion update(nsIntRect(0, 0, 15, 15));
     gfxASurface *asurf = mResizerImage->BeginUpdate(update);
     if (!asurf) {