Bug 997551 - Avoid copying data in GetSourceSurfaceForSurface whenever possible. r=Bas
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 25 Apr 2014 15:31:53 +1200
changeset 180914 7eba5b89f831b0205ad16c018ecc383c50b6a41d
parent 180913 d9a6a378349a840f72466549292c7dbf43b228bf
child 180915 d6a1810f209276176ef79068cc8e23ea29d6e145
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
reviewersBas
bugs997551
milestone31.0a1
Bug 997551 - Avoid copying data in GetSourceSurfaceForSurface whenever possible. r=Bas
gfx/2d/DrawTargetD2D.cpp
gfx/2d/DrawTargetD2D1.cpp
gfx/thebes/gfxPlatform.cpp
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -1217,17 +1217,17 @@ DrawTargetD2D::OptimizeSourceSurface(Sou
   }
 
   RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
   bool success = newSurf->InitFromData(map.mData, data->GetSize(), map.mStride, data->GetFormat(), mRT);
 
   data->Unmap();
 
   if (!success) {
-    return nullptr;
+    return data;
   }
   return newSurf;
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
 {
   if (aSurface.mType != NativeSurfaceType::D3D10_TEXTURE) {
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -938,17 +938,17 @@ DrawTargetD2D1::OptimizeSourceSurface(So
   RefPtr<ID2D1Bitmap1> bitmap;
   HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.mData, map.mStride,
                                  D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())),
                                  byRef(bitmap));
 
   data->Unmap();
 
   if (!bitmap) {
-    return nullptr;
+    return data;
   }
 
   return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize());
 }
 
 void
 DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
 {
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -749,86 +749,36 @@ gfxPlatform::GetSourceSurfaceForSurface(
       // keeping it creates a cycle.
       return srcBuffer;
     }
   }
 
   if (!srcBuffer) {
     nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
 
-    RefPtr<DataSourceSurface> copy;
-    if (!imgSurface) {
-      copy = CopySurface(aSurface);
+    RefPtr<DataSourceSurface> dataSurf;
 
-      if (!copy) {
-        return nullptr;
-      }
-
-      DataSourceSurface::MappedSurface map;
-      DebugOnly<bool> result = copy->Map(DataSourceSurface::WRITE, &map);
-      MOZ_ASSERT(result, "Should always succeed mapping raw data surfaces!");
-
-      imgSurface = new gfxImageSurface(map.mData, aSurface->GetSize(), map.mStride,
-                                       SurfaceFormatToImageFormat(copy->GetFormat()));
+    if (imgSurface) {
+      dataSurf = GetWrappedDataSourceSurface(aSurface);
+    } else {
+      dataSurf = CopySurface(aSurface);
     }
 
-    gfxImageFormat cairoFormat = imgSurface->Format();
-    switch(cairoFormat) {
-      case gfxImageFormat::ARGB32:
-        format = SurfaceFormat::B8G8R8A8;
-        break;
-      case gfxImageFormat::RGB24:
-        format = SurfaceFormat::B8G8R8X8;
-        break;
-      case gfxImageFormat::A8:
-        format = SurfaceFormat::A8;
-        break;
-      case gfxImageFormat::RGB16_565:
-        format = SurfaceFormat::R5G6B5;
-        break;
-      default:
-        NS_RUNTIMEABORT("Invalid surface format!");
-    }
-
-    IntSize size = IntSize(imgSurface->GetSize().width, imgSurface->GetSize().height);
-    srcBuffer = aTarget->CreateSourceSurfaceFromData(imgSurface->Data(),
-                                                     size,
-                                                     imgSurface->Stride(),
-                                                     format);
-
-    if (copy) {
-      copy->Unmap();
-    }
-
-    if (!srcBuffer) {
-      // If we had to make a copy, then just return that. Otherwise aSurface
-      // must have supported GetAsImageSurface, so we can just wrap that data.
-      if (copy) {
-        srcBuffer = copy;
-      } else {
-        return GetWrappedDataSourceSurface(aSurface);
-      }
-    }
-
-    if (!srcBuffer) {
+    if (!dataSurf) {
       return nullptr;
     }
 
-#if MOZ_TREE_CAIRO
-    cairo_surface_t *nullSurf =
-    cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
-    cairo_surface_set_user_data(nullSurf,
-                                &kSourceSurface,
-                                imgSurface,
-                                nullptr);
-    cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
-    cairo_surface_destroy(nullSurf);
-#else
-    cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
-#endif
+    srcBuffer = aTarget->OptimizeSourceSurface(dataSurf);
+
+    if (imgSurface && srcBuffer == dataSurf) {
+      // Our wrapping surface will hold a reference to its image surface. We cause
+      // a reference cycle if we add it to the cache. And caching it is pretty
+      // pointless since we'll just wrap it again next use.
+     return srcBuffer;
+    }
   }
 
   // Add user data to aSurface so we can cache lookups in the future.
   SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
   srcSurfUD->mBackendType = aTarget->GetType();
   srcSurfUD->mSrcSurface = srcBuffer;
   aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);