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/. */
6 #include "InProcessWinCompositorWidget.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/CompositorThread.h"
13 #include "mozilla/webrender/RenderThread.h"
14 #include "mozilla/widget/PlatformWidgetTypes.h"
15 #include "gfxPlatform.h"
16 #include "HeadlessCompositorWidget.h"
17 #include "HeadlessWidget.h"
19 #include "VsyncDispatcher.h"
20 #include "WinCompositorWindowThread.h"
28 using namespace mozilla::gfx
;
29 using namespace mozilla
;
32 RefPtr
<CompositorWidget
> CompositorWidget::CreateLocal(
33 const CompositorWidgetInitData
& aInitData
,
34 const layers::CompositorOptions
& aOptions
, nsIWidget
* aWidget
) {
35 if (aInitData
.type() ==
36 CompositorWidgetInitData::THeadlessCompositorWidgetInitData
) {
37 return new HeadlessCompositorWidget(
38 aInitData
.get_HeadlessCompositorWidgetInitData(), aOptions
,
39 static_cast<HeadlessWidget
*>(aWidget
));
41 return new InProcessWinCompositorWidget(
42 aInitData
.get_WinCompositorWidgetInitData(), aOptions
,
43 static_cast<nsWindow
*>(aWidget
));
47 InProcessWinCompositorWidget::InProcessWinCompositorWidget(
48 const WinCompositorWidgetInitData
& aInitData
,
49 const layers::CompositorOptions
& aOptions
, nsWindow
* aWindow
)
50 : WinCompositorWidget(aInitData
, aOptions
),
52 mWnd(reinterpret_cast<HWND
>(aInitData
.hWnd())),
53 mTransparentSurfaceLock("mTransparentSurfaceLock"),
54 mTransparencyMode(aInitData
.transparencyMode()),
56 mCompositeDC(nullptr),
57 mLockedBackBufferData(nullptr) {
59 MOZ_ASSERT(mWnd
&& ::IsWindow(mWnd
));
61 // mNotDeferEndRemoteDrawing is set on the main thread during init,
62 // but is only accessed after on the compositor thread.
63 mNotDeferEndRemoteDrawing
=
64 StaticPrefs::layers_offmainthreadcomposition_frame_rate() == 0 ||
65 gfxPlatform::IsInLayoutAsapMode() || gfxPlatform::ForceSoftwareVsync();
68 void InProcessWinCompositorWidget::OnDestroyWindow() {
69 gfx::CriticalSectionAutoEnter
presentLock(&mPresentLock
);
70 MutexAutoLock
lock(mTransparentSurfaceLock
);
71 mTransparentSurface
= nullptr;
75 bool InProcessWinCompositorWidget::OnWindowResize(
76 const LayoutDeviceIntSize
& aSize
) {
80 void InProcessWinCompositorWidget::OnWindowModeChange(nsSizeMode aSizeMode
) {}
82 bool InProcessWinCompositorWidget::PreRender(WidgetRenderingContext
* aContext
) {
83 // This can block waiting for WM_SETTEXT to finish
84 // Using PreRender is unnecessarily pessimistic because
85 // we technically only need to block during the present call
86 // not all of compositor rendering
91 void InProcessWinCompositorWidget::PostRender(
92 WidgetRenderingContext
* aContext
) {
96 LayoutDeviceIntSize
InProcessWinCompositorWidget::GetClientSize() {
98 if (!::GetClientRect(mWnd
, &r
)) {
99 return LayoutDeviceIntSize();
101 return LayoutDeviceIntSize(r
.right
- r
.left
, r
.bottom
- r
.top
);
104 already_AddRefed
<gfx::DrawTarget
>
105 InProcessWinCompositorWidget::StartRemoteDrawing() {
106 MutexAutoLock
lock(mTransparentSurfaceLock
);
108 MOZ_ASSERT(!mCompositeDC
);
110 RefPtr
<gfxASurface
> surf
;
111 if (mTransparencyMode
== eTransparencyTransparent
) {
112 surf
= EnsureTransparentSurface();
115 // Must call this after EnsureTransparentSurface(), since it could update
117 HDC dc
= GetWindowSurface();
122 uint32_t flags
= (mTransparencyMode
== eTransparencyOpaque
)
124 : gfxWindowsSurface::FLAG_IS_TRANSPARENT
;
125 surf
= new gfxWindowsSurface(dc
, flags
);
128 IntSize size
= surf
->GetSize();
129 if (size
.width
<= 0 || size
.height
<= 0) {
131 FreeWindowSurface(dc
);
136 RefPtr
<DrawTarget
> dt
=
137 mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(
138 surf
->CairoSurface(), size
);
142 FreeWindowSurface(dc
);
148 void InProcessWinCompositorWidget::EndRemoteDrawing() {
149 MOZ_ASSERT(!mLockedBackBufferData
);
151 if (mTransparencyMode
== eTransparencyTransparent
) {
152 MOZ_ASSERT(mTransparentSurface
);
153 RedrawTransparentWindow();
156 FreeWindowSurface(mCompositeDC
);
158 mCompositeDC
= nullptr;
161 bool InProcessWinCompositorWidget::NeedsToDeferEndRemoteDrawing() {
162 if (mNotDeferEndRemoteDrawing
) {
166 IDirectDraw7
* ddraw
= DeviceManagerDx::Get()->GetDirectDraw();
172 int height
= ::GetSystemMetrics(SM_CYSCREEN
);
173 HRESULT ret
= ddraw
->GetScanLine(&scanLine
);
174 if (ret
== DDERR_VERTICALBLANKINPROGRESS
) {
176 } else if (ret
!= DD_OK
) {
180 // Check if there is a risk of tearing with GDI.
181 if (static_cast<int>(scanLine
) > height
/ 2) {
189 already_AddRefed
<gfx::DrawTarget
>
190 InProcessWinCompositorWidget::GetBackBufferDrawTarget(
191 gfx::DrawTarget
* aScreenTarget
, const gfx::IntRect
& aRect
,
192 bool* aOutIsCleared
) {
193 MOZ_ASSERT(!mLockedBackBufferData
);
195 RefPtr
<gfx::DrawTarget
> target
= CompositorWidget::GetBackBufferDrawTarget(
196 aScreenTarget
, aRect
, aOutIsCleared
);
201 MOZ_ASSERT(target
->GetBackendType() == BackendType::CAIRO
);
206 SurfaceFormat destFormat
;
207 if (!target
->LockBits(&destData
, &destSize
, &destStride
, &destFormat
)) {
208 // LockBits is not supported. Use original DrawTarget.
209 return target
.forget();
212 RefPtr
<gfx::DrawTarget
> dataTarget
= Factory::CreateDrawTargetForData(
213 BackendType::CAIRO
, destData
, destSize
, destStride
, destFormat
);
214 mLockedBackBufferData
= destData
;
216 return dataTarget
.forget();
219 already_AddRefed
<gfx::SourceSurface
>
220 InProcessWinCompositorWidget::EndBackBufferDrawing() {
221 if (mLockedBackBufferData
) {
222 MOZ_ASSERT(mLastBackBuffer
);
223 mLastBackBuffer
->ReleaseBits(mLockedBackBufferData
);
224 mLockedBackBufferData
= nullptr;
226 return CompositorWidget::EndBackBufferDrawing();
229 bool InProcessWinCompositorWidget::InitCompositor(
230 layers::Compositor
* aCompositor
) {
234 void InProcessWinCompositorWidget::EnterPresentLock() { mPresentLock
.Enter(); }
236 void InProcessWinCompositorWidget::LeavePresentLock() { mPresentLock
.Leave(); }
238 RefPtr
<gfxASurface
> InProcessWinCompositorWidget::EnsureTransparentSurface() {
239 mTransparentSurfaceLock
.AssertCurrentThreadOwns();
240 MOZ_ASSERT(mTransparencyMode
== eTransparencyTransparent
);
242 IntSize size
= GetClientSize().ToUnknownSize();
243 if (!mTransparentSurface
|| mTransparentSurface
->GetSize() != size
) {
244 mTransparentSurface
= nullptr;
246 CreateTransparentSurface(size
);
249 RefPtr
<gfxASurface
> surface
= mTransparentSurface
;
250 return surface
.forget();
253 void InProcessWinCompositorWidget::CreateTransparentSurface(
254 const gfx::IntSize
& aSize
) {
255 mTransparentSurfaceLock
.AssertCurrentThreadOwns();
256 MOZ_ASSERT(!mTransparentSurface
&& !mMemoryDC
);
257 RefPtr
<gfxWindowsSurface
> surface
=
258 new gfxWindowsSurface(aSize
, SurfaceFormat::A8R8G8B8_UINT32
);
259 mTransparentSurface
= surface
;
260 mMemoryDC
= surface
->GetDC();
263 void InProcessWinCompositorWidget::UpdateTransparency(
264 nsTransparencyMode aMode
) {
265 gfx::CriticalSectionAutoEnter
presentLock(&mPresentLock
);
266 MutexAutoLock
lock(mTransparentSurfaceLock
);
267 if (mTransparencyMode
== aMode
) {
271 mTransparencyMode
= aMode
;
272 mTransparentSurface
= nullptr;
275 if (mTransparencyMode
== eTransparencyTransparent
) {
276 EnsureTransparentSurface();
280 void InProcessWinCompositorWidget::NotifyVisibilityUpdated(
281 nsSizeMode aSizeMode
, bool aIsFullyOccluded
) {
282 mSizeMode
= aSizeMode
;
283 mIsFullyOccluded
= aIsFullyOccluded
;
286 nsSizeMode
InProcessWinCompositorWidget::GetWindowSizeMode() const {
287 nsSizeMode sizeMode
= mSizeMode
;
291 bool InProcessWinCompositorWidget::GetWindowIsFullyOccluded() const {
292 bool isFullyOccluded
= mIsFullyOccluded
;
293 return isFullyOccluded
;
296 bool InProcessWinCompositorWidget::HasGlass() const {
297 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread() ||
298 wr::RenderThread::IsInRenderThread());
300 nsTransparencyMode transparencyMode
= mTransparencyMode
;
301 return transparencyMode
== eTransparencyGlass
||
302 transparencyMode
== eTransparencyBorderlessGlass
;
305 void InProcessWinCompositorWidget::ClearTransparentWindow() {
306 gfx::CriticalSectionAutoEnter
presentLock(&mPresentLock
);
307 MutexAutoLock
lock(mTransparentSurfaceLock
);
308 if (!mTransparentSurface
) {
312 EnsureTransparentSurface();
314 IntSize size
= mTransparentSurface
->GetSize();
315 if (!size
.IsEmpty()) {
316 RefPtr
<DrawTarget
> drawTarget
=
317 gfxPlatform::CreateDrawTargetForSurface(mTransparentSurface
, size
);
321 drawTarget
->ClearRect(Rect(0, 0, size
.width
, size
.height
));
322 RedrawTransparentWindow();
326 bool InProcessWinCompositorWidget::RedrawTransparentWindow() {
327 MOZ_ASSERT(mTransparencyMode
== eTransparencyTransparent
);
329 LayoutDeviceIntSize size
= GetClientSize();
333 BLENDFUNCTION bf
= {AC_SRC_OVER
, 0, 255, AC_SRC_ALPHA
};
334 SIZE winSize
= {size
.width
, size
.height
};
335 POINT srcPos
= {0, 0};
336 HWND hWnd
= WinUtils::GetTopLevelHWND(mWnd
, true);
338 ::GetWindowRect(hWnd
, &winRect
);
340 // perform the alpha blend
341 return !!::UpdateLayeredWindow(hWnd
, nullptr, (POINT
*)&winRect
, &winSize
,
342 mMemoryDC
, &srcPos
, 0, &bf
, ULW_ALPHA
);
345 HDC
InProcessWinCompositorWidget::GetWindowSurface() {
346 return eTransparencyTransparent
== mTransparencyMode
? mMemoryDC
350 void InProcessWinCompositorWidget::FreeWindowSurface(HDC dc
) {
351 if (eTransparencyTransparent
!= mTransparencyMode
) ::ReleaseDC(mWnd
, dc
);
354 bool InProcessWinCompositorWidget::IsHidden() const { return ::IsIconic(mWnd
); }
356 nsIWidget
* InProcessWinCompositorWidget::RealWidget() { return mWindow
; }
358 void InProcessWinCompositorWidget::ObserveVsync(VsyncObserver
* aObserver
) {
359 if (RefPtr
<CompositorVsyncDispatcher
> cvd
=
360 mWindow
->GetCompositorVsyncDispatcher()) {
361 cvd
->SetCompositorVsyncObserver(aObserver
);
365 } // namespace widget
366 } // namespace mozilla