Bug 1279063 - Part 1: Don't assume cairo is the default software backend. r=lsalzman
authorMason Chang <mchang@mozilla.com>
Mon, 25 Jul 2016 16:36:35 -0700
changeset 306601 f1f81ccfb6d434579b5b58c8e78f175a7ffb9d72
parent 306600 51d3deee1f3265cbb71b4bd3de8b369ba7610961
child 306602 9bbf47e4f280bb654257b0d88c0a2baea2c1ffb9
push id20110
push usercbook@mozilla.com
push dateTue, 26 Jul 2016 09:59:54 +0000
treeherderfx-team@864194eff6a9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1279063
milestone50.0a1
Bug 1279063 - Part 1: Don't assume cairo is the default software backend. r=lsalzman
gfx/2d/DrawTargetSkia.cpp
gfx/thebes/gfxWindowsPlatform.cpp
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -97,16 +97,83 @@ static void
 ReleaseTemporarySurface(void* aPixels, void* aContext)
 {
   DataSourceSurface* surf = static_cast<DataSourceSurface*>(aContext);
   if (surf) {
     surf->Release();
   }
 }
 
+#ifdef DEBUG
+static bool
+VerifyRGBXFormat(uint8_t* aData, const IntSize &aSize, const int32_t aStride, SurfaceFormat aFormat)
+{
+  if (aFormat != SurfaceFormat::B8G8R8X8 || aSize.IsEmpty()) {
+    return true;
+  }
+  // We should've initialized the data to be opaque already
+  // On debug builds, verify that this is actually true.
+  int height = aSize.height;
+  int width = aSize.width;
+
+  for (int row = 0; row < height; ++row) {
+    for (int column = 0; column < width; column += 4) {
+#ifdef IS_BIG_ENDIAN
+      MOZ_ASSERT(aData[column] == 0xFF);
+#else
+      MOZ_ASSERT(aData[column + 3] == 0xFF);
+#endif
+    }
+    aData += aStride;
+  }
+
+  return true;
+}
+
+// Since checking every pixel is expensive, this only checks the four corners and center
+// of a surface that their alpha value is 0xFF.
+static bool
+VerifyRGBXCorners(uint8_t* aData, const IntSize &aSize, const int32_t aStride, SurfaceFormat aFormat)
+{
+  if (aFormat != SurfaceFormat::B8G8R8X8 || aSize.IsEmpty()) {
+    return true;
+  }
+
+  int height = aSize.height;
+  int width = aSize.width;
+  const int pixelSize = 4;
+  const int strideDiff = aStride - (width * pixelSize);
+  MOZ_ASSERT(width * pixelSize <= aStride);
+
+#ifdef IS_BIG_ENDIAN
+  const int alphaOffset = 0;
+#else
+  const int alphaOffset = 3;
+#endif
+
+  const int topLeft = alphaOffset;
+  const int topRight = width * pixelSize + alphaOffset - pixelSize;
+  const int bottomRight = aStride * height - strideDiff + alphaOffset - pixelSize;
+  const int bottomLeft = aStride * height - aStride + alphaOffset;
+
+  // Lastly the center pixel
+  int middleRowHeight = height / 2;
+  int middleRowWidth = (width / 2) * pixelSize;
+  const int middle = aStride * middleRowHeight + middleRowWidth + alphaOffset;
+
+  MOZ_ASSERT(aData[topLeft] == 0xFF);
+  MOZ_ASSERT(aData[topRight] == 0xFF);
+  MOZ_ASSERT(aData[bottomRight] == 0xFF);
+  MOZ_ASSERT(aData[bottomLeft] == 0xFF);
+  MOZ_ASSERT(aData[middle] == 0xFF);
+
+  return true;
+}
+#endif
+
 static SkBitmap
 GetBitmapForSurface(SourceSurface* aSurface)
 {
   SkBitmap bitmap;
 
   if (!aSurface) {
     gfxDebug() << "Creating empty Skia bitmap from null SourceSurface";
     return bitmap;
@@ -124,16 +191,19 @@ GetBitmapForSurface(SourceSurface* aSurf
   }
 
   if (!bitmap.installPixels(MakeSkiaImageInfo(surf->GetSize(), surf->GetFormat()),
                             surf->GetData(), surf->Stride(), nullptr,
                             ReleaseTemporarySurface, surf)) {
     gfxDebug() << "Failed installing pixels on Skia bitmap for temporary surface";
   }
 
+  // Skia doesn't support RGBX surfaces so ensure that the alpha value is opaque white.
+  MOZ_ASSERT(VerifyRGBXCorners(surf->GetData(), surf->GetSize(),
+                               surf->Stride(), surf->GetFormat()));
   return bitmap;
 }
 
 DrawTargetSkia::DrawTargetSkia()
   : mSnapshot(nullptr)
 #ifdef MOZ_WIDGET_COCOA
   , mCG(nullptr)
   , mColorSpace(nullptr)
@@ -1329,17 +1399,20 @@ DrawTargetSkia::OptimizeSourceSurface(So
     RefPtr<SourceSurface> surface(aSurface);
     return surface.forget();
   }
 
   // If we're not using skia-gl then drawing doesn't require any
   // uploading, so any data surface is fine. Call GetDataSurface
   // to trigger any required readback so that it only happens
   // once.
-  return aSurface->GetDataSurface();
+  RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
+  MOZ_ASSERT(VerifyRGBXFormat(dataSurface->GetData(), dataSurface->GetSize(),
+                              dataSurface->Stride(), dataSurface->GetFormat()));
+  return dataSurface.forget();
 }
 
 already_AddRefed<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
 {
 #if USE_SKIA_GPU
   if (aSurface.mType == NativeSurfaceType::OPENGL_TEXTURE && UsingSkiaGPU()) {
     // Wrap the OpenGL texture id in a Skia texture handle.
@@ -1410,17 +1483,18 @@ DrawTargetSkia::Init(const IntSize &aSiz
   int stride = (BytesPerPixel(aFormat)*aSize.width + (4-1)) & -4;
 
   SkBitmap bitmap;
   bitmap.setInfo(MakeSkiaImageInfo(aSize, aFormat), stride);
   if (!bitmap.tryAllocPixels()) {
     return false;
   }
 
-  bitmap.eraseColor(SK_ColorTRANSPARENT);
+  SkColor clearColor = (aFormat == SurfaceFormat::B8G8R8X8) ? SK_ColorBLACK : SK_ColorTRANSPARENT;
+  bitmap.eraseColor(clearColor);
 
   mCanvas.adopt(new SkCanvas(bitmap));
   mSize = aSize;
 
   mFormat = aFormat;
   return true;
 }
 
@@ -1472,40 +1546,16 @@ DrawTargetSkia::InitWithGrContext(GrCont
 
   mCanvas = gpuSurface->getCanvas();
 
   return true;
 }
 
 #endif
 
-#ifdef DEBUG
-bool
-VerifyRGBXFormat(uint8_t* aData, const IntSize &aSize, const int32_t aStride, SurfaceFormat aFormat)
-{
-  // We should've initialized the data to be opaque already
-  // On debug builds, verify that this is actually true.
-  int height = aSize.height;
-  int width = aSize.width;
-
-  for (int row = 0; row < height; ++row) {
-    for (int column = 0; column < width; column += 4) {
-#ifdef IS_BIG_ENDIAN
-      MOZ_ASSERT(aData[column] == 0xFF);
-#else
-      MOZ_ASSERT(aData[column + 3] == 0xFF);
-#endif
-    }
-    aData += aStride;
-  }
-
-  return true;
-}
-#endif
-
 void
 DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized)
 {
   MOZ_ASSERT((aFormat != SurfaceFormat::B8G8R8X8) ||
               aUninitialized || VerifyRGBXFormat(aData, aSize, aStride, aFormat));
 
   SkBitmap bitmap;
   bitmap.setInfo(MakeSkiaImageInfo(aSize, aFormat), aStride);
@@ -1553,17 +1603,18 @@ DrawTargetSkia::CreatePathBuilder(FillRu
 }
 
 void
 DrawTargetSkia::ClearRect(const Rect &aRect)
 {
   MarkChanged();
   mCanvas->save();
   mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, true);
-  mCanvas->clear(SK_ColorTRANSPARENT);
+  SkColor clearColor = (mFormat == SurfaceFormat::B8G8R8X8) ? SK_ColorBLACK : SK_ColorTRANSPARENT;
+  mCanvas->clear(clearColor);
   mCanvas->restore();
 }
 
 void
 DrawTargetSkia::PushClip(const Path *aPath)
 {
   if (aPath->GetBackendType() != BackendType::SKIA) {
     return;
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -471,24 +471,22 @@ gfxWindowsPlatform::HandleDeviceReset()
   gfxAlphaBoxBlur::ShutdownBlurCache();
 
   InitializeDevices();
   UpdateANGLEConfig();
   BumpDeviceCounter();
   return true;
 }
 
-static const BackendType SOFTWARE_BACKEND = BackendType::CAIRO;
-
 void
 gfxWindowsPlatform::UpdateBackendPrefs()
 {
-  uint32_t canvasMask = BackendTypeBit(SOFTWARE_BACKEND);
-  uint32_t contentMask = BackendTypeBit(SOFTWARE_BACKEND);
-  BackendType defaultBackend = SOFTWARE_BACKEND;
+  uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
+  uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
+  BackendType defaultBackend = BackendType::CAIRO;
   if (gfxConfig::IsEnabled(Feature::DIRECT2D) && Factory::GetD2D1Device()) {
     contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
     canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
     defaultBackend = BackendType::DIRECT2D1_1;
   } else {
     canvasMask |= BackendTypeBit(BackendType::SKIA);
   }
   contentMask |= BackendTypeBit(BackendType::SKIA);
@@ -531,22 +529,28 @@ gfxWindowsPlatform::ForceDeviceReset(For
 
   mDeviceResetReason = DeviceResetReason::FORCED_RESET;
   mHasDeviceReset = true;
 }
 
 mozilla::gfx::BackendType
 gfxWindowsPlatform::GetContentBackendFor(mozilla::layers::LayersBackend aLayers)
 {
+  mozilla::gfx::BackendType defaultBackend = gfxPlatform::GetDefaultContentBackend();
   if (aLayers == LayersBackend::LAYERS_D3D11) {
-    return gfxPlatform::GetDefaultContentBackend();
+    return defaultBackend;
   }
 
-  // If we're not accelerated with D3D11, never use D2D.
-  return SOFTWARE_BACKEND;
+  if (defaultBackend == BackendType::DIRECT2D1_1) {
+    // We can't have D2D without D3D11 layers, so fallback to Cairo.
+    return BackendType::CAIRO;
+  }
+
+  // Otherwise we have some non-accelerated backend and that's ok.
+  return defaultBackend;
 }
 
 gfxPlatformFontList*
 gfxWindowsPlatform::CreatePlatformFontList()
 {
     gfxPlatformFontList *pfl;
 
     // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd