Bug 1428558 - Part 7. Suppress display list regeneration for animated image updates. r=nical
authorAndrew Osmond <aosmond@mozilla.com>
Tue, 02 Oct 2018 13:28:28 -0400
changeset 444120 f474d2aae3cba868923724c717e8b1e9e42037bc
parent 444119 5329d8f893139cac897b7061f060cf54e08aab1d
child 444121 7b45f9db5e932bc7dfd84eca325e0d9b4fd3c657
push id34982
push useraciure@mozilla.com
push dateFri, 02 Nov 2018 16:45:16 +0000
treeherdermozilla-central@78ac2f95aa4e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1428558
milestone65.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 1428558 - Part 7. Suppress display list regeneration for animated image updates. r=nical This patch allows us to intercept invalidation requests for display items, and avoid regenerating the display list for animated images which are using SharedSurfacesAnimation. Differential Revision: https://phabricator.services.mozilla.com/D7504
gfx/layers/wr/WebRenderUserData.cpp
gfx/layers/wr/WebRenderUserData.h
layout/generic/nsImageFrame.cpp
layout/style/ImageLoader.cpp
layout/xul/nsImageBoxFrame.cpp
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -38,16 +38,44 @@ WebRenderUserData::SupportsAsyncUpdate(n
   RefPtr<WebRenderImageData> data = GetWebRenderUserData<WebRenderImageData>(aFrame, static_cast<uint32_t>(DisplayItemType::TYPE_VIDEO));
   if (data) {
     return data->IsAsync();
   }
 
   return false;
 }
 
+/* static */ bool
+WebRenderUserData::ProcessInvalidateForImage(nsIFrame* aFrame, DisplayItemType aType)
+{
+  MOZ_ASSERT(aFrame);
+
+  if (!aFrame->HasProperty(WebRenderUserDataProperty::Key())) {
+    return false;
+  }
+
+  auto type = static_cast<uint32_t>(aType);
+  RefPtr<WebRenderFallbackData> fallback =
+    GetWebRenderUserData<WebRenderFallbackData>(aFrame, type);
+  if (fallback) {
+    fallback->SetInvalid(true);
+    aFrame->SchedulePaint();
+    return true;
+  }
+
+  RefPtr<WebRenderImageData> image =
+    GetWebRenderUserData<WebRenderImageData>(aFrame, type);
+  if (image && image->IsAsyncAnimatedImage()) {
+    return true;
+  }
+
+  aFrame->SchedulePaint();
+  return false;
+}
+
 WebRenderUserData::WebRenderUserData(WebRenderLayerManager* aWRManager, nsDisplayItem* aItem)
   : mWRManager(aWRManager)
   , mFrame(aItem->Frame())
   , mDisplayItemKey(aItem->GetPerFrameKey())
   , mTable(aWRManager->GetWebRenderUserDataTable())
   , mUsed(false)
 {
 }
@@ -78,16 +106,22 @@ WebRenderImageData::~WebRenderImageData(
 {
   ClearImageKey();
 
   if (mPipelineId) {
     WrBridge()->RemovePipelineIdForCompositable(mPipelineId.ref());
   }
 }
 
+bool
+WebRenderImageData::IsAsyncAnimatedImage() const
+{
+  return mContainer && mContainer->GetSharedSurfacesAnimation();
+}
+
 void
 WebRenderImageData::ClearImageKey()
 {
   if (mKey) {
     // If we don't own the key, then the owner is responsible for discarding the
     // key when appropriate.
     if (mOwnsKey) {
       mWRManager->AddImageKeyForDiscard(mKey.value());
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -52,16 +52,18 @@ protected:
 
 class WebRenderUserData
 {
 public:
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData> > WebRenderUserDataRefTable;
 
   static bool SupportsAsyncUpdate(nsIFrame* aFrame);
 
+  static bool ProcessInvalidateForImage(nsIFrame* aFrame, DisplayItemType aType);
+
   NS_INLINE_DECL_REFCOUNTING(WebRenderUserData)
 
   WebRenderUserData(WebRenderLayerManager* aWRManager, nsDisplayItem* aItem);
 
   virtual WebRenderImageData* AsImageData() { return nullptr; }
   virtual WebRenderFallbackData* AsFallbackData() { return nullptr; }
   virtual WebRenderCanvasData* AsCanvasData() { return nullptr; }
   virtual WebRenderGroupData* AsGroupData() { return nullptr; }
@@ -144,16 +146,18 @@ public:
 
   void CreateImageClientIfNeeded();
 
   bool IsAsync()
   {
     return mPipelineId.isSome();
   }
 
+  bool IsAsyncAnimatedImage() const;
+
 protected:
   void ClearImageKey();
 
   RefPtr<TextureClient> mTextureOfImage;
   Maybe<wr::ImageKey> mKey;
   RefPtr<ImageClient> mImageClient;
   Maybe<wr::PipelineId> mPipelineId;
   RefPtr<ImageContainer> mContainer;
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -763,26 +763,22 @@ nsImageFrame::OnFrameUpdate(imgIRequest*
 }
 
 void
 nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect,
                              const nsRect* aFrameInvalidRect)
 {
   // Check if WebRender has interacted with this frame. If it has
   // we need to let it know that things have changed.
-  if (HasProperty(WebRenderUserDataProperty::Key())) {
-    RefPtr<WebRenderFallbackData> data = GetWebRenderUserData<WebRenderFallbackData>(this, static_cast<uint32_t>(DisplayItemType::TYPE_IMAGE));
-    if (data) {
-      data->SetInvalid(true);
-    }
-    SchedulePaint();
+  const auto type = DisplayItemType::TYPE_IMAGE;
+  if (WebRenderUserData::ProcessInvalidateForImage(this, type)) {
     return;
   }
 
-  InvalidateLayer(DisplayItemType::TYPE_IMAGE,
+  InvalidateLayer(type,
                   aLayerInvalidRect,
                   aFrameInvalidRect);
 
   if (!mFirstFrameComplete) {
     InvalidateLayer(DisplayItemType::TYPE_ALT_FEEDBACK,
                     aLayerInvalidRect,
                     aFrameInvalidRect);
   }
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -539,22 +539,33 @@ InvalidateImages(nsIFrame* aFrame)
       data->Invalidate();
       invalidateFrame = true;
     }
   }
   if (auto userDataTable =
        aFrame->GetProperty(layers::WebRenderUserDataProperty::Key())) {
     for (auto iter = userDataTable->Iter(); !iter.Done(); iter.Next()) {
       RefPtr<layers::WebRenderUserData> data = iter.UserData();
-      if (data->GetType() == layers::WebRenderAnimationData::UserDataType::eFallback &&
-          !IsRenderNoImages(data->GetDisplayItemKey())) {
-        static_cast<layers::WebRenderFallbackData*>(data.get())->SetInvalid(true);
+      switch (data->GetType()) {
+        case layers::WebRenderUserData::UserDataType::eFallback:
+          if (!IsRenderNoImages(data->GetDisplayItemKey())) {
+            static_cast<layers::WebRenderFallbackData*>(data.get())->SetInvalid(true);
+          }
+          //XXX: handle Blob data
+          invalidateFrame = true;
+          break;
+        case layers::WebRenderUserData::UserDataType::eImage:
+          if (static_cast<layers::WebRenderImageData*>(data.get())->IsAsyncAnimatedImage()) {
+            break;
+          }
+          MOZ_FALLTHROUGH;
+        default:
+          invalidateFrame = true;
+          break;
       }
-      //XXX: handle Blob data
-      invalidateFrame = true;
     }
   }
 
   if (invalidateFrame) {
     aFrame->SchedulePaint();
   }
 }
 
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -907,28 +907,22 @@ nsresult
 nsImageBoxFrame::OnFrameUpdate(imgIRequest* aRequest)
 {
   if ((0 == mRect.width) || (0 == mRect.height)) {
     return NS_OK;
   }
 
   // Check if WebRender has interacted with this frame. If it has
   // we need to let it know that things have changed.
-  if (HasProperty(WebRenderUserDataProperty::Key())) {
-    uint32_t key = static_cast<uint32_t>(DisplayItemType::TYPE_XUL_IMAGE);
-    RefPtr<WebRenderFallbackData> data =
-      GetWebRenderUserData<WebRenderFallbackData>(this, key);
-    if (data) {
-      data->SetInvalid(true);
-    }
-    SchedulePaint();
+  const auto type = DisplayItemType::TYPE_XUL_IMAGE;
+  if (WebRenderUserData::ProcessInvalidateForImage(this, type)) {
     return NS_OK;
   }
 
-  InvalidateLayer(DisplayItemType::TYPE_XUL_IMAGE);
+  InvalidateLayer(type);
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(nsImageBoxListener, imgINotificationObserver)
 
 nsImageBoxListener::nsImageBoxListener(nsImageBoxFrame *frame)
   : mFrame(frame)