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 348699 f1f81ccfb6d434579b5b58c8e78f175a7ffb9d72
parent 348698 51d3deee1f3265cbb71b4bd3de8b369ba7610961
child 348700 9bbf47e4f280bb654257b0d88c0a2baea2c1ffb9
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1279063
milestone50.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 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