Bug 1508522 - Relax aysnc animation size restriction with WebRender r=mattwoodrow
authorsotaro <sotaro.ikeda.g@gmail.com>
Thu, 17 Jan 2019 23:59:44 +0000
changeset 511488 d1b5339852740fc2e559b66668204fc9202daf15
parent 511487 fd6b8be34aed51a18d91261abeb586bbbf350e50
child 511489 8a464d751ed487778109a90475332f4130372b56
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1508522
milestone66.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 1508522 - Relax aysnc animation size restriction with WebRender r=mattwoodrow Performance of sync animation with large images is worse with WebRender than non-WebRender case. We want to use async animation as much as possible and relax aysnc animation size restriction. With WebRender, memory usage increase for async animation is limited compared to non-WebRender case. Image does not needs additional TextureClient allocation for async animation and majority of frames are comverted to WebRenderCommands. Then we could relax aysnc animation size restriction with WebRender. Differential Revision: https://phabricator.services.mozilla.com/D16791
dom/animation/test/mozilla/file_restyles.html
layout/base/PresShell.cpp
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -1829,37 +1829,45 @@ waitForAllPaints(() => {
 
     const markers = await observeStylingInTargetWindow(iframe.contentWindow, 5);
     is(markers.length, 0,
        'Animation in out-of-view iframe should be throttled');
 
     await ensureElementRemoval(div);
   });
 
-  // Tests that transform animations are not able to run on the compositor due
-  // to layout restrictions (e.g. animations on a large size frame) doesn't
-  // flush layout at all.
+  // Tests that transform animations on a large size frame doesn't flush layout at all.
+  //
+  // With WebRender, the large size frame could run on compositor.
+  // Without WebRender, the large size frame is not able to run on the compositor
+  // due to layout restrictions.
   add_task(async function flush_layout_for_transform_animations() {
     // Set layout.animation.prerender.partial to disallow transform animations
     // on large frames to be sent to the compositor.
     await SpecialPowers.pushPrefEnv({
       set: [['layout.animation.prerender.partial', false]] });
     const div = addDiv(null, { style: 'width: 10000px; height: 10000px;' });
 
     const animation = div.animate([ { transform: 'rotate(360deg)', } ],
                                   { duration: 100 * MS_PER_SEC,
                                     // Set step-end to skip further restyles.
                                     easing: 'step-end' });
 
     const FLUSH_LAYOUT = SpecialPowers.DOMWindowUtils.FLUSH_LAYOUT;
+    const isWebRender =
+      SpecialPowers.DOMWindowUtils.layerManagerType == 'WebRender';
     ok(SpecialPowers.DOMWindowUtils.needsFlush(FLUSH_LAYOUT),
        'Flush layout is needed for the appended div');
     await waitForAnimationReadyToRestyle(animation);
 
-    ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
+    if (isWebRender) {
+      ok(SpecialPowers.wrap(animation).isRunningOnCompositor);
+    } else {
+      ok(!SpecialPowers.wrap(animation).isRunningOnCompositor);
+    }
     ok(!SpecialPowers.DOMWindowUtils.needsFlush(FLUSH_LAYOUT),
        'No further flush layout needed');
 
     await ensureElementRemoval(div);
   });
 
 });
 
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6064,16 +6064,19 @@ void PresShell::Paint(nsView* aViewToPai
   }
   if (aFlags & PAINT_SYNC_DECODE_IMAGES) {
     flags |= PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES;
   }
   if (mNextPaintCompressed) {
     flags |= PaintFrameFlags::PAINT_COMPRESSED;
     mNextPaintCompressed = false;
   }
+  if (layerManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
+    flags |= PaintFrameFlags::PAINT_FOR_WEBRENDER;
+  }
 
   if (frame) {
     // We can paint directly into the widget using its layer manager.
     nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor,
                               nsDisplayListBuilderMode::PAINTING, flags);
 
     // When recording/replaying, create a checkpoint after every paint. This
     // can cause content JS to run, so reset |nojs|.
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3452,16 +3452,19 @@ nsresult nsLayoutUtils::PaintFrame(gfxCo
   }
   if (aFlags & PaintFrameFlags::PAINT_SYNC_DECODE_IMAGES) {
     builder.SetSyncDecodeImages(true);
   }
   if (aFlags & (PaintFrameFlags::PAINT_WIDGET_LAYERS |
                 PaintFrameFlags::PAINT_TO_WINDOW)) {
     builder.SetPaintingToWindow(true);
   }
+  if (aFlags & PaintFrameFlags::PAINT_FOR_WEBRENDER) {
+    builder.SetPaintingForWebRender(true);
+  }
   if (aFlags & PaintFrameFlags::PAINT_IGNORE_SUPPRESSION) {
     builder.IgnorePaintSuppression();
   }
 
   if (nsIDocShell* doc = presContext->GetDocShell()) {
     bool isActive = false;
     doc->GetIsActive(&isActive);
     builder.SetInActiveDocShell(isActive);
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1072,17 +1072,18 @@ class nsLayoutUtils {
     PAINT_SYNC_DECODE_IMAGES = 0x02,
     PAINT_WIDGET_LAYERS = 0x04,
     PAINT_IGNORE_SUPPRESSION = 0x08,
     PAINT_DOCUMENT_RELATIVE = 0x10,
     PAINT_HIDE_CARET = 0x20,
     PAINT_TO_WINDOW = 0x40,
     PAINT_EXISTING_TRANSACTION = 0x80,
     PAINT_NO_COMPOSITE = 0x100,
-    PAINT_COMPRESSED = 0x200
+    PAINT_COMPRESSED = 0x200,
+    PAINT_FOR_WEBRENDER = 0x400,
   };
 
   /**
    * Given aFrame, the root frame of a stacking context, paint it and its
    * descendants to aRenderingContext.
    * @param aRenderingContext a rendering context translated so that (0,0)
    * is the origin of aFrame; for best results, (0,0) should transform
    * to pixel-aligned coordinates. This can be null, in which case
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -1039,16 +1039,17 @@ nsDisplayListBuilder::nsDisplayListBuild
       mAllowMergingAndFlattening(true),
       mWillComputePluginGeometry(false),
       mInTransform(false),
       mInFilter(false),
       mInPageSequence(false),
       mIsInChromePresContext(false),
       mSyncDecodeImages(false),
       mIsPaintingToWindow(false),
+      mIsPaintingForWebRender(false),
       mIsCompositingCheap(false),
       mContainsPluginItem(false),
       mAncestorHasApzAwareEventHandler(false),
       mHaveScrollableDisplayPort(false),
       mWindowDraggingAllowed(false),
       mIsBuildingForPopup(nsLayoutUtils::IsPopup(aReferenceFrame)),
       mForceLayerForScrollParent(false),
       mAsyncPanZoomEnabled(nsLayoutUtils::AsyncPanZoomEnabled(aReferenceFrame)),
@@ -7649,16 +7650,24 @@ bool nsDisplayBackgroundColor::CanUseAsy
 
   // If the incoming dirty rect already contains the entire overflow area,
   // we are already rendering the entire content.
   nsRect overflow = aFrame->GetVisualOverflowRectRelativeToSelf();
   if (aDirtyRect->Contains(overflow)) {
     return FullPrerender;
   }
 
+  // If painting is for WebRender, allow full prerender even for large size
+  // frame. With WebRender, memory usage increase for async animation is limited
+  // compared to non-WebRender case.
+  if (aBuilder->IsPaintingForWebRender()) {
+    *aDirtyRect = overflow;
+    return FullPrerender;
+  }
+
   float viewportRatioX = gfxPrefs::AnimationPrerenderViewportRatioLimitX();
   float viewportRatioY = gfxPrefs::AnimationPrerenderViewportRatioLimitY();
   uint32_t absoluteLimitX = gfxPrefs::AnimationPrerenderAbsoluteLimitX();
   uint32_t absoluteLimitY = gfxPrefs::AnimationPrerenderAbsoluteLimitY();
   nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
   // Only prerender if the transformed frame's size is <= a multiple of the
   // reference frame size (~viewport), and less than an absolute limit.
   // Both the ratio and the absolute limit are configurable.
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -670,16 +670,21 @@ class nsDisplayListBuilder {
    */
   bool IsIgnoringPaintSuppression() { return mIgnoreSuppression; }
   /**
    * Call this if we're doing normal painting to the window.
    */
   void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; }
   bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
   /**
+   * Call this if we're doing painting for WebRender
+   */
+  void SetPaintingForWebRender(bool aForWebRender) { mIsPaintingForWebRender = true; }
+  bool IsPaintingForWebRender() const { return mIsPaintingForWebRender; }
+  /**
    * Call this to prevent descending into subdocuments.
    */
   void SetDescendIntoSubdocuments(bool aDescend) {
     mDescendIntoSubdocuments = aDescend;
   }
 
   bool GetDescendIntoSubdocuments() { return mDescendIntoSubdocuments; }
 
@@ -1965,16 +1970,17 @@ class nsDisplayListBuilder {
   // True when we're building a display list that's directly or indirectly
   // under an nsDisplayTransform
   bool mInTransform;
   bool mInFilter;
   bool mInPageSequence;
   bool mIsInChromePresContext;
   bool mSyncDecodeImages;
   bool mIsPaintingToWindow;
+  bool mIsPaintingForWebRender;
   bool mIsCompositingCheap;
   bool mContainsPluginItem;
   bool mAncestorHasApzAwareEventHandler;
   // True when the first async-scrollable scroll frame for which we build a
   // display list has a display port. An async-scrollable scroll frame is one
   // which WantsAsyncScroll().
   bool mHaveScrollableDisplayPort;
   bool mWindowDraggingAllowed;