Bug 575521 - Use the APPLE_client_storage extension to reduce the number of copies of data we make when uploading textures. r=vlad
authorJoe Drew <joe@drew.ca>
Thu, 11 Nov 2010 15:31:23 -0500
changeset 57350 331f67eda6deb84be296c6303f56fa5603496d22
parent 57349 3be1fabf50b818bfc32a29185b6b409df270d927
child 57351 182eb3c4fc44c29adb959bafbe29825f05cedc25
push id16887
push userjdrew@mozilla.com
push dateThu, 11 Nov 2010 20:37:00 +0000
treeherdermozilla-central@182eb3c4fc44 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad
bugs575521
milestone2.0b8pre
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 575521 - Use the APPLE_client_storage extension to reduce the number of copies of data we make when uploading textures. r=vlad
gfx/thebes/GLContext.cpp
gfx/thebes/GLContext.h
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -504,43 +504,51 @@ 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
-    if (!mTextureInited)
-        // if the texture hasn't been initialized yet, force the
+    ImageFormat format =
+        (GetContentType() == gfxASurface::CONTENT_COLOR) ?
+        gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
+    if (!mTextureInited || !mBackingSurface ||
+        mBackingSurface->GetSize() != gfxIntSize(mSize.width, mSize.height) ||
+        mBackingSurface->Format() != format) {
+        // 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);
-    else
+        mTextureInited = PR_FALSE;
+    } else {
         mUpdateRect = aRegion.GetBounds();
+    }
+
     // the basic impl can't upload updates to disparate regions,
     // only rects
     aRegion = nsIntRegion(mUpdateRect);
-        
+
     nsIntSize rgnSize = mUpdateRect.Size();
     if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
         NS_ERROR("update outside of image");
         return NULL;
     }
 
-    ImageFormat format =
-        (GetContentType() == gfxASurface::CONTENT_COLOR) ?
-        gfxASurface::ImageFormatRGB24 : gfxASurface::ImageFormatARGB32;
     nsRefPtr<gfxASurface> updateSurface =
         CreateUpdateSurface(gfxIntSize(rgnSize.width, rgnSize.height),
                             format);
     if (!updateSurface)
         return NULL;
 
     updateSurface->SetDeviceOffset(gfxPoint(-mUpdateRect.x, -mUpdateRect.y));
 
@@ -567,42 +575,63 @@ BasicTextureImage::EndUpdate()
     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());
+
+        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 {
         mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
                                    0,
                                    mUpdateRect.x,
                                    mUpdateRect.y,
                                    mUpdateRect.width,
                                    mUpdateRect.height,
                                    LOCAL_GL_RGBA,
                                    LOCAL_GL_UNSIGNED_BYTE,
                                    uploadImage->Data());
     }
     mUpdateContext = NULL;
 
-    // Reset row length to use the default.
+    // Reset pixel store attributes to use the defaults.
     mGLContext->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
 
     return PR_TRUE;         // mTexture is bound
 }
 
 void
 BasicTextureImage::Resize(const nsIntSize& aSize)
 {
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -46,16 +46,17 @@
 #include <ctype.h>
 
 #ifdef WIN32
 #include <windows.h>
 #endif
 
 #include "GLDefs.h"
 #include "gfxASurface.h"
+#include "gfxImageSurface.h"
 #include "gfxContext.h"
 #include "gfxRect.h"
 #include "nsISupportsImpl.h"
 #include "prlink.h"
 
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsRegion.h"
@@ -272,16 +273,17 @@ protected:
     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;
 };
 
 struct THEBES_API ContextFormat
 {
     static const ContextFormat BasicRGBA32Format;