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 
6 #include "CompositorWidgetParent.h"
7 
8 #include "mozilla/Unused.h"
9 #include "mozilla/StaticPrefs_layers.h"
10 #include "mozilla/gfx/DeviceManagerDx.h"
11 #include "mozilla/gfx/Point.h"
12 #include "mozilla/layers/Compositor.h"
13 #include "mozilla/layers/CompositorBridgeParent.h"
14 #include "mozilla/layers/CompositorThread.h"
15 #include "mozilla/webrender/RenderThread.h"
16 #include "mozilla/widget/PlatformWidgetTypes.h"
17 #include "nsWindow.h"
18 #include "VsyncDispatcher.h"
19 #include "WinCompositorWindowThread.h"
20 #include "VRShMem.h"
21 #include "RemoteBackbuffer.h"
22 
23 #include <ddraw.h>
24 
25 namespace mozilla {
26 namespace widget {
27 
28 using namespace mozilla::gfx;
29 using namespace mozilla;
30 
CompositorWidgetParent(const CompositorWidgetInitData & aInitData,const layers::CompositorOptions & aOptions)31 CompositorWidgetParent::CompositorWidgetParent(
32     const CompositorWidgetInitData& aInitData,
33     const layers::CompositorOptions& aOptions)
34     : WinCompositorWidget(aInitData.get_WinCompositorWidgetInitData(),
35                           aOptions),
36       mWnd(reinterpret_cast<HWND>(
37           aInitData.get_WinCompositorWidgetInitData().hWnd())),
38       mTransparencyMode(
39           aInitData.get_WinCompositorWidgetInitData().transparencyMode()),
40       mLockedBackBufferData(nullptr),
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 
StartRemoteDrawing()79 already_AddRefed<gfx::DrawTarget> CompositorWidgetParent::StartRemoteDrawing() {
80   MOZ_ASSERT(mRemoteBackbufferClient);
81 
82   return mRemoteBackbufferClient->BorrowDrawTarget();
83 }
84 
EndRemoteDrawing()85 void CompositorWidgetParent::EndRemoteDrawing() {
86   MOZ_ASSERT(!mLockedBackBufferData);
87 
88   Unused << mRemoteBackbufferClient->PresentDrawTarget();
89 }
90 
NeedsToDeferEndRemoteDrawing()91 bool CompositorWidgetParent::NeedsToDeferEndRemoteDrawing() { return false; }
92 
93 already_AddRefed<gfx::DrawTarget>
GetBackBufferDrawTarget(gfx::DrawTarget * aScreenTarget,const gfx::IntRect & aRect,bool * aOutIsCleared)94 CompositorWidgetParent::GetBackBufferDrawTarget(gfx::DrawTarget* aScreenTarget,
95                                                 const gfx::IntRect& aRect,
96                                                 bool* aOutIsCleared) {
97   MOZ_ASSERT(!mLockedBackBufferData);
98 
99   RefPtr<gfx::DrawTarget> target = CompositorWidget::GetBackBufferDrawTarget(
100       aScreenTarget, aRect, aOutIsCleared);
101   if (!target) {
102     return nullptr;
103   }
104 
105   MOZ_ASSERT(target->GetBackendType() == BackendType::CAIRO);
106 
107   uint8_t* destData;
108   IntSize destSize;
109   int32_t destStride;
110   SurfaceFormat destFormat;
111   if (!target->LockBits(&destData, &destSize, &destStride, &destFormat)) {
112     // LockBits is not supported. Use original DrawTarget.
113     return target.forget();
114   }
115 
116   RefPtr<gfx::DrawTarget> dataTarget = Factory::CreateDrawTargetForData(
117       BackendType::CAIRO, destData, destSize, destStride, destFormat);
118   mLockedBackBufferData = destData;
119 
120   return dataTarget.forget();
121 }
122 
123 already_AddRefed<gfx::SourceSurface>
EndBackBufferDrawing()124 CompositorWidgetParent::EndBackBufferDrawing() {
125   if (mLockedBackBufferData) {
126     MOZ_ASSERT(mLastBackBuffer);
127     mLastBackBuffer->ReleaseBits(mLockedBackBufferData);
128     mLockedBackBufferData = nullptr;
129   }
130   return CompositorWidget::EndBackBufferDrawing();
131 }
132 
InitCompositor(layers::Compositor * aCompositor)133 bool CompositorWidgetParent::InitCompositor(layers::Compositor* aCompositor) {
134   if (aCompositor->GetBackendType() == layers::LayersBackend::LAYERS_BASIC) {
135     DeviceManagerDx::Get()->InitializeDirectDraw();
136   }
137   return true;
138 }
139 
HasGlass() const140 bool CompositorWidgetParent::HasGlass() const {
141   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread() ||
142              wr::RenderThread::IsInRenderThread());
143 
144   nsTransparencyMode transparencyMode = mTransparencyMode;
145   return transparencyMode == eTransparencyGlass ||
146          transparencyMode == eTransparencyBorderlessGlass;
147 }
148 
IsHidden() const149 bool CompositorWidgetParent::IsHidden() const { return ::IsIconic(mWnd); }
150 
RecvInitialize(const RemoteBackbufferHandles & aRemoteHandles)151 mozilla::ipc::IPCResult CompositorWidgetParent::RecvInitialize(
152     const RemoteBackbufferHandles& aRemoteHandles) {
153   Unused << Initialize(aRemoteHandles);
154   return IPC_OK();
155 }
156 
RecvEnterPresentLock()157 mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnterPresentLock() {
158   mPresentLock.Enter();
159   return IPC_OK();
160 }
161 
RecvLeavePresentLock()162 mozilla::ipc::IPCResult CompositorWidgetParent::RecvLeavePresentLock() {
163   mPresentLock.Leave();
164   return IPC_OK();
165 }
166 
RecvUpdateTransparency(const nsTransparencyMode & aMode)167 mozilla::ipc::IPCResult CompositorWidgetParent::RecvUpdateTransparency(
168     const nsTransparencyMode& aMode) {
169   mTransparencyMode = aMode;
170 
171   return IPC_OK();
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 
191   return IPC_OK();
192 }
193 
RealWidget()194 nsIWidget* CompositorWidgetParent::RealWidget() { return nullptr; }
195 
ObserveVsync(VsyncObserver * aObserver)196 void CompositorWidgetParent::ObserveVsync(VsyncObserver* aObserver) {
197   if (aObserver) {
198     Unused << SendObserveVsync();
199   } else {
200     Unused << SendUnobserveVsync();
201   }
202   mVsyncObserver = aObserver;
203 }
204 
GetVsyncObserver() const205 RefPtr<VsyncObserver> CompositorWidgetParent::GetVsyncObserver() const {
206   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
207   return mVsyncObserver;
208 }
209 
UpdateCompositorWnd(const HWND aCompositorWnd,const HWND aParentWnd)210 void CompositorWidgetParent::UpdateCompositorWnd(const HWND aCompositorWnd,
211                                                  const HWND aParentWnd) {
212   MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
213   MOZ_ASSERT(mRootLayerTreeID.isSome());
214 
215   RefPtr<CompositorWidgetParent> self = this;
216   SendUpdateCompositorWnd(reinterpret_cast<WindowsHandle>(aCompositorWnd),
217                           reinterpret_cast<WindowsHandle>(aParentWnd))
218       ->Then(
219           layers::CompositorThread(), __func__,
220           [self](const bool& aSuccess) {
221             if (aSuccess && self->mRootLayerTreeID.isSome()) {
222               self->mSetParentCompleted = true;
223               // Schedule composition after ::SetParent() call in parent
224               // process.
225               layers::CompositorBridgeParent::ScheduleForcedComposition(
226                   self->mRootLayerTreeID.ref());
227             }
228           },
229           [self](const mozilla::ipc::ResponseRejectReason&) {});
230 }
231 
SetRootLayerTreeID(const layers::LayersId & aRootLayerTreeId)232 void CompositorWidgetParent::SetRootLayerTreeID(
233     const layers::LayersId& aRootLayerTreeId) {
234   mRootLayerTreeID = Some(aRootLayerTreeId);
235 }
236 
ActorDestroy(ActorDestroyReason aWhy)237 void CompositorWidgetParent::ActorDestroy(ActorDestroyReason aWhy) {}
238 
239 }  // namespace widget
240 }  // namespace mozilla
241