Bug 1415586 - share mask image (WIP) draft
authorEthan Lin <ethlin@mozilla.com>
Mon, 27 Nov 2017 22:08:06 +0800
changeset 705017 335299b19ce5ff175f0037df5817045c789b8fd7
parent 704807 cb9092a90f6ef501e6de8eb5fc6ce19e2717193f
child 742228 3128896c5e0722e5a4acc242e776a474aa56d016
push id91325
push userbmo:ethlin@mozilla.com
push dateWed, 29 Nov 2017 09:51:35 +0000
bugs1415586
milestone59.0a1
Bug 1415586 - share mask image (WIP) MozReview-Commit-ID: HBSZjC4zdVO
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/layers/wr/WebRenderCommandBuilder.h
gfx/layers/wr/WebRenderUserData.cpp
gfx/layers/wr/WebRenderUserData.h
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/ScrollingLayersHelper.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/UpdateImageHelper.h"
 #include "gfxEnv.h"
 #include "nsDisplayListInvalidation.h"
+#include "SVGObserverUtils.h"
 #include "WebRenderCanvasRenderer.h"
 #include "LayersLogging.h"
 #include "LayerTreeInvalidation.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace gfx;
@@ -58,16 +59,19 @@ WebRenderCommandBuilder::BuildWebRenderC
                                                 wr::IpcResourceUpdateQueue& aResourceUpdates,
                                                 nsDisplayList* aDisplayList,
                                                 nsDisplayListBuilder* aDisplayListBuilder,
                                                 WebRenderScrollData& aScrollData,
                                                 wr::LayoutSize& aContentSize)
 {
   { // scoping for StackingContextHelper RAII
 
+    // Reset mask list
+    //mClipCacheManager.mMaskList.clear();
+
     StackingContextHelper sc;
     mParentCommands.Clear();
     aScrollData = WebRenderScrollData(mManager);
     MOZ_ASSERT(mLayerScrollData.empty());
     mLastCanvasDatas.Clear();
     mLastAsr = nullptr;
     mScrollingHelper.BeginBuild(mManager, aBuilder);
 
@@ -650,33 +654,85 @@ WebRenderCommandBuilder::GenerateFallbac
   fallbackData->SetBounds(paintBounds);
 
   MOZ_ASSERT(fallbackData->GetKey());
 
   return fallbackData.forget();
 }
 
 Maybe<wr::WrImageMask>
-WebRenderCommandBuilder::BuildWrMaskImage(nsDisplayItem* aItem,
+WebRenderCommandBuilder::BuildWrMaskImage(nsDisplayMask* aItem,
                                           wr::DisplayListBuilder& aBuilder,
                                           wr::IpcResourceUpdateQueue& aResources,
                                           const StackingContextHelper& aSc,
                                           nsDisplayListBuilder* aDisplayListBuilder,
-                                          const LayoutDeviceRect& aBounds)
+                                          const LayoutDeviceRect& aBounds,
+                                          MaskImage*& aMaskCache,
+                                          bool& aCached)
 {
-  LayoutDeviceRect imageRect;
-  RefPtr<WebRenderFallbackData> fallbackData = GenerateFallbackData(aItem, aBuilder, aResources,
-                                                                    aSc, aDisplayListBuilder,
-                                                                    imageRect);
-  if (!fallbackData) {
-    return Nothing();
+
+  nsIFrame* frame = aItem->Frame();
+  
+  //maskimage.opacity = aItem->mHandleOpacity ? frame->StyleEffects()->mOpacity;
+
+  nsIFrame* firstFrame =
+    nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
+
+  SVGObserverUtils::EffectProperties effectProperties =
+    SVGObserverUtils::GetEffectProperties(firstFrame);
+  const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
+
+  wr::ImageKey key;
+  bool cached = false;
+  RefPtr<MaskImage> maskimage;
+
+  if (svgReset->mClipPath.GetType() == StyleShapeSourceType::Shape) {
+    maskimage = new MaskImage();
+    //maskimage.opacity = aItem->mHandleOpacity ? frame->StyleEffects()->mOpacity : 1.0;
+    maskimage->opacity = frame->StyleEffects()->mOpacity;
+    maskimage->type = svgReset->mClipPath.GetType();
+    const UniquePtr<StyleBasicShape>& basicShape = svgReset->mClipPath.GetBasicShape();
+    maskimage->basicShape = new StyleBasicShape(StyleBasicShapeType::Polygon);
+    *(maskimage->basicShape) = *basicShape;
+
+    for (auto mask: mClipCacheManager.mMaskList) {
+      if (*mask->basicShape == *maskimage->basicShape) {
+        aMaskCache = mask.get();
+        aCached = true;
+        key = mask->key;
+        cached = true;
+        break;
+      }
+    }
+  }
+  
+  if (!cached) {
+    if (XRE_IsContentProcess()) {
+      printf_stderr("@@@not cahced\n");
+    }
+    LayoutDeviceRect imageRect;
+    RefPtr<WebRenderFallbackData> fallbackData = GenerateFallbackData(aItem, aBuilder, aResources,
+                                                                      aSc, aDisplayListBuilder,
+                                                                      imageRect);
+
+    if (!fallbackData) {
+      return Nothing();
+    }
+
+    key = fallbackData->GetKey().value();
+    if (maskimage) {
+      aMaskCache = maskimage.get();
+      maskimage->key = key;
+      fallbackData->SetMaskCache(maskimage);
+      mClipCacheManager.mMaskList.push_back(maskimage.forget());
+    }
   }
 
   wr::WrImageMask imageMask;
-  imageMask.image = fallbackData->GetKey().value();
+  imageMask.image = key;
   imageMask.rect = aSc.ToRelativeLayoutRect(aBounds);
   imageMask.repeat = false;
   return Some(imageMask);
 }
 
 bool
 WebRenderCommandBuilder::PushItemAsImage(nsDisplayItem* aItem,
                                          wr::DisplayListBuilder& aBuilder,
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -9,32 +9,53 @@
 
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/layers/ScrollingLayersHelper.h"
 #include "mozilla/layers/WebRenderMessages.h"
 #include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/layers/WebRenderUserData.h"
 #include "nsDisplayList.h"
 #include "nsIFrame.h"
+#include <list>
 
 namespace mozilla {
 
 namespace layers {
 
 class CanvasLayer;
 class ImageClient;
 class ImageContainer;
 class WebRenderBridgeChild;
 class WebRenderCanvasData;
 class WebRenderCanvasRendererAsync;
 class WebRenderImageData;
 class WebRenderFallbackData;
 class WebRenderParentCommand;
 class WebRenderUserData;
 
+class MaskImage {
+  NS_INLINE_DECL_REFCOUNTING(MaskImage)
+public:
+  float opacity;
+  StyleShapeSourceType type;
+  StyleBasicShape* basicShape;
+  wr::ImageKey key;
+  wr::WrClipId clipId;
+private:
+  ~MaskImage() {
+    delete basicShape;
+  }
+};
+
+class ClipCacheManager {
+public:
+  std::list<RefPtr<MaskImage>> mMaskList;
+
+};
+
 class WebRenderCommandBuilder {
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData>> WebRenderUserDataRefTable;
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderCanvasData>> CanvasDataSet;
 
 public:
   explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager)
   : mManager(aManager)
   , mLastAsr(nullptr)
@@ -65,22 +86,24 @@ public:
 
   bool PushImage(nsDisplayItem* aItem,
                  ImageContainer* aContainer,
                  mozilla::wr::DisplayListBuilder& aBuilder,
                  mozilla::wr::IpcResourceUpdateQueue& aResources,
                  const StackingContextHelper& aSc,
                  const LayoutDeviceRect& aRect);
 
-  Maybe<wr::WrImageMask> BuildWrMaskImage(nsDisplayItem* aItem,
+  Maybe<wr::WrImageMask> BuildWrMaskImage(nsDisplayMask* aItem,
                                           wr::DisplayListBuilder& aBuilder,
                                           wr::IpcResourceUpdateQueue& aResources,
                                           const StackingContextHelper& aSc,
                                           nsDisplayListBuilder* aDisplayListBuilder,
-                                          const LayoutDeviceRect& aBounds);
+                                          const LayoutDeviceRect& aBounds,
+                                          MaskImage*& aMaskCache,
+                                          bool& aCached);
 
   bool PushItemAsImage(nsDisplayItem* aItem,
                        wr::DisplayListBuilder& aBuilder,
                        wr::IpcResourceUpdateQueue& aResources,
                        const StackingContextHelper& aSc,
                        nsDisplayListBuilder* aDisplayListBuilder);
 
   void CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDisplayList,
@@ -184,14 +207,16 @@ private:
   // tree don't duplicate scroll metadata that their ancestors already have.
   std::vector<const ActiveScrolledRoot*> mAsrStack;
   const ActiveScrolledRoot* mLastAsr;
 
   WebRenderUserDataRefTable mWebRenderUserDatas;
 
   // Store of WebRenderCanvasData objects for use in empty transactions
   CanvasDataSet mLastCanvasDatas;
+
+  ClipCacheManager mClipCacheManager;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_WEBRENDERCOMMANDBUILDER_H */
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -234,16 +234,30 @@ WebRenderImageData::CreateImageClientIfN
 void
 WebRenderImageData::CreateExternalImageIfNeeded()
 {
   if (!mExternalImageId)  {
     mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
   }
 }
 
+Maybe<wr::ImageKey>
+WebRenderImageData::GetKey() {
+  if (mMaskCache) {
+    return Some(mMaskCache->key);
+  }
+  return mKey;
+}
+
+void WebRenderImageData::SetMaskCache(MaskImage* aMaskImage)
+{
+  mMaskCache = aMaskImage;
+  mKey = Nothing();
+}
+
 WebRenderFallbackData::WebRenderFallbackData(WebRenderLayerManager* aWRManager, nsDisplayItem* aItem)
   : WebRenderImageData(aWRManager, aItem)
   , mInvalid(false)
 {
 }
 
 WebRenderFallbackData::~WebRenderFallbackData()
 {
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -18,16 +18,17 @@ namespace mozilla {
 namespace wr {
 class IpcResourceUpdateQueue;
 }
 
 namespace layers {
 class CanvasLayer;
 class ImageClient;
 class ImageContainer;
+class MaskImage;
 class WebRenderBridgeChild;
 class WebRenderCanvasData;
 class WebRenderCanvasRendererAsync;
 class WebRenderImageData;
 class WebRenderFallbackData;
 class WebRenderLayerManager;
 
 class WebRenderUserData
@@ -74,17 +75,19 @@ class WebRenderImageData : public WebRen
 {
 public:
   explicit WebRenderImageData(WebRenderLayerManager* aWRManager, nsDisplayItem* aItem);
   virtual ~WebRenderImageData();
 
   virtual WebRenderImageData* AsImageData() override { return this; }
   virtual UserDataType GetType() override { return UserDataType::eImage; }
   static UserDataType Type() { return UserDataType::eImage; }
-  Maybe<wr::ImageKey> GetKey() { return mKey; }
+  //Maybe<wr::ImageKey> GetKey() { return mKey; }
+  Maybe<wr::ImageKey> GetKey();
+  void SetMaskCache(MaskImage* aMaskImage);
   void SetKey(const wr::ImageKey& aKey);
   already_AddRefed<ImageClient> GetImageClient();
 
   Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer,
                                      wr::IpcResourceUpdateQueue& aResources,
                                      bool aFallback = false);
 
   void CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
@@ -105,16 +108,17 @@ protected:
   void CreateExternalImageIfNeeded();
 
   wr::MaybeExternalImageId mExternalImageId;
   Maybe<wr::ImageKey> mKey;
   RefPtr<ImageClient> mImageClient;
   Maybe<wr::PipelineId> mPipelineId;
   RefPtr<ImageContainer> mContainer;
   bool mOwnsKey;
+  RefPtr<MaskImage> mMaskCache;
 };
 
 class WebRenderFallbackData : public WebRenderImageData
 {
 public:
   explicit WebRenderFallbackData(WebRenderLayerManager* aWRManager, nsDisplayItem* aItem);
   virtual ~WebRenderFallbackData();
 
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -9611,26 +9611,38 @@ nsDisplayMask::CreateWebRenderCommands(m
                                        mozilla::layers::WebRenderLayerManager* aManager,
                                        nsDisplayListBuilder* aDisplayListBuilder)
 {
   bool snap;
   float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsRect displayBound = GetBounds(aDisplayListBuilder, &snap);
   LayoutDeviceRect bounds = LayoutDeviceRect::FromAppUnits(displayBound, appUnitsPerDevPixel);
 
+  MaskImage* maskCache = nullptr;
+  bool cached = false;
+
+
   Maybe<wr::WrImageMask> mask = aManager->CommandBuilder().BuildWrMaskImage(this, aBuilder, aResources,
                                                                             aSc, aDisplayListBuilder,
-                                                                            bounds);
+                                                                            bounds, maskCache, cached);
   if (mask) {
-    wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), Nothing(),
-        aSc.ToRelativeLayoutRect(bounds), nullptr, mask.ptr());
-    // Don't record this clip push in aBuilder's internal clip stack, because
-    // otherwise any nested ScrollingLayersHelper instances that are created
-    // will get confused about which clips are pushed.
-    aBuilder.PushClip(clipId, GetClipChain());
+
+    //if (cached && maskCache) {
+    //  aBuilder.PushClip(maskCache->clipId, GetClipChain());
+    //} else {
+      wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), Nothing(),
+          aSc.ToRelativeLayoutRect(bounds), nullptr, mask.ptr());
+      // Don't record this clip push in aBuilder's internal clip stack, because
+      // otherwise any nested ScrollingLayersHelper instances that are created
+      // will get confused about which clips are pushed.
+      aBuilder.PushClip(clipId, GetClipChain());
+      //if (!cached && maskCache) {
+        //maskCache->clipId = clipId;
+      //}
+    //}
   }
 
   nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
 
   if (mask) {
     aBuilder.PopClip(GetClipChain());
   }