Bug 604101 - Part 4 - Use UploadSurfaceToTexture in TextureImage. r=joe a=blocking2.0
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 16 Dec 2010 23:29:23 -0800
changeset 59439 ac8edf791852bf6a66362c412745d88d68b9b7c0
parent 59438 d8d69903f209983d03d8567636d4d87f776415c3
child 59440 8dbba1a4f83f118577d22ff205536536c66f930d
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersjoe, blocking2
bugs604101
milestone2.0b9pre
Bug 604101 - Part 4 - Use UploadSurfaceToTexture in TextureImage. r=joe a=blocking2.0
gfx/layers/opengl/CanvasLayerOGL.cpp
gfx/layers/opengl/ImageLayerOGL.cpp
gfx/layers/opengl/ThebesLayerOGL.cpp
gfx/thebes/GLContext.cpp
gfx/thebes/GLContext.h
gfx/thebes/GLContextProviderCGL.mm
gfx/thebes/GLContextProviderEGL.cpp
gfx/thebes/GLContextProviderGLX.cpp
gfx/thebes/GLContextProviderWGL.cpp
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -326,18 +326,17 @@ void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   ColorTextureLayerProgram *program =
-    mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
-                                      mTexImage->IsRGB());
+    mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
   program->SetLayerTransform(GetEffectiveTransform());
   program->SetLayerOpacity(GetEffectiveOpacity());
   program->SetRenderOffset(aOffset);
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -776,18 +776,17 @@ void
 ShadowImageLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                  const nsIntPoint& aOffset)
 {
   mOGLManager->MakeCurrent();
 
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
   gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   ColorTextureLayerProgram *program =
-    mOGLManager->GetBasicLayerProgram(CanUseOpaqueSurface(),
-                                      mTexImage->IsRGB());
+    mOGLManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
 
   ApplyFilter(mFilter);
 
   program->Activate();
   program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mTexImage->GetSize()));
   program->SetLayerTransform(GetEffectiveTransform());
   program->SetLayerOpacity(GetEffectiveOpacity());
   program->SetRenderOffset(aOffset);
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -176,28 +176,27 @@ protected:
 
 void
 ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
                                LayerManagerOGL* aManager)
 {
   if (!mTexImage)
     return;
 
-  // Note BGR: Cairo's image surfaces are always in what
-  // OpenGL and our shaders consider BGR format.
-  ColorTextureLayerProgram *program =
-    aManager->GetBasicLayerProgram(mLayer->CanUseOpaqueSurface(),
-                                   mTexImage->IsRGB());
-
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 
   if (!mTexImage->InUpdate() || !mTexImage->EndUpdate()) {
     gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexImage->Texture());
   }
 
+  // Note BGR: Cairo's image surfaces are always in what
+  // OpenGL and our shaders consider BGR format.
+  ColorTextureLayerProgram *program =
+    aManager->GetColorTextureLayerProgram(mTexImage->GetShaderProgramType());
+
   float xres = mLayer->GetXResolution();
   float yres = mLayer->GetYResolution();
 
   nsIntRegionRectIterator iter(mLayer->GetEffectiveVisibleRegion());
   while (const nsIntRect *iterRect = iter.Next()) {
     nsIntRect quadRect = *iterRect;
     program->Activate();
     program->SetLayerQuadRect(quadRect);
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -531,43 +531,33 @@ BasicTextureImage::~BasicTextureImage()
     // 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);
     }
-
-    mBackingSurface = nsnull;
 }
 
 gfxContext*
 BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
 {
     NS_ASSERTION(!mUpdateContext, "BeginUpdate() without EndUpdate()?");
 
     // determine the region the client will need to repaint
     ImageFormat format =
         (GetContentType() == gfxASurface::CONTENT_COLOR) ?
         gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
-    PRBool repaintEverything = PR_FALSE;
-    if (mGLContext->IsExtensionSupported(gl::GLContext::APPLE_client_storage)) {
-        repaintEverything =
-            !(mBackingSurface &&
-              mBackingSurface->GetSize() == gfxIntSize(mSize.width, mSize.height) &&
-              mBackingSurface->Format() == format);
-    }
-    if (!mTextureInited || repaintEverything)
+    if (!mTextureInited)
     {
         // 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
         mUpdateRect = nsIntRect(nsIntPoint(0, 0), mSize);
-        mTextureInited = PR_FALSE;
     } else {
         mUpdateRect = aRegion.GetBounds();
     }
 
     // the basic impl can only upload updates to rectangles
     aRegion = nsIntRegion(mUpdateRect);
 
     nsIntSize rgnSize = mUpdateRect.Size();
@@ -595,82 +585,31 @@ BasicTextureImage::EndUpdate()
 
     // FIXME: this is the slow boat.  Make me fast (with GLXPixmap?).
     nsRefPtr<gfxASurface> originalSurface = mUpdateContext->OriginalSurface();
 
     // 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.
     originalSurface->SetDeviceOffset(gfxPoint(0, 0));
 
-    nsRefPtr<gfxImageSurface> uploadImage = GetImageForUpload(originalSurface);
-    if (!uploadImage)
-        return PR_FALSE;
-
-    mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
-
-    // The images that come out of the cairo quartz surface are 16-byte aligned
-    // for performance. We know this is an RGBA surface, so we divide the
-    // stride by 4 to represent the number of elements long the row is.
-    mGLContext->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH,
-                             uploadImage->Stride() / 4);
-
-    DEBUG_GL_ERROR_CHECK(mGLContext);
-
-    if (!mTextureInited)
-    {
-        // If we can use the client storage extension, we should.
-        if (mGLContext->IsExtensionSupported(gl::GLContext::APPLE_client_storage)) {
-            mGLContext->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE,
-                                     LOCAL_GL_TRUE);
-            DEBUG_GL_ERROR_CHECK(mGLContext);
-        }
-
-        mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
-                                0,
-                                LOCAL_GL_RGBA,
-                                mUpdateRect.width,
-                                mUpdateRect.height,
-                                0,
-                                LOCAL_GL_RGBA,
-                                LOCAL_GL_UNSIGNED_BYTE,
-                                uploadImage->Data());
+    // The rect to upload from the surface is mUpdateRect sized and located at mUpdateOffset.
+    nsIntRect surfaceRect(mUpdateOffset.x, mUpdateOffset.y, mUpdateRect.width, mUpdateRect.height);
+    if (!mTextureInited) {
+     surfaceRect.x = 0;
+     surfaceRect.y = 0;
+    }
 
-        DEBUG_GL_ERROR_CHECK(mGLContext);
-
-        mTextureInited = PR_TRUE;
-
-        // Reset the pixel store attribute, and hold on to the update surface
-        // because we're using the client storage extension.
-        if (mGLContext->IsExtensionSupported(gl::GLContext::APPLE_client_storage)) {
-            mBackingSurface = uploadImage;
-            mGLContext->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE,
-                                     LOCAL_GL_FALSE);
-          DEBUG_GL_ERROR_CHECK(mGLContext);
-        }
-    } else {
-        // By default, mUpdateOffset is initialized to (0, 0), so we will
-        // upload from the origin of the update surface. Subclasses can set
-        // mUpdateOffset in an overridden BeginUpdate or EndUpdate to change
-        // this.
-        unsigned char* data = uploadImage->Data() + mUpdateOffset.x * 4 +
-                                                    mUpdateOffset.y * uploadImage->Stride();
-        mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
-                                   0,
-                                   mUpdateRect.x,
-                                   mUpdateRect.y,
-                                   mUpdateRect.width,
-                                   mUpdateRect.height,
-                                   LOCAL_GL_RGBA,
-                                   LOCAL_GL_UNSIGNED_BYTE,
-                                   data);
-    }
-    mUpdateContext = NULL;
-
-    // Reset pixel store attributes to use the defaults.
-    mGLContext->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+    mShaderType =
+      mGLContext->UploadSurfaceToTexture(originalSurface,
+                                         surfaceRect,
+                                         mTexture,
+                                         !mTextureInited,
+                                         mUpdateRect.TopLeft());
+    mUpdateContext = nsnull;
+    mTextureInited = PR_TRUE;
 
     return PR_TRUE;         // mTexture is bound
 }
 
 void
 BasicTextureImage::Resize(const nsIntSize& aSize)
 {
     NS_ASSERTION(!mUpdateContext, "Resize() while in update?");
@@ -1269,17 +1208,17 @@ GLContext::UploadSurfaceToTexture(gfxASu
                                   const nsIntRect& aSrcRect,
                                   GLuint& aTexture,
                                   bool aOverwrite,
                                   const nsIntPoint& aDstPoint)
 {
   bool textureInited = aOverwrite ? false : true;
   MakeCurrent();
   fActiveTexture(LOCAL_GL_TEXTURE0);
-
+  
   if (!aTexture) {
     fGenTextures(1, &aTexture);
     fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, 
                    LOCAL_GL_TEXTURE_MIN_FILTER, 
                    LOCAL_GL_LINEAR);
     fTexParameteri(LOCAL_GL_TEXTURE_2D, 
                    LOCAL_GL_TEXTURE_MAG_FILTER, 
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -112,16 +112,29 @@ protected:
         mLibrary = nsnull;
         mLookupFunc = nsnull;
     }
 
     PRLibrary *mLibrary;
     PlatformLookupFunction mLookupFunc;
 };
 
+enum ShaderProgramType {
+    RGBALayerProgramType,
+    BGRALayerProgramType,
+    RGBXLayerProgramType,
+    BGRXLayerProgramType,
+    RGBARectLayerProgramType,
+    ColorLayerProgramType,
+    YCbCrLayerProgramType,
+    Copy2DProgramType,
+    Copy2DRectProgramType,
+    NumProgramTypes
+};
+
 
 /**
  * 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
@@ -195,16 +208,26 @@ public:
      *
      * The texture is only texture complete after either Resize
      * or a matching pair of BeginUpdate/EndUpdate have been called.
      * Otherwise, a texture ID may be returned, but the texture
      * may not be texture complete.
      */
     GLuint Texture() { return mTexture; }
 
+    /**
+     * Returns the shader program type that should be used to render
+     * this texture. Only valid after a matching BeginUpdate/EndUpdate
+     * pair have been called.
+     */
+    virtual ShaderProgramType GetShaderProgramType()
+    {
+         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; }
@@ -235,16 +258,17 @@ protected:
         , mIsRGBFormat(aIsRGB)
     {}
 
     GLuint mTexture;
     nsIntSize mSize;
     GLenum mWrapMode;
     ContentType mContentType;
     PRPackedBool mIsRGBFormat;
+    ShaderProgramType mShaderType;
 };
 
 /**
  * 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
@@ -275,22 +299,18 @@ protected:
         , mTextureInited(PR_FALSE)
         , mGLContext(aContext)
         , mUpdateOffset(0, 0)
     {}
 
     virtual already_AddRefed<gfxASurface>
     CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt) = 0;
 
-    virtual already_AddRefed<gfxImageSurface>
-    GetImageForUpload(gfxASurface* aUpdateSurface) = 0;
-
     PRBool mTextureInited;
     GLContext* mGLContext;
-    nsRefPtr<gfxImageSurface> mBackingSurface;
     nsRefPtr<gfxContext> mUpdateContext;
     nsIntRect mUpdateRect;
 
     // The offset into the update surface at which the update rect is located.
     nsIntPoint mUpdateOffset;
 };
 
 struct THEBES_API ContextFormat
@@ -350,29 +370,16 @@ struct THEBES_API ContextFormat
     int red, minRed;
     int green, minGreen;
     int blue, minBlue;
     int alpha, minAlpha;
 
     int colorBits() const { return red + green + blue; }
 };
 
-enum ShaderProgramType {
-    RGBALayerProgramType,
-    BGRALayerProgramType,
-    RGBXLayerProgramType,
-    BGRXLayerProgramType,
-    RGBARectLayerProgramType,
-    ColorLayerProgramType,
-    YCbCrLayerProgramType,
-    Copy2DProgramType,
-    Copy2DRectProgramType,
-    NumProgramTypes
-};
-
 class GLContext
     : public LibrarySymbolLoader
 {
     THEBES_INLINE_DECL_THREADSAFE_REFCOUNTING(GLContext)
 public:
     GLContext(const ContextFormat& aFormat,
               PRBool aIsOffscreen = PR_FALSE,
               GLContext *aSharedContext = nsnull)
--- a/gfx/thebes/GLContextProviderCGL.mm
+++ b/gfx/thebes/GLContextProviderCGL.mm
@@ -300,26 +300,34 @@ protected:
     BeginUpdate(nsIntRegion& aRegion)
     {
         ImageFormat format;
         if (GetContentType() == gfxASurface::CONTENT_COLOR)
             format = gfxASurface::ImageFormatRGB24;
         else
             format = gfxASurface::ImageFormatARGB32;
 
-        if (!mTextureInited || !mBackingSurface || !mUpdateSurface ||
-            nsIntSize(mBackingSurface->Width(), mBackingSurface->Height()) < mSize ||
-            mBackingSurface->Format() != format)
+        if (!mTextureInited || !mUpdateSurface ||
+            mUpdateSurface->GetContentType() != GetContentType())
         {
             mUpdateSurface = nsnull;
             mUpdateOffset = nsIntPoint(0, 0);
             // We need to (re)create our backing store. Let the base class to that.
             return BasicTextureImage::BeginUpdate(aRegion);
         }
 
+        nsRefPtr<gfxImageSurface> imageSurface = mUpdateSurface->GetAsImageSurface();
+        if (!imageSurface ||
+            nsIntSize(imageSurface->Width(), imageSurface->Height()) < mSize) {
+          mUpdateSurface = nsnull;
+          mUpdateOffset = nsIntPoint(0, 0);
+          // We need to (re)create our backing store. Let the base class to that.
+          return BasicTextureImage::BeginUpdate(aRegion);
+        }
+
         // the basic impl can only upload updates to rectangles
         mUpdateRect = aRegion.GetBounds();
         aRegion = nsIntRegion(mUpdateRect);
 
         if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
             NS_ERROR("update outside of image");
             return NULL;
         }
@@ -349,41 +357,16 @@ protected:
 
     virtual already_AddRefed<gfxASurface>
     CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt)
     {
         mUpdateFormat = aFmt;
         return gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
     }
 
-    virtual already_AddRefed<gfxImageSurface>
-    GetImageForUpload(gfxASurface* aUpdateSurface)
-    {
-        nsRefPtr<gfxImageSurface> image = aUpdateSurface->GetAsImageSurface();
-
-        if (image && image->Format() != mUpdateFormat) {
-          image = nsnull;
-        }
-
-        // If we don't get an image directly from the quartz surface, we have
-        // to take the slow boat.
-        if (!image) {
-          image = new gfxImageSurface(gfxIntSize(mUpdateRect.width,
-                                                 mUpdateRect.height),
-                                      mUpdateFormat);
-          nsRefPtr<gfxContext> tmpContext = new gfxContext(image);
-
-          tmpContext->SetSource(aUpdateSurface);
-          tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-          tmpContext->Paint();
-        }
-
-        return image.forget();
-    }
-
 private:
     TextureImageCGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
                     GLContext* aContext)
         : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext)
     {}
--- a/gfx/thebes/GLContextProviderEGL.cpp
+++ b/gfx/thebes/GLContextProviderEGL.cpp
@@ -965,16 +965,19 @@ public:
         // the stride right.
         if (mUpdateFormat == gfxASurface::ImageFormatRGB24) {
             mUpdateFormat = gfxASurface::ImageFormatARGB32;
         }
 
         if (gUseBackingSurface) {
             CreateBackingSurface(gfxIntSize(aSize.width, aSize.height));
         }
+
+        // We currently always use BGRA type textures
+        mShaderType = BGRALayerProgramType;
     }
 
     virtual ~TextureImageEGL()
     {
         GLContext *ctx = mGLContext;
         if (ctx->IsDestroyed() || !NS_IsMainThread()) {
             ctx = ctx->GetSharedContext();
         }
--- a/gfx/thebes/GLContextProviderGLX.cpp
+++ b/gfx/thebes/GLContextProviderGLX.cpp
@@ -421,32 +421,16 @@ class TextureImageGLX : public BasicText
 protected:
     virtual already_AddRefed<gfxASurface>
     CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt)
     {
         mUpdateFormat = aFmt;
         return gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
     }
 
-    virtual already_AddRefed<gfxImageSurface>
-    GetImageForUpload(gfxASurface* aUpdateSurface)
-    {
-        nsRefPtr<gfxImageSurface> image =
-            new gfxImageSurface(gfxIntSize(mUpdateRect.width,
-                                           mUpdateRect.height),
-                                mUpdateFormat);
-        nsRefPtr<gfxContext> tmpContext = new gfxContext(image);
-
-        tmpContext->SetSource(aUpdateSurface);
-        tmpContext->SetOperator(gfxContext::OPERATOR_SOURCE);
-        tmpContext->Paint();
-
-        return image.forget();
-    }
-
 private:
     TextureImageGLX(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
                     GLContext* aContext)
         : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext)
     {}
--- a/gfx/thebes/GLContextProviderWGL.cpp
+++ b/gfx/thebes/GLContextProviderWGL.cpp
@@ -459,34 +459,16 @@ protected:
     CreateUpdateSurface(const gfxIntSize& aSize, ImageFormat aFmt)
     {
         mUpdateSize = aSize;
         mUpdateFormat = aFmt;
 
         return gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFmt));
     }
 
-    virtual already_AddRefed<gfxImageSurface>
-    GetImageForUpload(gfxASurface* aUpdateSurface)
-    {
-        nsRefPtr<gfxImageSurface> uploadImage;
-
-        if (aUpdateSurface->GetType() == gfxASurface::SurfaceTypeWin32) {
-            uploadImage = aUpdateSurface->GetAsImageSurface();
-        } else {
-            uploadImage = new gfxImageSurface(mUpdateSize, mUpdateFormat);
-            nsRefPtr<gfxContext> cx(new gfxContext(uploadImage));
-            cx->SetSource(aUpdateSurface);
-            cx->SetOperator(gfxContext::OPERATOR_SOURCE);
-            cx->Paint();
-        }
-
-        return uploadImage.forget();
-    }
-
 private:
     TextureImageWGL(GLuint aTexture,
                     const nsIntSize& aSize,
                     GLenum aWrapMode,
                     ContentType aContentType,
                     GLContext* aContext)
         : BasicTextureImage(aTexture, aSize, aWrapMode, aContentType, aContext)
     {}