Bug 1414264 - Check invalidation region when we use layer system to paint items. r=jrmuizel draft
authorEthan Lin <ethlin@mozilla.com>
Tue, 07 Nov 2017 14:40:08 +0800
changeset 696871 5ddedaa4ea7171ace04c01b114b6f15e98e495a6
parent 695940 ed94dc665071d8d510688ff50bbedad2c7cb33ee
child 739949 740dd58e2e44c9e44e505a2d9498254599b4371a
push id88812
push userbmo:ethlin@mozilla.com
push dateSun, 12 Nov 2017 06:48:14 +0000
reviewersjrmuizel
bugs1414264
milestone58.0a1
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,
@@ -529,53 +550,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);
   }