Bug 1244228 - fix DrawTargetSkia::OptimizeSourceSurface to still create Skia surfaces for GPU canvases even if creating a GPU surface failed. r=jmuizelaar, a=lizzard
authorLee Salzman <lsalzman@mozilla.com>
Wed, 03 Feb 2016 13:49:36 -0500
changeset 304148 ca4016cf7300c81ec23bd75c910e5a6fc1358c86
parent 304147 2cfe2a55e06adcb5a3b5205d7d8f1b0ac0547629
child 304149 e9d96b7d7d7b69bec7f466a10de5335ed8e00d70
push id9109
push usercbook@mozilla.com
push dateMon, 22 Feb 2016 14:23:59 +0000
treeherdermozilla-aurora@ca4016cf7300 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar, lizzard
bugs1244228
milestone46.0a2
Bug 1244228 - fix DrawTargetSkia::OptimizeSourceSurface to still create Skia surfaces for GPU canvases even if creating a GPU surface failed. r=jmuizelaar, a=lizzard
gfx/2d/DrawTargetSkia.cpp
gfx/2d/DrawTargetSkia.h
gfx/2d/HelpersSkia.h
gfx/2d/SourceSurfaceSkia.cpp
gfx/2d/SourceSurfaceSkia.h
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -692,17 +692,18 @@ DrawTargetSkia::CreateSourceSurfaceFromD
 
 already_AddRefed<DrawTarget>
 DrawTargetSkia::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
 {
   RefPtr<DrawTargetSkia> target = new DrawTargetSkia();
 #ifdef USE_SKIA_GPU
   if (UsingSkiaGPU()) {
     // Try to create a GPU draw target first if we're currently using the GPU.
-    if (target->InitWithGrContext(mGrContext.get(), aSize, aFormat)) {
+    // Mark the DT as cached so that shadow DTs, extracted subrects, and similar can be reused.
+    if (target->InitWithGrContext(mGrContext.get(), aSize, aFormat, true)) {
       return target.forget();
     }
     // Otherwise, just fall back to a software draw target.
   }
 #endif
   if (!target->Init(aSize, aFormat)) {
     return nullptr;
   }
@@ -726,27 +727,41 @@ DrawTargetSkia::OptimizeSourceSurface(So
   if (UsingSkiaGPU()) {
     // Check if the underlying SkBitmap already has an associated GrTexture.
     if (aSurface->GetType() == SurfaceType::SKIA &&
         static_cast<SourceSurfaceSkia*>(aSurface)->GetBitmap().getTexture()) {
       RefPtr<SourceSurface> surface(aSurface);
       return surface.forget();
     }
 
+    SkBitmap bitmap = GetBitmapForSurface(aSurface);
+
     // Upload the SkBitmap to a GrTexture otherwise.
     SkAutoTUnref<GrTexture> texture(
-      GrRefCachedBitmapTexture(mGrContext.get(),
-                               GetBitmapForSurface(aSurface),
-                               GrTextureParams::ClampBilerp()));
+      GrRefCachedBitmapTexture(mGrContext.get(), bitmap, GrTextureParams::ClampBilerp()));
 
-    // Create a new SourceSurfaceSkia whose SkBitmap contains the GrTexture.
-    RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
-    if (surface->InitFromGrTexture(texture, aSurface->GetSize(), aSurface->GetFormat())) {
+    if (texture) {
+      // Create a new SourceSurfaceSkia whose SkBitmap contains the GrTexture.
+      RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
+      if (surface->InitFromGrTexture(texture, aSurface->GetSize(), aSurface->GetFormat())) {
+        return surface.forget();
+      }
+    }
+
+    // The data was too big to fit in a GrTexture.
+    if (aSurface->GetType() == SurfaceType::SKIA) {
+      // It is already a Skia source surface, so just reuse it as-is.
+      RefPtr<SourceSurface> surface(aSurface);
       return surface.forget();
     }
+
+    // Wrap it in a Skia source surface so that can do tiled uploads on-demand.
+    RefPtr<SourceSurfaceSkia> surface = new SourceSurfaceSkia();
+    surface->InitFromBitmap(bitmap);
+    return surface.forget();
   }
 #endif
 
   if (aSurface->GetType() == SurfaceType::SKIA) {
     RefPtr<SourceSurface> surface(aSurface);
     return surface.forget();
   }
 
@@ -842,30 +857,53 @@ DrawTargetSkia::Init(const IntSize &aSiz
   mCanvas.adopt(new SkCanvas(bitmap));
   mSize = aSize;
 
   mFormat = aFormat;
   return true;
 }
 
 #ifdef USE_SKIA_GPU
+/** Indicating a DT should be cached means that space will be reserved in Skia's cache
+ * for the render target at creation time, with any unused resources exceeding the cache
+ * limits being purged. When the DT is freed, it will then be guaranteed to be kept around
+ * for subsequent allocations until it gets incidentally purged.
+ *
+ * If it is not marked as cached, no space will be purged to make room for the render
+ * target in the cache. When the DT is freed, If there is space within the resource limits
+ * it may be added to the cache, otherwise it will be freed immediately if the cache is
+ * already full.
+ *
+ * If you want to ensure that the resources will be kept around for reuse, it is better
+ * to mark them as cached. Such resources should be short-lived to ensure they don't
+ * permanently tie up cache resource limits. Long-lived resources should generally be
+ * left as uncached.
+ *
+ * In neither case will cache resource limits affect whether the resource allocation
+ * succeeds. The amount of in-use GPU resources is allowed to exceed the size of the cache.
+ * Thus, only hard GPU out-of-memory conditions will cause resource allocation to fail.
+ */
 bool
 DrawTargetSkia::InitWithGrContext(GrContext* aGrContext,
                                   const IntSize &aSize,
-                                  SurfaceFormat aFormat)
+                                  SurfaceFormat aFormat,
+                                  bool aCached)
 {
   MOZ_ASSERT(aGrContext, "null GrContext");
 
   if (size_t(std::max(aSize.width, aSize.height)) > GetMaxSurfaceSize()) {
     return false;
   }
 
   // Create a GPU rendertarget/texture using the supplied GrContext.
   // NewRenderTarget also implicitly clears the underlying texture on creation.
-  SkAutoTUnref<SkSurface> gpuSurface(SkSurface::NewRenderTarget(aGrContext, SkSurface::kNo_Budgeted, MakeSkiaImageInfo(aSize, aFormat)));
+  SkAutoTUnref<SkSurface> gpuSurface(
+    SkSurface::NewRenderTarget(aGrContext,
+                               SkSurface::Budgeted(aCached),
+                               MakeSkiaImageInfo(aSize, aFormat)));
   if (!gpuSurface) {
     return false;
   }
 
   mGrContext = aGrContext;
   mSize = aSize;
   mFormat = aFormat;
 
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -111,17 +111,24 @@ public:
   virtual void *GetNativeSurface(NativeSurfaceType aType) override;
 
   bool Init(const IntSize &aSize, SurfaceFormat aFormat);
   void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
 
 #ifdef USE_SKIA_GPU
   bool InitWithGrContext(GrContext* aGrContext,
                          const IntSize &aSize,
-                         SurfaceFormat aFormat) override;
+                         SurfaceFormat aFormat,
+                         bool aCached);
+  virtual bool
+    InitWithGrContext(GrContext* aGrContext,
+                      const IntSize &aSize,
+                      SurfaceFormat aFormat) override {
+    return InitWithGrContext(aGrContext, aSize, aFormat, false);
+  }
 #endif
 
   // Skia assumes that texture sizes fit in 16-bit signed integers.
   static size_t GetMaxSurfaceSize() {
     return 32767;
   }
 
   operator std::string() const {
--- a/gfx/2d/HelpersSkia.h
+++ b/gfx/2d/HelpersSkia.h
@@ -35,22 +35,23 @@ GfxFormatToSkiaColorType(SurfaceFormat f
     case SurfaceFormat::A8:
       return kAlpha_8_SkColorType;
     default:
       return kRGBA_8888_SkColorType;
   }
 }
 
 static inline SurfaceFormat
-SkiaColorTypeToGfxFormat(SkColorType type)
+SkiaColorTypeToGfxFormat(SkColorType aColorType, SkAlphaType aAlphaType = kPremul_SkAlphaType)
 {
-  switch (type)
+  switch (aColorType)
   {
     case kBGRA_8888_SkColorType:
-      return SurfaceFormat::B8G8R8A8;
+      return aAlphaType == kOpaque_SkAlphaType ?
+               SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
     case kRGB_565_SkColorType:
       return SurfaceFormat::R5G6B5_UINT16;
     case kAlpha_8_SkColorType:
       return SurfaceFormat::A8;
     default:
       return SurfaceFormat::B8G8R8A8;
   }
 }
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -76,16 +76,26 @@ SourceSurfaceSkia::InitFromData(unsigned
   }
 
   mSize = aSize;
   mFormat = aFormat;
   mStride = mBitmap.rowBytes();
   return true;
 }
 
+void
+SourceSurfaceSkia::InitFromBitmap(const SkBitmap& aBitmap)
+{
+  mBitmap = aBitmap;
+
+  mSize = IntSize(mBitmap.width(), mBitmap.height());
+  mFormat = SkiaColorTypeToGfxFormat(mBitmap.colorType(), mBitmap.alphaType());
+  mStride = mBitmap.rowBytes();
+}
+
 #ifdef USE_SKIA_GPU
 bool
 SourceSurfaceSkia::InitFromGrTexture(GrTexture* aTexture,
                                      const IntSize &aSize,
                                      SurfaceFormat aFormat)
 {
   if (!aTexture) {
     return false;
--- a/gfx/2d/SourceSurfaceSkia.h
+++ b/gfx/2d/SourceSurfaceSkia.h
@@ -34,16 +34,18 @@ public:
                     const IntSize &aSize,
                     int32_t aStride,
                     SurfaceFormat aFormat);
 
   bool InitFromCanvas(SkCanvas* aCanvas,
                       SurfaceFormat aFormat,
                       DrawTargetSkia* aOwner);
 
+  void InitFromBitmap(const SkBitmap& aBitmap);
+
 #ifdef USE_SKIA_GPU
   /**
    * NOTE: While wrapping a Texture for SkiaGL, the texture *must* be created
    *       with the same GLcontext of DrawTargetSkia
    */
   bool InitFromGrTexture(GrTexture* aTexture,
                          const IntSize &aSize,
                          SurfaceFormat aFormat);