Bug 717921. Only have one thebes surface. r=bas
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Fri, 13 Jan 2012 09:48:29 -0500
changeset 84642 fb32032a3982e099ee7a6af2914545d9c3200ef2
parent 84641 91ee34dffc9f3f51f0e16c16fc2923877e2cacd4
child 84643 656fff80b58ad4c3375e424655edc98cce092d7d
push id21868
push usermak77@bonardo.net
push dateTue, 17 Jan 2012 15:23:07 +0000
treeherdermozilla-central@ff1bedd7d463 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbas
bugs717921
milestone12.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 717921. Only have one thebes surface. r=bas
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
gfx/thebes/gfxPlatformMac.cpp
gfx/thebes/gfxWindowsPlatform.cpp
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -527,35 +527,58 @@ gfxPlatform::GetScaledFontForFont(gfxFon
 
 cairo_user_data_key_t kDrawSourceSurface;
 static void
 DataSourceSurfaceDestroy(void *dataSourceSurface)
 {
       static_cast<DataSourceSurface*>(dataSourceSurface)->Release();
 }
 
+void DestroyThebesSurface(void *data)
+{
+  gfxASurface *surface = static_cast<gfxASurface*>(data);
+  surface->Release();
+}
+
+UserDataKey ThebesSurfaceKey;
+
+// The semantics of this function are sort of weird. We snapshot the first
+// time and then return the snapshotted surface for the lifetime of the
+// draw target
 already_AddRefed<gfxASurface>
 gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
 {
+  void *surface = aTarget->GetUserData(&ThebesSurfaceKey);
+  if (surface) {
+    nsRefPtr<gfxASurface> surf = static_cast<gfxASurface*>(surface);
+    return surf.forget();
+  }
+
   RefPtr<SourceSurface> source = aTarget->Snapshot();
   RefPtr<DataSourceSurface> data = source->GetDataSurface();
 
   if (!data) {
     return NULL;
   }
 
   IntSize size = data->GetSize();
   gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat()));
   
-  nsRefPtr<gfxImageSurface> image =
+  nsRefPtr<gfxImageSurface> surf =
     new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height),
                         data->Stride(), format);
 
-  image->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
-  return image.forget();
+  surf->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy);
+
+  // add a reference to be held by the drawTarget
+  // careful, the reference graph is getting complicated here
+  surf->AddRef();
+  aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface);
+
+  return surf.forget();
 }
 
 RefPtr<DrawTarget>
 gfxPlatform::CreateOffscreenDrawTarget(const IntSize& aSize, SurfaceFormat aFormat)
 {
   BackendType backend;
   if (!SupportsAzure(backend)) {
     return NULL;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -66,16 +66,19 @@ struct gfxFontStyle;
 class gfxUserFontSet;
 class gfxFontEntry;
 class gfxProxyFontEntry;
 class gfxPlatformFontList;
 class gfxTextRun;
 class nsIURI;
 class nsIAtom;
 
+extern mozilla::gfx::UserDataKey ThebesSurfaceKey;
+void DestroyThebesSurface(void *data);
+
 extern cairo_user_data_key_t kDrawTarget;
 
 // pref lang id's for font prefs
 // !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
 // !!! don't use as bit mask, this may grow larger !!!
 
 enum eFontPrefLang {
     eFontPrefLang_Western     =  0,
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -298,26 +298,36 @@ gfxPlatformMac::ReadAntiAliasingThreshol
 
     return threshold;
 }
 
 already_AddRefed<gfxASurface>
 gfxPlatformMac::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
 {
   if (aTarget->GetType() == BACKEND_COREGRAPHICS) {
-    CGContextRef cg = static_cast<CGContextRef>(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT));
+    void *surface = aTarget->GetUserData(&ThebesSurfaceKey);
+    if (surface) {
+      nsRefPtr<gfxASurface> surf = static_cast<gfxQuartzSurface*>(surface);
+      return surf.forget();
+    } else {
+      CGContextRef cg = static_cast<CGContextRef>(aTarget->GetNativeSurface(NATIVE_SURFACE_CGCONTEXT));
 
-    //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize
-    IntSize intSize = aTarget->GetSize();
-    gfxIntSize size(intSize.width, intSize.height);
+      //XXX: it would be nice to have an implicit conversion from IntSize to gfxIntSize
+      IntSize intSize = aTarget->GetSize();
+      gfxIntSize size(intSize.width, intSize.height);
+
+      nsRefPtr<gfxASurface> surf =
+        new gfxQuartzSurface(cg, size);
 
-    nsRefPtr<gfxASurface> surf =
-      new gfxQuartzSurface(cg, size);
+      // add a reference to be held by the drawTarget
+      surf->AddRef();
+      aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface);
 
-    return surf.forget();
+      return surf.forget();
+    }
   }
 
   return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
 }
 
 
 qcms_profile *
 gfxPlatformMac::GetPlatformCMSOutputProfile()
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -502,32 +502,45 @@ gfxWindowsPlatform::GetScaledFontForFont
   return scaledFont;
 }
 
 already_AddRefed<gfxASurface>
 gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
 {
 #ifdef XP_WIN
   if (aTarget->GetType() == BACKEND_DIRECT2D) {
-    RefPtr<ID3D10Texture2D> texture =
-      static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE));
+    void *surface = aTarget->GetUserData(&ThebesSurfaceKey);
+    if (surface) {
+      nsRefPtr<gfxASurface> surf = static_cast<gfxASurface*>(surface);
+      return surf.forget();
+    } else {
+      RefPtr<ID3D10Texture2D> texture =
+        static_cast<ID3D10Texture2D*>(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE));
 
-    if (!texture) {
-      return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
-    }
+      if (!texture) {
+        return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
+      }
+
+      aTarget->Flush();
 
-    aTarget->Flush();
-
-    nsRefPtr<gfxASurface> surf =
-      new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat()));
+      nsRefPtr<gfxASurface> surf =
+        new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat()));
 
-    // shouldn't this hold a reference?
-    surf->SetData(&kDrawTarget, aTarget, NULL);
+      // add a reference to be held by the drawTarget
+      surf->AddRef();
+      aTarget->AddUserData(&ThebesSurfaceKey, surf.get(), DestroyThebesSurface);
+      /* "It might be worth it to clear cairo surfaces associated with a drawtarget.
+	  The strong reference means for example for D2D that cairo's scratch surface
+	  will be kept alive (well after a user being done) and consume extra VRAM.
+	  We can deal with this in a follow-up though." */
 
-    return surf.forget();
+      // shouldn't this hold a reference?
+      surf->SetData(&kDrawTarget, aTarget, NULL);
+      return surf.forget();
+    }
   }
 #endif
 
   return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget);
 }
 
 bool
 gfxWindowsPlatform::SupportsAzure(BackendType& aBackend)