Bug 1376855 - Introduce WebRenderUserData and WebRenderImageData. r=kats draft
authorMorris Tseng <mtseng@mozilla.com>
Wed, 28 Jun 2017 15:03:27 -0700
changeset 603969 d8bb6f47a807a4397a75d589456d08fa95a7be26
parent 603793 acbd9a64c0fa4e1980c7732735d4f4c2761ca4c9
child 603970 859960e7df22bcfc1cab42aca72872dee237b235
push id66921
push userbmo:mtseng@mozilla.com
push dateWed, 05 Jul 2017 03:31:35 +0000
reviewerskats
bugs1376855
milestone56.0a1
Bug 1376855 - Introduce WebRenderUserData and WebRenderImageData. r=kats Layers are retained between transaction and we store some data in the layers. Thus, if we no longer use layers, we need find another storage to place those data. I use frame's property to retain WebRenderUserData between transaction. MozReview-Commit-ID: Ku5VGBXa3w6
gfx/layers/moz.build
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
gfx/layers/wr/WebRenderUserData.cpp
gfx/layers/wr/WebRenderUserData.h
layout/generic/nsIFrame.h
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -233,16 +233,17 @@ EXPORTS.mozilla.layers += [
     'wr/WebRenderImageHost.h',
     'wr/WebRenderLayer.h',
     'wr/WebRenderLayerManager.h',
     'wr/WebRenderLayersLogging.h',
     'wr/WebRenderMessageUtils.h',
     'wr/WebRenderScrollData.h',
     'wr/WebRenderScrollDataWrapper.h',
     'wr/WebRenderTextureHost.h',
+    'wr/WebRenderUserData.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
         'basic/TextureClientX11.h',
         'basic/X11TextureSourceBasic.h',
         'composite/X11TextureHost.h',
         'ipc/ShadowLayerUtilsX11.h',
@@ -462,16 +463,17 @@ UNIFIED_SOURCES += [
     'wr/WebRenderImageLayer.cpp',
     'wr/WebRenderLayer.cpp',
     'wr/WebRenderLayerManager.cpp',
     'wr/WebRenderLayersLogging.cpp',
     'wr/WebRenderPaintedLayer.cpp',
     'wr/WebRenderPaintedLayerBlob.cpp',
     'wr/WebRenderScrollData.cpp',
     'wr/WebRenderTextLayer.cpp',
+    'wr/WebRenderUserData.cpp',
     # XXX here are some unified build error.
     #'wr/WebRenderTextureHost.cpp'
 ]
 
 SOURCES += [
     'basic/BasicImageLayer.cpp',
     'ImageContainer.cpp',
     'Layers.cpp',
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -15,17 +15,16 @@
 #include "WebRenderCanvasLayer.h"
 #include "WebRenderColorLayer.h"
 #include "WebRenderContainerLayer.h"
 #include "WebRenderImageLayer.h"
 #include "WebRenderPaintedLayer.h"
 #include "WebRenderPaintedLayerBlob.h"
 #include "WebRenderTextLayer.h"
 #include "WebRenderDisplayItemLayer.h"
-#include "nsDisplayList.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
@@ -239,16 +238,76 @@ WebRenderLayerManager::EndTransactionWit
   WrBridge()->RemoveExpiredFontKeys();
   EndTransactionInternal(nullptr,
                          nullptr,
                          EndTransactionFlags::END_DEFAULT,
                          aDisplayList,
                          aDisplayListBuilder);
 }
 
+Maybe<wr::ImageKey>
+WebRenderLayerManager::CreateImageKey(nsDisplayItem* aItem,
+                                      ImageContainer* aContainer,
+                                      mozilla::wr::DisplayListBuilder& aBuilder,
+                                      const StackingContextHelper& aSc,
+                                      gfx::IntSize& aSize)
+{
+  RefPtr<WebRenderImageData> imageData = CreateOrRecycleWebRenderUserData<WebRenderImageData>(aItem);
+  MOZ_ASSERT(imageData);
+
+  if (aContainer->IsAsync()) {
+    bool snap;
+    nsRect bounds = aItem->GetBounds(nullptr, &snap);
+    int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+    LayerRect rect = ViewAs<LayerPixel>(
+      LayoutDeviceRect::FromAppUnits(bounds, appUnitsPerDevPixel),
+      PixelCastJustification::WebRenderHasUnitResolution);
+    LayerRect scBounds(0, 0, rect.width, rect.height);
+    imageData->CreateAsyncImageWebRenderCommands(aBuilder,
+                                                 aContainer,
+                                                 aSc,
+                                                 rect,
+                                                 scBounds,
+                                                 gfx::Matrix4x4(),
+                                                 Nothing(),
+                                                 wr::ImageRendering::Auto,
+                                                 wr::MixBlendMode::Normal);
+    return Nothing();
+  }
+
+  AutoLockImage autoLock(aContainer);
+  if (!autoLock.HasImage()) {
+    return Nothing();
+  }
+  mozilla::layers::Image* image = autoLock.GetImage();
+  aSize = image->GetSize();
+
+  return imageData->UpdateImageKey(aContainer);
+}
+
+bool
+WebRenderLayerManager::PushImage(nsDisplayItem* aItem,
+                                 ImageContainer* aContainer,
+                                 mozilla::wr::DisplayListBuilder& aBuilder,
+                                 const StackingContextHelper& aSc,
+                                 const LayerRect& aRect)
+{
+  gfx::IntSize size;
+  Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer, aBuilder, aSc, size);
+  if (!key) {
+    return false;
+  }
+
+  wr::ImageRendering filter = wr::ImageRendering::Auto;
+  auto r = aSc.ToRelativeWrRect(aRect);
+  aBuilder.PushImage(r, r, filter, key.value());
+
+  return true;
+}
+
 void
 WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                       void* aCallbackData,
                                       EndTransactionFlags aFlags)
 {
   mEndTransactionWithoutLayers = false;
   DiscardImages();
   WrBridge()->RemoveExpiredFontKeys();
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -7,21 +7,22 @@
 #define GFX_WEBRENDERLAYERMANAGER_H
 
 #include "Layers.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/layers/APZTestData.h"
 #include "mozilla/layers/FocusTarget.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TransactionIdAllocator.h"
+#include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/WebRenderTypes.h"
+#include "nsDisplayList.h"
 
 class nsIWidget;
-class nsDisplayList;
 
 namespace mozilla {
 namespace layers {
 
 class CompositorBridgeChild;
 class KnowsCompositor;
 class PCompositorBridgeChild;
 class WebRenderBridgeChild;
@@ -47,16 +48,26 @@ public:
   WebRenderLayerManager* AsWebRenderLayerManager() override { return this; }
   virtual CompositorBridgeChild* GetCompositorBridgeChild() override;
 
   virtual int32_t GetMaxTextureSize() const override;
 
   virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override;
   virtual bool BeginTransaction() override;
   virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
+  Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
+                                     ImageContainer* aContainer,
+                                     mozilla::wr::DisplayListBuilder& aBuilder,
+                                     const StackingContextHelper& aSc,
+                                     gfx::IntSize& aSize);
+  bool PushImage(nsDisplayItem* aItem,
+                 ImageContainer* aContainer,
+                 mozilla::wr::DisplayListBuilder& aBuilder,
+                 const StackingContextHelper& aSc,
+                 const LayerRect& aRect);
   void CreateWebRenderCommandsFromDisplayList(nsDisplayList* aDisplayList,
                                               nsDisplayListBuilder* aDisplayListBuilder,
                                               StackingContextHelper& aSc,
                                               wr::DisplayListBuilder& aBuilder);
   void EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
                                   nsDisplayListBuilder* aDisplayListBuilder);
   bool IsLayersFreeTransaction() { return mEndTransactionWithoutLayers; }
   virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
@@ -147,16 +158,44 @@ public:
                                   const std::string& aKey,
                                   const std::string& aValue) {
     mApzTestData.LogTestDataForPaint(mPaintSequenceNumber, aScrollId, aKey, aValue);
   }
   // See equivalent function in ClientLayerManager
   const APZTestData& GetAPZTestData() const
   { return mApzTestData; }
 
+  // Those are data that we kept between transactions. We used to cache some
+  // data in the layer. But in layers free mode, we don't have layer which
+  // means we need some other place to cached the data between transaction.
+  // We store the data in frame's property.
+  template<class T> already_AddRefed<T>
+  CreateOrRecycleWebRenderUserData(nsDisplayItem* aItem)
+  {
+    MOZ_ASSERT(aItem);
+    nsIFrame* frame = aItem->Frame();
+
+    if (!frame->HasProperty(nsIFrame::WebRenderUserDataProperty())) {
+      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 = new T(this);
+    }
+
+    MOZ_ASSERT(data);
+    MOZ_ASSERT(data->GetType() == T::Type());
+    RefPtr<T> res = static_cast<T*>(data.get());
+    return res.forget();
+  }
+
 private:
   /**
    * Take a snapshot of the parent context, and copy
    * it into mTarget.
    */
   void MakeSnapshotIfRequired(LayoutDeviceIntSize aSize);
 
   void ClearLayer(Layer* aLayer);
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -0,0 +1,144 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebRenderUserData.h"
+
+namespace mozilla {
+namespace layers {
+
+WebRenderBridgeChild*
+WebRenderUserData::WrBridge() const
+{
+  return mWRManager->WrBridge();
+}
+
+WebRenderImageData::WebRenderImageData(WebRenderLayerManager* aWRManager)
+  : WebRenderUserData(aWRManager)
+{
+}
+
+WebRenderImageData::~WebRenderImageData()
+{
+  if (mKey) {
+    mWRManager->AddImageKeyForDiscard(mKey.value());
+  }
+
+  if (mExternalImageId) {
+    WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
+  }
+
+  if (mPipelineId) {
+    WrBridge()->RemovePipelineIdForAsyncCompositable(mPipelineId.ref());
+  }
+}
+
+Maybe<wr::ImageKey>
+WebRenderImageData::UpdateImageKey(ImageContainer* aContainer)
+{
+  CreateImageClientIfNeeded();
+  CreateExternalImageIfNeeded();
+
+  if (!mImageClient || !mExternalImageId) {
+    return Nothing();
+  }
+
+  MOZ_ASSERT(mImageClient->AsImageClientSingle());
+  MOZ_ASSERT(aContainer);
+
+  ImageClientSingle* imageClient = mImageClient->AsImageClientSingle();
+  uint32_t oldCounter = imageClient->GetLastUpdateGenerationCounter();
+
+  bool ret = imageClient->UpdateImage(aContainer, /* unused */0);
+  if (!ret || imageClient->IsEmpty()) {
+    // Delete old key
+    if (mKey) {
+      mWRManager->AddImageKeyForDiscard(mKey.value());
+      mKey = Nothing();
+    }
+    return Nothing();
+  }
+
+  // Reuse old key if generation is not updated.
+  if (oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) {
+    return mKey;
+  }
+
+  // Delete old key, we are generating a new key.
+  if (mKey) {
+    mWRManager->AddImageKeyForDiscard(mKey.value());
+  }
+
+  WrImageKey key = WrBridge()->GetNextImageKey();
+  mWRManager->WrBridge()->AddWebRenderParentCommand(OpAddExternalImage(mExternalImageId.value(), key));
+  mKey = Some(key);
+
+  return mKey;
+}
+
+void
+WebRenderImageData::CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                      ImageContainer* aContainer,
+                                                      const StackingContextHelper& aSc,
+                                                      const LayerRect& aBounds,
+                                                      const LayerRect& aSCBounds,
+                                                      const Matrix4x4& aSCTransform,
+                                                      const MaybeIntSize& aScaleToSize,
+                                                      const WrImageRendering& aFilter,
+                                                      const WrMixBlendMode& aMixBlendMode)
+{
+  MOZ_ASSERT(aContainer->IsAsync());
+  if (!mPipelineId) {
+    // Alloc async image pipeline id.
+    mPipelineId = Some(WrBridge()->GetCompositorBridgeChild()->GetNextPipelineId());
+    WrBridge()->AddPipelineIdForAsyncCompositable(mPipelineId.ref(),
+                                                  aContainer->GetAsyncContainerHandle());
+  }
+  MOZ_ASSERT(!mImageClient);
+  MOZ_ASSERT(!mExternalImageId);
+
+  // Push IFrame for async image pipeline.
+  //
+  // We don't push a stacking context for this async image pipeline here.
+  // Instead, we do it inside the iframe that hosts the image. As a result,
+  // a bunch of the calculations normally done as part of that stacking
+  // context need to be done manually and pushed over to the parent side,
+  // where it will be done when we build the display list for the iframe.
+  // That happens in WebRenderCompositableHolder.
+  WrRect r = aSc.ToRelativeWrRect(aBounds);
+  aBuilder.PushIFrame(r, r, mPipelineId.ref());
+
+  WrBridge()->AddWebRenderParentCommand(OpUpdateAsyncImagePipeline(mPipelineId.value(),
+                                                                   aSCBounds,
+                                                                   aSCTransform,
+                                                                   aScaleToSize,
+                                                                   aFilter,
+                                                                   aMixBlendMode));
+}
+
+void
+WebRenderImageData::CreateImageClientIfNeeded()
+{
+  if (!mImageClient) {
+    mImageClient = ImageClient::CreateImageClient(CompositableType::IMAGE,
+                                                  WrBridge(),
+                                                  TextureFlags::DEFAULT);
+    if (!mImageClient) {
+      return;
+    }
+
+    mImageClient->Connect();
+  }
+}
+
+void
+WebRenderImageData::CreateExternalImageIfNeeded()
+{
+  if (!mExternalImageId)  {
+    mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
+  }
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef GFX_WEBRENDERUSERDATA_H
+#define GFX_WEBRENDERUSERDATA_H
+
+#include "mozilla/layers/StackingContextHelper.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+
+namespace mozilla {
+namespace layers {
+class ImageClient;
+class ImageContainer;
+class WebRenderBridgeChild;
+class WebRenderImageData;
+class WebRenderLayerManager;
+
+class WebRenderUserData
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(WebRenderUserData)
+
+  explicit WebRenderUserData(WebRenderLayerManager* aWRManager)
+    : mWRManager(aWRManager)
+  { }
+
+  virtual WebRenderImageData* AsImageData() { return nullptr; }
+
+  enum class UserDataType {
+    eImage,
+  };
+
+  virtual UserDataType GetType() = 0;
+
+protected:
+  virtual ~WebRenderUserData() {}
+
+  WebRenderBridgeChild* WrBridge() const;
+
+  WebRenderLayerManager* mWRManager;
+};
+
+class WebRenderImageData : public WebRenderUserData
+{
+public:
+  explicit WebRenderImageData(WebRenderLayerManager* aWRManager);
+  virtual ~WebRenderImageData();
+
+  virtual WebRenderImageData* AsImageData() override { return this; }
+  virtual UserDataType GetType() override { return UserDataType::eImage; }
+  static UserDataType Type() { return UserDataType::eImage; }
+
+  Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer);
+
+  void CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                         ImageContainer* aContainer,
+                                         const StackingContextHelper& aSc,
+                                         const LayerRect& aBounds,
+                                         const LayerRect& aSCBounds,
+                                         const gfx::Matrix4x4& aSCTransform,
+                                         const gfx::MaybeIntSize& aScaleToSize,
+                                         const WrImageRendering& aFilter,
+                                         const WrMixBlendMode& aMixBlendMode);
+
+protected:
+  void CreateImageClientIfNeeded();
+  void CreateExternalImageIfNeeded();
+
+  wr::MaybeExternalImageId mExternalImageId;
+  Maybe<wr::ImageKey> mKey;
+  RefPtr<ImageClient> mImageClient;
+  Maybe<wr::PipelineId> mPipelineId;
+  RefPtr<ImageContainer> mContainer;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* GFX_WEBRENDERUSERDATA_H */
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -27,16 +27,17 @@
 #include "FrameProperties.h"
 #include "mozilla/layout/FrameChildList.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/SmallPointerArray.h"
 #include "mozilla/WritingModes.h"
 #include "nsDirection.h"
 #include "nsFrameList.h"
 #include "nsFrameState.h"
+#include "mozilla/layers/WebRenderUserData.h"
 #include "mozilla/ReflowOutput.h"
 #include "nsITheme.h"
 #include "nsLayoutUtils.h"
 #include "nsQueryFrame.h"
 #include "nsStringGlue.h"
 #include "nsStyleContext.h"
 #include "nsStyleStruct.h"
 #include "Visibility.h"
@@ -1126,16 +1127,19 @@ public:
   virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
   { return aChild->GetPosition(); }
 
   nsPoint GetPositionIgnoringScrolling();
 
   typedef AutoTArray<nsIContent*, 2> ContentArray;
   static void DestroyContentArray(ContentArray* aArray);
 
+  typedef mozilla::layers::WebRenderUserData WebRenderUserData;
+  typedef nsRefPtrHashtable<nsUint32HashKey, WebRenderUserData> WebRenderUserDataTable;
+
 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, dtor)             \
   static const mozilla::FramePropertyDescriptor<type>* prop() {           \
     /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */    \
     static const auto descriptor =                                        \
       mozilla::FramePropertyDescriptor<type>::NewWithDestructor<dtor>();  \
     return &descriptor;                                                   \
   }
 
@@ -1223,16 +1227,17 @@ public:
   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BBaselinePadProperty, nscoord)
 
   NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(GenConProperty, ContentArray,
                                       DestroyContentArray)
 
   NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
 
   NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty, nsPlaceholderFrame)
+  NS_DECLARE_FRAME_PROPERTY_DELETABLE(WebRenderUserDataProperty, WebRenderUserDataTable)
 
   mozilla::FrameBidiData GetBidiData() const
   {
     bool exists;
     mozilla::FrameBidiData bidiData = GetProperty(BidiDataProperty(), &exists);
     if (!exists) {
       bidiData.precedingControl = mozilla::kBidiLevelNone;
     }