Bug 1444447 - While recording profile screenshots, create a full-window render target and buffer all draws to it r=mstange
authorBarret Rennie <barret@brennie.ca>
Mon, 21 Jan 2019 17:42:21 +0000
changeset 454715 a115176a8faa34bb59da329fc5d458f5ab7f9267
parent 454714 53d1b01b992467d1ab77ab9023444098280ba7a6
child 454716 28e336f7b9da63ef319650a7bd698289574a4f11
push id35411
push usercsabou@mozilla.com
push dateTue, 22 Jan 2019 03:53:40 +0000
treeherdermozilla-central@ada22b635f8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1444447
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 1444447 - While recording profile screenshots, create a full-window render target and buffer all draws to it r=mstange On some platforms we do not always have a DrawTarget that is the size of the entire window, so we will be unable to record the contents into screenshots in the profiler output. Now we create an additional DrawTarget that will contain the contents of the entire window so that we can record it for screenshots. This only adds the overhead of allocation while profiling and only when screenshots are requested. The initial screenshots end up blank but then the following screenshots are rendered correctly. Differential Revision: https://phabricator.services.mozilla.com/D14874
gfx/layers/basic/BasicCompositor.cpp
gfx/layers/basic/BasicCompositor.h
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -1,27 +1,29 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "BasicCompositor.h"
 #include "BasicLayersImpl.h"  // for FillRectWithMask
+#include "GeckoProfiler.h"
 #include "TextureHostBasic.h"
 #include "mozilla/layers/Effects.h"
 #include "nsIWidget.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/Helpers.h"
 #include "mozilla/gfx/Tools.h"
 #include "mozilla/gfx/ssse3-scaler.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/SSE.h"
+#include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "YCbCrUtils.h"
 #include <algorithm>
 #include "ImageContainer.h"
 #include "gfxPrefs.h"
 
 namespace mozilla {
 using namespace mozilla::gfx;
@@ -174,17 +176,19 @@ class WrappingTextureSourceYCbCrBasic : 
   BufferTextureHost* mTexture;
   const gfx::IntSize mSize;
   RefPtr<gfx::DataSourceSurface> mSurface;
   bool mNeedsUpdate;
 };
 
 BasicCompositor::BasicCompositor(CompositorBridgeParent* aParent,
                                  widget::CompositorWidget* aWidget)
-    : Compositor(aWidget, aParent), mIsPendingEndRemoteDrawing(false) {
+    : Compositor(aWidget, aParent),
+      mIsPendingEndRemoteDrawing(false),
+      mFullWindowRenderTarget(nullptr) {
   MOZ_COUNT_CTOR(BasicCompositor);
 
   mMaxTextureSize = Factory::GetMaxSurfaceSize(gfxVars::ContentBackend());
 }
 
 BasicCompositor::~BasicCompositor() { MOZ_COUNT_DTOR(BasicCompositor); }
 
 bool BasicCompositor::Initialize(nsCString* const out_failureReason) {
@@ -276,16 +280,20 @@ BasicCompositor::CreateRenderTargetForWi
     // Adjust bounds rect to account for new origin at (0, 0).
     if (windowRect.Size() != mDrawTarget->GetSize()) {
       windowRect.ExpandToEnclose(IntPoint(0, 0));
     }
     rt = new BasicCompositingRenderTarget(mDrawTarget, windowRect);
     if (!aClearRect.IsEmpty()) {
       IntRect clearRect = aClearRect.ToUnknownRect();
       mDrawTarget->ClearRect(Rect(clearRect - rt->GetOrigin()));
+
+      if (mFullWindowRenderTarget) {
+        mFullWindowRenderTarget->mDrawTarget->ClearRect(Rect(clearRect));
+      }
     }
   }
 
   return rt.forget();
 }
 
 already_AddRefed<DataTextureSource> BasicCompositor::CreateDataTextureSource(
     TextureFlags aFlags) {
@@ -802,38 +810,57 @@ void BasicCompositor::DrawGeometry(
     }
   }
 
   buffer->PopClip();
 }
 
 void BasicCompositor::ClearRect(const gfx::Rect& aRect) {
   mRenderTarget->mDrawTarget->ClearRect(aRect);
+
+  if (mFullWindowRenderTarget) {
+    mFullWindowRenderTarget->mDrawTarget->ClearRect(aRect);
+  }
 }
 
 void BasicCompositor::BeginFrame(
     const nsIntRegion& aInvalidRegion, const gfx::IntRect* aClipRectIn,
     const gfx::IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion,
     gfx::IntRect* aClipRectOut /* = nullptr */,
     gfx::IntRect* aRenderBoundsOut /* = nullptr */) {
   if (mIsPendingEndRemoteDrawing) {
     // Force to end previous remote drawing.
     TryToEndRemoteDrawing(/* aForceToEnd */ true);
     MOZ_ASSERT(!mIsPendingEndRemoteDrawing);
   }
 
   LayoutDeviceIntRect intRect(LayoutDeviceIntPoint(), mWidget->GetClientSize());
   IntRect rect = IntRect(0, 0, intRect.Width(), intRect.Height());
 
-  LayoutDeviceIntRegion invalidRegionSafe;
-  // Sometimes the invalid region is larger than we want to draw.
-  invalidRegionSafe.And(
-      LayoutDeviceIntRegion::FromUnknownRegion(aInvalidRegion), intRect);
+#ifdef MOZ_GECKO_PROFILER
+  const bool shouldInvalidateWindow =
+      (profiler_feature_active(ProfilerFeature::Screenshots) &&
+       (!mFullWindowRenderTarget ||
+        mFullWindowRenderTarget->mDrawTarget->GetSize() !=
+            rect.ToUnknownRect().Size()));
+#else
+  const bool shouldInvalidateWindow = false;
+#endif  // MOZ_GECKO_PROFILER
 
-  mInvalidRegion = invalidRegionSafe;
+  if (shouldInvalidateWindow) {
+    mInvalidRegion = intRect;
+  } else {
+    LayoutDeviceIntRegion invalidRegionSafe;
+    // Sometimes the invalid region is larger than we want to draw.
+    invalidRegionSafe.And(
+        LayoutDeviceIntRegion::FromUnknownRegion(aInvalidRegion), intRect);
+
+    mInvalidRegion = invalidRegionSafe;
+  }
+
   mInvalidRect = mInvalidRegion.GetBounds();
 
   if (aRenderBoundsOut) {
     *aRenderBoundsOut = IntRect();
   }
 
   BufferMode bufferMode = BufferMode::BUFFERED;
   if (mTarget) {
@@ -874,16 +901,37 @@ void BasicCompositor::BeginFrame(
   // Prevent CreateRenderTargetForWindow from clearing unwanted area.
   gfxUtils::ClipToRegion(mDrawTarget, mInvalidRegion.ToUnknownRegion());
 
   // Setup an intermediate render target to buffer all compositing. We will
   // copy this into mDrawTarget (the widget), and/or mTarget in EndFrame()
   RefPtr<CompositingRenderTarget> target =
       CreateRenderTargetForWindow(mInvalidRect, clearRect, bufferMode);
 
+#ifdef MOZ_GECKO_PROFILER
+  if (profiler_feature_active(ProfilerFeature::Screenshots)) {
+    IntSize windowSize = rect.ToUnknownRect().Size();
+
+    // On some platforms (notably Linux with X11) we do not always have a
+    // full-size draw target. While capturing profiles with screenshots, we need
+    // access to a full-size target so we can record the contents.
+    if (!mFullWindowRenderTarget ||
+        mFullWindowRenderTarget->mDrawTarget->GetSize() != windowSize) {
+      // We have either (1) just started recording and not yet allocated a
+      // buffer or (2) are already recording and have resized the window. In
+      // either case, we need a new render target.
+      RefPtr<gfx::DrawTarget> drawTarget = mDrawTarget->CreateSimilarDrawTarget(
+          windowSize, mDrawTarget->GetFormat());
+
+      mFullWindowRenderTarget =
+          new BasicCompositingRenderTarget(drawTarget, rect);
+    }
+  }
+#endif  // MOZ_GECKO_PROFILER
+
   mDrawTarget->PopClip();
 
   if (!target) {
     if (!mTarget) {
       mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
     }
     return;
   }
@@ -926,16 +974,25 @@ void BasicCompositor::EndFrame() {
         IntRectToRect(mInvalidRegion.GetBounds()).ToUnknownRect(),
         ColorPattern(Color(r, g, b, 0.2f)));
   }
 
   // Pop aInvalidregion
   mRenderTarget->mDrawTarget->PopClip();
 
   TryToEndRemoteDrawing();
+
+#ifdef MOZ_GECKO_PROFILER
+  // If we are no longer recording a profile, we can drop the render target if
+  // it exists.
+  if (mFullWindowRenderTarget &&
+      !profiler_feature_active(ProfilerFeature::Screenshots)) {
+    mFullWindowRenderTarget = nullptr;
+  }
+#endif  // MOZ_GECKO_PROFILER
 }
 
 void BasicCompositor::TryToEndRemoteDrawing(bool aForceToEnd) {
   if (mIsDestroyed || !mRenderTarget) {
     return;
   }
 
   // It it is not a good timing for EndRemoteDrawing, defter to call it.
@@ -946,31 +1003,47 @@ void BasicCompositor::TryToEndRemoteDraw
     RefPtr<BasicCompositor> self = this;
     RefPtr<Runnable> runnable =
         NS_NewRunnableFunction("layers::BasicCompositor::TryToEndRemoteDrawing",
                                [self]() { self->TryToEndRemoteDrawing(); });
     MessageLoop::current()->PostDelayedTask(runnable.forget(), retryMs);
     return;
   }
 
-  if (mRenderTarget->mDrawTarget != mDrawTarget) {
-    // Note: Most platforms require us to buffer drawing to the widget surface.
-    // That's why we don't draw to mDrawTarget directly.
-    RefPtr<SourceSurface> source = mWidget->EndBackBufferDrawing();
+  if (mRenderTarget->mDrawTarget != mDrawTarget || mFullWindowRenderTarget) {
+    RefPtr<SourceSurface> source;
 
-    nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint();
+    if (mRenderTarget->mDrawTarget != mDrawTarget) {
+      source = mWidget->EndBackBufferDrawing();
+
+      // Note: Most platforms require us to buffer drawing to the widget
+      // surface. That's why we don't draw to mDrawTarget directly.
+      nsIntPoint offset = mTarget ? mTargetBounds.TopLeft() : nsIntPoint();
 
-    // The source DrawTarget is clipped to the invalidation region, so we have
-    // to copy the individual rectangles in the region or else we'll draw blank
-    // pixels.
-    for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
-      const LayoutDeviceIntRect& r = iter.Get();
-      mDrawTarget->CopySurface(source,
-                               r.ToUnknownRect() - mRenderTarget->GetOrigin(),
-                               r.TopLeft().ToUnknownPoint() - offset);
+      // The source DrawTarget is clipped to the invalidation region, so we have
+      // to copy the individual rectangles in the region or else we'll draw
+      // blank pixels.
+      for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
+        const LayoutDeviceIntRect& r = iter.Get();
+        mDrawTarget->CopySurface(source,
+                                 r.ToUnknownRect() - mRenderTarget->GetOrigin(),
+                                 r.TopLeft().ToUnknownPoint() - offset);
+      }
+    } else {
+      source = mRenderTarget->mDrawTarget->Snapshot();
+    }
+
+    if (mFullWindowRenderTarget) {
+      for (auto iter = mInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
+        const LayoutDeviceIntRect& r = iter.Get();
+        mFullWindowRenderTarget->mDrawTarget->CopySurface(
+            source, r.ToUnknownRect(), r.TopLeft().ToUnknownPoint());
+      }
+
+      mFullWindowRenderTarget->mDrawTarget->Flush();
     }
   }
 
   if (aForceToEnd || !mTarget) {
     mWidget->EndRemoteDrawingInRegion(mDrawTarget, mInvalidRegion);
   }
 
   mDrawTarget = nullptr;
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -82,16 +82,21 @@ class BasicCompositor : public Composito
   virtual bool SupportsEffect(EffectTypes aEffect) override;
 
   bool SupportsLayerGeometry() const override;
 
   virtual void SetRenderTarget(CompositingRenderTarget* aSource) override {
     mRenderTarget = static_cast<BasicCompositingRenderTarget*>(aSource);
     mRenderTarget->BindRenderTarget();
   }
+
+  virtual CompositingRenderTarget* GetWindowRenderTarget() const override {
+    return mFullWindowRenderTarget;
+  }
+
   virtual CompositingRenderTarget* GetCurrentRenderTarget() const override {
     return mRenderTarget;
   }
 
   virtual void DrawQuad(const gfx::Rect& aRect, const gfx::IntRect& aClipRect,
                         const EffectChain& aEffectChain, gfx::Float aOpacity,
                         const gfx::Matrix4x4& aTransform,
                         const gfx::Rect& aVisibleRect) override;
@@ -156,16 +161,21 @@ class BasicCompositor : public Composito
   // The current render target for drawing
   RefPtr<BasicCompositingRenderTarget> mRenderTarget;
 
   LayoutDeviceIntRect mInvalidRect;
   LayoutDeviceIntRegion mInvalidRegion;
 
   uint32_t mMaxTextureSize;
   bool mIsPendingEndRemoteDrawing;
+
+  // mDrawTarget will not be the full window on all platforms. We therefore need
+  // to keep a full window render target around when we are capturing
+  // screenshots on those platforms.
+  RefPtr<BasicCompositingRenderTarget> mFullWindowRenderTarget;
 };
 
 BasicCompositor* AssertBasicCompositor(Compositor* aCompositor);
 
 }  // namespace layers
 }  // namespace mozilla
 
 #endif /* MOZILLA_GFX_BASICCOMPOSITOR_H */