Bug 1404091 - In layers-free mode, we should do NotifyInvalidation after EndTransaction if there is any scheduled flush. r=kats draft
authorEthan Lin <ethlin@mozilla.com>
Tue, 03 Oct 2017 16:00:38 +0800
changeset 674390 4360531051fca25cd3ca023c279f3daf02243bf9
parent 674389 bb2a1f41d82a1fc2414c6f0d435fa6c054244d62
child 674391 7351a8b6b2747c909a5021f917168eeb59019e9d
push id82818
push userbmo:ethlin@mozilla.com
push dateTue, 03 Oct 2017 18:11:41 +0000
reviewerskats
bugs1404091
milestone58.0a1
Bug 1404091 - In layers-free mode, we should do NotifyInvalidation after EndTransaction if there is any scheduled flush. r=kats MozReview-Commit-ID: D0LNF0LgWYq
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
layout/base/nsRefreshDriver.cpp
layout/base/nsRefreshDriver.h
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -37,17 +37,16 @@ WebRenderLayerManager::WebRenderLayerMan
   : mWidget(aWidget)
   , mLatestTransactionId(0)
   , mLastAsr(nullptr)
   , mNeedsComposite(false)
   , mIsFirstPaint(false)
   , mEndTransactionWithoutLayers(false)
   , mTarget(nullptr)
   , mPaintSequenceNumber(0)
-  , mShouldNotifyInvalidation(false)
 {
   MOZ_COUNT_CTOR(WebRenderLayerManager);
 }
 
 KnowsCompositor*
 WebRenderLayerManager::AsKnowsCompositor()
 {
   return mWrChild;
@@ -331,24 +330,16 @@ WebRenderLayerManager::CreateWebRenderCo
       // If we're going to create a new layer data for this item, stash the
       // ASR so that if we recurse into a sublist they will know where to stop
       // walking up their ASR chain when building scroll metadata.
       if (forceNewLayerData) {
         mAsrStack.push_back(asr);
       }
     }
 
-    // If there is any invalid item, we should notify nsPresContext after EndTransaction.
-    if (!mShouldNotifyInvalidation) {
-      nsRect invalid;
-      if (item->IsInvalid(invalid)) {
-        mShouldNotifyInvalidation = true;
-      }
-    }
-
     { // scope the ScrollingLayersHelper
       ScrollingLayersHelper clip(item, aBuilder, aSc, mClipIdCache, AsyncPanZoomEnabled());
 
       // Note: this call to CreateWebRenderCommands can recurse back into
       // this function if the |item| is a wrapper for a sublist.
       if (!item->CreateWebRenderCommands(aBuilder, aResources, aSc, this,
                                          aDisplayListBuilder)) {
         PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
@@ -513,25 +504,18 @@ PaintItemByDrawTarget(nsDisplayItem* aIt
 
       if (layer) {
         UniquePtr<LayerProperties> props;
         props = Move(LayerProperties::CloneFrom(aManager->GetRoot()));
 
         aManager->SetRoot(layer);
         layerBuilder->WillEndTransaction();
 
-        nsIntRegion invalid;
-        props->ComputeDifferences(layer, invalid, nullptr);
-
         static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aDisplayListBuilder,
                                                            context, aManager);
-
-        if (!invalid.IsEmpty()) {
-          aWrManager->SetNotifyInvalidation(true);
-        }
       }
 
       if (aManager->InTransaction()) {
         aManager->AbortTransaction();
       }
       aManager->SetTarget(nullptr);
       break;
     }
@@ -768,19 +752,16 @@ WebRenderLayerManager::EndTransactionInt
   }
   DiscardCompositorAnimations();
 
   wr::LayoutSize contentSize { (float)size.width, (float)size.height };
   wr::DisplayListBuilder builder(WrBridge()->GetPipeline(), contentSize);
   wr::IpcResourceUpdateQueue resourceUpdates(WrBridge()->GetShmemAllocator());
 
   if (mEndTransactionWithoutLayers) {
-    // Reset the notification flag at the begin of the EndTransaction.
-    mShouldNotifyInvalidation = false;
-
     // aDisplayList being null here means this is an empty transaction following a layers-free
     // transaction, so we reuse the previously built displaylist and scroll
     // metadata information
     if (aDisplayList && aDisplayListBuilder) {
       StackingContextHelper sc;
       mParentCommands.Clear();
       mScrollData = WebRenderScrollData();
       MOZ_ASSERT(mLayerScrollData.empty());
@@ -819,19 +800,16 @@ WebRenderLayerManager::EndTransactionInt
 
       // Remove the user data those are not displayed on the screen and
       // also reset the data to unused for next transaction.
       RemoveUnusedAndResetWebRenderUserData();
     } else {
       for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
         RefPtr<WebRenderCanvasData> canvasData = iter.Get()->GetKey();
         WebRenderCanvasRendererAsync* canvas = canvasData->GetCanvasRenderer();
-        if (canvas->IsDirty()) {
-          mShouldNotifyInvalidation = true;
-        }
         canvas->UpdateCompositableClient();
       }
     }
 
     builder.PushBuiltDisplayList(mBuiltDisplayList);
     WrBridge()->AddWebRenderParentCommands(mParentCommands);
   } else {
     mScrollData = WebRenderScrollData();
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -241,19 +241,16 @@ public:
 
     if (T::Type() == WebRenderUserData::UserDataType::eCanvas) {
       mLastCanvasDatas.PutEntry(data->AsCanvasData());
     }
     RefPtr<T> res = static_cast<T*>(data.get());
     return res.forget();
   }
 
-  bool ShouldNotifyInvalidation() const { return mShouldNotifyInvalidation; }
-  void SetNotifyInvalidation(bool aShouldNotifyInvalidation) { mShouldNotifyInvalidation = aShouldNotifyInvalidation; }
-
   bool SetPendingScrollUpdateForNextTransaction(FrameMetrics::ViewID aScrollId,
                                                 const ScrollUpdateInfo& aUpdateInfo) override;
 
 private:
   /**
    * Take a snapshot of the parent context, and copy
    * it into mTarget.
    */
@@ -383,19 +380,15 @@ private:
   uint32_t mPaintSequenceNumber;
   // See equivalent field in ClientLayerManager
   APZTestData mApzTestData;
 
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderCanvasData>> CanvasDataSet;
   // Store of WebRenderCanvasData objects for use in empty transactions
   CanvasDataSet mLastCanvasDatas;
 
-  // True if the layers-free transaction has invalidation region and then
-  // we should send notification after EndTransaction
-  bool mShouldNotifyInvalidation;
-
   WebRenderUserDataRefTable mWebRenderUserDatas;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_WEBRENDERLAYERMANAGER_H */
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -1196,16 +1196,17 @@ nsRefreshDriver::nsRefreshDriver(nsPresC
     mFreezeCount(0),
     mThrottledFrameRequestInterval(TimeDuration::FromMilliseconds(
                                      GetThrottledTimerInterval())),
     mMinRecomputeVisibilityInterval(GetMinRecomputeVisibilityInterval()),
     mThrottled(false),
     mNeedToRecomputeVisibility(false),
     mTestControllingRefreshes(false),
     mViewManagerFlushIsPending(false),
+    mHasScheduleFlush(false),
     mInRefresh(false),
     mWaitingForTransaction(false),
     mSkippedPaints(false),
     mResizeSuppressed(false),
     mWarningThreshold(REFRESH_WAIT_WARNING)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mPresContext,
@@ -2090,16 +2091,17 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
 
     for (nsDocShell* docShell : profilingDocShells) {
       MOZ_ASSERT(timelines);
       MOZ_ASSERT(timelines->HasConsumer(docShell));
       timelines->AddMarkerForDocShell(docShell, "Paint",  MarkerTracingType::END);
     }
 
     dispatchRunnablesAfterTick = true;
+    mHasScheduleFlush = false;
   }
 
 #ifndef ANDROID  /* bug 1142079 */
   mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::REFRESH_DRIVER_TICK, mTickStart);
 #endif
 
   nsTObserverArray<nsAPostRefreshObserver*>::ForwardIterator iter(mPostRefreshObservers);
   while (iter.HasMore()) {
@@ -2363,16 +2365,17 @@ nsRefreshDriver::IsRefreshObserver(nsARe
 #endif
 
 void
 nsRefreshDriver::ScheduleViewManagerFlush()
 {
   NS_ASSERTION(mPresContext->IsRoot(),
                "Should only schedule view manager flush on root prescontexts");
   mViewManagerFlushIsPending = true;
+  mHasScheduleFlush = true;
   EnsureTimerStarted(eNeverAdjustTimer);
 }
 
 void
 nsRefreshDriver::ScheduleFrameRequestCallbacks(nsIDocument* aDocument)
 {
   NS_ASSERTION(mFrameRequestCallbackDocs.IndexOf(aDocument) ==
                mFrameRequestCallbackDocs.NoIndex &&
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -212,16 +212,19 @@ public:
    */
   void ScheduleViewManagerFlush();
   void RevokeViewManagerFlush() {
     mViewManagerFlushIsPending = false;
   }
   bool ViewManagerFlushIsPending() {
     return mViewManagerFlushIsPending;
   }
+  bool HasScheduleFlush() {
+    return mHasScheduleFlush;
+  }
 
   /**
    * Add a document for which we have FrameRequestCallbacks
    */
   void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
    * Remove a document for which we have FrameRequestCallbacks
@@ -437,16 +440,21 @@ private:
   // interval, we only recompute visibility when we've seen a layout or style
   // flush since the last time we did it.
   const mozilla::TimeDuration mMinRecomputeVisibilityInterval;
 
   bool mThrottled;
   bool mNeedToRecomputeVisibility;
   bool mTestControllingRefreshes;
   bool mViewManagerFlushIsPending;
+
+  // True if the view manager needs a flush. Layers-free mode uses this value
+  // to know when to notify invalidation.
+  bool mHasScheduleFlush;
+
   bool mInRefresh;
 
   // True if the refresh driver is suspended waiting for transaction
   // id's to be returned and shouldn't do any work during Tick().
   bool mWaitingForTransaction;
   // True if Tick() was skipped because of mWaitingForTransaction and
   // we should schedule a new Tick immediately when resumed instead
   // of waiting until the next interval.
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2182,17 +2182,17 @@ already_AddRefed<LayerManager> nsDisplay
       frame->ClearInvalidationStateBits();
     }
 
     aBuilder->SetIsCompositingCheap(temp);
     if (document && widgetTransaction) {
       TriggerPendingAnimations(document, layerManager->GetAnimationReadyTime());
     }
 
-    if (wrManager->ShouldNotifyInvalidation()) {
+    if (presContext->RefreshDriver()->HasScheduleFlush()) {
       presContext->NotifyInvalidation(layerManager->GetLastTransactionId(), nsIntRect());
     }
 
     return layerManager.forget();
   }
 
   NotifySubDocInvalidationFunc computeInvalidFunc =
     presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0;