1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "WindowSurfaceProvider.h"
9 #include "gfxPlatformGtk.h"
10 #include "GtkCompositorWidget.h"
11 #include "mozilla/gfx/Logging.h"
12 #include "mozilla/layers/LayersTypes.h"
14 #include "mozilla/ScopeExit.h"
17 # include "mozilla/StaticPrefs_widget.h"
18 # include "WindowSurfaceWaylandMultiBuffer.h"
21 # include "mozilla/X11Util.h"
22 # include "WindowSurfaceX11Image.h"
23 # include "WindowSurfaceX11SHM.h"
28 # include "mozilla/Logging.h"
29 # include "nsTArray.h"
31 extern mozilla::LazyLogModule gWidgetLog
;
32 # define LOG(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args)
35 #endif /* MOZ_LOGGING */
40 using namespace mozilla::layers
;
42 WindowSurfaceProvider::WindowSurfaceProvider()
43 : mWindowSurface(nullptr),
44 mMutex("WindowSurfaceProvider"),
45 mWindowSurfaceValid(false)
56 WindowSurfaceProvider::~WindowSurfaceProvider() {
58 MOZ_DIAGNOSTIC_ASSERT(!mWidget
,
59 "nsWindow reference is still live, we're leaking it!");
62 MOZ_DIAGNOSTIC_ASSERT(!mXWindow
, "mXWindow should be released on quit!");
67 bool WindowSurfaceProvider::Initialize(RefPtr
<nsWindow
> aWidget
) {
68 mWindowSurfaceValid
= false;
69 mWidget
= std::move(aWidget
);
72 bool WindowSurfaceProvider::Initialize(GtkCompositorWidget
* aCompositorWidget
) {
73 mWindowSurfaceValid
= false;
74 mCompositorWidget
= aCompositorWidget
;
75 mWidget
= static_cast<nsWindow
*>(aCompositorWidget
->RealWidget());
80 bool WindowSurfaceProvider::Initialize(Window aWindow
, bool aIsShaped
) {
81 mWindowSurfaceValid
= false;
83 // Grab the window's visual and depth
84 XWindowAttributes windowAttrs
;
85 if (!XGetWindowAttributes(DefaultXDisplay(), aWindow
, &windowAttrs
)) {
86 NS_WARNING("GtkCompositorWidget(): XGetWindowAttributes() failed!");
91 mXVisual
= windowAttrs
.visual
;
92 mXDepth
= windowAttrs
.depth
;
93 mIsShaped
= aIsShaped
;
98 void WindowSurfaceProvider::CleanupResources() {
99 MutexAutoLock
lock(mMutex
);
100 mWindowSurfaceValid
= false;
112 RefPtr
<WindowSurface
> WindowSurfaceProvider::CreateWindowSurface() {
114 if (GdkIsWaylandDisplay()) {
115 // We're called too early or we're unmapped.
119 return MakeRefPtr
<WindowSurfaceWaylandMB
>(mWidget
, mCompositorWidget
);
123 if (GdkIsX11Display()) {
124 // We're called too early or we're unmapped.
128 // Blit to the window with the following priority:
131 # ifdef MOZ_HAVE_SHMIMAGE
132 if (!mIsShaped
&& nsShmImage::UseShm()) {
133 LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", (Window
)mXWindow
));
134 return MakeRefPtr
<WindowSurfaceX11SHM
>(DefaultXDisplay(), mXWindow
,
137 # endif // MOZ_HAVE_SHMIMAGE
139 LOG(("Drawing to Window 0x%lx will use XPutImage\n", (Window
)mXWindow
));
140 return MakeRefPtr
<WindowSurfaceX11Image
>(DefaultXDisplay(), mXWindow
,
141 mXVisual
, mXDepth
, mIsShaped
);
144 MOZ_RELEASE_ASSERT(false);
147 // We need to ignore thread safety checks here. We need to hold mMutex
148 // between StartRemoteDrawingInRegion()/EndRemoteDrawingInRegion() calls
149 // which confuses it.
150 MOZ_PUSH_IGNORE_THREAD_SAFETY
152 already_AddRefed
<gfx::DrawTarget
>
153 WindowSurfaceProvider::StartRemoteDrawingInRegion(
154 const LayoutDeviceIntRegion
& aInvalidRegion
,
155 layers::BufferMode
* aBufferMode
) {
156 if (aInvalidRegion
.IsEmpty()) {
160 // We return a reference to mWindowSurface inside draw target so we need to
161 // hold the mutex untill EndRemoteDrawingInRegion() call where draw target
163 // If we return null dt, EndRemoteDrawingInRegion() won't be called to
166 auto unlockMutex
= MakeScopeExit([&] { mMutex
.Unlock(); });
168 if (!mWindowSurfaceValid
) {
169 mWindowSurface
= nullptr;
170 mWindowSurfaceValid
= true;
173 if (!mWindowSurface
) {
174 mWindowSurface
= CreateWindowSurface();
175 if (!mWindowSurface
) {
180 *aBufferMode
= BufferMode::BUFFER_NONE
;
181 RefPtr
<gfx::DrawTarget
> dt
= mWindowSurface
->Lock(aInvalidRegion
);
183 if (!dt
&& GdkIsX11Display() && !mWindowSurface
->IsFallback()) {
184 // We can't use WindowSurfaceX11Image fallback on Wayland but
185 // Lock() call on WindowSurfaceWayland should never fail.
187 << "Failed to lock WindowSurface, falling back to XPutImage backend.";
188 mWindowSurface
= MakeRefPtr
<WindowSurfaceX11Image
>(
189 DefaultXDisplay(), mXWindow
, mXVisual
, mXDepth
, mIsShaped
);
190 dt
= mWindowSurface
->Lock(aInvalidRegion
);
194 // We have valid dt, mutex will be released in EndRemoteDrawingInRegion().
195 unlockMutex
.release();
201 void WindowSurfaceProvider::EndRemoteDrawingInRegion(
202 gfx::DrawTarget
* aDrawTarget
, const LayoutDeviceIntRegion
& aInvalidRegion
) {
203 // Unlock mutex from StartRemoteDrawingInRegion().
204 mMutex
.AssertCurrentThreadOwns();
205 auto unlockMutex
= MakeScopeExit([&] { mMutex
.Unlock(); });
207 // Commit to mWindowSurface only if we have a valid one.
208 if (!mWindowSurface
|| !mWindowSurfaceValid
) {
211 #if defined(MOZ_WAYLAND)
212 if (GdkIsWaylandDisplay()) {
213 // We're called too early or we're unmapped.
214 // Don't draw anything.
215 if (!mWidget
|| !mWidget
->IsMapped()) {
218 if (moz_container_wayland_is_commiting_to_parent(
219 mWidget
->GetMozContainer())) {
220 // If we're drawing directly to wl_surface owned by Gtk we need to use it
221 // in main thread to sync with Gtk access to it.
222 NS_DispatchToMainThread(NS_NewRunnableFunction(
223 "WindowSurfaceProvider::EndRemoteDrawingInRegion",
224 [widget
= RefPtr
{mWidget
}, this, aInvalidRegion
]() {
225 if (!widget
->IsMapped()) {
228 MutexAutoLock
lock(mMutex
);
229 // Commit to mWindowSurface only when we have a valid one.
230 if (mWindowSurface
&& mWindowSurfaceValid
) {
231 mWindowSurface
->Commit(aInvalidRegion
);
238 mWindowSurface
->Commit(aInvalidRegion
);
241 MOZ_POP_THREAD_SAFETY
243 } // namespace widget
244 } // namespace mozilla