Bug 892934 - Pass RGB image format into CreateTextureImage r=mattwoodrow a=akeybl
authorEdwin Flores <eflores@mozilla.com>
Tue, 13 Aug 2013 11:41:54 +1200
changeset 153718 a4dbc38c75101c4a83f6c42653aabbc7956d5c7e
parent 153717 d303977a2b437dd880d35b21960c0016d8ed5791
child 153719 d0d1f4933029cd8a756e6f878cc0bd10a7eca187
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow, akeybl
bugs892934
milestone25.0a2
Bug 892934 - Pass RGB image format into CreateTextureImage r=mattwoodrow a=akeybl
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLTextureImage.cpp
gfx/gl/GLTextureImage.h
gfx/layers/ipc/AutoOpenSurface.h
gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
gfx/layers/ipc/ShadowLayerUtilsMac.cpp
gfx/layers/ipc/ShadowLayerUtilsX11.cpp
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/ShadowLayers.h
gfx/layers/opengl/TextureHostOGL.cpp
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -918,19 +918,21 @@ GLContext::ListHasExtension(const GLubyt
     }
     return false;
 }
 
 already_AddRefed<TextureImage>
 GLContext::CreateTextureImage(const nsIntSize& aSize,
                               TextureImage::ContentType aContentType,
                               GLenum aWrapMode,
-                              TextureImage::Flags aFlags)
+                              TextureImage::Flags aFlags,
+                              TextureImage::ImageFormat aImageFormat)
 {
-    return CreateBasicTextureImage(this, aSize, aContentType, aWrapMode, aFlags);
+    return CreateBasicTextureImage(this, aSize, aContentType, aWrapMode,
+                                   aFlags, aImageFormat);
 }
 
 void GLContext::ApplyFilterToBoundTexture(gfxPattern::GraphicsFilter aFilter)
 {
     ApplyFilterToBoundTexture(LOCAL_GL_TEXTURE_2D, aFilter);
 }
 
 void GLContext::ApplyFilterToBoundTexture(GLuint aTarget,
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2606,45 +2606,49 @@ public:
     }
 
     virtual GLenum GetPreferredARGB32Format() { return LOCAL_GL_RGBA; }
 
     virtual bool RenewSurface() { return false; }
 
     /**
      * Return a valid, allocated TextureImage of |aSize| with
-     * |aContentType|.  The TextureImage's texture is configured to
-     * use |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
+     * |aContentType|.  If |aContentType| is COLOR, |aImageFormat| can be used
+     * to hint at the preferred RGB format, however it is not necessarily
+     * respected.  The TextureImage's texture is configured to use
+     * |aWrapMode| (usually GL_CLAMP_TO_EDGE or GL_REPEAT) and by
      * default, GL_LINEAR filtering.  Specify
      * |aFlags=UseNearestFilter| for GL_NEAREST filtering. Specify
      * |aFlags=NeedsYFlip| if the image is flipped. Return
      * nullptr if creating the TextureImage fails.
      *
      * The returned TextureImage may only be used with this GLContext.
      * Attempting to use the returned TextureImage after this
      * GLContext is destroyed will result in undefined (and likely
      * crashy) behavior.
      */
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags);
+                       TextureImage::Flags aFlags = TextureImage::NoFlags,
+                       TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown);
 
     /**
      * 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,
-                TextureImage::Flags aFlags = TextureImage::NoFlags)
+                TextureImage::Flags aFlags = TextureImage::NoFlags,
+                TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown)
     {
         return nullptr;
     }
 
     /**
      * 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:
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -179,22 +179,24 @@ public:
     }
 
     bool ResizeOffscreen(const gfxIntSize& aNewSize);
 
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags) MOZ_OVERRIDE;
+                       TextureImage::Flags aFlags = TextureImage::NoFlags,
+                       TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown) MOZ_OVERRIDE;
 
     virtual already_AddRefed<TextureImage>
     TileGenFunc(const nsIntSize& aSize,
                 TextureImage::ContentType aContentType,
-                TextureImage::Flags aFlags = TextureImage::NoFlags) MOZ_OVERRIDE;
+                TextureImage::Flags aFlags = TextureImage::NoFlags,
+                TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown) MOZ_OVERRIDE;
 
     virtual SharedTextureHandle CreateSharedHandle(SharedTextureShareType shareType,
                                                    void* buffer,
                                                    SharedTextureBufferType bufferType)
     {
         return GLContextProviderCGL::CreateSharedHandle(shareType, buffer, bufferType);
     }
 
@@ -226,33 +228,35 @@ public:
 
     NSOpenGLContext *mContext;
     GLuint mTempTextureName;
 
     already_AddRefed<TextureImage>
     CreateTextureImageInternal(const nsIntSize& aSize,
                                TextureImage::ContentType aContentType,
                                GLenum aWrapMode,
-                               TextureImage::Flags aFlags);
+                               TextureImage::Flags aFlags,
+                               TextureImage::ImageFormat aImageFormat);
 
 };
 
 bool
 GLContextCGL::ResizeOffscreen(const gfxIntSize& aNewSize)
 {
     return ResizeScreenBuffer(aNewSize);
 }
 
 class TextureImageCGL : public BasicTextureImage
 {
     friend already_AddRefed<TextureImage>
     GLContextCGL::CreateTextureImageInternal(const nsIntSize& aSize,
                                              TextureImage::ContentType aContentType,
                                              GLenum aWrapMode,
-                                             TextureImage::Flags aFlags);
+                                             TextureImage::Flags aFlags,
+                                             TextureImage::ImageFormat aImageFormat);
 public:
     ~TextureImageCGL()
     {
         if (mPixelBuffer) {
             mGLContext->MakeCurrent();
             mGLContext->fDeleteBuffers(1, &mPixelBuffer);
         }
     }
@@ -329,33 +333,36 @@ protected:
     }
 
 private:
     TextureImageCGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
                     GLContext* aContext,
-                    TextureImage::Flags aFlags = TextureImage::NoFlags)
-        : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext, aFlags)
+                    TextureImage::Flags aFlags = TextureImage::NoFlags,
+                    TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown)
+        : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType,
+                            aContext, aFlags, aImageFormat)
         , mPixelBuffer(0)
         , mPixelBufferSize(0)
         , mBoundPixelBuffer(false)
     {}
     
     GLuint mPixelBuffer;
     int32_t mPixelBufferSize;
     bool mBoundPixelBuffer;
 };
 
 already_AddRefed<TextureImage>
 GLContextCGL::CreateTextureImageInternal(const nsIntSize& aSize,
                                          TextureImage::ContentType aContentType,
                                          GLenum aWrapMode,
-                                         TextureImage::Flags aFlags)
+                                         TextureImage::Flags aFlags,
+                                         TextureImage::ImageFormat aImageFormat)
 {
     bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
     MakeCurrent();
 
     GLuint texture;
     fGenTextures(1, &texture);
 
     fActiveTexture(LOCAL_GL_TEXTURE0);
@@ -363,43 +370,49 @@ GLContextCGL::CreateTextureImageInternal
 
     GLint texfilter = useNearestFilter ? 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);
 
     nsRefPtr<TextureImageCGL> teximage
-        (new TextureImageCGL(texture, aSize, aWrapMode, aContentType, this, aFlags));
+        (new TextureImageCGL(texture, aSize, aWrapMode, aContentType,
+                             this, aFlags, aImageFormat));
     return teximage.forget();
 }
 
 already_AddRefed<TextureImage>
 GLContextCGL::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
-                                 TextureImage::Flags aFlags)
+                                 TextureImage::Flags aFlags,
+                                 TextureImage::ImageFormat aImageFormat)
 {
     if (!IsOffscreenSizeAllowed(gfxIntSize(aSize.width, aSize.height)) &&
         gfxPlatform::OffMainThreadCompositingEnabled()) {
       NS_ASSERTION(aWrapMode == LOCAL_GL_CLAMP_TO_EDGE, "Can't support wrapping with tiles!");
-      nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aFlags);
+      nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType,
+                                                           aFlags, aImageFormat);
       return t.forget();
     }
 
-    return CreateBasicTextureImage(this, aSize, aContentType, aWrapMode, aFlags);
+    return CreateBasicTextureImage(this, aSize, aContentType, aWrapMode,
+                                   aFlags, aImageFormat);
 }
 
 already_AddRefed<TextureImage>
 GLContextCGL::TileGenFunc(const nsIntSize& aSize,
                           TextureImage::ContentType aContentType,
-                          TextureImage::Flags aFlags)
+                          TextureImage::Flags aFlags,
+                          TextureImage::ImageFormat aImageFormat)
 {
     return CreateTextureImageInternal(aSize, aContentType,
-                                      LOCAL_GL_CLAMP_TO_EDGE, aFlags);
+                                      LOCAL_GL_CLAMP_TO_EDGE, aFlags,
+                                      aImageFormat);
 }
 
 static GLContextCGL *
 GetGlobalContextCGL()
 {
     return static_cast<GLContextCGL*>(GLContextProviderCGL::GetGlobalContext());
 }
 
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -604,23 +604,25 @@ public:
             return false;
         }
     }
     // GLContext interface - returns Tiled Texture Image in our case
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags);
+                       TextureImage::Flags aFlags = TextureImage::NoFlags,
+                       TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown);
 
     // a function to generate Tiles for Tiled Texture Image
     virtual already_AddRefed<TextureImage>
     TileGenFunc(const nsIntSize& aSize,
                 TextureImage::ContentType aContentType,
-                TextureImage::Flags aFlags = TextureImage::NoFlags) MOZ_OVERRIDE;
+                TextureImage::Flags aFlags = TextureImage::NoFlags,
+                TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown) MOZ_OVERRIDE;
     // hold a reference to the given surface
     // for the lifetime of this context.
     void HoldSurface(gfxASurface *aSurf) {
         mThebesSurface = aSurf;
     }
 
     void SetPlatformContext(void *context) {
         mPlatformContext = context;
@@ -1098,28 +1100,31 @@ class TextureImageEGL
 {
 public:
     TextureImageEGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
                     GLContext* aContext,
                     Flags aFlags = TextureImage::NoFlags,
-                    TextureState aTextureState = Created)
+                    TextureState aTextureState = Created,
+                    TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown)
         : TextureImage(aSize, aWrapMode, aContentType, aFlags)
         , mGLContext(aContext)
-        , mUpdateFormat(gfxASurface::ImageFormatUnknown)
+        , mUpdateFormat(aImageFormat)
         , mEGLImage(nullptr)
         , mTexture(aTexture)
         , mSurface(nullptr)
         , mConfig(nullptr)
         , mTextureState(aTextureState)
         , mBound(false)
     {
-        mUpdateFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType());
+        if (mUpdateFormat == gfxASurface::ImageFormatUnknown) {
+            mUpdateFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType());
+        }
 
         if (gUseBackingSurface) {
             if (mUpdateFormat != gfxASurface::ImageFormatARGB32) {
                 mTextureFormat = FORMAT_R8G8B8X8;
             } else {
                 mTextureFormat = FORMAT_R8G8B8A8;
             }
             Resize(aSize);
@@ -1524,34 +1529,37 @@ protected:
         mGLContext->ApplyFilterToBoundTexture(mFilter);
     }
 };
 
 already_AddRefed<TextureImage>
 GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
-                                 TextureImage::Flags aFlags)
+                                 TextureImage::Flags aFlags,
+                                 TextureImage::ImageFormat aImageFormat)
 {
-    nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aFlags);
+    nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aFlags, aImageFormat);
     return t.forget();
 }
 
 already_AddRefed<TextureImage>
 GLContextEGL::TileGenFunc(const nsIntSize& aSize,
                           TextureImage::ContentType aContentType,
-                          TextureImage::Flags aFlags)
+                          TextureImage::Flags aFlags,
+                          TextureImage::ImageFormat aImageFormat)
 {
   MakeCurrent();
 
   GLuint texture;
   fGenTextures(1, &texture);
 
   nsRefPtr<TextureImageEGL> teximage =
-      new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this, aFlags);
+      new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType,
+                          this, aFlags, TextureImage::Created, aImageFormat);
   
   teximage->BindTexture(LOCAL_GL_TEXTURE0);
 
   GLint texfilter = aFlags & TextureImage::UseNearestFilter ? 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, LOCAL_GL_CLAMP_TO_EDGE);
   fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -935,17 +935,18 @@ TRY_AGAIN_NO_SHARING:
     {
         return mGLX->UseTextureFromPixmap();
     }
 
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
-                       TextureImage::Flags aFlags = TextureImage::NoFlags);
+                       TextureImage::Flags aFlags = TextureImage::NoFlags,
+                       TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown);
 
 private:
     friend class GLContextProviderGLX;
 
     GLContextGLX(const SurfaceCaps& caps,
                  GLContext* shareContext,
                  bool isOffscreen,
                  Display *aDisplay,
@@ -983,17 +984,18 @@ private:
 };
 
 class TextureImageGLX : public TextureImage
 {
     friend already_AddRefed<TextureImage>
     GLContextGLX::CreateTextureImage(const nsIntSize&,
                                      ContentType,
                                      GLenum,
-                                     TextureImage::Flags);
+                                     TextureImage::Flags,
+                                     TextureImage::ImageFormat);
 
 public:
     virtual ~TextureImageGLX()
     {
         mGLContext->MakeCurrent();
         mGLContext->fDeleteTextures(1, &mTexture);
         sGLXLib.DestroyPixmap(mPixmap);
     }
@@ -1082,23 +1084,25 @@ private:
         mGLContext->ApplyFilterToBoundTexture(mFilter);
     }
 };
 
 already_AddRefed<TextureImage>
 GLContextGLX::CreateTextureImage(const nsIntSize& aSize,
                                  TextureImage::ContentType aContentType,
                                  GLenum aWrapMode,
-                                 TextureImage::Flags aFlags)
+                                 TextureImage::Flags aFlags,
+                                 TextureImage::ImageFormat aImageFormat)
 {
     if (!TextureImageSupportsGetBackingSurface()) {
         return GLContext::CreateTextureImage(aSize, 
                                              aContentType, 
                                              aWrapMode, 
-                                             aFlags);
+                                             aFlags,
+                                             aImageFormat);
     }
 
     Display *display = DefaultXDisplay();
     int xscreen = DefaultScreen(display);
     gfxASurface::gfxImageFormat imageFormat =
         gfxPlatform::GetPlatform()->OptimalFormatForContent(aContentType);
 
     XRenderPictFormat* xrenderFormat =
@@ -1122,17 +1126,18 @@ GLContextGLX::CreateTextureImage(const n
     MakeCurrent();
     GLXPixmap pixmap = mGLX->CreatePixmap(surface);
     // GLX might not be able to give us an A8 pixmap. If so, just use CPU
     // memory.
     if (!pixmap && imageFormat == gfxASurface::ImageFormatA8) {
         return GLContext::CreateTextureImage(aSize,
                                              aContentType,
                                              aWrapMode,
-                                             aFlags);
+                                             aFlags,
+                                             aImageFormat);
     }
     NS_ASSERTION(pixmap, "Failed to create pixmap!");
 
     GLuint texture;
     fGenTextures(1, &texture);
 
     fActiveTexture(LOCAL_GL_TEXTURE0);
     fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
--- a/gfx/gl/GLTextureImage.cpp
+++ b/gfx/gl/GLTextureImage.cpp
@@ -206,25 +206,27 @@ BasicTextureImage::Resize(const nsIntSiz
 
     mTextureState = Allocated;
     mSize = aSize;
 }
 
 TiledTextureImage::TiledTextureImage(GLContext* aGL,
                                      nsIntSize aSize,
                                      TextureImage::ContentType aContentType,
-                                     TextureImage::Flags aFlags)
+                                     TextureImage::Flags aFlags,
+                                     TextureImage::ImageFormat aImageFormat)
     : TextureImage(aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, aFlags)
     , mCurrentImage(0)
     , mIterationCallback(nullptr)
     , mInUpdate(false)
     , mRows(0)
     , mColumns(0)
     , mGL(aGL)
     , mTextureState(Created)
+    , mImageFormat(aImageFormat)
 {
     if (!(aFlags & TextureImage::DisallowBigImage) && mGL->WantsSmallTiles()) {
       mTileSize = 256;
     } else {
       mGL->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*) &mTileSize);
     }
     if (aSize.width != 0 && aSize.height != 0) {
         Resize(aSize);
@@ -557,17 +559,17 @@ void TiledTextureImage::Resize(const nsI
                     // Width hasn't changed, reuse existing tile.
                     i++;
                     continue;
                 }
             }
 
             // Create a new tile.
             nsRefPtr<TextureImage> teximg =
-                    mGL->TileGenFunc(size, mContentType, mFlags);
+                    mGL->TileGenFunc(size, mContentType, mFlags, mImageFormat);
             if (replace)
                 mImages.ReplaceElementAt(i, teximg.forget());
             else
                 mImages.InsertElementAt(i, teximg.forget());
             i++;
         }
 
         // Prune any unused tiles on the end of the column.
@@ -606,31 +608,33 @@ TextureImage::ScopedBindTexture::ScopedB
     }
 }
 
 already_AddRefed<TextureImage>
 CreateBasicTextureImage(GLContext* aGL,
                         const nsIntSize& aSize,
                         TextureImage::ContentType aContentType,
                         GLenum aWrapMode,
-                        TextureImage::Flags aFlags)
+                        TextureImage::Flags aFlags,
+                        TextureImage::ImageFormat aImageFormat)
 {
     bool useNearestFilter = aFlags & TextureImage::UseNearestFilter;
     aGL->MakeCurrent();
 
     GLuint texture = 0;
     aGL->fGenTextures(1, &texture);
 
     ScopedBindTexture bind(aGL, texture);
 
     GLint texfilter = useNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
     aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
 
     nsRefPtr<BasicTextureImage> texImage =
-        new BasicTextureImage(texture, aSize, aWrapMode, aContentType, aGL, aFlags);
+        new BasicTextureImage(texture, aSize, aWrapMode, aContentType,
+                              aGL, aFlags, aImageFormat);
     return texImage.forget();
 }
 
 } // namespace
 } // namespace
--- a/gfx/gl/GLTextureImage.h
+++ b/gfx/gl/GLTextureImage.h
@@ -38,34 +38,33 @@ class GLContext;
  *
  *  (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)
-protected:
-    typedef gfxASurface::gfxImageFormat ImageFormat;
 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,
         DisallowBigImage = 0x4
     };
 
     typedef gfxASurface::gfxContentType ContentType;
+    typedef gfxASurface::gfxImageFormat ImageFormat;
 
     static already_AddRefed<TextureImage> Create(
                        GLContext* gl,
                        const nsIntSize& aSize,
                        TextureImage::ContentType aContentType,
                        GLenum aWrapMode,
                        TextureImage::Flags aFlags = TextureImage::NoFlags);
 
@@ -227,16 +226,17 @@ public:
      * If this TextureImage has a permanent gfxASurface backing,
      * return it.  Otherwise return nullptr.
      */
     virtual already_AddRefed<gfxASurface> GetBackingSurface()
     { return nullptr; }
 
     const nsIntSize& GetSize() const { return mSize; }
     ContentType GetContentType() const { return mContentType; }
+    ImageFormat GetImageFormat() const { return mImageFormat; }
     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.
@@ -249,31 +249,34 @@ protected:
     /**
      * 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)
+                 Flags aFlags = NoFlags,
+                 ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown)
         : mSize(aSize)
         , mWrapMode(aWrapMode)
         , mContentType(aContentType)
+        , mImageFormat(aImageFormat)
         , mFilter(gfxPattern::FILTER_GOOD)
         , mFlags(aFlags)
     {}
 
     virtual nsIntRect GetSrcTileRect() {
         return nsIntRect(nsIntPoint(0,0), mSize);
     }
 
     nsIntSize mSize;
     GLenum mWrapMode;
     ContentType mContentType;
+    ImageFormat mImageFormat;
     gfx::SurfaceFormat mTextureFormat;
     gfxPattern::GraphicsFilter mFilter;
     Flags mFlags;
 };
 
 /**
  * BasicTextureImage is the baseline TextureImage implementation ---
  * it updates its texture by allocating a scratch buffer for the
@@ -289,18 +292,19 @@ class BasicTextureImage
 public:
     virtual ~BasicTextureImage();
 
     BasicTextureImage(GLuint aTexture,
                       const nsIntSize& aSize,
                       GLenum aWrapMode,
                       ContentType aContentType,
                       GLContext* aContext,
-                      TextureImage::Flags aFlags = TextureImage::NoFlags)
-        : TextureImage(aSize, aWrapMode, aContentType, aFlags)
+                      TextureImage::Flags aFlags = TextureImage::NoFlags,
+                      TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown)
+        : TextureImage(aSize, aWrapMode, aContentType, aFlags, aImageFormat)
         , mTexture(aTexture)
         , mTextureState(Created)
         , mGLContext(aContext)
         , mUpdateOffset(0, 0)
     {}
 
     virtual void BindTexture(GLenum aTextureUnit);
 
@@ -344,18 +348,21 @@ protected:
  * 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(GLContext* aGL,
+                      nsIntSize aSize,
+                      TextureImage::ContentType,
+                      TextureImage::Flags aFlags = TextureImage::NoFlags,
+                      TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown);
     ~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();
@@ -383,26 +390,28 @@ protected:
     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;
+    TextureImage::ImageFormat mImageFormat;
 };
 
 /**
  * Creates a TextureImage of the basic implementation, can be useful in cases
  * where we know we don't want to use platform-specific TextureImage.
  * In doubt, use GLContext::CreateTextureImage instead.
  */
 already_AddRefed<TextureImage>
 CreateBasicTextureImage(GLContext* aGL,
                         const nsIntSize& aSize,
                         TextureImage::ContentType aContentType,
                         GLenum aWrapMode,
-                        TextureImage::Flags aFlags);
+                        TextureImage::Flags aFlags,
+                        TextureImage::ImageFormat aImageFormat = gfxASurface::ImageFormatUnknown);
 
 } // namespace gl
 } // namespace mozilla
 
 #endif /* GLTEXTUREIMAGE_H_ */
--- a/gfx/layers/ipc/AutoOpenSurface.h
+++ b/gfx/layers/ipc/AutoOpenSurface.h
@@ -22,28 +22,30 @@ namespace layers {
  * tries to put off opening surfaces as long as it can, until
  * ahsolutely necessary.  And after being forced to open, it remembers
  * the mapping so it doesn't need to be redone.
  */
 class MOZ_STACK_CLASS AutoOpenSurface
 {
 public:
   typedef gfxASurface::gfxContentType gfxContentType;
+  typedef gfxASurface::gfxImageFormat gfxImageFormat;
 
   /** |aDescriptor| must be valid while AutoOpenSurface is
    * in scope. */
   AutoOpenSurface(OpenMode aMode, const SurfaceDescriptor& aDescriptor);
 
   ~AutoOpenSurface();
 
   /**
    * These helpers do not necessarily need to open the descriptor to
    * return an answer.
    */
   gfxContentType ContentType();
+  gfxImageFormat ImageFormat();
   gfxIntSize Size();
 
   /** This can't escape the scope of AutoOpenSurface. */
   gfxASurface* Get();
 
   /**
    * This can't escape the scope of AutoOpenSurface.
    *
--- a/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
@@ -56,16 +56,26 @@ ShadowLayerForwarder::PlatformGetDescrip
   const SurfaceDescriptor&,
   OpenMode,
   gfxIntSize*,
   gfxASurface**)
 {
   return false;
 }
 
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceImageFormat(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxImageFormat*,
+  gfxASurface**)
+{
+  return false;
+}
+
 bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor*)
 {
   return false;
 }
 
 /*static*/ void
 ShadowLayerForwarder::PlatformSyncBeforeUpdate()
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -500,16 +500,33 @@ ShadowLayerForwarder::PlatformGetDescrip
 
   sp<GraphicBuffer> buffer =
     GrallocBufferActor::GetFrom(aDescriptor.get_SurfaceDescriptorGralloc());
   *aSize = aDescriptor.get_SurfaceDescriptorGralloc().size();
   return true;
 }
 
 /*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceImageFormat(
+  const SurfaceDescriptor& aDescriptor,
+  OpenMode aMode,
+  gfxImageFormat* aImageFormat,
+  gfxASurface** aSurface)
+{
+  if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aDescriptor.type()) {
+    return false;
+  }
+
+  sp<GraphicBuffer> buffer =
+    GrallocBufferActor::GetFrom(aDescriptor.get_SurfaceDescriptorGralloc());
+  *aImageFormat = ImageFormatForPixelFormat(buffer->getPixelFormat());
+  return true;
+}
+
+/*static*/ bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface)
 {
   if (SurfaceDescriptor::TSurfaceDescriptorGralloc != aSurface->type()) {
     return false;
   }
 
   PGrallocBufferChild* gbp =
     aSurface->get_SurfaceDescriptorGralloc().bufferChild();
--- a/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsMac.cpp
@@ -69,16 +69,26 @@ ShadowLayerForwarder::PlatformGetDescrip
 ShadowLayerForwarder::PlatformGetDescriptorSurfaceSize(
   const SurfaceDescriptor& aDescriptor, OpenMode aMode,
   gfxIntSize* aSize,
   gfxASurface** aSurface)
 {
   return false;
 }
 
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceImageFormat(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxImageFormat*,
+  gfxASurface**)
+{
+  return false;
+}
+
 bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface)
 {
   return false;
 }
 
 /*static*/ void
 ShadowLayerForwarder::PlatformSyncBeforeUpdate()
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -160,16 +160,26 @@ ShadowLayerForwarder::PlatformGetDescrip
 ShadowLayerForwarder::PlatformGetDescriptorSurfaceSize(
   const SurfaceDescriptor& aDescriptor, OpenMode aMode,
   gfxIntSize* aSize,
   gfxASurface** aSurface)
 {
   return false;
 }
 
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceImageFormat(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxImageFormat*,
+  gfxASurface**)
+{
+  return false;
+}
+
 bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor* aSurface)
 {
   if (SurfaceDescriptor::TSurfaceDescriptorX11 != aSurface->type()) {
     return false;
   }
   return TakeAndDestroyXlibSurface(aSurface);
 }
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -630,16 +630,40 @@ ShadowLayerForwarder::GetDescriptorSurfa
   }
 
   nsRefPtr<gfxASurface> surface = OpenDescriptor(aMode, aDescriptor);
   size = surface->GetSize();
   *aSurface = surface.forget().get();
   return size;
 }
 
+/*static*/ gfxImageFormat
+ShadowLayerForwarder::GetDescriptorSurfaceImageFormat(
+  const SurfaceDescriptor& aDescriptor, OpenMode aMode,
+  gfxASurface** aSurface)
+{
+  gfxImageFormat format;
+  if (PlatformGetDescriptorSurfaceImageFormat(aDescriptor, aMode, &format, aSurface)) {
+    return format;
+  }
+
+  nsRefPtr<gfxASurface> surface = OpenDescriptor(aMode, aDescriptor);
+  NS_ENSURE_TRUE(surface, gfxASurface::ImageFormatUnknown);
+
+  nsRefPtr<gfxImageSurface> img = surface->GetAsImageSurface();
+  NS_ENSURE_TRUE(img, gfxASurface::ImageFormatUnknown);
+
+  format = img->Format();
+  NS_ASSERTION(format != gfxASurface::ImageFormatUnknown,
+               "ImageSurface RGB format should be known");
+
+  *aSurface = surface.forget().get();
+  return format;
+}
+
 /*static*/ void
 ShadowLayerForwarder::CloseDescriptor(const SurfaceDescriptor& aDescriptor)
 {
   PlatformCloseDescriptor(aDescriptor);
   // There's no "close" needed for Shmem surfaces.
 }
 
 PLayerChild*
@@ -679,16 +703,26 @@ ShadowLayerForwarder::PlatformGetDescrip
   const SurfaceDescriptor&,
   OpenMode,
   gfxIntSize*,
   gfxASurface**)
 {
   return false;
 }
 
+/*static*/ bool
+ShadowLayerForwarder::PlatformGetDescriptorSurfaceImageFormat(
+  const SurfaceDescriptor&,
+  OpenMode,
+  gfxImageFormat*,
+  gfxASurface**)
+{
+  return false;
+}
+
 bool
 ShadowLayerForwarder::PlatformDestroySharedSurface(SurfaceDescriptor*)
 {
   return false;
 }
 
 /*static*/ void
 ShadowLayerForwarder::PlatformSyncBeforeUpdate()
@@ -724,16 +758,34 @@ AutoOpenSurface::ContentType()
 {
   if (mSurface) {
     return mSurface->GetContentType();
   }
   return ShadowLayerForwarder::GetDescriptorSurfaceContentType(
     mDescriptor, mMode, getter_AddRefs(mSurface));
 }
 
+gfxImageFormat
+AutoOpenSurface::ImageFormat()
+{
+  if (mSurface) {
+    nsRefPtr<gfxImageSurface> img = mSurface->GetAsImageSurface();
+    if (img) {
+      gfxImageFormat format = img->Format();
+      NS_ASSERTION(format != gfxASurface::ImageFormatUnknown,
+                   "ImageSurface RGB format should be known");
+
+      return format;
+    }
+  }
+
+  return ShadowLayerForwarder::GetDescriptorSurfaceImageFormat(
+    mDescriptor, mMode, getter_AddRefs(mSurface));
+}
+
 gfxIntSize
 AutoOpenSurface::Size()
 {
   if (mSurface) {
     return mSurface->GetSize();
   }
   return ShadowLayerForwarder::GetDescriptorSurfaceSize(
     mDescriptor, mMode, getter_AddRefs(mSurface));
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -135,16 +135,18 @@ class TextureClient;
  */
 
 class ShadowLayerForwarder : public CompositableForwarder
 {
   friend class AutoOpenSurface;
   friend class DeprecatedTextureClientShmem;
   friend class ContentClientIncremental;
 
+  typedef gfxASurface::gfxImageFormat gfxImageFormat;
+
 public:
   virtual ~ShadowLayerForwarder();
 
   /**
    * Setup the IPDL actor for aCompositable to be part of layers
    * transactions.
    */
   void Connect(CompositableClient* aCompositable);
@@ -449,16 +451,28 @@ private:
   GetDescriptorSurfaceSize(const SurfaceDescriptor& aDescriptor,
                            OpenMode aMode,
                            gfxASurface** aSurface);
   static bool
   PlatformGetDescriptorSurfaceSize(const SurfaceDescriptor& aDescriptor,
                                    OpenMode aMode,
                                    gfxIntSize* aSize,
                                    gfxASurface** aSurface);
+  // And again, for the image format.
+  // This function will return ImageFormatUnknown only if |aDescriptor|
+  // describes a non-ImageSurface.
+  static gfxImageFormat
+  GetDescriptorSurfaceImageFormat(const SurfaceDescriptor& aDescriptor,
+                                  OpenMode aMode,
+                                  gfxASurface** aSurface);
+  static bool
+  PlatformGetDescriptorSurfaceImageFormat(const SurfaceDescriptor& aDescriptor,
+                                          OpenMode aMode,
+                                          gfxImageFormat* aContent,
+                                          gfxASurface** aSurface);
 
   static already_AddRefed<gfxASurface>
   PlatformOpenDescriptor(OpenMode aMode, const SurfaceDescriptor& aDescriptor);
 
   /**
    * Make this descriptor unusable for gfxASurface clients. A
    * private interface with AutoOpenSurface.
    */
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -417,26 +417,32 @@ void
 TextureImageDeprecatedTextureHostOGL::UpdateImpl(const SurfaceDescriptor& aImage,
                                        nsIntRegion* aRegion,
                                        nsIntPoint* aOffset)
 {
   if (!mGL) {
     NS_WARNING("trying to update TextureImageDeprecatedTextureHostOGL without a compositor?");
     return;
   }
+
   AutoOpenSurface surf(OPEN_READ_ONLY, aImage);
   nsIntSize size = surf.Size();
+  TextureImage::ImageFormat format = surf.ImageFormat();
 
   if (!mTexture ||
       (mTexture->GetSize() != size && !aOffset) ||
-      mTexture->GetContentType() != surf.ContentType()) {
+      mTexture->GetContentType() != surf.ContentType() ||
+      (mTexture->GetImageFormat() != format &&
+       mTexture->GetImageFormat() != gfxASurface::ImageFormatUnknown)) {
+
     mTexture = mGL->CreateTextureImage(size,
                                        surf.ContentType(),
                                        WrapMode(mGL, mFlags & AllowRepeat),
-                                       FlagsToGLFlags(mFlags));
+                                       FlagsToGLFlags(mFlags),
+                                       format);
   }
 
   // XXX this is always just ridiculously slow
   nsIntRegion updateRegion;
 
   if (!aRegion) {
     updateRegion = nsIntRegion(nsIntRect(0, 0, size.width, size.height));
   } else {