Bug 1593574. Create an opaque surface for fallback when possible. r=mattwoodrow
authorJeff Muizelaar <jrmuizel@gmail.com>
Tue, 14 Jan 2020 19:37:42 +0000
changeset 510284 ffe6b31202b5a45c89d39faaddc51373e2d0adb3
parent 510283 f980191897a2ceb0514f83df997dc05a349f54db
child 510285 16dbf91296d4becc28cf5cc1a46aed4ef206b30f
push id37017
push usercsabou@mozilla.com
push dateWed, 15 Jan 2020 09:38:07 +0000
treeherdermozilla-central@5ba39736e74b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1593574
milestone74.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 1593574. Create an opaque surface for fallback when possible. r=mattwoodrow This moves the opaqueness calculation out of if (blob) condition and changes how we calculate the size of the fallback surface depending on whether we have a compltely opaque snapped item or now. This change allows scrollbars to marked as opaque on Windows which reduces the GPU utilization in the DWM with DirectComposite on from 21% to 17% at 1080p and 29% to 24% at 4k Differential Revision: https://phabricator.services.mozilla.com/D51557
gfx/layers/wr/WebRenderCommandBuilder.cpp
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1386,16 +1386,42 @@ static mozilla::gfx::IntRect ScaleToOuts
           aOffset.x),
       NSToIntCeil(
           NSAppUnitsToFloatPixels(aRect.YMost(), float(aAppUnitsPerPixel)) *
               aYScale +
           aOffset.y));
   return rect;
 }
 
+/* This function is the same as the above except that it rounds to the
+ * nearest instead of rounding out. We use it for attempting to compute the
+ * actual pixel bounds of opaque items */
+static mozilla::gfx::IntRect ScaleToNearestPixelsOffset(
+    nsRect aRect, float aXScale, float aYScale, nscoord aAppUnitsPerPixel,
+    LayerPoint aOffset) {
+  mozilla::gfx::IntRect rect;
+  rect.SetNonEmptyBox(
+      NSToIntFloor(NSAppUnitsToFloatPixels(aRect.x, float(aAppUnitsPerPixel)) *
+                       aXScale +
+                   aOffset.x + 0.5),
+      NSToIntFloor(NSAppUnitsToFloatPixels(aRect.y, float(aAppUnitsPerPixel)) *
+                       aYScale +
+                   aOffset.y + 0.5),
+      NSToIntFloor(
+          NSAppUnitsToFloatPixels(aRect.XMost(), float(aAppUnitsPerPixel)) *
+              aXScale +
+          aOffset.x + 0.5),
+      NSToIntFloor(
+          NSAppUnitsToFloatPixels(aRect.YMost(), float(aAppUnitsPerPixel)) *
+              aYScale +
+          aOffset.y + 0.5));
+  return rect;
+}
+
+
 RenderRootStateManager* WebRenderCommandBuilder::GetRenderRootStateManager(
     wr::RenderRoot aRenderRoot) {
   return mManager->GetRenderRootStateManager(aRenderRoot);
 }
 
 void WebRenderCommandBuilder::DoGroupingForDisplayList(
     nsDisplayList* aList, nsDisplayItem* aWrappingItem,
     nsDisplayListBuilder* aDisplayListBuilder, const StackingContextHelper& aSc,
@@ -2140,25 +2166,51 @@ WebRenderCommandBuilder::GenerateFallbac
 
   LayoutDeviceToLayerScale2D layerScale(scale.width, scale.height);
 
   auto trans =
       ViewAs<LayerPixel>(aSc.GetSnappingSurfaceTransform().GetTranslation());
   auto snappedTrans = LayerIntPoint::Floor(trans);
   LayerPoint residualOffset = trans - snappedTrans;
 
-  auto dtRect = LayerIntRect::FromUnknownRect(
+  nsRegion opaqueRegion =
+    aItem->GetOpaqueRegion(aDisplayListBuilder, &snap);
+  wr::OpacityType opacity = opaqueRegion.Contains(paintBounds)
+    ? wr::OpacityType::Opaque
+    : wr::OpacityType::HasAlphaChannel;
+
+  LayerIntRect dtRect, visibleRect;
+  // If we think the item is opaque we round the bounds
+  // to the nearest pixel instead of rounding them out. If we rounded
+  // out we'd potentially introduce transparent pixels.
+  //
+  // Ideally we'd be able to ask an item its bounds in pixels and whether
+  // they're all opaque. Unfortunately no such API exists so we currently
+  // just hope that we get it right.
+  if (opacity == wr::OpacityType::Opaque && snap) {
+    dtRect = LayerIntRect::FromUnknownRect(
+      ScaleToNearestPixelsOffset(paintBounds, scale.width, scale.height,
+                                 appUnitsPerDevPixel, residualOffset));
+
+    visibleRect = LayerIntRect::FromUnknownRect(
+                         ScaleToNearestPixelsOffset(
+                             aItem->GetBuildingRect(), scale.width,
+                             scale.height, appUnitsPerDevPixel, residualOffset))
+                         .Intersect(dtRect);
+  } else {
+    dtRect = LayerIntRect::FromUnknownRect(
       ScaleToOutsidePixelsOffset(paintBounds, scale.width, scale.height,
                                  appUnitsPerDevPixel, residualOffset));
 
-  auto visibleRect = LayerIntRect::FromUnknownRect(
+    visibleRect = LayerIntRect::FromUnknownRect(
                          ScaleToOutsidePixelsOffset(
                              aItem->GetBuildingRect(), scale.width,
                              scale.height, appUnitsPerDevPixel, residualOffset))
                          .Intersect(dtRect);
+  }
 
   auto visibleSize = visibleRect.Size();
   if (visibleSize.IsEmpty()) {
     return nullptr;
   }
 
   if (useBlobImage) {
     // Display item bounds should be unscaled
@@ -2206,25 +2258,22 @@ WebRenderCommandBuilder::GenerateFallbac
 
   if (needPaint || !fallbackData->GetImageKey()) {
     nsAutoPtr<nsDisplayItemGeometry> newGeometry;
     newGeometry = aItem->AllocateGeometry(aDisplayListBuilder);
     fallbackData->mGeometry = std::move(newGeometry);
 
     gfx::SurfaceFormat format = aItem->GetType() == DisplayItemType::TYPE_MASK
                                     ? gfx::SurfaceFormat::A8
-                                    : gfx::SurfaceFormat::B8G8R8A8;
+                                    : (opacity == wr::OpacityType::Opaque ?
+                                       gfx::SurfaceFormat::B8G8R8X8 :
+                                       gfx::SurfaceFormat::B8G8R8A8);
     if (useBlobImage) {
-      bool snapped;
-      nsRegion opaqueRegion =
-          aItem->GetOpaqueRegion(aDisplayListBuilder, &snapped);
       MOZ_ASSERT(!opaqueRegion.IsComplex());
-      wr::OpacityType opacity = opaqueRegion.Contains(paintBounds)
-                                    ? wr::OpacityType::Opaque
-                                    : wr::OpacityType::HasAlphaChannel;
+
       std::vector<RefPtr<ScaledFont>> fonts;
       bool validFonts = true;
       RefPtr<WebRenderDrawEventRecorder> recorder =
           MakeAndAddRef<WebRenderDrawEventRecorder>(
               [&](MemStream& aStream,
                   std::vector<RefPtr<ScaledFont>>& aScaledFonts) {
                 size_t count = aScaledFonts.size();
                 aStream.write((const char*)&count, sizeof(count));