Bug 1825170 - [wayland] Improve access to nsWaylandDisplay. r=stransky

As above, but with a bit more type safety, plus a TLS cache so we don't
need to lock in the common case we have already initialized the wayland
display.

Differential Revision: https://phabricator.services.mozilla.com/D173964
This commit is contained in:
Emilio Cobos Álvarez 2023-03-30 09:36:31 +00:00
Родитель a5c0f1918b
Коммит 35becb740f
3 изменённых файлов: 70 добавлений и 58 удалений

Просмотреть файл

@ -898,15 +898,14 @@ std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplayLocked(
} else {
void* nativeDisplay = EGL_DEFAULT_DISPLAY;
#ifdef MOZ_WAYLAND
GdkDisplay* gdkDisplay = gdk_display_get_default();
if (!gdkDisplay) {
if (!gdk_display_get_default()) {
ret = GetAndInitDeviceDisplay(*this, aProofOfLock);
if (!ret) {
ret = GetAndInitSurfacelessDisplay(*this, aProofOfLock);
}
} else if (widget::GdkIsWaylandDisplay(gdkDisplay)) {
} else if (widget::GdkIsWaylandDisplay()) {
// Wayland does not support EGL_DEFAULT_DISPLAY
nativeDisplay = widget::WaylandDisplayGetWLDisplay(gdkDisplay);
nativeDisplay = widget::WaylandDisplayGetWLDisplay();
if (!nativeDisplay) {
NS_WARNING("Failed to get wl_display.");
return nullptr;

Просмотреть файл

@ -1,6 +1,5 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:expandtab:shiftwidth=4:tabstop=4:
*/
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
@ -12,30 +11,30 @@
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for NewRunnableMethod, etc
#include "mozilla/StaticMutex.h"
#include "mozilla/Array.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/StaticPrefs_widget.h"
#include "WidgetUtilsGtk.h"
struct _GdkSeat;
typedef struct _GdkSeat GdkSeat;
namespace mozilla {
namespace widget {
namespace mozilla::widget {
// nsWaylandDisplay needs to be created for each calling thread(main thread,
// compositor thread and render thread)
#define MAX_DISPLAY_CONNECTIONS 10
// An array of active wayland displays. We need a display for every thread
// where is wayland interface used as we need to dispatch waylands events
// there.
static RefPtr<nsWaylandDisplay> gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
static StaticMutex gWaylandDisplayArrayWriteMutex MOZ_UNANNOTATED;
// An array of active Wayland displays. We need a display for every thread
// where Wayland interface used as we need to dispatch Wayland's events there.
static StaticDataMutex<
Array<StaticRefPtr<nsWaylandDisplay>, MAX_DISPLAY_CONNECTIONS>>
gWaylandDisplays{"gWaylandDisplays"};
MOZ_THREAD_LOCAL(nsWaylandDisplay*) sTLSDisplay;
// Dispatch events to Compositor/Render queues
void WaylandDispatchDisplays() {
MOZ_ASSERT(NS_IsMainThread(),
"WaylandDispatchDisplays() is supposed to run in main thread");
for (auto& display : gWaylandDisplays) {
auto lock = gWaylandDisplays.Lock();
for (auto& display : *lock) {
if (display) {
display->DispatchEventQueue();
}
@ -43,49 +42,61 @@ void WaylandDispatchDisplays() {
}
void WaylandDisplayRelease() {
StaticMutexAutoLock lock(gWaylandDisplayArrayWriteMutex);
for (auto& display : gWaylandDisplays) {
auto lock = gWaylandDisplays.Lock();
for (auto& display : *lock) {
if (display) {
display = nullptr;
display->ShutdownEventQueue();
// NOTE: Intentionally leaking the object as otherwise the TLS cache is
// stale.
}
}
}
// Get WaylandDisplay for given wl_display and actual calling thread.
RefPtr<nsWaylandDisplay> WaylandDisplayGet(GdkDisplay* aGdkDisplay) {
wl_display* waylandDisplay = WaylandDisplayGetWLDisplay(aGdkDisplay);
RefPtr<nsWaylandDisplay> WaylandDisplayGet() {
bool hasTLS = false;
if (MOZ_LIKELY(sTLSDisplay.init())) {
if (auto* disp = sTLSDisplay.get()) {
return disp;
}
hasTLS = true;
}
wl_display* waylandDisplay = WaylandDisplayGetWLDisplay();
if (!waylandDisplay) {
return nullptr;
}
RefPtr<nsWaylandDisplay> ret;
if (MOZ_LIKELY(hasTLS)) {
ret = new nsWaylandDisplay(waylandDisplay);
sTLSDisplay.set(ret.get());
}
auto lock = gWaylandDisplays.Lock();
// Search existing display connections for wl_display:thread combination.
for (auto& display : gWaylandDisplays) {
if (display && display->Matches(waylandDisplay)) {
for (auto& display : *lock) {
if (display) {
if (display->Matches(waylandDisplay)) {
MOZ_ASSERT(!hasTLS, "We shouldn't have got here");
return display;
}
} else {
display = ret ? ret.get() : new nsWaylandDisplay(waylandDisplay);
return display;
}
}
StaticMutexAutoLock arrayLock(gWaylandDisplayArrayWriteMutex);
for (auto& display : gWaylandDisplays) {
if (display == nullptr) {
display = new nsWaylandDisplay(waylandDisplay);
return display;
}
}
MOZ_CRASH("There's too many wayland display conections!");
return nullptr;
}
wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay) {
if (!aGdkDisplay) {
aGdkDisplay = gdk_display_get_default();
if (!GdkIsWaylandDisplay(aGdkDisplay)) {
return nullptr;
}
wl_display* WaylandDisplayGetWLDisplay() {
GdkDisplay* disp = gdk_display_get_default();
if (!GdkIsWaylandDisplay(disp)) {
return nullptr;
}
return gdk_wayland_display_get_wl_display(aGdkDisplay);
return gdk_wayland_display_get_wl_display(disp);
}
void nsWaylandDisplay::SetShm(wl_shm* aShm) { mShm = aShm; }
@ -192,11 +203,19 @@ static void global_registry_remover(void* data, wl_registry* registry,
static const struct wl_registry_listener registry_listener = {
global_registry_handler, global_registry_remover};
bool nsWaylandDisplay::DispatchEventQueue() {
void nsWaylandDisplay::DispatchEventQueue() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (mEventQueue) {
wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
}
return true;
}
void nsWaylandDisplay::ShutdownEventQueue() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (mEventQueue) {
wl_event_queue_destroy(mEventQueue);
mEventQueue = nullptr;
}
}
void nsWaylandDisplay::SyncEnd() {
@ -304,13 +323,6 @@ nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay)
"We're missing subcompositor interface!");
}
nsWaylandDisplay::~nsWaylandDisplay() {
if (mEventQueue) {
wl_event_queue_destroy(mEventQueue);
mEventQueue = nullptr;
}
mDisplay = nullptr;
}
nsWaylandDisplay::~nsWaylandDisplay() { ShutdownEventQueue(); }
} // namespace widget
} // namespace mozilla
} // namespace mozilla::widget

Просмотреть файл

@ -34,7 +34,8 @@ class nsWaylandDisplay {
// connection.
explicit nsWaylandDisplay(wl_display* aDisplay);
bool DispatchEventQueue();
void DispatchEventQueue();
void ShutdownEventQueue();
void SyncBegin();
void QueueSyncBegin();
@ -99,8 +100,8 @@ class nsWaylandDisplay {
void WaylandDispatchDisplays();
void WaylandDisplayRelease();
RefPtr<nsWaylandDisplay> WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay = nullptr);
RefPtr<nsWaylandDisplay> WaylandDisplayGet();
wl_display* WaylandDisplayGetWLDisplay();
} // namespace widget
} // namespace mozilla