Bug 1604412 - Enable remote backbuffer GDI compositing r=jmathies,jld
☠☠ backed out by 49f05e87c72e ☠ ☠
authorChris Martin <cmartin@mozilla.com>
Thu, 13 Feb 2020 03:59:13 +0000
changeset 513675 71e63781b38cbde024a9057553cae96c98e5ecb2
parent 513674 f2088b5ae50d3e547b370309c9608188ed853e03
child 513676 57223bd1c4c68418bb9c276cb8d42e65b62182ea
push id37120
push usercbrindusan@mozilla.com
push dateThu, 13 Feb 2020 18:21:33 +0000
treeherdermozilla-central@b47e32ff95b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmathies, jld
bugs1604412
milestone75.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 1604412 - Enable remote backbuffer GDI compositing r=jmathies,jld This change adds new "remote backbuffer" logic when compositing without HW acceleration on Windows (IE compositing through Cairo using the Win32 GDI) A new piece of shared memory is created between the GPU process and the UI process, and the GPU process sends requests to the UI process to first "borrow" a properly-sized buffer to draw into, and then sends a "present" request to tell the UI process to actually blit the buffer to the Win32 window. This is needed for the GPU sandbox to work, since Windows rightly doesn't allow the untrusted GPU process to directly draw the contents of a window owned by the trusted UI process. Differential Revision: https://phabricator.services.mozilla.com/D61370
ipc/ipdl/sync-messages.ini
widget/windows/CompositorWidgetChild.cpp
widget/windows/CompositorWidgetChild.h
widget/windows/CompositorWidgetParent.cpp
widget/windows/CompositorWidgetParent.h
widget/windows/PCompositorWidget.ipdl
widget/windows/RemoteBackbuffer.cpp
widget/windows/RemoteBackbuffer.h
widget/windows/moz.build
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -1106,28 +1106,31 @@ description = bug 1364626
 [PCompositorBridge::StartFrameTimeRecording]
 description = legacy sync IPC - please add detailed description
 [PCompositorBridge::StopFrameTimeRecording]
 description = legacy sync IPC - please add detailed description
 [PCompositorBridge::SyncWithCompositor]
 description = legacy sync IPC - please add detailed description
 [PCompositorBridge::CheckContentOnlyTDR]
 description = legacy sync IPC - please add detailed description
+[PCompositorWidget::Initialize]
+description = Fallable initialization for the widget. Must be called right after construction before any other messages are sent
+platform = win
 [PCompositorWidget::EnterPresentLock]
-description = legacy sync IPC - please add detailed description
+description = Obtain exclusive access to the widget surface. Used to ensure events don't change the surface while it's being used as a render target
 platform = win
 [PCompositorWidget::LeavePresentLock]
-description = legacy sync IPC - please add detailed description
+description = Release the exclusive lock that EnterPresentLock obtained
 platform = win
 [PCompositorBridge::SupportsAsyncDXGISurface]
 description = legacy sync IPC - please add detailed description
 [PCompositorBridge::PreferredDXGIAdapter]
 description = legacy sync IPC - please add detailed description
 [PCompositorWidget::ClearTransparentWindow]
-description = legacy sync IPC - please add detailed description
+description = Synchronously clear the widget surface. Does not rely on (Enter|Leave)PresentLock. When call returns, window surface has been fully updated with cleared pixel values.
 platform = win
 [PImageBridge::WillClose]
 description = legacy sync IPC - please add detailed description
 [PImageBridge::NewCompositable]
 description = legacy sync IPC - please add detailed description
 [PImageBridge::MakeAsyncPluginSurfaces]
 description = When plugin asks content to synchronously make surfaces, content needs to synchronously get those surfaces from the compositor process since sandboxing forbids content to make them itself.
 [PImageBridge::ReadbackAsyncPluginSurface]
--- a/widget/windows/CompositorWidgetChild.cpp
+++ b/widget/windows/CompositorWidgetChild.cpp
@@ -5,39 +5,55 @@
 
 #include "CompositorWidgetChild.h"
 #include "mozilla/Unused.h"
 #include "mozilla/widget/CompositorWidgetVsyncObserver.h"
 #include "mozilla/widget/PlatformWidgetTypes.h"
 #include "nsBaseWidget.h"
 #include "VsyncDispatcher.h"
 #include "gfxPlatform.h"
+#include "RemoteBackbuffer.h"
 
 namespace mozilla {
 namespace widget {
 
 CompositorWidgetChild::CompositorWidgetChild(
     RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
     RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver,
     const CompositorWidgetInitData& aInitData)
     : mVsyncDispatcher(aVsyncDispatcher),
       mVsyncObserver(aVsyncObserver),
       mCompositorWnd(nullptr),
       mWnd(reinterpret_cast<HWND>(
           aInitData.get_WinCompositorWidgetInitData().hWnd())),
       mTransparencyMode(
-          aInitData.get_WinCompositorWidgetInitData().transparencyMode()) {
+          aInitData.get_WinCompositorWidgetInitData().transparencyMode()),
+      mRemoteBackbufferProvider() {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(!gfxPlatform::IsHeadless());
   MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
 }
 
 CompositorWidgetChild::~CompositorWidgetChild() {}
 
-bool CompositorWidgetChild::Initialize() { return true; }
+bool CompositorWidgetChild::Initialize() {
+  mRemoteBackbufferProvider = std::make_unique<remote_backbuffer::Provider>();
+  if (!mRemoteBackbufferProvider->Initialize(mWnd, OtherPid())) {
+    return false;
+  }
+
+  auto maybeRemoteHandles = mRemoteBackbufferProvider->CreateRemoteHandles();
+  if (!maybeRemoteHandles) {
+    return false;
+  }
+
+  Unused << SendInitialize(*maybeRemoteHandles);
+
+  return true;
+}
 
 void CompositorWidgetChild::EnterPresentLock() {
   Unused << SendEnterPresentLock();
 }
 
 void CompositorWidgetChild::LeavePresentLock() {
   Unused << SendLeavePresentLock();
 }
--- a/widget/windows/CompositorWidgetChild.h
+++ b/widget/windows/CompositorWidgetChild.h
@@ -10,16 +10,20 @@
 #include "mozilla/widget/PCompositorWidgetChild.h"
 #include "mozilla/widget/CompositorWidgetVsyncObserver.h"
 
 namespace mozilla {
 class CompositorVsyncDispatcher;
 
 namespace widget {
 
+namespace remote_backbuffer {
+class Provider;
+}
+
 class CompositorWidgetChild final : public PCompositorWidgetChild,
                                     public PlatformCompositorWidgetDelegate {
  public:
   CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
                         RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver,
                         const CompositorWidgetInitData& aInitData);
   ~CompositorWidgetChild() override;
 
@@ -41,14 +45,16 @@ class CompositorWidgetChild final : publ
 
  private:
   RefPtr<CompositorVsyncDispatcher> mVsyncDispatcher;
   RefPtr<CompositorWidgetVsyncObserver> mVsyncObserver;
   HWND mCompositorWnd;
 
   HWND mWnd;
   nsTransparencyMode mTransparencyMode;
+
+  std::unique_ptr<remote_backbuffer::Provider> mRemoteBackbufferProvider;
 };
 
 }  // namespace widget
 }  // namespace mozilla
 
 #endif  // widget_windows_CompositorWidgetChild_h
--- a/widget/windows/CompositorWidgetParent.cpp
+++ b/widget/windows/CompositorWidgetParent.cpp
@@ -13,50 +13,53 @@
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/webrender/RenderThread.h"
 #include "mozilla/widget/PlatformWidgetTypes.h"
 #include "nsWindow.h"
 #include "VsyncDispatcher.h"
 #include "WinCompositorWindowThread.h"
 #include "VRShMem.h"
+#include "RemoteBackbuffer.h"
 
 #include <ddraw.h>
 
 namespace mozilla {
 namespace widget {
 
 using namespace mozilla::gfx;
 using namespace mozilla;
 
 CompositorWidgetParent::CompositorWidgetParent(
     const CompositorWidgetInitData& aInitData,
     const layers::CompositorOptions& aOptions)
     : WinCompositorWidget(aInitData.get_WinCompositorWidgetInitData(),
                           aOptions),
       mWnd(reinterpret_cast<HWND>(
           aInitData.get_WinCompositorWidgetInitData().hWnd())),
-      mTransparentSurfaceLock("mTransparentSurfaceLock"),
       mTransparencyMode(
           aInitData.get_WinCompositorWidgetInitData().transparencyMode()),
-      mMemoryDC(nullptr),
-      mCompositeDC(nullptr),
-      mLockedBackBufferData(nullptr) {
+      mLockedBackBufferData(nullptr),
+      mRemoteBackbufferClient() {
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
   MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
-
-  // mNotDeferEndRemoteDrawing is set on the main thread during init,
-  // but is only accessed after on the compositor thread.
-  mNotDeferEndRemoteDrawing =
-      StaticPrefs::layers_offmainthreadcomposition_frame_rate() == 0 ||
-      gfxPlatform::IsInLayoutAsapMode() || gfxPlatform::ForceSoftwareVsync();
 }
 
 CompositorWidgetParent::~CompositorWidgetParent() {}
 
+bool CompositorWidgetParent::Initialize(
+    const RemoteBackbufferHandles& aRemoteHandles) {
+  mRemoteBackbufferClient = std::make_unique<remote_backbuffer::Client>();
+  if (!mRemoteBackbufferClient->Initialize(aRemoteHandles)) {
+    return false;
+  }
+
+  return true;
+}
+
 bool CompositorWidgetParent::PreRender(WidgetRenderingContext* aContext) {
   // This can block waiting for WM_SETTEXT to finish
   // Using PreRender is unnecessarily pessimistic because
   // we technically only need to block during the present call
   // not all of compositor rendering
   mPresentLock.Enter();
   return true;
 }
@@ -69,98 +72,28 @@ LayoutDeviceIntSize CompositorWidgetPare
   RECT r;
   if (!::GetClientRect(mWnd, &r)) {
     return LayoutDeviceIntSize();
   }
   return LayoutDeviceIntSize(r.right - r.left, r.bottom - r.top);
 }
 
 already_AddRefed<gfx::DrawTarget> CompositorWidgetParent::StartRemoteDrawing() {
-  MutexAutoLock lock(mTransparentSurfaceLock);
-
-  MOZ_ASSERT(!mCompositeDC);
-
-  RefPtr<gfxASurface> surf;
-  if (mTransparencyMode == eTransparencyTransparent) {
-    surf = EnsureTransparentSurface();
-  }
+  MOZ_ASSERT(mRemoteBackbufferClient);
 
-  // Must call this after EnsureTransparentSurface(), since it could update
-  // the DC.
-  HDC dc = GetWindowSurface();
-  if (!surf) {
-    if (!dc) {
-      return nullptr;
-    }
-    uint32_t flags = (mTransparencyMode == eTransparencyOpaque)
-                         ? 0
-                         : gfxWindowsSurface::FLAG_IS_TRANSPARENT;
-    surf = new gfxWindowsSurface(dc, flags);
-  }
-
-  IntSize size = surf->GetSize();
-  if (size.width <= 0 || size.height <= 0) {
-    if (dc) {
-      FreeWindowSurface(dc);
-    }
-    return nullptr;
-  }
-
-  RefPtr<DrawTarget> dt =
-      mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(
-          surf->CairoSurface(), size);
-  if (dt) {
-    mCompositeDC = dc;
-  } else {
-    FreeWindowSurface(dc);
-  }
-
-  return dt.forget();
+  return mRemoteBackbufferClient->BorrowDrawTarget();
 }
 
 void CompositorWidgetParent::EndRemoteDrawing() {
   MOZ_ASSERT(!mLockedBackBufferData);
 
-  if (mTransparencyMode == eTransparencyTransparent) {
-    MOZ_ASSERT(mTransparentSurface);
-    RedrawTransparentWindow();
-  }
-  if (mCompositeDC) {
-    FreeWindowSurface(mCompositeDC);
-  }
-  mCompositeDC = nullptr;
+  Unused << mRemoteBackbufferClient->PresentDrawTarget();
 }
 
-bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() {
-  if (mNotDeferEndRemoteDrawing) {
-    return false;
-  }
-
-  IDirectDraw7* ddraw = DeviceManagerDx::Get()->GetDirectDraw();
-  if (!ddraw) {
-    return false;
-  }
-
-  DWORD scanLine = 0;
-  int height = ::GetSystemMetrics(SM_CYSCREEN);
-  HRESULT ret = ddraw->GetScanLine(&scanLine);
-  if (ret == DDERR_VERTICALBLANKINPROGRESS) {
-    scanLine = 0;
-  } else if (ret != DD_OK) {
-    return false;
-  }
-
-  // Check if there is a risk of tearing with GDI.
-  if (static_cast<int>(scanLine) > height / 2) {
-    // No need to defer.
-    return false;
-  }
-
-  return true;
-}
+bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() { return false; }
 
 already_AddRefed<gfx::DrawTarget>
 CompositorWidgetParent::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
                                                 const gfx::IntRect& aRect,
                                                 bool* aOutIsCleared) {
   MOZ_ASSERT(!mLockedBackBufferData);
 
   RefPtr<gfx::DrawTarget> target = CompositorWidget::GetBackBufferDrawTarget(
@@ -199,125 +132,67 @@ CompositorWidgetParent::EndBackBufferDra
 
 bool CompositorWidgetParent::InitCompositor(layers::Compositor* aCompositor) {
   if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_BASIC) {
     DeviceManagerDx::Get()->InitializeDirectDraw();
   }
   return true;
 }
 
-RefPtr<gfxASurface> CompositorWidgetParent::EnsureTransparentSurface() {
-  mTransparentSurfaceLock.AssertCurrentThreadOwns();
-  MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
-
-  IntSize size = GetClientSize().ToUnknownSize();
-  if (!mTransparentSurface || mTransparentSurface->GetSize() != size) {
-    mTransparentSurface = nullptr;
-    mMemoryDC = nullptr;
-    CreateTransparentSurface(size);
-  }
-
-  RefPtr<gfxASurface> surface = mTransparentSurface;
-  return surface.forget();
-}
-
-void CompositorWidgetParent::CreateTransparentSurface(
-    const gfx::IntSize& aSize) {
-  mTransparentSurfaceLock.AssertCurrentThreadOwns();
-  MOZ_ASSERT(!mTransparentSurface && !mMemoryDC);
-  RefPtr<gfxWindowsSurface> surface =
-      new gfxWindowsSurface(aSize, SurfaceFormat::A8R8G8B8_UINT32);
-  mTransparentSurface = surface;
-  mMemoryDC = surface->GetDC();
-}
-
 bool CompositorWidgetParent::HasGlass() const {
   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread() ||
              wr::RenderThread::IsInRenderThread());
 
   nsTransparencyMode transparencyMode = mTransparencyMode;
   return transparencyMode == eTransparencyGlass ||
          transparencyMode == eTransparencyBorderlessGlass;
 }
 
-bool CompositorWidgetParent::RedrawTransparentWindow() {
-  MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent);
-
-  LayoutDeviceIntSize size = GetClientSize();
-
-  ::GdiFlush();
-
-  BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
-  SIZE winSize = {size.width, size.height};
-  POINT srcPos = {0, 0};
-  HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true);
-  RECT winRect;
-  ::GetWindowRect(hWnd, &winRect);
+bool CompositorWidgetParent::IsHidden() const { return ::IsIconic(mWnd); }
 
-  // perform the alpha blend
-  return !!::UpdateLayeredWindow(hWnd, nullptr, (POINT*)&winRect, &winSize,
-                                 mMemoryDC, &srcPos, 0, &bf, ULW_ALPHA);
+mozilla::ipc::IPCResult CompositorWidgetParent::RecvInitialize(
+    const RemoteBackbufferHandles& aRemoteHandles) {
+  Unused << Initialize(aRemoteHandles);
+  return IPC_OK();
 }
 
-HDC CompositorWidgetParent::GetWindowSurface() {
-  return eTransparencyTransparent == mTransparencyMode ? mMemoryDC
-                                                       : ::GetDC(mWnd);
-}
-
-void CompositorWidgetParent::FreeWindowSurface(HDC dc) {
-  if (eTransparencyTransparent != mTransparencyMode) ::ReleaseDC(mWnd, dc);
-}
-
-bool CompositorWidgetParent::IsHidden() const { return ::IsIconic(mWnd); }
-
 mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnterPresentLock() {
   mPresentLock.Enter();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult CompositorWidgetParent::RecvLeavePresentLock() {
   mPresentLock.Leave();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult CompositorWidgetParent::RecvUpdateTransparency(
     const nsTransparencyMode& aMode) {
-  MutexAutoLock lock(mTransparentSurfaceLock);
-  if (mTransparencyMode == aMode) {
-    return IPC_OK();
-  }
+  mTransparencyMode = aMode;
 
-  mTransparencyMode = aMode;
-  mTransparentSurface = nullptr;
-  mMemoryDC = nullptr;
-
-  if (mTransparencyMode == eTransparencyTransparent) {
-    EnsureTransparentSurface();
-  }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult CompositorWidgetParent::RecvClearTransparentWindow() {
-  MutexAutoLock lock(mTransparentSurfaceLock);
-  if (!mTransparentSurface) {
+  gfx::CriticalSectionAutoEnter lock(&mPresentLock);
+
+  RefPtr<DrawTarget> drawTarget = mRemoteBackbufferClient->BorrowDrawTarget();
+  if (!drawTarget) {
     return IPC_OK();
   }
 
-  EnsureTransparentSurface();
+  IntSize size = drawTarget->GetSize();
+  if (size.IsEmpty()) {
+    return IPC_OK();
+  }
 
-  IntSize size = mTransparentSurface->GetSize();
-  if (!size.IsEmpty()) {
-    RefPtr<DrawTarget> drawTarget =
-        gfxPlatform::CreateDrawTargetForSurface(mTransparentSurface, size);
-    if (!drawTarget) {
-      return IPC_OK();
-    }
-    drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
-    RedrawTransparentWindow();
-  }
+  drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
+
+  Unused << mRemoteBackbufferClient->PresentDrawTarget();
+
   return IPC_OK();
 }
 
 nsIWidget* CompositorWidgetParent::RealWidget() { return nullptr; }
 
 void CompositorWidgetParent::ObserveVsync(VsyncObserver* aObserver) {
   if (aObserver) {
     Unused << SendObserveVsync();
--- a/widget/windows/CompositorWidgetParent.h
+++ b/widget/windows/CompositorWidgetParent.h
@@ -8,38 +8,46 @@
 
 #include "WinCompositorWidget.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/widget/PCompositorWidgetParent.h"
 
 namespace mozilla {
 namespace widget {
 
+namespace remote_backbuffer {
+class Client;
+}
+
 class CompositorWidgetParent final : public PCompositorWidgetParent,
                                      public WinCompositorWidget {
  public:
   explicit CompositorWidgetParent(const CompositorWidgetInitData& aInitData,
                                   const layers::CompositorOptions& aOptions);
   ~CompositorWidgetParent() override;
 
+  bool Initialize(const RemoteBackbufferHandles& aRemoteHandles);
+
   bool PreRender(WidgetRenderingContext*) override;
   void PostRender(WidgetRenderingContext*) override;
   already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
   void EndRemoteDrawing() override;
   bool NeedsToDeferEndRemoteDrawing() override;
   LayoutDeviceIntSize GetClientSize() override;
   already_AddRefed<gfx::DrawTarget> GetBackBufferDrawTarget(
       gfx::DrawTarget* aScreenTarget, const gfx::IntRect& aRect,
       bool* aOutIsCleared) override;
   already_AddRefed<gfx::SourceSurface> EndBackBufferDrawing() override;
   bool InitCompositor(layers::Compositor* aCompositor) override;
   bool IsHidden() const override;
 
   bool HasGlass() const override;
 
+  mozilla::ipc::IPCResult RecvInitialize(
+      const RemoteBackbufferHandles& aRemoteHandles) override;
   mozilla::ipc::IPCResult RecvEnterPresentLock() override;
   mozilla::ipc::IPCResult RecvLeavePresentLock() override;
   mozilla::ipc::IPCResult RecvUpdateTransparency(
       const nsTransparencyMode& aMode) override;
   mozilla::ipc::IPCResult RecvClearTransparentWindow() override;
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   nsIWidget* RealWidget() override;
@@ -47,43 +55,29 @@ class CompositorWidgetParent final : pub
   RefPtr<VsyncObserver> GetVsyncObserver() const override;
 
   // PlatformCompositorWidgetDelegate Overrides
   void UpdateCompositorWnd(const HWND aCompositorWnd,
                            const HWND aParentWnd) override;
   void SetRootLayerTreeID(const layers::LayersId& aRootLayerTreeId) override;
 
  private:
-  bool RedrawTransparentWindow();
-
-  // Ensure that a transparent surface exists, then return it.
-  RefPtr<gfxASurface> EnsureTransparentSurface();
-
-  HDC GetWindowSurface();
-  void FreeWindowSurface(HDC dc);
-
-  void CreateTransparentSurface(const gfx::IntSize& aSize);
-
   RefPtr<VsyncObserver> mVsyncObserver;
   Maybe<layers::LayersId> mRootLayerTreeID;
 
   HWND mWnd;
 
   gfx::CriticalSection mPresentLock;
 
   // Transparency handling.
-  mozilla::Mutex mTransparentSurfaceLock;
   mozilla::Atomic<nsTransparencyMode, MemoryOrdering::Relaxed>
       mTransparencyMode;
-  RefPtr<gfxASurface> mTransparentSurface;
-  HDC mMemoryDC;
-  HDC mCompositeDC;
 
   // Locked back buffer of BasicCompositor
   uint8_t* mLockedBackBufferData;
 
-  bool mNotDeferEndRemoteDrawing;
+  std::unique_ptr<remote_backbuffer::Client> mRemoteBackbufferClient;
 };
 
 }  // namespace widget
 }  // namespace mozilla
 
 #endif  // widget_windows_CompositorWidgetParent_h
--- a/widget/windows/PCompositorWidget.ipdl
+++ b/widget/windows/PCompositorWidget.ipdl
@@ -8,21 +8,29 @@ include protocol PCompositorBridge;
 
 using mozilla::gfx::IntSize from "mozilla/gfx/Point.h";
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using nsTransparencyMode from "mozilla/widget/WidgetMessageUtils.h";
 
 namespace mozilla {
 namespace widget {
 
+struct RemoteBackbufferHandles {
+  WindowsHandle fileMapping;
+  WindowsHandle requestReadyEvent;
+  WindowsHandle responseReadyEvent;
+};
+
 sync protocol PCompositorWidget
 {
   manager PCompositorBridge;
 
 parent:
+  sync Initialize(RemoteBackbufferHandles aRemoteHandles);
+  
   sync EnterPresentLock();
   sync LeavePresentLock();
   async UpdateTransparency(nsTransparencyMode aMode);
   sync ClearTransparentWindow();
   async __delete__();
 
 child:
   async ObserveVsync();
new file mode 100644
--- /dev/null
+++ b/widget/windows/RemoteBackbuffer.cpp
@@ -0,0 +1,567 @@
+/* -*- 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"
+
+namespace mozilla {
+namespace widget {
+namespace remote_backbuffer {
+
+enum class ResponseResult {
+  Unknown,
+  Error,
+  BorrowSuccess,
+  BorrowSameBuffer,
+  PresentSuccess
+};
+
+enum class SharedDataType {
+  BorrowRequest,
+  BorrowResponse,
+  PresentRequest,
+  PresentResponse
+};
+
+struct BorrowResponseData {
+  ResponseResult result;
+  int32_t width;
+  int32_t height;
+  HANDLE fileMapping;
+};
+
+struct PresentResponseData {
+  ResponseResult result;
+};
+
+struct SharedData {
+  SharedDataType dataType;
+  union {
+    BorrowResponseData borrowResponse;
+    PresentResponseData presentResponse;
+  } data;
+};
+
+class SharedImage {
+ public:
+  SharedImage()
+      : mWidth(0), mHeight(0), mFileMapping(nullptr), mPixelData(nullptr) {}
+
+  ~SharedImage() {
+    if (mPixelData) {
+      MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mPixelData));
+    }
+
+    if (mFileMapping) {
+      MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
+    }
+  }
+
+  bool Initialize(int32_t aWidth, int32_t aHeight) {
+    MOZ_ASSERT(aWidth);
+    MOZ_ASSERT(aHeight);
+
+    mWidth = aWidth;
+    mHeight = aHeight;
+
+    DWORD bufferSize = static_cast<DWORD>(mHeight * GetStride());
+
+    mFileMapping = ::CreateFileMappingW(
+        INVALID_HANDLE_VALUE, nullptr /*secattr*/, PAGE_READWRITE,
+        0 /*sizeHigh*/, bufferSize, nullptr /*name*/);
+    if (!mFileMapping) {
+      return false;
+    }
+
+    void* mappedFilePtr =
+        ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
+                        0 /*offsetLow*/, 0 /*bytesToMap*/);
+    if (!mappedFilePtr) {
+      return false;
+    }
+
+    mPixelData = reinterpret_cast<unsigned char*>(mappedFilePtr);
+
+    return true;
+  }
+
+  bool InitializeRemote(int32_t aWidth, int32_t aHeight, HANDLE aFileMapping) {
+    MOZ_ASSERT(aWidth);
+    MOZ_ASSERT(aHeight);
+    MOZ_ASSERT(aFileMapping);
+
+    mWidth = aWidth;
+    mHeight = aHeight;
+    mFileMapping = aFileMapping;
+
+    void* mappedFilePtr =
+        ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
+                        0 /*offsetLow*/, 0 /*bytesToMap*/);
+    if (!mappedFilePtr) {
+      return false;
+    }
+
+    mPixelData = reinterpret_cast<unsigned char*>(mappedFilePtr);
+
+    return true;
+  }
+
+  HBITMAP CreateDIBSection() {
+    BITMAPINFO bitmapInfo = {};
+    bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader);
+    bitmapInfo.bmiHeader.biWidth = mWidth;
+    bitmapInfo.bmiHeader.biHeight = -mHeight;
+    bitmapInfo.bmiHeader.biPlanes = 1;
+    bitmapInfo.bmiHeader.biBitCount = 32;
+    bitmapInfo.bmiHeader.biCompression = BI_RGB;
+    void* dummy = nullptr;
+    return ::CreateDIBSection(nullptr /*paletteDC*/, &bitmapInfo,
+                              DIB_RGB_COLORS, &dummy, mFileMapping,
+                              0 /*offset*/);
+  }
+
+  HANDLE CreateRemoteFileMapping(DWORD aTargetProcessId) {
+    MOZ_ASSERT(aTargetProcessId);
+
+    HANDLE fileMapping = nullptr;
+    if (!ipc::DuplicateHandle(mFileMapping, aTargetProcessId, &fileMapping,
+                              0 /*desiredAccess*/, DUPLICATE_SAME_ACCESS)) {
+      return nullptr;
+    }
+    return fileMapping;
+  }
+
+  already_AddRefed<gfx::DrawTarget> CreateDrawTarget() {
+    return gfx::Factory::CreateDrawTargetForData(
+        gfx::BackendType::CAIRO, mPixelData, IntSize(mWidth, mHeight),
+        GetStride(), gfx::SurfaceFormat::B8G8R8A8);
+  }
+
+  int32_t GetWidth() { return mWidth; }
+
+  int32_t GetHeight() { return mHeight; }
+
+  SharedImage(const SharedImage&) = delete;
+  SharedImage(SharedImage&&) = delete;
+  SharedImage& operator=(const SharedImage&) = delete;
+  SharedImage& operator=(SharedImage&&) = delete;
+
+ private:
+  int32_t GetStride() {
+    constexpr int32_t kBytesPerPixel = 4;
+
+    // DIB requires 32-bit row alignment
+    return (((mWidth * kBytesPerPixel) + 3) / 4) * 4;
+  }
+
+  int32_t mWidth;
+  int32_t mHeight;
+  HANDLE mFileMapping;
+  unsigned char* mPixelData;
+};
+
+class PresentableSharedImage {
+ public:
+  PresentableSharedImage()
+      : mSharedImage(),
+        mDeviceContext(nullptr),
+        mDIBSection(nullptr),
+        mSavedObject(nullptr) {}
+
+  ~PresentableSharedImage() {
+    if (mSavedObject) {
+      MOZ_ALWAYS_TRUE(::SelectObject(mDeviceContext, mSavedObject));
+    }
+
+    if (mDIBSection) {
+      MOZ_ALWAYS_TRUE(::DeleteObject(mDIBSection));
+    }
+
+    if (mDeviceContext) {
+      MOZ_ALWAYS_TRUE(::DeleteDC(mDeviceContext));
+    }
+  }
+
+  bool Initialize(int32_t aWidth, int32_t aHeight) {
+    if (!mSharedImage.Initialize(aWidth, aHeight)) {
+      return false;
+    }
+
+    mDeviceContext = ::CreateCompatibleDC(nullptr);
+    if (!mDeviceContext) {
+      return false;
+    }
+
+    mDIBSection = mSharedImage.CreateDIBSection();
+    if (!mDIBSection) {
+      return false;
+    }
+
+    mSavedObject = ::SelectObject(mDeviceContext, mDIBSection);
+    if (!mSavedObject) {
+      return false;
+    }
+
+    return true;
+  }
+
+  bool PresentToWindow(HWND aWindowHandle) {
+    bool isLayered =
+        ::GetWindowLongPtrW(aWindowHandle, GWL_EXSTYLE) & WS_EX_LAYERED;
+
+    if (isLayered) {
+      BLENDFUNCTION bf = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
+      SIZE winSize = {mSharedImage.GetWidth(), mSharedImage.GetHeight()};
+      POINT srcPos = {0, 0};
+      return !!::UpdateLayeredWindow(
+          aWindowHandle, nullptr /*paletteDC*/, nullptr /*newPos*/, &winSize,
+          mDeviceContext, &srcPos, 0 /*colorKey*/, &bf, ULW_ALPHA);
+    }
+
+    HDC windowDC = ::GetDC(aWindowHandle);
+    if (!windowDC) {
+      return false;
+    }
+
+    bool result = ::BitBlt(windowDC, 0 /*dstX*/, 0 /*dstY*/,
+                           mSharedImage.GetWidth(), mSharedImage.GetHeight(),
+                           mDeviceContext, 0 /*srcX*/, 0 /*srcY*/, SRCCOPY);
+
+    MOZ_ALWAYS_TRUE(::ReleaseDC(aWindowHandle, windowDC));
+
+    return result;
+  }
+
+  HANDLE CreateRemoteFileMapping(DWORD aTargetProcessId) {
+    return mSharedImage.CreateRemoteFileMapping(aTargetProcessId);
+  }
+
+  already_AddRefed<gfx::DrawTarget> CreateDrawTarget() {
+    return mSharedImage.CreateDrawTarget();
+  }
+
+  int32_t GetWidth() { return mSharedImage.GetWidth(); }
+
+  int32_t GetHeight() { return mSharedImage.GetHeight(); }
+
+  PresentableSharedImage(const PresentableSharedImage&) = delete;
+  PresentableSharedImage(PresentableSharedImage&&) = delete;
+  PresentableSharedImage& operator=(const PresentableSharedImage&) = delete;
+  PresentableSharedImage& operator=(PresentableSharedImage&&) = delete;
+
+ private:
+  SharedImage mSharedImage;
+  HDC mDeviceContext;
+  HBITMAP mDIBSection;
+  HGDIOBJ mSavedObject;
+};
+
+Provider::Provider()
+    : mWindowHandle(nullptr),
+      mTargetProcessId(0),
+      mFileMapping(nullptr),
+      mRequestReadyEvent(nullptr),
+      mResponseReadyEvent(nullptr),
+      mSharedDataPtr(nullptr),
+      mStopServiceThread(false),
+      mServiceThread(),
+      mBackbuffer() {}
+
+Provider::~Provider() {
+  mBackbuffer.reset();
+
+  if (mServiceThread.joinable()) {
+    mStopServiceThread = true;
+    MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
+    mServiceThread.join();
+  }
+
+  if (mSharedDataPtr) {
+    MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mSharedDataPtr));
+  }
+
+  if (mResponseReadyEvent) {
+    MOZ_ALWAYS_TRUE(::CloseHandle(mResponseReadyEvent));
+  }
+
+  if (mRequestReadyEvent) {
+    MOZ_ALWAYS_TRUE(::CloseHandle(mRequestReadyEvent));
+  }
+
+  if (mFileMapping) {
+    MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
+  }
+}
+
+bool Provider::Initialize(HWND aWindowHandle, DWORD aTargetProcessId) {
+  MOZ_ASSERT(aWindowHandle);
+  MOZ_ASSERT(aTargetProcessId);
+
+  mWindowHandle = aWindowHandle;
+  mTargetProcessId = aTargetProcessId;
+
+  mFileMapping = ::CreateFileMappingW(
+      INVALID_HANDLE_VALUE, nullptr /*secattr*/, PAGE_READWRITE, 0 /*sizeHigh*/,
+      static_cast<DWORD>(sizeof(SharedData)), nullptr /*name*/);
+  if (!mFileMapping) {
+    return false;
+  }
+
+  mRequestReadyEvent =
+      ::CreateEventW(nullptr /*secattr*/, FALSE /*manualReset*/,
+                     FALSE /*initialState*/, nullptr /*name*/);
+  if (!mRequestReadyEvent) {
+    return false;
+  }
+
+  mResponseReadyEvent =
+      ::CreateEventW(nullptr /*secattr*/, FALSE /*manualReset*/,
+                     FALSE /*initialState*/, nullptr /*name*/);
+  if (!mResponseReadyEvent) {
+    return false;
+  }
+
+  void* mappedFilePtr =
+      ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
+                      0 /*offsetLow*/, 0 /*bytesToMap*/);
+  if (!mappedFilePtr) {
+    return false;
+  }
+
+  mSharedDataPtr = reinterpret_cast<SharedData*>(mappedFilePtr);
+
+  mStopServiceThread = false;
+
+  mServiceThread = std::thread([this] { this->ThreadMain(); });
+
+  return true;
+}
+
+Maybe<RemoteBackbufferHandles> Provider::CreateRemoteHandles() {
+  HANDLE fileMapping = nullptr;
+  if (!ipc::DuplicateHandle(mFileMapping, mTargetProcessId, &fileMapping,
+                            0 /*desiredAccess*/, DUPLICATE_SAME_ACCESS)) {
+    return Nothing();
+  }
+
+  HANDLE requestReadyEvent = nullptr;
+  if (!ipc::DuplicateHandle(mRequestReadyEvent, mTargetProcessId,
+                            &requestReadyEvent, 0 /*desiredAccess*/,
+                            DUPLICATE_SAME_ACCESS)) {
+    return Nothing();
+  }
+
+  HANDLE responseReadyEvent = nullptr;
+  if (!ipc::DuplicateHandle(mResponseReadyEvent, mTargetProcessId,
+                            &responseReadyEvent, 0 /*desiredAccess*/,
+                            DUPLICATE_SAME_ACCESS)) {
+    return Nothing();
+  }
+
+  return Some(RemoteBackbufferHandles(
+      reinterpret_cast<WindowsHandle>(fileMapping),
+      reinterpret_cast<WindowsHandle>(requestReadyEvent),
+      reinterpret_cast<WindowsHandle>(responseReadyEvent)));
+}
+
+void Provider::ThreadMain() {
+  while (true) {
+    MOZ_ALWAYS_TRUE(::WaitForSingleObject(mRequestReadyEvent, INFINITE) ==
+                    WAIT_OBJECT_0);
+
+    if (mStopServiceThread) {
+      break;
+    }
+
+    switch (mSharedDataPtr->dataType) {
+      case SharedDataType::BorrowRequest: {
+        BorrowResponseData responseData = {};
+
+        HandleBorrowRequest(&responseData);
+
+        mSharedDataPtr->dataType = SharedDataType::BorrowResponse;
+        mSharedDataPtr->data.borrowResponse = responseData;
+
+        MOZ_ALWAYS_TRUE(::SetEvent(mResponseReadyEvent));
+
+        break;
+      }
+      case SharedDataType::PresentRequest: {
+        PresentResponseData responseData = {};
+
+        HandlePresentRequest(&responseData);
+
+        mSharedDataPtr->dataType = SharedDataType::PresentResponse;
+        mSharedDataPtr->data.presentResponse = responseData;
+
+        MOZ_ALWAYS_TRUE(::SetEvent(mResponseReadyEvent));
+
+        break;
+      }
+      default:
+        break;
+    };
+  }
+}
+
+void Provider::HandleBorrowRequest(BorrowResponseData* aResponseData) {
+  MOZ_ASSERT(aResponseData);
+
+  aResponseData->result = ResponseResult::Error;
+
+  RECT clientRect = {};
+  if (!::GetClientRect(mWindowHandle, &clientRect)) {
+    return;
+  }
+
+  MOZ_ASSERT(clientRect.left == 0);
+  MOZ_ASSERT(clientRect.top == 0);
+
+  int32_t width = clientRect.right ? clientRect.right : 1;
+  int32_t height = clientRect.bottom ? clientRect.bottom : 1;
+
+  bool needNewBackbuffer = !mBackbuffer || (mBackbuffer->GetWidth() != width) ||
+                           (mBackbuffer->GetHeight() != height);
+
+  if (!needNewBackbuffer) {
+    aResponseData->result = ResponseResult::BorrowSameBuffer;
+    return;
+  }
+
+  mBackbuffer.reset();
+
+  mBackbuffer = std::make_unique<PresentableSharedImage>();
+  if (!mBackbuffer->Initialize(width, height)) {
+    return;
+  }
+
+  HANDLE remoteFileMapping =
+      mBackbuffer->CreateRemoteFileMapping(mTargetProcessId);
+  if (!remoteFileMapping) {
+    return;
+  }
+
+  aResponseData->result = ResponseResult::BorrowSuccess;
+  aResponseData->width = width;
+  aResponseData->height = height;
+  aResponseData->fileMapping = remoteFileMapping;
+}
+
+void Provider::HandlePresentRequest(PresentResponseData* aResponseData) {
+  MOZ_ASSERT(aResponseData);
+
+  aResponseData->result = ResponseResult::Error;
+
+  if (!mBackbuffer) {
+    return;
+  }
+
+  if (!mBackbuffer->PresentToWindow(mWindowHandle)) {
+    return;
+  }
+
+  aResponseData->result = ResponseResult::PresentSuccess;
+}
+
+Client::Client()
+    : mFileMapping(nullptr),
+      mRequestReadyEvent(nullptr),
+      mResponseReadyEvent(nullptr),
+      mSharedDataPtr(nullptr),
+      mBackbuffer() {}
+
+Client::~Client() {
+  mBackbuffer.reset();
+
+  if (mSharedDataPtr) {
+    MOZ_ALWAYS_TRUE(::UnmapViewOfFile(mSharedDataPtr));
+  }
+
+  if (mResponseReadyEvent) {
+    MOZ_ALWAYS_TRUE(::CloseHandle(mResponseReadyEvent));
+  }
+
+  if (mRequestReadyEvent) {
+    MOZ_ALWAYS_TRUE(::CloseHandle(mRequestReadyEvent));
+  }
+
+  if (mFileMapping) {
+    MOZ_ALWAYS_TRUE(::CloseHandle(mFileMapping));
+  }
+}
+
+bool Client::Initialize(const RemoteBackbufferHandles& aRemoteHandles) {
+  MOZ_ASSERT(aRemoteHandles.fileMapping());
+  MOZ_ASSERT(aRemoteHandles.requestReadyEvent());
+  MOZ_ASSERT(aRemoteHandles.responseReadyEvent());
+
+  mFileMapping = reinterpret_cast<HANDLE>(aRemoteHandles.fileMapping());
+  mRequestReadyEvent =
+      reinterpret_cast<HANDLE>(aRemoteHandles.requestReadyEvent());
+  mResponseReadyEvent =
+      reinterpret_cast<HANDLE>(aRemoteHandles.responseReadyEvent());
+
+  void* mappedFilePtr =
+      ::MapViewOfFile(mFileMapping, FILE_MAP_ALL_ACCESS, 0 /*offsetHigh*/,
+                      0 /*offsetLow*/, 0 /*bytesToMap*/);
+  if (!mappedFilePtr) {
+    return false;
+  }
+
+  mSharedDataPtr = reinterpret_cast<SharedData*>(mappedFilePtr);
+
+  return true;
+}
+
+already_AddRefed<gfx::DrawTarget> Client::BorrowDrawTarget() {
+  mSharedDataPtr->dataType = SharedDataType::BorrowRequest;
+  MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
+  MOZ_ALWAYS_TRUE(::WaitForSingleObject(mResponseReadyEvent, INFINITE) ==
+                  WAIT_OBJECT_0);
+
+  if (mSharedDataPtr->dataType != SharedDataType::BorrowResponse) {
+    return nullptr;
+  }
+
+  BorrowResponseData responseData = mSharedDataPtr->data.borrowResponse;
+
+  if ((responseData.result != ResponseResult::BorrowSameBuffer) &&
+      (responseData.result != ResponseResult::BorrowSuccess)) {
+    return nullptr;
+  }
+
+  if (responseData.result == ResponseResult::BorrowSuccess) {
+    mBackbuffer.reset();
+
+    mBackbuffer = std::make_unique<SharedImage>();
+    if (!mBackbuffer->InitializeRemote(responseData.width, responseData.height,
+                                       responseData.fileMapping)) {
+      return nullptr;
+    }
+  }
+
+  return mBackbuffer->CreateDrawTarget();
+}
+
+bool Client::PresentDrawTarget() {
+  mSharedDataPtr->dataType = SharedDataType::PresentRequest;
+  MOZ_ALWAYS_TRUE(::SetEvent(mRequestReadyEvent));
+  MOZ_ALWAYS_TRUE(::WaitForSingleObject(mResponseReadyEvent, INFINITE) ==
+                  WAIT_OBJECT_0);
+
+  if (mSharedDataPtr->dataType != SharedDataType::PresentResponse) {
+    return false;
+  }
+
+  if (mSharedDataPtr->data.presentResponse.result !=
+      ResponseResult::PresentSuccess) {
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace remote_backbuffer
+}  // namespace widget
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/windows/RemoteBackbuffer.h
@@ -0,0 +1,81 @@
+/* -*- 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 <thread>
+#include <windows.h>
+#include "mozilla/Maybe.h"
+
+namespace mozilla {
+namespace widget {
+namespace remote_backbuffer {
+
+struct SharedData;
+struct BorrowResponseData;
+struct PresentResponseData;
+class SharedImage;
+class PresentableSharedImage;
+
+class Provider {
+ public:
+  Provider();
+  ~Provider();
+
+  bool Initialize(HWND aWindowHandle, DWORD aTargetProcessId);
+
+  Maybe<RemoteBackbufferHandles> CreateRemoteHandles();
+
+  Provider(const Provider&) = delete;
+  Provider(Provider&&) = delete;
+  Provider& operator=(const Provider&) = delete;
+  Provider& operator=(Provider&&) = delete;
+
+ private:
+  void ThreadMain();
+
+  void HandleBorrowRequest(BorrowResponseData* aResponseData);
+  void HandlePresentRequest(PresentResponseData* aResponseData);
+
+  HWND mWindowHandle;
+  DWORD mTargetProcessId;
+  HANDLE mFileMapping;
+  HANDLE mRequestReadyEvent;
+  HANDLE mResponseReadyEvent;
+  SharedData* mSharedDataPtr;
+  bool mStopServiceThread;
+  std::thread mServiceThread;
+  std::unique_ptr<PresentableSharedImage> mBackbuffer;
+};
+
+class Client {
+ public:
+  Client();
+  ~Client();
+
+  bool Initialize(const RemoteBackbufferHandles& aRemoteHandles);
+
+  already_AddRefed<gfx::DrawTarget> BorrowDrawTarget();
+  bool PresentDrawTarget();
+
+  Client(const Client&) = delete;
+  Client(Client&&) = delete;
+  Client& operator=(const Client&) = delete;
+  Client& operator=(Client&&) = delete;
+
+ private:
+  HANDLE mFileMapping;
+  HANDLE mRequestReadyEvent;
+  HANDLE mResponseReadyEvent;
+  SharedData* mSharedDataPtr;
+  std::unique_ptr<SharedImage> mBackbuffer;
+};
+
+}  // namespace remote_backbuffer
+}  // namespace widget
+}  // namespace mozilla
+
+#endif  // widget_windows_RemoteBackbuffer_h
\ No newline at end of file
--- a/widget/windows/moz.build
+++ b/widget/windows/moz.build
@@ -63,16 +63,17 @@ UNIFIED_SOURCES += [
     'nsToolkit.cpp',
     'nsUXThemeData.cpp',
     'nsWindow.cpp',
     'nsWindowBase.cpp',
     'nsWindowDbg.cpp',
     'nsWindowGfx.cpp',
     'nsWinGesture.cpp',
     'ProcInfo.cpp',
+    'RemoteBackbuffer.cpp',
     'ScreenHelperWin.cpp',
     'TaskbarPreview.cpp',
     'TaskbarPreviewButton.cpp',
     'TaskbarTabPreview.cpp',
     'TaskbarWindowPreview.cpp',
     'WidgetTraceEvent.cpp',
     'WinCompositorWindowThread.cpp',
     'WindowHook.cpp',