1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "CompositorWidgetParent.h"
6 
7 #include "mozilla/Unused.h"
8 #include "mozilla/StaticPrefs_layers.h"
9 #include "mozilla/gfx/DeviceManagerDx.h"
10 #include "mozilla/gfx/Point.h"
11 #include "mozilla/layers/Compositor.h"
12 #include "mozilla/layers/CompositorBridgeParent.h"
13 #include "mozilla/layers/CompositorThread.h"
14 #include "mozilla/webrender/RenderThread.h"
15 #include "mozilla/widget/PlatformWidgetTypes.h"
16 #include "nsWindow.h"
17 #include "VsyncDispatcher.h"
18 #include "WinCompositorWindowThread.h"
19 #include "VRShMem.h"
20 #include "RemoteBackbuffer.h"
21 
22 #include <ddraw.h>
23 
24 namespace mozilla {
25 namespace widget {
26 
27 using namespace mozilla::gfx;
28 using namespace mozilla;
29 
CompositorWidgetParent(const CompositorWidgetInitData & aInitData,const layers::CompositorOptions & aOptions)30 CompositorWidgetParent::CompositorWidgetParent(
31     const CompositorWidgetInitData& aInitData,
32     const layers::CompositorOptions& aOptions)
33     : WinCompositorWidget(aInitData.get_WinCompositorWidgetInitData(),
34                           aOptions),
35       mWnd(reinterpret_cast<HWND>(
36           aInitData.get_WinCompositorWidgetInitData().hWnd())),
37       mTransparencyMode(
38           aInitData.get_WinCompositorWidgetInitData().transparencyMode()),
39       mSizeMode(nsSizeMode_Normal),
40       mIsFullyOccluded(false),
41       mRemoteBackbufferClient() {
42   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
43   MOZ_ASSERT(mWnd && ::IsWindow(mWnd));
44 }
45 
~CompositorWidgetParent()46 CompositorWidgetParent::~CompositorWidgetParent() {}
47 
Initialize(const RemoteBackbufferHandles & aRemoteHandles)48 bool CompositorWidgetParent::Initialize(
49     const RemoteBackbufferHandles& aRemoteHandles) {
50   mRemoteBackbufferClient = std::make_unique<remote_backbuffer::Client>();
51   if (!mRemoteBackbufferClient->Initialize(aRemoteHandles)) {
52     return false;
53   }
54 
55   return true;
56 }
57 
PreRender(WidgetRenderingContext * aContext)58 bool CompositorWidgetParent::PreRender(WidgetRenderingContext* aContext) {
59   // This can block waiting for WM_SETTEXT to finish
60   // Using PreRender is unnecessarily pessimistic because
61   // we technically only need to block during the present call
62   // not all of compositor rendering
63   mPresentLock.Enter();
64   return true;
65 }
66 
PostRender(WidgetRenderingContext * aContext)67 void CompositorWidgetParent::PostRender(WidgetRenderingContext* aContext) {
68   mPresentLock.Leave();
69 }
70 
GetClientSize()71 LayoutDeviceIntSize CompositorWidgetParent::GetClientSize() {
72   RECT r;
73   if (!::GetClientRect(mWnd, &r)) {
74     return LayoutDeviceIntSize();
75   }
76   return LayoutDeviceIntSize(r.right - r.left, r.bottom - r.top);
77 }
78 
79 already_AddRefed<gfx::DrawTarget>
StartRemoteDrawingInRegion(const LayoutDeviceIntRegion & aInvalidRegion,layers::BufferMode * aBufferMode)80 CompositorWidgetParent::StartRemoteDrawingInRegion(
81     const LayoutDeviceIntRegion& aInvalidRegion,
82     layers::BufferMode* aBufferMode) {
83   MOZ_ASSERT(mRemoteBackbufferClient);
84   MOZ_ASSERT(aBufferMode);
85 
86   // Because we use remote backbuffering, there is no need to use a local
87   // backbuffer too.
88   (*aBufferMode) = layers::BufferMode::BUFFER_NONE;
89 
90   return mRemoteBackbufferClient->BorrowDrawTarget();
91 }
92 
EndRemoteDrawingInRegion(gfx::DrawTarget * aDrawTarget,const LayoutDeviceIntRegion & aInvalidRegion)93 void CompositorWidgetParent::EndRemoteDrawingInRegion(
94     gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
95   Unused << mRemoteBackbufferClient->PresentDrawTarget(
96       aInvalidRegion.ToUnknownRegion());
97 }
98 
NeedsToDeferEndRemoteDrawing()99 bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() { return false; }
100 
101 already_AddRefed<gfx::DrawTarget>
GetBackBufferDrawTarget(gfx::DrawTarget * aScreenTarget,const gfx::IntRect & aRect,bool * aOutIsCleared)102 CompositorWidgetParent::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
103                                                 const gfx::IntRect& aRect,
104                                                 bool* aOutIsCleared) {
105   MOZ_CRASH(
106       "Unexpected call to GetBackBufferDrawTarget() with remote "
107       "backbuffering in use");
108 }
109 
110 already_AddRefed<gfx::SourceSurface>
EndBackBufferDrawing()111 CompositorWidgetParent::EndBackBufferDrawing() {
112   MOZ_CRASH(
113       "Unexpected call to EndBackBufferDrawing() with remote "
114       "backbuffering in use");
115 }
116 
InitCompositor(layers::Compositor * aCompositor)117 bool CompositorWidgetParent::InitCompositor(layers::Compositor* aCompositor) {
118   return true;
119 }
120 
HasGlass() const121 bool CompositorWidgetParent::HasGlass() const {
122   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread() ||
123              wr::RenderThread::IsInRenderThread());
124 
125   nsTransparencyMode transparencyMode = mTransparencyMode;
126   return transparencyMode == eTransparencyGlass ||
127          transparencyMode == eTransparencyBorderlessGlass;
128 }
129 
IsHidden() const130 bool CompositorWidgetParent::IsHidden() const { return ::IsIconic(mWnd); }
131 
RecvInitialize(const RemoteBackbufferHandles & aRemoteHandles)132 mozilla::ipc::IPCResult CompositorWidgetParent::RecvInitialize(
133     const RemoteBackbufferHandles& aRemoteHandles) {
134   Unused << Initialize(aRemoteHandles);
135   return IPC_OK();
136 }
137 
RecvEnterPresentLock()138 mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnterPresentLock() {
139   mPresentLock.Enter();
140   return IPC_OK();
141 }
142 
RecvLeavePresentLock()143 mozilla::ipc::IPCResult CompositorWidgetParent::RecvLeavePresentLock() {
144   mPresentLock.Leave();
145   return IPC_OK();
146 }
147 
RecvUpdateTransparency(const nsTransparencyMode & aMode)148 mozilla::ipc::IPCResult CompositorWidgetParent::RecvUpdateTransparency(
149     const nsTransparencyMode& aMode) {
150   mTransparencyMode = aMode;
151 
152   return IPC_OK();
153 }
154 
RecvNotifyVisibilityUpdated(const nsSizeMode & aSizeMode,const bool & aIsFullyOccluded)155 mozilla::ipc::IPCResult CompositorWidgetParent::RecvNotifyVisibilityUpdated(
156     const nsSizeMode& aSizeMode, const bool& aIsFullyOccluded) {
157   mSizeMode = aSizeMode;
158   mIsFullyOccluded = aIsFullyOccluded;
159   return IPC_OK();
160 }
161 
GetWindowSizeMode() const162 nsSizeMode CompositorWidgetParent::CompositorWidgetParent::GetWindowSizeMode()
163     const {
164   nsSizeMode sizeMode = mSizeMode;
165   return sizeMode;
166 }
167 
GetWindowIsFullyOccluded() const168 bool CompositorWidgetParent::CompositorWidgetParent::GetWindowIsFullyOccluded()
169     const {
170   bool isFullyOccluded = mIsFullyOccluded;
171   return isFullyOccluded;
172 }
173 
RecvClearTransparentWindow()174 mozilla::ipc::IPCResult CompositorWidgetParent::RecvClearTransparentWindow() {
175   gfx::CriticalSectionAutoEnter lock(&mPresentLock);
176 
177   RefPtr<DrawTarget> drawTarget = mRemoteBackbufferClient->BorrowDrawTarget();
178   if (!drawTarget) {
179     return IPC_OK();
180   }
181 
182   IntSize size = drawTarget->GetSize();
183   if (size.IsEmpty()) {
184     return IPC_OK();
185   }
186 
187   drawTarget->ClearRect(Rect(0, 0, size.width, size.height));
188 
189   Unused << mRemoteBackbufferClient->PresentDrawTarget(
190       IntRect(0, 0, size.width, size.height));
191 
192   return IPC_OK();
193 }
194 
RealWidget()195 nsIWidget* CompositorWidgetParent::RealWidget() { return nullptr; }
196 
ObserveVsync(VsyncObserver * aObserver)197 void CompositorWidgetParent::ObserveVsync(VsyncObserver* aObserver) {
198   if (aObserver) {
199     Unused << SendObserveVsync();
200   } else {
201     Unused << SendUnobserveVsync();
202   }
203   mVsyncObserver = aObserver;
204 }
205 
GetVsyncObserver() const206 RefPtr<VsyncObserver> CompositorWidgetParent::GetVsyncObserver() const {
207   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
208   return mVsyncObserver;
209 }
210 
UpdateCompositorWnd(const HWND aCompositorWnd,const HWND aParentWnd)211 void CompositorWidgetParent::UpdateCompositorWnd(const HWND aCompositorWnd,
212                                                  const HWND aParentWnd) {
213   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
214   MOZ_ASSERT(mRootLayerTreeID.isSome());
215 
216   RefPtr<CompositorWidgetParent> self = this;
217   SendUpdateCompositorWnd(reinterpret_cast<WindowsHandle>(aCompositorWnd),
218                           reinterpret_cast<WindowsHandle>(aParentWnd))
219       ->Then(
220           layers::CompositorThread(), __func__,
221           [self](const bool& aSuccess) {
222             if (aSuccess && self->mRootLayerTreeID.isSome()) {
223               self->mSetParentCompleted = true;
224               // Schedule composition after ::SetParent() call in parent
225               // process.
226               layers::CompositorBridgeParent::ScheduleForcedComposition(
227                   self->mRootLayerTreeID.ref(), wr::RenderReasons::WIDGET);
228             }
229           },
230           [self](const mozilla::ipc::ResponseRejectReason&) {});
231 }
232 
SetRootLayerTreeID(const layers::LayersId & aRootLayerTreeId)233 void CompositorWidgetParent::SetRootLayerTreeID(
234     const layers::LayersId& aRootLayerTreeId) {
235   mRootLayerTreeID = Some(aRootLayerTreeId);
236 }
237 
ActorDestroy(ActorDestroyReason aWhy)238 void CompositorWidgetParent::ActorDestroy(ActorDestroyReason aWhy) {}
239 
240 }  // namespace widget
241 }  // namespace mozilla
242