Bug 1829303 [Wayland] Remove thread specific wayland display objects r=emilio

- Remove nsWaylandDisplay thread specific objects as we don't need them.
- Use nsWaylandDisplay as non-referenced objects. There's only a global one.
- Create nsWaylandDisplay global object in nsAppRunner when Firefox starts. That ensures we create it in main thread.
- Remove mEventQueue, we don't need it.
- Remove mSyncCallback, it's unused.

Differential Revision: https://phabricator.services.mozilla.com/D176125
This commit is contained in:
stransky 2023-04-22 06:08:08 +00:00
parent 1c6beb8f65
commit 3aefdbee32
10 changed files with 49 additions and 238 deletions

View file

@ -359,7 +359,7 @@ NativeLayerWayland::NativeLayerWayland(
MOZ_RELEASE_ASSERT(mSurfacePoolHandle,
"Need a non-null surface pool handle.");
RefPtr<widget::nsWaylandDisplay> waylandDisplay = widget::WaylandDisplayGet();
widget::nsWaylandDisplay* waylandDisplay = widget::WaylandDisplayGet();
wl_compositor* compositor = waylandDisplay->GetCompositor();
mWlSurface = wl_compositor_create_surface(compositor);

View file

@ -5112,6 +5112,15 @@ int XREMain::XRE_mainStartup(bool* aExitFlag) {
GfxInfo::FireGLXTestProcess();
#endif
#ifdef MOZ_WAYLAND
// Make sure we have wayland connection for main thread.
// It's used as template to create display connections
// for different threads.
if (IsWaylandEnabled()) {
MOZ_UNUSED(WaylandDisplayGet());
}
#endif
return 0;
}

View file

@ -713,7 +713,7 @@ bool DMABufSurfaceRGBA::CreateWlBuffer() {
return false;
}
RefPtr<nsWaylandDisplay> waylandDisplay = widget::WaylandDisplayGet();
nsWaylandDisplay* waylandDisplay = widget::WaylandDisplayGet();
if (!waylandDisplay->GetDmabuf()) {
CloseFileDescriptors(lockFD);
return false;

View file

@ -262,12 +262,12 @@ bool WakeLockTopic::InhibitXScreenSaver(bool inhibit) {
/* static */
bool WakeLockTopic::CheckWaylandIdleInhibitSupport() {
RefPtr<nsWaylandDisplay> waylandDisplay = WaylandDisplayGet();
nsWaylandDisplay* waylandDisplay = WaylandDisplayGet();
return waylandDisplay && waylandDisplay->GetIdleInhibitManager() != nullptr;
}
bool WakeLockTopic::InhibitWaylandIdle() {
RefPtr<nsWaylandDisplay> waylandDisplay = WaylandDisplayGet();
nsWaylandDisplay* waylandDisplay = WaylandDisplayGet();
if (!waylandDisplay) {
return false;
}

View file

@ -101,8 +101,8 @@ static int WaylandAllocateShmMemory(int aSize) {
}
/* static */
RefPtr<WaylandShmPool> WaylandShmPool::Create(
const RefPtr<nsWaylandDisplay>& aWaylandDisplay, int aSize) {
RefPtr<WaylandShmPool> WaylandShmPool::Create(nsWaylandDisplay* aWaylandDisplay,
int aSize) {
if (!aWaylandDisplay->GetShm()) {
NS_WARNING("Missing Wayland shm interface!");
return nullptr;
@ -128,10 +128,6 @@ RefPtr<WaylandShmPool> WaylandShmPool::Create(
return nullptr;
}
// We set our queue to get mShmPool events at compositor thread.
wl_proxy_set_queue((struct wl_proxy*)shmPool->mShmPool,
aWaylandDisplay->GetEventQueue());
return shmPool;
}
@ -193,7 +189,7 @@ void WaylandBuffer::BufferReleaseCallbackHandler(void* aData,
RefPtr<WaylandBufferSHM> WaylandBufferSHM::Create(
const LayoutDeviceIntSize& aSize) {
RefPtr<WaylandBufferSHM> buffer = new WaylandBufferSHM(aSize);
RefPtr<nsWaylandDisplay> waylandDisplay = WaylandDisplayGet();
nsWaylandDisplay* waylandDisplay = WaylandDisplayGet();
int size = aSize.width * aSize.height * BUFFER_BPP;
buffer->mShmPool = WaylandShmPool::Create(waylandDisplay, size);
@ -208,13 +204,11 @@ RefPtr<WaylandBufferSHM> WaylandBufferSHM::Create(
return nullptr;
}
wl_proxy_set_queue((struct wl_proxy*)buffer->GetWlBuffer(),
waylandDisplay->GetEventQueue());
wl_buffer_add_listener(buffer->GetWlBuffer(), &sBufferListenerWaylandBuffer,
buffer.get());
LOGWAYLAND("WaylandBufferSHM Created [%p] WaylandDisplay [%p]\n",
buffer.get(), waylandDisplay.get());
buffer.get(), waylandDisplay);
return buffer;
}
@ -282,9 +276,6 @@ RefPtr<WaylandBufferDMABUF> WaylandBufferDMABUF::Create(
return nullptr;
}
RefPtr<nsWaylandDisplay> waylandDisplay = WaylandDisplayGet();
wl_proxy_set_queue((struct wl_proxy*)buffer->GetWlBuffer(),
waylandDisplay->GetEventQueue());
wl_buffer_add_listener(buffer->GetWlBuffer(), &sBufferListenerWaylandBuffer,
buffer.get());

View file

@ -23,8 +23,8 @@ class WaylandShmPool {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WaylandShmPool);
static RefPtr<WaylandShmPool> Create(
const RefPtr<nsWaylandDisplay>& aWaylandDisplay, int aSize);
static RefPtr<WaylandShmPool> Create(nsWaylandDisplay* aWaylandDisplay,
int aSize);
wl_shm_pool* GetShmPool() { return mShmPool; };
void* GetImageData() { return mImageData; };

View file

@ -424,8 +424,5 @@ bool nsAppShell::ProcessNextNativeEvent(bool mayWait) {
return false;
}
bool didProcessEvent = g_main_context_iteration(nullptr, mayWait);
#ifdef MOZ_WAYLAND
mozilla::widget::WaylandDispatchDisplays();
#endif
return didProcessEvent;
}

View file

@ -22,81 +22,22 @@
namespace mozilla::widget {
// nsWaylandDisplay needs to be created for each calling thread(main thread,
// compositor thread and render thread)
#define MAX_DISPLAY_CONNECTIONS 10
GbmFormat nsWaylandDisplay::sXRGBFormat = {true, false, GBM_FORMAT_XRGB8888,
nullptr, 0};
GbmFormat nsWaylandDisplay::sARGBFormat = {true, true, GBM_FORMAT_ARGB8888,
nullptr, 0};
// 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() {
auto lock = gWaylandDisplays.Lock();
for (auto& display : *lock) {
if (display) {
display->DispatchEventQueue();
}
}
}
static nsWaylandDisplay* gWaylandDisplay;
void WaylandDisplayRelease() {
auto lock = gWaylandDisplays.Lock();
for (auto& display : *lock) {
if (display) {
display->ShutdownEventQueue();
// NOTE: Intentionally leaking the object as otherwise the TLS cache is
// stale.
}
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
"WaylandDisplay can be released in main thread only!");
if (!gWaylandDisplay) {
NS_WARNING("WaylandDisplayRelease(): Wayland display is missing!");
return;
}
}
// Get WaylandDisplay for given wl_display and actual calling thread.
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 : *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;
}
}
MOZ_CRASH("There's too many wayland display conections!");
return nullptr;
delete gWaylandDisplay;
gWaylandDisplay = nullptr;
}
wl_display* WaylandDisplayGetWLDisplay() {
@ -107,6 +48,19 @@ wl_display* WaylandDisplayGetWLDisplay() {
return gdk_wayland_display_get_wl_display(disp);
}
nsWaylandDisplay* WaylandDisplayGet() {
if (!gWaylandDisplay) {
MOZ_RELEASE_ASSERT(NS_IsMainThread(),
"WaylandDisplay can be created in main thread only!");
wl_display* waylandDisplay = WaylandDisplayGetWLDisplay();
if (!waylandDisplay) {
return nullptr;
}
gWaylandDisplay = new nsWaylandDisplay(waylandDisplay);
}
return gWaylandDisplay;
}
void nsWaylandDisplay::SetShm(wl_shm* aShm) { mShm = aShm; }
void nsWaylandDisplay::SetCompositor(wl_compositor* aCompositor) {
@ -206,49 +160,37 @@ static void global_registry_handler(void* data, wl_registry* registry,
if (strcmp(interface, "wl_shm") == 0) {
auto* shm = WaylandRegistryBind<wl_shm>(registry, id, &wl_shm_interface, 1);
wl_proxy_set_queue((struct wl_proxy*)shm, display->GetEventQueue());
display->SetShm(shm);
} else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0) {
auto* idle_inhibit_manager =
WaylandRegistryBind<zwp_idle_inhibit_manager_v1>(
registry, id, &zwp_idle_inhibit_manager_v1_interface, 1);
wl_proxy_set_queue((struct wl_proxy*)idle_inhibit_manager,
display->GetEventQueue());
display->SetIdleInhibitManager(idle_inhibit_manager);
} else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
auto* relative_pointer_manager =
WaylandRegistryBind<zwp_relative_pointer_manager_v1>(
registry, id, &zwp_relative_pointer_manager_v1_interface, 1);
wl_proxy_set_queue((struct wl_proxy*)relative_pointer_manager,
display->GetEventQueue());
display->SetRelativePointerManager(relative_pointer_manager);
} else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
auto* pointer_constraints = WaylandRegistryBind<zwp_pointer_constraints_v1>(
registry, id, &zwp_pointer_constraints_v1_interface, 1);
wl_proxy_set_queue((struct wl_proxy*)pointer_constraints,
display->GetEventQueue());
display->SetPointerConstraints(pointer_constraints);
} else if (strcmp(interface, "wl_compositor") == 0) {
// Requested wl_compositor version 4 as we need wl_surface_damage_buffer().
auto* compositor = WaylandRegistryBind<wl_compositor>(
registry, id, &wl_compositor_interface, 4);
wl_proxy_set_queue((struct wl_proxy*)compositor, display->GetEventQueue());
display->SetCompositor(compositor);
} else if (strcmp(interface, "wl_subcompositor") == 0) {
auto* subcompositor = WaylandRegistryBind<wl_subcompositor>(
registry, id, &wl_subcompositor_interface, 1);
wl_proxy_set_queue((struct wl_proxy*)subcompositor,
display->GetEventQueue());
display->SetSubcompositor(subcompositor);
} else if (strcmp(interface, "wp_viewporter") == 0) {
auto* viewporter = WaylandRegistryBind<wp_viewporter>(
registry, id, &wp_viewporter_interface, 1);
wl_proxy_set_queue((struct wl_proxy*)viewporter, display->GetEventQueue());
display->SetViewporter(viewporter);
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version > 2) {
auto* dmabuf = WaylandRegistryBind<zwp_linux_dmabuf_v1>(
registry, id, &zwp_linux_dmabuf_v1_interface, 3);
wl_proxy_set_queue((struct wl_proxy*)dmabuf, display->GetEventQueue());
display->SetDmabuf(dmabuf);
if (NS_IsMainThread()) {
zwp_linux_dmabuf_v1_add_listener(dmabuf, &dmabuf_listener, nullptr);
@ -273,92 +215,7 @@ static void global_registry_remover(void* data, wl_registry* registry,
static const struct wl_registry_listener registry_listener = {
global_registry_handler, global_registry_remover};
void nsWaylandDisplay::DispatchEventQueue() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (mEventQueue) {
wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
}
}
void nsWaylandDisplay::ShutdownEventQueue() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (mEventQueue) {
wl_event_queue_destroy(mEventQueue);
mEventQueue = nullptr;
}
}
void nsWaylandDisplay::SyncEnd() {
wl_callback_destroy(mSyncCallback);
mSyncCallback = nullptr;
}
static void wayland_sync_callback(void* data, struct wl_callback* callback,
uint32_t time) {
auto display = static_cast<nsWaylandDisplay*>(data);
display->SyncEnd();
}
static const struct wl_callback_listener sync_callback_listener = {
.done = wayland_sync_callback};
void nsWaylandDisplay::SyncBegin() {
WaitForSyncEnd();
// Use wl_display_sync() to synchronize wayland events.
// See dri2_wl_swap_buffers_with_damage() from MESA
// or wl_display_roundtrip_queue() from wayland-client.
struct wl_display* displayWrapper =
static_cast<wl_display*>(wl_proxy_create_wrapper((void*)mDisplay));
if (!displayWrapper) {
NS_WARNING("Failed to create wl_proxy wrapper!");
return;
}
wl_proxy_set_queue((struct wl_proxy*)displayWrapper, mEventQueue);
mSyncCallback = wl_display_sync(displayWrapper);
wl_proxy_wrapper_destroy((void*)displayWrapper);
if (!mSyncCallback) {
NS_WARNING("Failed to create wl_display_sync callback!");
return;
}
wl_callback_add_listener(mSyncCallback, &sync_callback_listener, this);
wl_display_flush(mDisplay);
}
void nsWaylandDisplay::QueueSyncBegin() {
RefPtr<nsWaylandDisplay> self(this);
NS_DispatchToMainThread(
NS_NewRunnableFunction("nsWaylandDisplay::QueueSyncBegin",
[self]() -> void { self->SyncBegin(); }));
}
void nsWaylandDisplay::WaitForSyncEnd() {
MOZ_RELEASE_ASSERT(
NS_IsMainThread(),
"nsWaylandDisplay::WaitForSyncEnd() can be called in main thread only!");
// We're done here
if (!mSyncCallback) {
return;
}
while (mSyncCallback != nullptr) {
// TODO: wl_display_dispatch_queue() should not be called while
// glib main loop is iterated at nsAppShell::ProcessNextNativeEvent().
if (wl_display_dispatch_queue(mDisplay, mEventQueue) == -1) {
NS_WARNING("wl_display_dispatch_queue failed!");
SyncEnd();
return;
}
}
}
bool nsWaylandDisplay::Matches(wl_display* aDisplay) {
return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
}
nsWaylandDisplay::~nsWaylandDisplay() {}
static void WlLogHandler(const char* format, va_list args) {
char error[1000];
@ -366,28 +223,16 @@ static void WlLogHandler(const char* format, va_list args) {
gfxCriticalNote << "Wayland protocol error: " << error;
}
// TODO: Make sure we always have nsWaylandDisplay for main thread
// and we keep it around.
nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay)
: mThreadId(PR_GetCurrentThread()), mDisplay(aDisplay) {
// GTK sets the log handler on display creation, thus we overwrite it here
// in a similar fashion
wl_log_set_handler_client(WlLogHandler);
wl_registry* registry = wl_display_get_registry(mDisplay);
wl_registry_add_listener(registry, &registry_listener, this);
if (!NS_IsMainThread()) {
mEventQueue = wl_display_create_queue(mDisplay);
wl_proxy_set_queue((struct wl_proxy*)registry, mEventQueue);
}
if (mEventQueue) {
wl_display_roundtrip_queue(mDisplay, mEventQueue);
wl_display_roundtrip_queue(mDisplay, mEventQueue);
} else {
wl_display_roundtrip(mDisplay);
wl_display_roundtrip(mDisplay);
}
wl_registry_destroy(registry);
mRegistry = wl_display_get_registry(mDisplay);
wl_registry_add_listener(mRegistry, &registry_listener, this);
wl_display_roundtrip(mDisplay);
wl_display_roundtrip(mDisplay);
// Check we have critical Wayland interfaces.
// Missing ones indicates a compositor bug and we can't continue.
@ -397,14 +242,4 @@ nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay)
"We're missing subcompositor interface!");
}
nsWaylandDisplay::~nsWaylandDisplay() {
ShutdownEventQueue();
if (NS_IsMainThread()) {
free(sARGBFormat.mModifiers);
sARGBFormat.mModifiers = nullptr;
free(sXRGBFormat.mModifiers);
sXRGBFormat.mModifiers = nullptr;
}
}
} // namespace mozilla::widget

View file

@ -36,24 +36,11 @@ struct GbmFormat {
// We have a global nsWaylandDisplay object for each thread.
class nsWaylandDisplay {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsWaylandDisplay)
// Create nsWaylandDisplay object on top of native Wayland wl_display
// connection.
explicit nsWaylandDisplay(wl_display* aDisplay);
void DispatchEventQueue();
void ShutdownEventQueue();
void SyncBegin();
void QueueSyncBegin();
void SyncEnd();
void WaitForSyncEnd();
bool Matches(wl_display* aDisplay);
wl_display* GetDisplay() { return mDisplay; };
wl_event_queue* GetEventQueue() { return mEventQueue; };
wl_compositor* GetCompositor() { return mCompositor; };
wl_subcompositor* GetSubcompositor() { return mSubcompositor; };
wl_shm* GetShm() { return mShm; };
@ -70,8 +57,6 @@ class nsWaylandDisplay {
zwp_linux_dmabuf_v1* GetDmabuf() { return mDmabuf; };
xdg_activation_v1* GetXdgActivation() { return mXdgActivation; };
bool IsMainThreadDisplay() { return mEventQueue == nullptr; }
void SetShm(wl_shm* aShm);
void SetCompositor(wl_compositor* aCompositor);
void SetSubcompositor(wl_subcompositor* aSubcompositor);
@ -84,22 +69,19 @@ class nsWaylandDisplay {
void SetDmabuf(zwp_linux_dmabuf_v1* aDmabuf);
void SetXdgActivation(xdg_activation_v1* aXdgActivation);
bool IsExplicitSyncEnabled() { return mExplicitSync; }
~nsWaylandDisplay();
static GbmFormat* GetGbmFormat(bool aHasAlpha);
static void AddFormatModifier(bool aHasAlpha, int aFormat,
uint32_t aModifierHi, uint32_t aModifierLo);
private:
~nsWaylandDisplay();
PRThread* mThreadId = nullptr;
wl_registry* mRegistry = nullptr;
wl_display* mDisplay = nullptr;
wl_event_queue* mEventQueue = nullptr;
wl_compositor* mCompositor = nullptr;
wl_subcompositor* mSubcompositor = nullptr;
wl_shm* mShm = nullptr;
wl_callback* mSyncCallback = nullptr;
zwp_idle_inhibit_manager_v1* mIdleInhibitManager = nullptr;
zwp_relative_pointer_manager_v1* mRelativePointerManager = nullptr;
zwp_pointer_constraints_v1* mPointerConstraints = nullptr;
@ -112,11 +94,9 @@ class nsWaylandDisplay {
static GbmFormat sARGBFormat;
};
void WaylandDispatchDisplays();
void WaylandDisplayRelease();
RefPtr<nsWaylandDisplay> WaylandDisplayGet();
wl_display* WaylandDisplayGetWLDisplay();
nsWaylandDisplay* WaylandDisplayGet();
void WaylandDisplayRelease();
} // namespace widget
} // namespace mozilla

View file

@ -423,7 +423,6 @@ class nsWindow final : public nsBaseWidget {
void SetEGLNativeWindowSize(const LayoutDeviceIntSize& aEGLWindowSize);
void WaylandDragWorkaround(GdkEventButton* aEvent);
wl_display* GetWaylandDisplay();
void CreateCompositorVsyncDispatcher() override;
LayoutDeviceIntPoint GetNativePointerLockCenter() {
return mNativePointerLockCenter;