Bug 1414264 - Check invalidation region when we use layer system to paint items. r=jrmuizel
authorEthan Lin <ethlin@mozilla.com>
Tue, 07 Nov 2017 14:40:08 +0800
changeset 444711 b42edef23af75eeac529ea4df6191570ffda340d
parent 444710 b0ae922973c1294a875dee38c6a0295957adee8b
child 444720 d63b1d316177d7a5d238c390f3c7cb718310f18d
child 445727 ae668855bc6ecb341599a1674dddd11c90b2d62e
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1414264
milestone58.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 1414264 - Check invalidation region when we use layer system to paint items. r=jrmuizel MozReview-Commit-ID: Dc5e13NQmP5
gfx/layers/wr/WebRenderCommandBuilder.cpp
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -334,116 +334,137 @@ WebRenderCommandBuilder::PushImage(nsDis
 
   auto r = aSc.ToRelativeLayoutRect(aRect);
   gfx::SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
   aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), wr::ToImageRendering(sampleFilter), key.value());
 
   return true;
 }
 
-static void
+static bool
 PaintByLayer(nsDisplayItem* aItem,
              nsDisplayListBuilder* aDisplayListBuilder,
              RefPtr<BasicLayerManager>& aManager,
              gfxContext* aContext,
              const std::function<void()>& aPaintFunc)
 {
   if (aManager == nullptr) {
     aManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
   }
 
+  UniquePtr<LayerProperties> props;
+  if (aManager->GetRoot()) {
+    props = Move(LayerProperties::CloneFrom(aManager->GetRoot()));
+  }
   FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
   layerBuilder->Init(aDisplayListBuilder, aManager, nullptr, true);
   layerBuilder->DidBeginRetainedLayerTransaction(aManager);
 
   aManager->BeginTransactionWithTarget(aContext);
+  bool isInvalidated = false;
 
   ContainerLayerParameters param;
-  RefPtr<Layer> layer = aItem->BuildLayer(aDisplayListBuilder, aManager, param);
-  if (layer) {
-    UniquePtr<LayerProperties> props;
-    props = Move(LayerProperties::CloneFrom(aManager->GetRoot()));
+  RefPtr<Layer> root = aItem->BuildLayer(aDisplayListBuilder, aManager, param);
 
-    aManager->SetRoot(layer);
+  if (root) {
+    aManager->SetRoot(root);
     layerBuilder->WillEndTransaction();
 
     aPaintFunc();
+
+    // Check if there is any invalidation region.
+    nsIntRegion invalid;
+    if (props) {
+      props->ComputeDifferences(root, invalid, nullptr);
+      if (!invalid.IsEmpty()) {
+        isInvalidated = true;
+      }
+    } else {
+      isInvalidated = true;
+    }
   }
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::DumpDisplayList() || gfxEnv::DumpPaint()) {
     fprintf_stderr(gfxUtils::sDumpPaintFile, "Basic layer tree for painting contents of display item %s(%p):\n", aItem->Name(), aItem->Frame());
     std::stringstream stream;
     aManager->Dump(stream, "", gfxEnv::DumpPaintToFile());
     fprint_stderr(gfxUtils::sDumpPaintFile, stream);  // not a typo, fprint_stderr declared in LayersLogging.h
   }
 #endif
 
   if (aManager->InTransaction()) {
     aManager->AbortTransaction();
   }
 
   aManager->SetTarget(nullptr);
+
+  return isInvalidated;
 }
 
-static void
+static bool
 PaintItemByDrawTarget(nsDisplayItem* aItem,
                       gfx::DrawTarget* aDT,
                       const LayerRect& aImageRect,
                       const LayoutDevicePoint& aOffset,
                       nsDisplayListBuilder* aDisplayListBuilder,
                       RefPtr<BasicLayerManager>& aManager,
                       WebRenderLayerManager* aWrManager,
                       const gfx::Size& aScale)
 {
   MOZ_ASSERT(aDT);
 
+  bool isInvalidated = false;
   aDT->ClearRect(aImageRect.ToUnknownRect());
   RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT);
   MOZ_ASSERT(context);
 
   context->SetMatrix(context->CurrentMatrix().PreScale(aScale.width, aScale.height).PreTranslate(-aOffset.x, -aOffset.y));
 
   switch (aItem->GetType()) {
   case DisplayItemType::TYPE_MASK:
     static_cast<nsDisplayMask*>(aItem)->PaintMask(aDisplayListBuilder, context);
+    isInvalidated = true;
     break;
   case DisplayItemType::TYPE_SVG_WRAPPER:
     {
-      PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() {
+      isInvalidated = PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() {
         aManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aDisplayListBuilder);
       });
       break;
     }
 
   case DisplayItemType::TYPE_FILTER:
     {
-      PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() {
+      isInvalidated = PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() {
         static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aDisplayListBuilder,
                                                            context, aManager);
       });
       break;
     }
 
   default:
     aItem->Paint(aDisplayListBuilder, context);
+    isInvalidated = true;
     break;
   }
 
   if (gfxPrefs::WebRenderHighlightPaintedLayers()) {
     aDT->SetTransform(gfx::Matrix());
     aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(gfx::Color(1.0, 0.0, 0.0, 0.5)));
   }
-  if (aItem->Frame()->PresContext()->GetPaintFlashing()) {
+  if (aItem->Frame()->PresContext()->GetPaintFlashing() && isInvalidated) {
     aDT->SetTransform(gfx::Matrix());
     float r = float(rand()) / RAND_MAX;
     float g = float(rand()) / RAND_MAX;
     float b = float(rand()) / RAND_MAX;
     aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(gfx::Color(r, g, b, 0.5)));
   }
+
+  return isInvalidated;
 }
 
 already_AddRefed<WebRenderFallbackData>
 WebRenderCommandBuilder::GenerateFallbackData(nsDisplayItem* aItem,
                                               wr::DisplayListBuilder& aBuilder,
                                               wr::IpcResourceUpdateQueue& aResources,
                                               const StackingContextHelper& aSc,
                                               nsDisplayListBuilder* aDisplayListBuilder,
@@ -537,53 +558,74 @@ WebRenderCommandBuilder::GenerateFallbac
           for (auto unscaled : aUnscaledFonts) {
             wr::FontKey key = mManager->WrBridge()->GetFontKeyForUnscaledFont(unscaled);
             aStream.write((const char*)&key, sizeof(key));
           }
         });
       RefPtr<gfx::DrawTarget> dummyDt =
         gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), format);
       RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, paintSize.ToUnknownSize());
-      PaintItemByDrawTarget(aItem, dt, paintRect, offset, aDisplayListBuilder,
-                            fallbackData->mBasicLayerManager, mManager, scale);
+      bool isInvalidated = PaintItemByDrawTarget(aItem, dt, paintRect, offset, aDisplayListBuilder,
+                                                 fallbackData->mBasicLayerManager, mManager, scale);
       recorder->FlushItem(IntRect());
       recorder->Finish();
 
-      Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
-      wr::ImageKey key = mManager->WrBridge()->GetNextImageKey();
-      wr::ImageDescriptor descriptor(paintSize.ToUnknownSize(), 0, dt->GetFormat(), isOpaque);
-      if (!aResources.AddBlobImage(key, descriptor, bytes)) {
-        return nullptr;
+      if (isInvalidated) {
+        Range<uint8_t> bytes((uint8_t *)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
+        wr::ImageKey key = mManager->WrBridge()->GetNextImageKey();
+        wr::ImageDescriptor descriptor(paintSize.ToUnknownSize(), 0, dt->GetFormat(), isOpaque);
+        if (!aResources.AddBlobImage(key, descriptor, bytes)) {
+          return nullptr;
+        }
+        fallbackData->SetKey(key);
+      } else {
+        // If there is no invalidation region and we don't have a image key,
+        // it means we don't need to push image for the item.
+        if (!fallbackData->GetKey().isSome()) {
+          return nullptr;
+        }
       }
-      fallbackData->SetKey(key);
+
+
     } else {
       fallbackData->CreateImageClientIfNeeded();
       RefPtr<ImageClient> imageClient = fallbackData->GetImageClient();
       RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
+      bool isInvalidated = false;
 
       {
         UpdateImageHelper helper(imageContainer, imageClient, paintSize.ToUnknownSize(), format);
         {
           RefPtr<gfx::DrawTarget> dt = helper.GetDrawTarget();
           if (!dt) {
             return nullptr;
           }
-          PaintItemByDrawTarget(aItem, dt, paintRect, offset,
-                                aDisplayListBuilder,
-                                fallbackData->mBasicLayerManager, mManager, scale);
+          isInvalidated = PaintItemByDrawTarget(aItem, dt, paintRect, offset,
+                                               aDisplayListBuilder,
+                                               fallbackData->mBasicLayerManager, mManager, scale);
         }
-        if (!helper.UpdateImage()) {
-          return nullptr;
+
+        if (isInvalidated) {
+          // Update image if there it's invalidated.
+          if (!helper.UpdateImage()) {
+            return nullptr;
+          }
+        } else {
+          // If there is no invalidation region and we don't have a image key,
+          // it means we don't need to push image for the item.
+          if (!fallbackData->GetKey().isSome()) {
+            return nullptr;
+          }
         }
       }
 
       // Force update the key in fallback data since we repaint the image in this path.
       // If not force update, fallbackData may reuse the original key because it
       // doesn't know UpdateImageHelper already updated the image container.
-      if (!fallbackData->UpdateImageKey(imageContainer, aResources, true)) {
+      if (isInvalidated && !fallbackData->UpdateImageKey(imageContainer, aResources, true)) {
         return nullptr;
       }
     }
 
     geometry = aItem->AllocateGeometry(aDisplayListBuilder);
     fallbackData->SetScale(scale);
     fallbackData->SetInvalid(false);
   }