Bug 1654617 - Remote Backbuffer: Use multiple dirty rectangles during present r=tkikuchi
authorChris Martin <cmartin@mozilla.com>
Mon, 14 Sep 2020 19:46:21 +0000
changeset 548589 a55474bb26c71af50afaf370e3691f036ac9af07
parent 548588 77a41f4b6fa0e392f48de79a805ca5bb3bea10b4
child 548590 59fbb6793bb5f99fbbe09bf40268a07047b12657
push id37784
push usermalexandru@mozilla.com
push dateTue, 15 Sep 2020 03:29:59 +0000
treeherdermozilla-central@8c8f6d93ade3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstkikuchi
bugs1654617, 1647877
milestone82.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 1654617 - Remote Backbuffer: Use multiple dirty rectangles during present r=tkikuchi In Bug 1647877, I changed remote backbuffer to use a dirty rectangle instead of always repainting the entire window. This changeset allows multiple dirty rectangles to be used (currently maximum of 8) for higher efficiency. Differential Revision: https://phabricator.services.mozilla.com/D89833
widget/windows/CompositorWidgetParent.cpp
widget/windows/RemoteBackbuffer.cpp
widget/windows/RemoteBackbuffer.h
--- a/widget/windows/CompositorWidgetParent.cpp
+++ b/widget/windows/CompositorWidgetParent.cpp
@@ -1,13 +1,12 @@
 /* -*- 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 "CompositorWidgetParent.h"
 
 #include "mozilla/Unused.h"
 #include "mozilla/StaticPrefs_layers.h"
 #include "mozilla/gfx/DeviceManagerDx.h"
 #include "mozilla/gfx/Point.h"
 #include "mozilla/layers/Compositor.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
@@ -84,17 +83,17 @@ CompositorWidgetParent::StartRemoteDrawi
   return mRemoteBackbufferClient->BorrowDrawTarget();
 }
 
 void CompositorWidgetParent::EndRemoteDrawingInRegion(
     gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
   MOZ_ASSERT(!mLockedBackBufferData);
 
   Unused << mRemoteBackbufferClient->PresentDrawTarget(
-      aInvalidRegion.GetBounds().ToUnknownRect());
+      aInvalidRegion.ToUnknownRegion());
 }
 
 bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() { return false; }
 
 already_AddRefed<gfx::DrawTarget>
 CompositorWidgetParent::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
                                                 const gfx::IntRect& aRect,
                                                 bool* aOutIsCleared) {
--- a/widget/windows/RemoteBackbuffer.cpp
+++ b/widget/windows/RemoteBackbuffer.cpp
@@ -1,21 +1,25 @@
 /* -*- 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 "RemoteBackbuffer.h"
+#include "mozilla/Span.h"
 #include <algorithm>
 #include <type_traits>
 
 namespace mozilla {
 namespace widget {
 namespace remote_backbuffer {
 
+// This number can be adjusted as a time-memory tradeoff
+constexpr uint8_t kMaxDirtyRects = 8;
+
 struct IpcSafeRect {
   explicit IpcSafeRect(const gfx::IntRect& aRect)
       : x(aRect.x), y(aRect.y), width(aRect.width), height(aRect.height) {}
   int32_t x;
   int32_t y;
   int32_t width;
   int32_t height;
 };
@@ -39,17 +43,18 @@ enum class SharedDataType {
 struct BorrowResponseData {
   ResponseResult result;
   int32_t width;
   int32_t height;
   HANDLE fileMapping;
 };
 
 struct PresentRequestData {
-  IpcSafeRect dirtyRect;
+  uint8_t lenDirtyRects;
+  IpcSafeRect dirtyRects[kMaxDirtyRects];
 };
 
 struct PresentResponseData {
   ResponseResult result;
 };
 
 struct SharedData {
   SharedDataType dataType;
@@ -223,17 +228,17 @@ class PresentableSharedImage {
     if (!mSavedObject) {
       return false;
     }
 
     return true;
   }
 
   bool PresentToWindow(HWND aWindowHandle, nsTransparencyMode aTransparencyMode,
-                       const IpcSafeRect& aDirtyRect) {
+                       Span<const IpcSafeRect> aDirtyRects) {
     if (aTransparencyMode == eTransparencyTransparent) {
       // If our window is a child window or a child-of-a-child, the window
       // that needs to be updated is the top level ancestor of the tree
       HWND topLevelWindow = WinUtils::GetTopLevelHWND(aWindowHandle, true);
       MOZ_ASSERT(::GetWindowLongPtr(topLevelWindow, GWL_EXSTYLE) &
                  WS_EX_LAYERED);
 
       BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
@@ -241,28 +246,36 @@ class PresentableSharedImage {
       POINT srcPos = {0, 0};
       return !!::UpdateLayeredWindow(
           topLevelWindow, nullptr /*paletteDC*/, nullptr /*newPos*/, &winSize,
           mDeviceContext, &srcPos, 0 /*colorKey*/, &bf, ULW_ALPHA);
     }
 
     IntRect sharedImageRect{0, 0, mSharedImage.GetWidth(),
                             mSharedImage.GetHeight()};
-    IntRect dirtyRect{aDirtyRect.x, aDirtyRect.y, aDirtyRect.width,
-                      aDirtyRect.height};
-    IntRect bltRect = dirtyRect.Intersect(sharedImageRect);
+
+    bool result = true;
 
     HDC windowDC = ::GetDC(aWindowHandle);
     if (!windowDC) {
       return false;
     }
 
-    bool result = ::BitBlt(windowDC, bltRect.x /*dstX*/, bltRect.y /*dstY*/,
-                           bltRect.width, bltRect.height, mDeviceContext,
-                           bltRect.x /*srcX*/, bltRect.y /*srcY*/, SRCCOPY);
+    for (auto& ipcDirtyRect : aDirtyRects) {
+      IntRect dirtyRect{ipcDirtyRect.x, ipcDirtyRect.y, ipcDirtyRect.width,
+                        ipcDirtyRect.height};
+      IntRect bltRect = dirtyRect.Intersect(sharedImageRect);
+
+      if (!::BitBlt(windowDC, bltRect.x /*dstX*/, bltRect.y /*dstY*/,
+                    bltRect.width, bltRect.height, mDeviceContext,
+                    bltRect.x /*srcX*/, bltRect.y /*srcY*/, SRCCOPY)) {
+        result = false;
+        break;
+      }
+    }
 
     MOZ_ALWAYS_TRUE(::ReleaseDC(aWindowHandle, windowDC));
 
     return result;
   }
 
   HANDLE CreateRemoteFileMapping(DWORD aTargetProcessId) {
     return mSharedImage.CreateRemoteFileMapping(aTargetProcessId);
@@ -493,24 +506,27 @@ void Provider::HandleBorrowRequest(Borro
 
   mBackbuffer = std::move(newBackbuffer);
 }
 
 void Provider::HandlePresentRequest(const PresentRequestData& aRequestData,
                                     PresentResponseData* aResponseData) {
   MOZ_ASSERT(aResponseData);
 
+  Span rectSpan(aRequestData.dirtyRects, kMaxDirtyRects);
+
   aResponseData->result = ResponseResult::Error;
 
   if (!mBackbuffer) {
     return;
   }
 
-  if (!mBackbuffer->PresentToWindow(mWindowHandle, mTransparencyMode,
-                                    aRequestData.dirtyRect)) {
+  if (!mBackbuffer->PresentToWindow(
+          mWindowHandle, mTransparencyMode,
+          rectSpan.First(aRequestData.lenDirtyRects))) {
     return;
   }
 
   aResponseData->result = ResponseResult::PresentSuccess;
 }
 
 Client::Client()
     : mFileMapping(nullptr),
@@ -595,19 +611,32 @@ already_AddRefed<gfx::DrawTarget> Client
     mBackbuffer = std::move(newBackbuffer);
   }
 
   MOZ_ASSERT(mBackbuffer);
 
   return mBackbuffer->CreateDrawTarget();
 }
 
-bool Client::PresentDrawTarget(const gfx::IntRect& aDirtyRect) {
+bool Client::PresentDrawTarget(gfx::IntRegion aDirtyRegion) {
   mSharedDataPtr->dataType = SharedDataType::PresentRequest;
-  mSharedDataPtr->data.presentRequest.dirtyRect = IpcSafeRect(aDirtyRect);
+
+  // Simplify the region until it has <= kMaxDirtyRects
+  aDirtyRegion.SimplifyOutward(kMaxDirtyRects);
+
+  Span rectSpan(mSharedDataPtr->data.presentRequest.dirtyRects, kMaxDirtyRects);
+
+  uint8_t rectIndex = 0;
+  for (auto iter = aDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
+    rectSpan[rectIndex] = IpcSafeRect(iter.Get());
+    ++rectIndex;
+  }
+
+  mSharedDataPtr->data.presentRequest.lenDirtyRects = rectIndex;
+
   MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
   MOZ_ALWAYS_TRUE(::WaitForSingleObject(mResponseReadyEvent, INFINITE) ==
                   WAIT_OBJECT_0);
 
   if (mSharedDataPtr->dataType != SharedDataType::PresentResponse) {
     return false;
   }
 
--- a/widget/windows/RemoteBackbuffer.h
+++ b/widget/windows/RemoteBackbuffer.h
@@ -1,19 +1,21 @@
 /* -*- 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/. */
 
 #ifndef widget_windows_RemoteBackbuffer_h
 #define widget_windows_RemoteBackbuffer_h
 
+#include "nsIWidget.h"
+#include "mozilla/widget/PCompositorWidgetParent.h"
+#include "mozilla/Maybe.h"
 #include <thread>
 #include <windows.h>
-#include "mozilla/Maybe.h"
 
 namespace mozilla {
 namespace widget {
 namespace remote_backbuffer {
 
 struct IpcRect;
 struct SharedData;
 struct BorrowResponseData;
@@ -63,17 +65,17 @@ class Provider {
 class Client {
  public:
   Client();
   ~Client();
 
   bool Initialize(const RemoteBackbufferHandles& aRemoteHandles);
 
   already_AddRefed<gfx::DrawTarget> BorrowDrawTarget();
-  bool PresentDrawTarget(const gfx::IntRect& aDirtyRect);
+  bool PresentDrawTarget(gfx::IntRegion aDirtyRegion);
 
   Client(const Client&) = delete;
   Client(Client&&) = delete;
   Client& operator=(const Client&) = delete;
   Client& operator=(Client&&) = delete;
 
  private:
   HANDLE mFileMapping;