Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / gtk / WindowSurfaceProvider.cpp
blobc8b2c5a7d65cfab2f9b865d03747166cdc487fe9
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"
13 #include "nsWindow.h"
14 #include "mozilla/ScopeExit.h"
16 #ifdef MOZ_WAYLAND
17 # include "mozilla/StaticPrefs_widget.h"
18 # include "WindowSurfaceWaylandMultiBuffer.h"
19 #endif
20 #ifdef MOZ_X11
21 # include "mozilla/X11Util.h"
22 # include "WindowSurfaceX11Image.h"
23 # include "WindowSurfaceX11SHM.h"
24 #endif
26 #undef LOG
27 #ifdef MOZ_LOGGING
28 # include "mozilla/Logging.h"
29 # include "nsTArray.h"
30 # include "Units.h"
31 extern mozilla::LazyLogModule gWidgetLog;
32 # define LOG(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args)
33 #else
34 # define LOG(args)
35 #endif /* MOZ_LOGGING */
37 namespace mozilla {
38 namespace widget {
40 using namespace mozilla::layers;
42 WindowSurfaceProvider::WindowSurfaceProvider()
43 : mWindowSurface(nullptr),
44 mMutex("WindowSurfaceProvider"),
45 mWindowSurfaceValid(false)
46 #ifdef MOZ_X11
48 mIsShaped(false),
49 mXDepth(0),
50 mXWindow(0),
51 mXVisual(nullptr)
52 #endif
56 WindowSurfaceProvider::~WindowSurfaceProvider() {
57 #ifdef MOZ_WAYLAND
58 MOZ_DIAGNOSTIC_ASSERT(!mWidget,
59 "nsWindow reference is still live, we're leaking it!");
60 #endif
61 #ifdef MOZ_X11
62 MOZ_DIAGNOSTIC_ASSERT(!mXWindow, "mXWindow should be released on quit!");
63 #endif
66 #ifdef MOZ_WAYLAND
67 bool WindowSurfaceProvider::Initialize(RefPtr<nsWindow> aWidget) {
68 mWindowSurfaceValid = false;
69 mWidget = std::move(aWidget);
70 return true;
72 bool WindowSurfaceProvider::Initialize(GtkCompositorWidget* aCompositorWidget) {
73 mWindowSurfaceValid = false;
74 mCompositorWidget = aCompositorWidget;
75 mWidget = static_cast<nsWindow*>(aCompositorWidget->RealWidget());
76 return true;
78 #endif
79 #ifdef MOZ_X11
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!");
87 return false;
90 mXWindow = aWindow;
91 mXVisual = windowAttrs.visual;
92 mXDepth = windowAttrs.depth;
93 mIsShaped = aIsShaped;
94 return true;
96 #endif
98 void WindowSurfaceProvider::CleanupResources() {
99 MutexAutoLock lock(mMutex);
100 mWindowSurfaceValid = false;
101 #ifdef MOZ_WAYLAND
102 mWidget = nullptr;
103 #endif
104 #ifdef MOZ_X11
105 mXWindow = 0;
106 mXVisual = 0;
107 mXDepth = 0;
108 mIsShaped = false;
109 #endif
112 RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
113 #ifdef MOZ_WAYLAND
114 if (GdkIsWaylandDisplay()) {
115 // We're called too early or we're unmapped.
116 if (!mWidget) {
117 return nullptr;
119 return MakeRefPtr<WindowSurfaceWaylandMB>(mWidget, mCompositorWidget);
121 #endif
122 #ifdef MOZ_X11
123 if (GdkIsX11Display()) {
124 // We're called too early or we're unmapped.
125 if (!mXWindow) {
126 return nullptr;
128 // Blit to the window with the following priority:
129 // 1. MIT-SHM
130 // 2. XPutImage
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,
135 mXVisual, mXDepth);
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);
143 #endif
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()) {
157 return nullptr;
160 // We return a reference to mWindowSurface inside draw target so we need to
161 // hold the mutex untill EndRemoteDrawingInRegion() call where draw target
162 // is returned.
163 // If we return null dt, EndRemoteDrawingInRegion() won't be called to
164 // release mutex.
165 mMutex.Lock();
166 auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
168 if (!mWindowSurfaceValid) {
169 mWindowSurface = nullptr;
170 mWindowSurfaceValid = true;
173 if (!mWindowSurface) {
174 mWindowSurface = CreateWindowSurface();
175 if (!mWindowSurface) {
176 return nullptr;
180 *aBufferMode = BufferMode::BUFFER_NONE;
181 RefPtr<gfx::DrawTarget> dt = mWindowSurface->Lock(aInvalidRegion);
182 #ifdef MOZ_X11
183 if (!dt && GdkIsX11Display() && !mWindowSurface->IsFallback()) {
184 // We can't use WindowSurfaceX11Image fallback on Wayland but
185 // Lock() call on WindowSurfaceWayland should never fail.
186 gfxWarningOnce()
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);
192 #endif
193 if (dt) {
194 // We have valid dt, mutex will be released in EndRemoteDrawingInRegion().
195 unlockMutex.release();
198 return dt.forget();
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) {
209 return;
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()) {
216 return;
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()) {
226 return;
228 MutexAutoLock lock(mMutex);
229 // Commit to mWindowSurface only when we have a valid one.
230 if (mWindowSurface && mWindowSurfaceValid) {
231 mWindowSurface->Commit(aInvalidRegion);
233 }));
234 return;
237 #endif
238 mWindowSurface->Commit(aInvalidRegion);
241 MOZ_POP_THREAD_SAFETY
243 } // namespace widget
244 } // namespace mozilla