Bug 1377571 - Add fallback path for layers-free. r=jrmuizel draft
authorEthan Lin <ethlin@mozilla.com>
Thu, 06 Jul 2017 00:29:41 +0800
changeset 606678 c46eb001e1dae4acf100f81a36eefd73f0523740
parent 604819 4bd7db49d22847111dff9c1dd63ed573903faa5b
child 636827 79c139b6b75b46342a78088822e0fa671f4f26e6
push id67768
push userbmo:ethlin@mozilla.com
push dateTue, 11 Jul 2017 08:17:08 +0000
reviewersjrmuizel
bugs1377571
milestone56.0a1
Bug 1377571 - Add fallback path for layers-free. r=jrmuizel MozReview-Commit-ID: KOM7JXYljX2
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
gfx/layers/wr/WebRenderUserData.cpp
gfx/layers/wr/WebRenderUserData.h
layout/generic/nsBulletFrame.cpp
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -8,16 +8,17 @@
 #include "gfxPrefs.h"
 #include "GeckoProfiler.h"
 #include "LayersLogging.h"
 #include "mozilla/gfx/DrawEventRecorder.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/StackingContextHelper.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
+#include "mozilla/layers/UpdateImageHelper.h"
 #include "WebRenderCanvasLayer.h"
 #include "WebRenderColorLayer.h"
 #include "WebRenderContainerLayer.h"
 #include "WebRenderImageLayer.h"
 #include "WebRenderPaintedLayer.h"
 #include "WebRenderPaintedLayerBlob.h"
 #include "WebRenderTextLayer.h"
 #include "WebRenderDisplayItemLayer.h"
@@ -218,17 +219,17 @@ WebRenderLayerManager::CreateWebRenderCo
       item->~nsDisplayItem();
       continue;
     }
 
     savedItems.AppendToTop(item);
 
     if (!item->CreateWebRenderCommands(aBuilder, aSc, mParentCommands, this,
                                        aDisplayListBuilder)) {
-      // TODO: fallback
+      PushItemAsImage(item, aBuilder, aSc, aDisplayListBuilder);
     }
   }
   aDisplayList->AppendToTop(&savedItems);
 }
 
 void
 WebRenderLayerManager::EndTransactionWithoutLayer(nsDisplayList* aDisplayList,
                                                   nsDisplayListBuilder* aDisplayListBuilder)
@@ -299,59 +300,141 @@ WebRenderLayerManager::PushImage(nsDispl
 
   wr::ImageRendering filter = wr::ImageRendering::Auto;
   auto r = aSc.ToRelativeWrRect(aRect);
   aBuilder.PushImage(r, r, filter, key.value());
 
   return true;
 }
 
+static void
+PaintItemByDrawTarget(nsDisplayItem* aItem,
+                      DrawTarget* aDT,
+                      const LayerRect& aImageRect,
+                      const LayerPoint& aOffset,
+                      nsDisplayListBuilder* aDisplayListBuilder)
+{
+  aDT->ClearRect(aImageRect.ToUnknownRect());
+  RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT, aOffset.ToUnknownPoint());
+  MOZ_ASSERT(context);
+  aItem->Paint(aDisplayListBuilder, context);
+
+  if (gfxPrefs::WebRenderHighlightPaintedLayers()) {
+    aDT->SetTransform(Matrix());
+    aDT->FillRect(Rect(0, 0, aImageRect.width, aImageRect.height), ColorPattern(Color(1.0, 0.0, 0.0, 0.5)));
+  }
+  if (aItem->Frame()->PresContext()->GetPaintFlashing()) {
+    aDT->SetTransform(Matrix());
+    float r = float(rand()) / RAND_MAX;
+    float g = float(rand()) / RAND_MAX;
+    float b = float(rand()) / RAND_MAX;
+    aDT->FillRect(Rect(0, 0, aImageRect.width, aImageRect.height), ColorPattern(Color(r, g, b, 0.5)));
+  }
+}
+
 bool
-WebRenderLayerManager::PushItemAsBlobImage(nsDisplayItem* aItem,
-                                           wr::DisplayListBuilder& aBuilder,
-                                           const StackingContextHelper& aSc,
-                                           nsDisplayListBuilder* aDisplayListBuilder)
+WebRenderLayerManager::PushItemAsImage(nsDisplayItem* aItem,
+                                       wr::DisplayListBuilder& aBuilder,
+                                       const StackingContextHelper& aSc,
+                                       nsDisplayListBuilder* aDisplayListBuilder)
 {
-  const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
+  RefPtr<WebRenderFallbackData> fallbackData = CreateOrRecycleWebRenderUserData<WebRenderFallbackData>(aItem);
 
   bool snap;
+  nsRect itemBounds = aItem->GetBounds(aDisplayListBuilder, &snap);
+  nsRect clippedBounds = itemBounds;
+
+  const DisplayItemClip& clip = aItem->GetClip();
+  if (clip.HasClip()) {
+    clippedBounds = itemBounds.Intersect(clip.GetClipRect());
+  }
+
+  const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
   LayerRect bounds = ViewAs<LayerPixel>(
-      LayoutDeviceRect::FromAppUnits(aItem->GetBounds(aDisplayListBuilder, &snap), appUnitsPerDevPixel),
+      LayoutDeviceRect::FromAppUnits(clippedBounds, appUnitsPerDevPixel),
       PixelCastJustification::WebRenderHasUnitResolution);
+
   LayerIntSize imageSize = RoundedToInt(bounds.Size());
   LayerRect imageRect;
   imageRect.SizeTo(LayerSize(imageSize));
+  if (imageSize.width == 0 || imageSize.height == 0) {
+    return true;
+  }
 
-  RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
-  RefPtr<gfx::DrawTarget> dummyDt =
-    gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8);
-  RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize());
+  nsPoint shift = clippedBounds.TopLeft() - itemBounds.TopLeft();
   LayerPoint offset = ViewAs<LayerPixel>(
-      LayoutDevicePoint::FromAppUnits(aItem->ToReferenceFrame(), appUnitsPerDevPixel),
+      LayoutDevicePoint::FromAppUnits(aItem->ToReferenceFrame() + shift, appUnitsPerDevPixel),
       PixelCastJustification::WebRenderHasUnitResolution);
 
-  {
-    dt->ClearRect(imageRect.ToUnknownRect());
-    RefPtr<gfxContext> context = gfxContext::CreateOrNull(dt, offset.ToUnknownPoint());
-    MOZ_ASSERT(context);
+  nsRegion invalidRegion;
+  nsAutoPtr<nsDisplayItemGeometry> geometry = fallbackData->GetGeometry();
 
-    aItem->Paint(aDisplayListBuilder, context);
+  if (geometry) {
+    nsPoint shift = itemBounds.TopLeft() - geometry->mBounds.TopLeft();
+    geometry->MoveBy(shift);
+    aItem->ComputeInvalidationRegion(aDisplayListBuilder, geometry, &invalidRegion);
+    nsRect lastBounds = fallbackData->GetBounds();
+    lastBounds.MoveBy(shift);
+
+    if (!lastBounds.IsEqualInterior(clippedBounds)) {
+      invalidRegion.OrWith(lastBounds);
+      invalidRegion.OrWith(clippedBounds);
+    }
   }
 
-  wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData);
+  if (!geometry || !invalidRegion.IsEmpty()) {
+    Maybe<wr::ImageKey> key;
+    if (gfxPrefs::WebRenderBlobImages()) {
+      RefPtr<gfx::DrawEventRecorderMemory> recorder = MakeAndAddRef<gfx::DrawEventRecorderMemory>();
+      RefPtr<gfx::DrawTarget> dummyDt =
+        gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8X8);
+      RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, imageSize.ToUnknownSize());
+      PaintItemByDrawTarget(aItem, dt, imageRect, offset, aDisplayListBuilder);
+      recorder->Finish();
+
+      wr::ByteBuffer bytes(recorder->mOutputStream.mLength, (uint8_t*)recorder->mOutputStream.mData);
+      key = Some(WrBridge()->GetNextImageKey());
+      WrBridge()->SendAddBlobImage(key.value(), imageSize.ToUnknownSize(), imageSize.width * 4, dt->GetFormat(), bytes);
+      fallbackData->SetKey(key);
+    } else {
+      fallbackData->CreateImageClientIfNeeded();
+      RefPtr<ImageClient> imageClient = fallbackData->GetImageClient();
+      RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
+
+      UpdateImageHelper helper(imageContainer, imageClient, imageSize.ToUnknownSize());
+      RefPtr<gfx::DrawTarget> dt = helper.GetDrawTarget();
+      PaintItemByDrawTarget(aItem, dt, imageRect, offset, aDisplayListBuilder);
+      if (!helper.UpdateImage()) {
+        return false;
+      }
+
+      // Force update the key in fallback data since we repaint the image in this path.
+      // If not force update, fallbackData may reuse the original key because it
+      // doesn't know UpdateImageHelper already updated the image container.
+      key = fallbackData->UpdateImageKey(imageContainer, true);
+    }
+
+    if (!key) {
+      return false;
+    }
+
+    geometry = aItem->AllocateGeometry(aDisplayListBuilder);
+  }
+
+  // Update current bounds to fallback data
+  fallbackData->SetGeometry(Move(geometry));
+  fallbackData->SetBounds(clippedBounds);
+
+  MOZ_ASSERT(fallbackData->GetKey());
 
   WrRect dest = aSc.ToRelativeWrRect(imageRect + offset);
-  WrImageKey key = WrBridge()->GetNextImageKey();
-  WrBridge()->SendAddBlobImage(key, imageSize.ToUnknownSize(), imageSize.width * 4, dt->GetFormat(), bytes);
-  AddImageKeyForDiscard(key);
-
   aBuilder.PushImage(dest,
                      dest,
                      wr::ImageRendering::Auto,
-                     key);
+                     fallbackData->GetKey().value());
   return true;
 }
 
 void
 WebRenderLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
                                       void* aCallbackData,
                                       EndTransactionFlags aFlags)
 {
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -59,20 +59,20 @@ public:
                                      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);
-  bool PushItemAsBlobImage(nsDisplayItem* aItem,
-                           wr::DisplayListBuilder& aBuilder,
-                           const StackingContextHelper& aSc,
-                           nsDisplayListBuilder* aDisplayListBuilder);
+  bool PushItemAsImage(nsDisplayItem* aItem,
+                       wr::DisplayListBuilder& aBuilder,
+                       const StackingContextHelper& aSc,
+                       nsDisplayListBuilder* aDisplayListBuilder);
   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,
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -1,14 +1,15 @@
 /* -*- 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"
+#include "nsDisplayListInvalidation.h"
 
 namespace mozilla {
 namespace layers {
 
 WebRenderBridgeChild*
 WebRenderUserData::WrBridge() const
 {
   return mWRManager->WrBridge();
@@ -30,17 +31,17 @@ WebRenderImageData::~WebRenderImageData(
   }
 
   if (mPipelineId) {
     WrBridge()->RemovePipelineIdForAsyncCompositable(mPipelineId.ref());
   }
 }
 
 Maybe<wr::ImageKey>
-WebRenderImageData::UpdateImageKey(ImageContainer* aContainer)
+WebRenderImageData::UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate)
 {
   CreateImageClientIfNeeded();
   CreateExternalImageIfNeeded();
 
   if (!mImageClient || !mExternalImageId) {
     return Nothing();
   }
 
@@ -56,32 +57,39 @@ WebRenderImageData::UpdateImageKey(Image
     if (mKey) {
       mWRManager->AddImageKeyForDiscard(mKey.value());
       mKey = Nothing();
     }
     return Nothing();
   }
 
   // Reuse old key if generation is not updated.
-  if (oldCounter == imageClient->GetLastUpdateGenerationCounter() && mKey) {
+  if (!aForceUpdate && 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;
 }
 
+already_AddRefed<ImageClient>
+WebRenderImageData::GetImageClient()
+{
+  RefPtr<ImageClient> imageClient = mImageClient;
+  return imageClient.forget();
+}
+
 void
 WebRenderImageData::CreateAsyncImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                       ImageContainer* aContainer,
                                                       const StackingContextHelper& aSc,
                                                       const LayerRect& aBounds,
                                                       const LayerRect& aSCBounds,
                                                       const Matrix4x4& aSCTransform,
                                                       const MaybeIntSize& aScaleToSize,
@@ -135,10 +143,21 @@ WebRenderImageData::CreateImageClientIfN
 void
 WebRenderImageData::CreateExternalImageIfNeeded()
 {
   if (!mExternalImageId)  {
     mExternalImageId = Some(WrBridge()->AllocExternalImageIdForCompositable(mImageClient));
   }
 }
 
+WebRenderFallbackData::WebRenderFallbackData(WebRenderLayerManager* aWRManager)
+  : WebRenderImageData(aWRManager)
+{
+}
+
+void
+WebRenderFallbackData::SetGeometry(nsAutoPtr<nsDisplayItemGeometry> aGeometry)
+{
+  mGeometry = aGeometry;
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderUserData.h
+++ b/gfx/layers/wr/WebRenderUserData.h
@@ -4,16 +4,18 @@
  * 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"
 
+class nsDisplayItemGeometry;
+
 namespace mozilla {
 namespace layers {
 class ImageClient;
 class ImageContainer;
 class WebRenderBridgeChild;
 class WebRenderImageData;
 class WebRenderLayerManager;
 
@@ -25,16 +27,17 @@ public:
   explicit WebRenderUserData(WebRenderLayerManager* aWRManager)
     : mWRManager(aWRManager)
   { }
 
   virtual WebRenderImageData* AsImageData() { return nullptr; }
 
   enum class UserDataType {
     eImage,
+    eFallback,
   };
 
   virtual UserDataType GetType() = 0;
 
 protected:
   virtual ~WebRenderUserData() {}
 
   WebRenderBridgeChild* WrBridge() const;
@@ -46,36 +49,58 @@ class WebRenderImageData : public WebRen
 {
 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> GetKey() { return mKey; }
+  void SetKey(Maybe<wr::ImageKey> aKey) { mKey = aKey; }
+  already_AddRefed<ImageClient> GetImageClient();
 
-  Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer);
+  Maybe<wr::ImageKey> UpdateImageKey(ImageContainer* aContainer, bool aForceUpdate = false);
 
   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);
 
+  void CreateImageClientIfNeeded();
+
 protected:
-  void CreateImageClientIfNeeded();
   void CreateExternalImageIfNeeded();
 
   wr::MaybeExternalImageId mExternalImageId;
   Maybe<wr::ImageKey> mKey;
   RefPtr<ImageClient> mImageClient;
   Maybe<wr::PipelineId> mPipelineId;
   RefPtr<ImageContainer> mContainer;
 };
 
+class WebRenderFallbackData : public WebRenderImageData
+{
+public:
+  explicit WebRenderFallbackData(WebRenderLayerManager* aWRManager);
+  virtual ~WebRenderFallbackData() {}
+
+  virtual UserDataType GetType() override { return UserDataType::eFallback; }
+  static UserDataType Type() { return UserDataType::eFallback; }
+  nsAutoPtr<nsDisplayItemGeometry> GetGeometry() { return mGeometry; }
+  void SetGeometry(nsAutoPtr<nsDisplayItemGeometry> aGeometry);
+  nsRect GetBounds() { return mBounds; }
+  void SetBounds(const nsRect& aRect) { mBounds = aRect; }
+
+protected:
+  nsAutoPtr<nsDisplayItemGeometry> mGeometry;
+  nsRect mBounds;
+};
+
 } // namespace layers
 } // namespace mozilla
 
 #endif /* GFX_WEBRENDERUSERDATA_H */
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -485,17 +485,17 @@ BulletRenderer::CreateWebRenderCommandsF
                                                wr::DisplayListBuilder& aBuilder,
                                                const layers::StackingContextHelper& aSc,
                                                nsTArray<layers::WebRenderParentCommand>& aParentCommands,
                                                mozilla::layers::WebRenderLayerManager* aManager,
                                                nsDisplayListBuilder* aDisplayListBuilder)
 {
   MOZ_ASSERT(IsPathType());
 
-  if (!aManager->PushItemAsBlobImage(aItem, aBuilder, aSc, aDisplayListBuilder)) {
+  if (!aManager->PushItemAsImage(aItem, aBuilder, aSc, aDisplayListBuilder)) {
     NS_WARNING("Fail to create WebRender commands for Bullet path.");
   }
 }
 
 void
 BulletRenderer::CreateWebRenderCommandsForText(nsDisplayItem* aItem,
                                                wr::DisplayListBuilder& aBuilder,
                                                const layers::StackingContextHelper& aSc,