1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WindowSurfaceProvider.h"
#include "gfxPlatformGtk.h"
#include "GtkCompositorWidget.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsWindow.h"
#include "mozilla/ScopeExit.h"
#include "WidgetUtilsGtk.h"
#ifdef MOZ_WAYLAND
# include "mozilla/StaticPrefs_widget.h"
# include "WindowSurfaceCairo.h"
# include "WindowSurfaceWaylandMultiBuffer.h"
#endif
#ifdef MOZ_X11
# include "mozilla/X11Util.h"
# include "WindowSurfaceX11Image.h"
# include "WindowSurfaceX11SHM.h"
#endif
#undef LOG
#ifdef MOZ_LOGGING
# include "mozilla/Logging.h"
# include "nsTArray.h"
# include "Units.h"
extern mozilla::LazyLogModule gWidgetLog;
# define LOG(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args)
#else
# define LOG(args)
#endif /* MOZ_LOGGING */
namespace mozilla {
namespace widget {
using namespace mozilla::layers;
WindowSurfaceProvider::WindowSurfaceProvider()
: mWindowSurface(nullptr),
mMutex("WindowSurfaceProvider"),
mWindowSurfaceValid(false)
#ifdef MOZ_X11
,
mXDepth(0),
mXWindow(0),
mXVisual(nullptr)
#endif
{
}
WindowSurfaceProvider::~WindowSurfaceProvider() {
#ifdef MOZ_WAYLAND
MOZ_DIAGNOSTIC_ASSERT(!mWidget,
"nsWindow reference is still live, we're leaking it!");
#endif
#ifdef MOZ_X11
MOZ_DIAGNOSTIC_ASSERT(!mXWindow, "mXWindow should be released on quit!");
#endif
}
#ifdef MOZ_WAYLAND
bool WindowSurfaceProvider::Initialize(RefPtr<nsWindow> aWidget) {
mWindowSurfaceValid = false;
mWidget = std::move(aWidget);
return true;
}
bool WindowSurfaceProvider::Initialize(GtkCompositorWidget* aCompositorWidget) {
mWindowSurfaceValid = false;
mCompositorWidget = aCompositorWidget;
mWidget = static_cast<nsWindow*>(aCompositorWidget->RealWidget());
return true;
}
#endif
#ifdef MOZ_X11
bool WindowSurfaceProvider::Initialize(Window aWindow) {
mWindowSurfaceValid = false;
// Grab the window's visual and depth
XWindowAttributes windowAttrs;
if (!XGetWindowAttributes(DefaultXDisplay(), aWindow, &windowAttrs)) {
NS_WARNING("GtkCompositorWidget(): XGetWindowAttributes() failed!");
return false;
}
mXWindow = aWindow;
mXVisual = windowAttrs.visual;
mXDepth = windowAttrs.depth;
return true;
}
#endif
void WindowSurfaceProvider::CleanupResources() {
MutexAutoLock lock(mMutex);
mWindowSurfaceValid = false;
#ifdef MOZ_WAYLAND
mWidget = nullptr;
#endif
#ifdef MOZ_X11
mXWindow = 0;
mXVisual = 0;
mXDepth = 0;
#endif
}
RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
#ifdef MOZ_WAYLAND
if (GdkIsWaylandDisplay()) {
// We're called too early or we're unmapped.
if (!mWidget) {
return nullptr;
}
if (mWidget->IsDragPopup()) {
return MakeRefPtr<WindowSurfaceCairo>(mWidget);
}
return MakeRefPtr<WindowSurfaceWaylandMB>(mWidget, mCompositorWidget);
}
#endif
#ifdef MOZ_X11
if (GdkIsX11Display()) {
// We're called too early or we're unmapped.
if (!mXWindow) {
return nullptr;
}
// Blit to the window with the following priority:
// 1. MIT-SHM
// 2. XPutImage
# ifdef MOZ_HAVE_SHMIMAGE
if (nsShmImage::UseShm()) {
LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", (Window)mXWindow));
return MakeRefPtr<WindowSurfaceX11SHM>(DefaultXDisplay(), mXWindow,
mXVisual, mXDepth);
}
# endif // MOZ_HAVE_SHMIMAGE
LOG(("Drawing to Window 0x%lx will use XPutImage\n", (Window)mXWindow));
return MakeRefPtr<WindowSurfaceX11Image>(DefaultXDisplay(), mXWindow,
mXVisual, mXDepth);
}
#endif
MOZ_RELEASE_ASSERT(false);
}
// We need to ignore thread safety checks here. We need to hold mMutex
// between StartRemoteDrawingInRegion()/EndRemoteDrawingInRegion() calls
// which confuses it.
MOZ_PUSH_IGNORE_THREAD_SAFETY
already_AddRefed<gfx::DrawTarget>
WindowSurfaceProvider::StartRemoteDrawingInRegion(
const LayoutDeviceIntRegion& aInvalidRegion) {
if (aInvalidRegion.IsEmpty()) {
return nullptr;
}
// We return a reference to mWindowSurface inside draw target so we need to
// hold the mutex untill EndRemoteDrawingInRegion() call where draw target
// is returned.
// If we return null dt, EndRemoteDrawingInRegion() won't be called to
// release mutex.
mMutex.Lock();
auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
if (!mWindowSurfaceValid) {
mWindowSurface = nullptr;
mWindowSurfaceValid = true;
}
if (!mWindowSurface) {
mWindowSurface = CreateWindowSurface();
if (!mWindowSurface) {
return nullptr;
}
}
RefPtr<gfx::DrawTarget> dt = mWindowSurface->Lock(aInvalidRegion);
#ifdef MOZ_X11
if (!dt && GdkIsX11Display() && !mWindowSurface->IsFallback()) {
// We can't use WindowSurfaceX11Image fallback on Wayland but
// Lock() call on WindowSurfaceWayland should never fail.
gfxWarningOnce()
<< "Failed to lock WindowSurface, falling back to XPutImage backend.";
mWindowSurface = MakeRefPtr<WindowSurfaceX11Image>(
DefaultXDisplay(), mXWindow, mXVisual, mXDepth);
dt = mWindowSurface->Lock(aInvalidRegion);
}
#endif
if (dt) {
// We have valid dt, mutex will be released in EndRemoteDrawingInRegion().
unlockMutex.release();
}
return dt.forget();
}
void WindowSurfaceProvider::EndRemoteDrawingInRegion(
gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
// Unlock mutex from StartRemoteDrawingInRegion().
mMutex.AssertCurrentThreadOwns();
auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
// Commit to mWindowSurface only if we have a valid one.
if (!mWindowSurface || !mWindowSurfaceValid) {
return;
}
#if defined(MOZ_WAYLAND)
if (GdkIsWaylandDisplay()) {
// We're called too early or we're unmapped.
// Don't draw anything.
if (!mWidget || !mWidget->IsMapped()) {
return;
}
}
#endif
mWindowSurface->Commit(aInvalidRegion);
}
MOZ_POP_THREAD_SAFETY
} // namespace widget
} // namespace mozilla
|