Bug 1397375 - Part2. Add a table in layer manaher to keep webrender user data. r=jrmuizel draft
authorEthan Lin <ethlin@mozilla.com>
Mon, 11 Sep 2017 17:57:09 +0800
changeset 662293 fbf34a12545ea0f3724ab2bf9f89c4b5ca7e4b31
parent 662292 2f714ea9c0f9928b8a7b5a74bc7f90fb705fb710
child 662294 61cddc8f6390acb03a8db4a04511e607d28473a2
push id79015
push userbmo:ethlin@mozilla.com
push dateMon, 11 Sep 2017 09:59:00 +0000
reviewersjrmuizel
bugs1397375
milestone57.0a1
Bug 1397375 - Part2. Add a table in layer manaher to keep webrender user data. r=jrmuizel MozReview-Commit-ID: HsO3BCc2eeL
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -721,16 +721,19 @@ WebRenderLayerManager::EndTransactionInt
     if (aDisplayList && aDisplayListBuilder) {
       StackingContextHelper sc;
       mParentCommands.Clear();
       mScrollData = WebRenderScrollData();
       MOZ_ASSERT(mLayerScrollData.empty());
       mLastCanvasDatas.Clear();
       mLastAsr = nullptr;
 
+      // Mark all webrender user data as unused before creating webrender commands.
+      UnuseWebRenderUserData();
+
       CreateWebRenderCommandsFromDisplayList(aDisplayList, aDisplayListBuilder, sc, builder);
 
       builder.Finalize(contentSize, mBuiltDisplayList);
 
       // Make a "root" layer data that has everything else as descendants
       mLayerScrollData.emplace_back();
       mLayerScrollData.back().InitializeRoot(mLayerScrollData.size() - 1);
       if (aDisplayListBuilder->IsBuildingLayerEventRegions()) {
@@ -750,16 +753,19 @@ WebRenderLayerManager::EndTransactionInt
       // Append the WebRenderLayerScrollData items into WebRenderScrollData
       // in reverse order, from topmost to bottommost. This is in keeping with
       // the semantics of WebRenderScrollData.
       for (auto i = mLayerScrollData.crbegin(); i != mLayerScrollData.crend(); i++) {
         mScrollData.AddLayerData(*i);
       }
       mLayerScrollData.clear();
       mClipIdCache.clear();
+
+      // Remove the user data those are not displayed on the screen.
+      RemoveUnusedWebRenderUserData();
     } 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();
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -33,16 +33,17 @@ class CompositorBridgeChild;
 class KnowsCompositor;
 class PCompositorBridgeChild;
 class WebRenderBridgeChild;
 class WebRenderParentCommand;
 
 class WebRenderLayerManager final : public LayerManager
 {
   typedef nsTArray<RefPtr<Layer> > LayerRefArray;
+  typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData> > WebRenderUserDataRefTable;
 
 public:
   explicit WebRenderLayerManager(nsIWidget* aWidget);
   bool Initialize(PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId, TextureFactoryIdentifier* aTextureFactoryIdentifier);
 
   virtual void Destroy() override;
 
   void DoDestroy(bool aIsSync);
@@ -202,24 +203,33 @@ public:
       frame->AddProperty(nsIFrame::WebRenderUserDataProperty(),
                          new nsIFrame::WebRenderUserDataTable());
     }
 
     nsIFrame::WebRenderUserDataTable* userDataTable =
       frame->GetProperty(nsIFrame::WebRenderUserDataProperty());
     RefPtr<WebRenderUserData>& data = userDataTable->GetOrInsert(aItem->GetPerFrameKey());
     if (!data || (data->GetType() != T::Type()) || !data->IsDataValid(this)) {
-      data = new T(this);
+      // To recreate a new user data, we should remove the data from the table first.
+      if (data) {
+        data->RemoveFromTable();
+      }
+      data = new T(this, aItem, &mWebRenderUserDatas);
+      mWebRenderUserDatas.PutEntry(data);
       if (aOutIsRecycled) {
         *aOutIsRecycled = false;
       }
     }
 
     MOZ_ASSERT(data);
     MOZ_ASSERT(data->GetType() == T::Type());
+
+    // Mark the data as being used. We will remove unused user data in the end of EndTransaction.
+    data->SetUsed(true);
+
     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; }
@@ -234,16 +244,45 @@ private:
   void ClearLayer(Layer* aLayer);
 
   bool EndTransactionInternal(DrawPaintedLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags,
                               nsDisplayList* aDisplayList = nullptr,
                               nsDisplayListBuilder* aDisplayListBuilder = nullptr);
 
+  void UnuseWebRenderUserData()
+  {
+    for (auto iter = mWebRenderUserDatas.Iter(); !iter.Done(); iter.Next()) {
+      WebRenderUserData* data = iter.Get()->GetKey();
+      data->SetUsed(false);
+    }
+  }
+
+  void RemoveUnusedWebRenderUserData()
+  {
+    for (auto iter = mWebRenderUserDatas.Iter(); !iter.Done(); iter.Next()) {
+      WebRenderUserData* data = iter.Get()->GetKey();
+      if (!data->IsUsed()) {
+        MOZ_ASSERT(frame->HasProperty(nsIFrame::WebRenderUserDataProperty()));
+
+        nsIFrame* frame = data->GetFrame();
+        nsIFrame::WebRenderUserDataTable* userDataTable =
+          frame->GetProperty(nsIFrame::WebRenderUserDataProperty());
+        if (userDataTable->Count()) {
+          userDataTable->Remove(data->GetDisplayItemKey());
+        }
+        if (!userDataTable->Count()) {
+          frame->RemoveProperty(nsIFrame::WebRenderUserDataProperty());
+        }
+        iter.Remove();
+      }
+    }
+  }
+
 private:
   nsIWidget* MOZ_NON_OWNING_REF mWidget;
   wr::ResourceUpdateQueue mImageKeysToDelete;
   nsTArray<uint64_t> mDiscardedCompositorAnimationsIds;
 
   /* PaintedLayer callbacks; valid at the end of a transaciton,
    * while rendering */
   DrawPaintedLayerCallback mPaintedLayerCallback;
@@ -320,14 +359,16 @@ private:
 
   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 */