Bug 1547737 - Make RecvRequestScreenPixels work with WR. r=jnicol
authorKris Taeleman <ktaeleman@mozilla.com>
Fri, 18 Oct 2019 13:40:40 +0000
changeset 498344 b31c9e27fc97f8343d3764c123652dcd957f3d64
parent 498343 27c5749f319a58c1a12a1ab71ea7be1f2bf37488
child 498345 8b6445c96a49e190644b674821638d7385ee5885
push id36717
push usernbeleuzu@mozilla.com
push dateMon, 21 Oct 2019 21:51:55 +0000
treeherdermozilla-central@563f437f24b9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjnicol
bugs1547737
milestone71.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 1547737 - Make RecvRequestScreenPixels work with WR. r=jnicol Differential Revision: https://phabricator.services.mozilla.com/D49492
gfx/layers/ipc/UiCompositorControllerParent.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
--- a/gfx/layers/ipc/UiCompositorControllerParent.cpp
+++ b/gfx/layers/ipc/UiCompositorControllerParent.cpp
@@ -9,16 +9,17 @@
 #  include "apz/src/APZCTreeManager.h"
 #  include "mozilla/layers/AsyncCompositionManager.h"
 #endif
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/UiCompositorControllerMessageTypes.h"
+#include "mozilla/layers/WebRenderBridgeParent.h"
 #include "mozilla/gfx/Types.h"
 #include "mozilla/Move.h"
 #include "mozilla/Unused.h"
 
 #include "FrameMetrics.h"
 #include "SynchronousTask.h"
 
 namespace mozilla {
@@ -170,16 +171,19 @@ UiCompositorControllerParent::RecvReques
 #if defined(MOZ_WIDGET_ANDROID)
   LayerTreeState* state =
       CompositorBridgeParent::GetIndirectShadowTree(mRootLayerTreeId);
 
   if (state && state->mLayerManager && state->mParent) {
     state->mLayerManager->RequestScreenPixels(this);
     state->mParent->Invalidate();
     state->mParent->ScheduleComposition();
+  } else if (state && state->mWrBridge) {
+    state->mWrBridge->RequestScreenPixels(this);
+    state->mWrBridge->ScheduleForcedGenerateFrame();
   }
 #endif  // defined(MOZ_WIDGET_ANDROID)
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 UiCompositorControllerParent::RecvEnableLayerUpdateNotifications(
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -328,16 +328,19 @@ WebRenderBridgeParent::WebRenderBridgePa
       mCompositorScheduler(aScheduler),
       mAnimStorage(aAnimStorage),
       mVsyncRate(aVsyncRate),
       mChildLayersObserverEpoch{0},
       mParentLayersObserverEpoch{0},
       mWrEpoch{0},
       mIdNamespace(aApis[0]->GetNamespace()),
       mRenderRootRectMutex("WebRenderBridgeParent::mRenderRootRectMutex"),
+#if defined(MOZ_WIDGET_ANDROID)
+      mScreenPixelsTarget(nullptr),
+#endif
       mPaused(false),
       mDestroyed(false),
       mReceivedDisplayList(false),
       mIsFirstPaint(true),
       mSkippedComposite(false) {
   MOZ_ASSERT(mAsyncImageManager);
   MOZ_ASSERT(mAnimStorage);
   mAsyncImageManager->AddPipeline(mPipelineId, this);
@@ -1712,16 +1715,59 @@ void WebRenderBridgeParent::FlushFramePr
   // This sends a message to the render backend thread to send a message
   // to the renderer thread, and waits for that message to be processed. So
   // this effectively blocks on the render backend and renderer threads,
   // following the same codepath that WebRender takes to render and composite
   // a frame.
   mApis[wr::RenderRoot::Default]->WaitFlushed();
 }
 
+#if defined(MOZ_WIDGET_ANDROID)
+void WebRenderBridgeParent::RequestScreenPixels(
+    UiCompositorControllerParent* aController) {
+  mScreenPixelsTarget = aController;
+}
+
+void WebRenderBridgeParent::MaybeCaptureScreenPixels() {
+  if (!mScreenPixelsTarget) {
+    return;
+  }
+
+  if (mDestroyed) {
+    return;
+  }
+  MOZ_ASSERT(!mPaused);
+
+  // This function should only get called in the root WRBP.
+  MOZ_ASSERT(IsRootWebRenderBridgeParent());
+
+  SurfaceFormat format = SurfaceFormat::R8G8B8A8;  // On android we use RGBA8
+  auto client_size = mWidget->GetClientSize();
+  size_t buffer_size =
+      client_size.width * client_size.height * BytesPerPixel(format);
+
+  ipc::Shmem mem;
+  if (!mScreenPixelsTarget->AllocPixelBuffer(buffer_size, &mem)) {
+    // Failed to alloc shmem, Just bail out.
+    return;
+  }
+
+  IntSize size(client_size.width, client_size.height);
+
+  mApis[wr::RenderRoot::Default]->Readback(
+      TimeStamp::Now(), size, format,
+      Range<uint8_t>(mem.get<uint8_t>(), buffer_size));
+
+  Unused << mScreenPixelsTarget->SendScreenPixels(
+      std::move(mem), ScreenIntSize(client_size.width, client_size.height));
+
+  mScreenPixelsTarget = nullptr;
+}
+#endif
+
 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
     PTextureParent* aTexture) {
   if (mDestroyed) {
     return IPC_OK();
   }
   MOZ_ASSERT(!mPaused);
 
   // This function should only get called in the root WRBP. If this function
@@ -2352,16 +2398,20 @@ void WebRenderBridgeParent::MaybeGenerat
     auto renderRoot = api->GetRenderRoot();
     if (generateFrame[renderRoot]) {
       fastTxns[renderRoot]->GenerateFrame();
       generateFrameTxns[renderRoot] = fastTxns[renderRoot].ptr();
     }
   }
   wr::WebRenderAPI::SendTransactions(mApis, generateFrameTxns);
 
+#if defined(MOZ_WIDGET_ANDROID)
+  MaybeCaptureScreenPixels();
+#endif
+
   mMostRecentComposite = TimeStamp::Now();
 }
 
 void WebRenderBridgeParent::HoldPendingTransactionId(
     const wr::Epoch& aWrEpoch, TransactionId aTransactionId,
     bool aContainsSVGGroup, const VsyncId& aVsyncId,
     const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
     const TimeStamp& aTxnStartTime, const nsCString& aTxnURL,
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -293,16 +293,24 @@ class WebRenderBridgeParent final
 
   /**
    * Write the frames collected by the |WebRenderCompositionRecorder| to disk.
    *
    * If there is not currently a recorder, this is a no-op.
    */
   void WriteCollectedFrames();
 
+#if defined(MOZ_WIDGET_ANDROID)
+  /**
+   * Request a screengrab for android
+   */
+  void RequestScreenPixels(UiCompositorControllerParent* aController);
+  void MaybeCaptureScreenPixels();
+#endif
+
  private:
   class ScheduleSharedSurfaceRelease;
 
   explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId);
   virtual ~WebRenderBridgeParent();
 
   wr::WebRenderAPI* Api(wr::RenderRoot aRenderRoot) {
     if (IsRootWebRenderBridgeParent()) {
@@ -543,16 +551,19 @@ class WebRenderBridgeParent final
   TimeStamp mMostRecentComposite;
 
   // Kind of clunky, but I can't sort out a more elegant way of getting this to
   // work.
   Mutex mRenderRootRectMutex;
   wr::NonDefaultRenderRootArray<ScreenRect> mRenderRootRects;
 
   Maybe<wr::RenderRoot> mRenderRoot;
+#if defined(MOZ_WIDGET_ANDROID)
+  UiCompositorControllerParent* mScreenPixelsTarget;
+#endif
   bool mPaused;
   bool mDestroyed;
   bool mReceivedDisplayList;
   bool mIsFirstPaint;
   bool mSkippedComposite;
 };
 
 }  // namespace layers