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