Bug 1551735 - Record compositions in Web Render r=kats
☠☠ backed out by 1b10a1e394f4 ☠ ☠
authorBarret Rennie <barret@brennie.ca>
Wed, 29 May 2019 23:05:54 +0000
changeset 476258 e7b857609786878b7fc2c7637b6a224a45677f92
parent 476257 f2a2396a0d4a63b57a9ca072c67d9e4235cf0d20
child 476259 aa165d8c181d94af56e0b93d225bfae77acd4b8b
push id36090
push usernbeleuzu@mozilla.com
push dateFri, 31 May 2019 03:59:09 +0000
treeherdermozilla-central@63568b2a8178 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1551735
milestone69.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 1551735 - Record compositions in Web Render r=kats Now that we have a suitable composition recorder infrastructure, it is just a matter of plumbing the `WebRenderCompositionRecorder` from the `CompositorBridgeParent` to the `RenderThread` to start recording frames. Differential Revision: https://phabricator.services.mozilla.com/D32234
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/webrender_bindings/RenderThread.cpp
gfx/webrender_bindings/RenderThread.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -2604,28 +2604,38 @@ int32_t RecordContentFrameTime(
     return result;
   }
 
   return 0;
 }
 
 mozilla::ipc::IPCResult CompositorBridgeParent::RecvBeginRecording(
     const TimeStamp& aRecordingStart) {
-  mCompositionRecorder = new CompositionRecorder(aRecordingStart);
-
   if (mLayerManager) {
+    mCompositionRecorder = new CompositionRecorder(aRecordingStart);
     mLayerManager->SetCompositionRecorder(do_AddRef(mCompositionRecorder));
+  } else if (mWrBridge) {
+    RefPtr<WebRenderCompositionRecorder> recorder =
+        new WebRenderCompositionRecorder(aRecordingStart,
+                                         mWrBridge->PipelineId());
+    mCompositionRecorder = recorder;
+    mWrBridge->SetCompositionRecorder(std::move(recorder));
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecording() {
   if (mLayerManager) {
     mLayerManager->SetCompositionRecorder(nullptr);
   }
+
+  // If we are using WebRender, the |RenderThread| will have a handle to this
+  // |WebRenderCompositionRecorder|, which it will release once the frames have
+  // been written.
+
   mCompositionRecorder->WriteCollectedFrames();
   mCompositionRecorder = nullptr;
   return IPC_OK();
 }
 
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -796,16 +796,21 @@ void WebRenderBridgeParent::RemoveEpochD
     mCompositorAnimationsToDelete.pop();
   }
 }
 
 bool WebRenderBridgeParent::IsRootWebRenderBridgeParent() const {
   return !!mWidget;
 }
 
+void WebRenderBridgeParent::SetCompositionRecorder(
+    RefPtr<layers::WebRenderCompositionRecorder>&& aRecorder) {
+  Api(wr::RenderRoot::Default)->SetCompositionRecorder(std::move(aRecorder));
+}
+
 CompositorBridgeParent* WebRenderBridgeParent::GetRootCompositorBridgeParent()
     const {
   if (!mCompositorBridge) {
     return nullptr;
   }
 
   if (IsRootWebRenderBridgeParent()) {
     // This WebRenderBridgeParent is attached to the root
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -12,16 +12,17 @@
 
 #include "CompositableHost.h"  // for CompositableHost, ImageCompositeNotificationInfo
 #include "GLContextProvider.h"
 #include "mozilla/layers/CompositableTransactionParent.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/CompositorVsyncSchedulerOwner.h"
 #include "mozilla/layers/PWebRenderBridgeParent.h"
 #include "mozilla/layers/UiCompositorControllerParent.h"
+#include "mozilla/layers/WebRenderCompositionRecorder.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "nsTArrayForwardDeclare.h"
 
@@ -267,16 +268,19 @@ class WebRenderBridgeParent final
    * transaction is flushed.
    */
   void ForceIsFirstPaint() { mIsFirstPaint = true; }
 
   bool IsRootWebRenderBridgeParent() const;
   LayersId GetLayersId() const;
   WRRootId GetWRRootId() const;
 
+  void SetCompositionRecorder(
+      RefPtr<layers::WebRenderCompositionRecorder>&& aRecorder);
+
  private:
   class ScheduleSharedSurfaceRelease;
 
   explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId);
   virtual ~WebRenderBridgeParent() = default;
 
   wr::WebRenderAPI* Api(wr::RenderRoot aRenderRoot) {
     if (IsRootWebRenderBridgeParent()) {
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -193,16 +193,17 @@ void RenderThread::AddRenderer(wr::Windo
 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
   MOZ_ASSERT(IsInRenderThread());
 
   if (mHasShutdown) {
     return;
   }
 
   mRenderers.erase(aWindowId);
+  mCompositionRecorders.erase(aWindowId);
 
   if (mRenderers.size() == 0 && mHandlingDeviceReset) {
     mHandlingDeviceReset = false;
   }
 
   auto windows = mWindowInfos.Lock();
   auto it = windows->find(AsUint64(aWindowId));
   MOZ_ASSERT(it != windows->end());
@@ -224,16 +225,25 @@ RendererOGL* RenderThread::GetRenderer(w
   return it->second.get();
 }
 
 size_t RenderThread::RendererCount() {
   MOZ_ASSERT(IsInRenderThread());
   return mRenderers.size();
 }
 
+void RenderThread::SetCompositionRecorderForWindow(
+    wr::WindowId aWindowId,
+    RefPtr<layers::WebRenderCompositionRecorder>&& aCompositionRecorder) {
+  MOZ_ASSERT(IsInRenderThread());
+  MOZ_ASSERT(GetRenderer(aWindowId));
+
+  mCompositionRecorders[aWindowId] = std::move(aCompositionRecorder);
+}
+
 void RenderThread::HandleFrame(wr::WindowId aWindowId, bool aRender) {
   if (mHasShutdown) {
     return;
   }
 
   if (!IsInRenderThread()) {
     Loop()->PostTask(NewRunnableMethod<wr::WindowId, bool>(
         "wr::RenderThread::NewFrameReady", this, &RenderThread::HandleFrame,
@@ -377,24 +387,39 @@ void RenderThread::UpdateAndRender(
         aReadbackSize, aReadbackFormat, aReadbackBuffer, aHadSlowFrame, &stats);
   } else {
     renderer->Update();
   }
   // Check graphics reset status even when rendering is skipped.
   renderer->CheckGraphicsResetStatus();
 
   TimeStamp end = TimeStamp::Now();
-  auto info = renderer->FlushPipelineInfo();
+  RefPtr<WebRenderPipelineInfo> info = renderer->FlushPipelineInfo();
 
   layers::CompositorThreadHolder::Loop()->PostTask(
       NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
                           renderer->GetCompositorBridge(), info, aStartId,
                           aStartTime, start, end, aRender, stats));
 
   if (rendered) {
+    auto recorderIt = mCompositionRecorders.find(aWindowId);
+    if (recorderIt != mCompositionRecorders.end()) {
+      bool shouldRelease = recorderIt->second->MaybeRecordFrame(
+          renderer->GetRenderer(), info.get());
+
+      if (shouldRelease) {
+        mCompositionRecorders.erase(recorderIt);
+
+        wr_renderer_release_composition_recorder_structures(
+            renderer->GetRenderer());
+      }
+    }
+  }
+
+  if (rendered) {
     // Wait for GPU after posting NotifyDidRender, since the wait is not
     // necessary for the NotifyDidRender.
     // The wait is necessary for Textures recycling of AsyncImagePipelineManager
     // and for avoiding GPU queue is filled with too much tasks.
     // WaitForGPU's implementation is different for each platform.
     renderer->WaitForGPU();
   }
 
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -15,16 +15,17 @@
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/DataMutex.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/layers/SynchronousTask.h"
+#include "mozilla/layers/WebRenderCompositionRecorder.h"
 #include "mozilla/VsyncDispatcher.h"
 
 #include <list>
 #include <queue>
 #include <unordered_map>
 
 namespace mozilla {
 namespace gl {
@@ -251,16 +252,20 @@ class RenderThread final {
   void HandleDeviceReset(const char* aWhere, bool aNotify);
   /// Can only be called from the render thread.
   bool IsHandlingDeviceReset();
   /// Can be called from any thread.
   void SimulateDeviceReset();
 
   size_t RendererCount();
 
+  void SetCompositionRecorderForWindow(
+      wr::WindowId aWindowId,
+      RefPtr<layers::WebRenderCompositionRecorder>&& aCompositionRecorder);
+
  private:
   explicit RenderThread(base::Thread* aThread);
 
   void DeferredRenderTextureHostDestroy();
   void ShutDownTask(layers::SynchronousTask* aTask);
   void InitDeviceTask();
 
   void DoAccumulateMemoryReport(MemoryReport,
@@ -275,16 +280,18 @@ class RenderThread final {
   UniquePtr<WebRenderProgramCache> mProgramCache;
   UniquePtr<WebRenderShaders> mShaders;
 
   // An optional shared GLContext to be used for all
   // windows.
   RefPtr<gl::GLContext> mSharedGL;
 
   std::map<wr::WindowId, UniquePtr<RendererOGL>> mRenderers;
+  std::map<wr::WindowId, RefPtr<layers::WebRenderCompositionRecorder>>
+      mCompositionRecorders;
 
   struct WindowInfo {
     bool mIsDestroyed = false;
     bool mRender = false;
     int64_t mPendingCount = 0;
     int64_t mRenderingCount = 0;
     uint8_t mDocFramesSeen = 0;
     // One entry in this queue for each pending frame, so the length
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -572,16 +572,44 @@ void WebRenderAPI::WaitFlushed() {
 }
 
 void WebRenderAPI::Capture() {
   uint8_t bits = 3;                 // TODO: get from JavaScript
   const char* path = "wr-capture";  // TODO: get from JavaScript
   wr_api_capture(mDocHandle, path, bits);
 }
 
+void WebRenderAPI::SetCompositionRecorder(
+    RefPtr<layers::WebRenderCompositionRecorder>&& aRecorder) {
+  class SetCompositionRecorderEvent final : public RendererEvent {
+   public:
+    explicit SetCompositionRecorderEvent(
+        RefPtr<layers::WebRenderCompositionRecorder>&& aRecorder)
+        : mRecorder(std::move(aRecorder)) {
+      MOZ_COUNT_CTOR(SetCompositionRecorderEvent);
+    }
+
+    ~SetCompositionRecorderEvent() {
+      MOZ_COUNT_DTOR(SetCompositionRecorderEvent);
+    }
+
+    void Run(RenderThread& aRenderThread, WindowId aWindowId) override {
+      MOZ_ASSERT(mRecorder);
+
+      aRenderThread.SetCompositionRecorderForWindow(aWindowId,
+                                                    std::move(mRecorder));
+    }
+
+   private:
+    RefPtr<layers::WebRenderCompositionRecorder> mRecorder;
+  };
+
+  auto event = MakeUnique<SetCompositionRecorderEvent>(std::move(aRecorder));
+  RunOnRenderThread(std::move(event));
+}
 void TransactionBuilder::Clear() { wr_resource_updates_clear(mTxn); }
 
 void TransactionBuilder::Notify(wr::Checkpoint aWhen,
                                 UniquePtr<NotificationHandler> aEvent) {
   wr_transaction_notify(mTxn, aWhen,
                         reinterpret_cast<uintptr_t>(aEvent.release()));
 }
 
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -11,16 +11,17 @@
 #include <unordered_map>
 #include <unordered_set>
 
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/gfx/CompositorHitTestInfo.h"
 #include "mozilla/layers/IpcResourceUpdateQueue.h"
 #include "mozilla/layers/ScrollableLayerGuid.h"
 #include "mozilla/layers/SyncObject.h"
+#include "mozilla/layers/WebRenderCompositionRecorder.h"
 #include "mozilla/Range.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "GLTypes.h"
 #include "Units.h"
 
 class nsDisplayItem;
 class nsDisplayTransform;
@@ -253,16 +254,19 @@ class WebRenderAPI final {
   uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
   bool GetUseANGLE() const { return mUseANGLE; }
   bool GetUseDComp() const { return mUseDComp; }
   bool GetUseTripleBuffering() const { return mUseTripleBuffering; }
   layers::SyncHandle GetSyncHandle() const { return mSyncHandle; }
 
   void Capture();
 
+  void SetCompositionRecorder(
+      RefPtr<layers::WebRenderCompositionRecorder>&& aRecorder);
+
  protected:
   WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId,
                uint32_t aMaxTextureSize, bool aUseANGLE, bool aUseDComp,
                bool aUseTripleBuffering, layers::SyncHandle aSyncHandle,
                wr::RenderRoot aRenderRoot);
 
   ~WebRenderAPI();
   // Should be used only for shutdown handling