Bug 1517205 - Make nsWaylandDisplay() global, r=lsalzman

Lazilly create nsWaylandDisplay objects and remove them at Firefox quit.

nsWaylandDisplay objects should stay as global objects and don't be created/released.
The creation/removal wastes resources on server side as the wl_registry objects at nsWaylandDisplay has to be stored at server
side and can't be removed until firefox ends [1] anyway.

Also the removed nsWaylandDisplay causes crashes when display
topology changes due to the global nature of the wl_registry.

[1] https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_registry

Differential Revision: https://phabricator.services.mozilla.com/D26673

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Martin Stransky 2019-04-09 21:39:51 +00:00
Родитель 7ebd463919
Коммит 1ffeea40ca
5 изменённых файлов: 33 добавлений и 60 удалений

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

@ -413,16 +413,6 @@ WindowSurfaceWayland::~WindowSurfaceWayland() {
delete mBackupBuffer[i];
}
}
if (!mIsMainThread) {
// We can be destroyed from main thread even though we was created/used
// in compositor thread. We have to unref/delete WaylandDisplay in
// compositor thread then and we can't use MessageLoop::current() here.
mDisplayThreadMessageLoop->PostTask(NewRunnableFunction(
"WaylandDisplayRelease", &WaylandDisplayRelease, mWaylandDisplay));
} else {
WaylandDisplayRelease(mWaylandDisplay);
}
}
WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth,

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

@ -610,7 +610,6 @@ struct wl_surface *moz_container_get_wl_surface(MozContainer *container) {
wl_surface_commit(container->surface);
wl_display_flush(waylandDisplay->GetDisplay());
WaylandDisplayRelease(waylandDisplay);
}
LOGWAYLAND(("%s [%p] created surface %p\n", __FUNCTION__, (void *)container,

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

@ -639,7 +639,6 @@ static gboolean offer_hash_remove(gpointer wl_offer, gpointer aDataOffer,
nsRetrievalContextWayland::~nsRetrievalContextWayland(void) {
g_hash_table_foreach_remove(mActiveOffers, offer_hash_remove, nullptr);
g_hash_table_destroy(mActiveOffers);
WaylandDisplayRelease(mDisplay);
}
GdkAtom *nsRetrievalContextWayland::GetTargets(int32_t aWhichClipboard,

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

@ -21,6 +21,13 @@ namespace widget {
static nsWaylandDisplay *gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
static StaticMutex gWaylandDisplaysMutex;
static void ReleaseDisplaysAtExit() {
for (int i = 0; i < MAX_DISPLAY_CONNECTIONS; i++) {
delete gWaylandDisplays[i];
gWaylandDisplays[i] = nullptr;
}
}
// Each thread which is using wayland connection (wl_display) has to operate
// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
@ -31,19 +38,24 @@ static StaticMutex gWaylandDisplaysMutex;
static void WaylandDisplayLoop(wl_display *aDisplay);
// Get WaylandDisplay for given wl_display and actual calling thread.
static nsWaylandDisplay *WaylandDisplayGetLocked(wl_display *aDisplay,
static nsWaylandDisplay *WaylandDisplayGetLocked(GdkDisplay *aGdkDisplay,
const StaticMutexAutoLock &) {
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
wl_display *waylandDisplay = sGdkWaylandDisplayGetWlDisplay(aGdkDisplay);
// Search existing display connections for wl_display:thread combination.
for (auto &display : gWaylandDisplays) {
if (display && display->Matches(aDisplay)) {
NS_ADDREF(display);
if (display && display->Matches(waylandDisplay)) {
return display;
}
}
for (auto &display : gWaylandDisplays) {
if (display == nullptr) {
display = new nsWaylandDisplay(aDisplay);
NS_ADDREF(display);
display = new nsWaylandDisplay(waylandDisplay);
atexit(ReleaseDisplaysAtExit);
return display;
}
}
@ -57,34 +69,8 @@ nsWaylandDisplay *WaylandDisplayGet(GdkDisplay *aGdkDisplay) {
aGdkDisplay = gdk_display_get_default();
}
// Available as of GTK 3.8+
static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
wl_display *display = sGdkWaylandDisplayGetWlDisplay(aGdkDisplay);
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
return WaylandDisplayGetLocked(display, lock);
}
static bool WaylandDisplayReleaseLocked(nsWaylandDisplay *aDisplay,
const StaticMutexAutoLock &) {
for (auto &display : gWaylandDisplays) {
if (display == aDisplay) {
int rc = display->Release();
if (rc == 0) {
display = nullptr;
}
return true;
}
}
MOZ_ASSERT(false, "Missing nsWaylandDisplay for this thread!");
return false;
}
void WaylandDisplayRelease(nsWaylandDisplay *aDisplay) {
StaticMutexAutoLock lock(gWaylandDisplaysMutex);
WaylandDisplayReleaseLocked(aDisplay, lock);
return WaylandDisplayGetLocked(aGdkDisplay, lock);
}
static void WaylandDisplayLoopLocked(wl_display *aDisplay,
@ -130,6 +116,8 @@ static void global_registry_handler(void *data, wl_registry *registry,
uint32_t id, const char *interface,
uint32_t version) {
auto display = reinterpret_cast<nsWaylandDisplay *>(data);
if (!display)
return;
if (strcmp(interface, "wl_shm") == 0) {
auto shm = static_cast<wl_shm *>(
@ -180,9 +168,7 @@ bool nsWaylandDisplay::Matches(wl_display *aDisplay) {
return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
}
NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay)
: mThreadId(PR_GetCurrentThread()),
mDisplay(aDisplay),
mEventQueue(nullptr),
@ -190,9 +176,10 @@ nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
mSubcompositor(nullptr),
mSeat(nullptr),
mShm(nullptr),
mPrimarySelectionDeviceManager(nullptr) {
wl_registry *registry = wl_display_get_registry(mDisplay);
wl_registry_add_listener(registry, &registry_listener, this);
mPrimarySelectionDeviceManager(nullptr),
mRegistry(nullptr) {
mRegistry = wl_display_get_registry(mDisplay);
wl_registry_add_listener(mRegistry, &registry_listener, this);
if (NS_IsMainThread()) {
// Use default event queue in main thread operated by Gtk+.
@ -203,17 +190,19 @@ nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
mEventQueue = wl_display_create_queue(mDisplay);
MessageLoop::current()->PostTask(NewRunnableFunction(
"WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue);
wl_proxy_set_queue((struct wl_proxy *)mRegistry, mEventQueue);
wl_display_roundtrip_queue(mDisplay, mEventQueue);
wl_display_roundtrip_queue(mDisplay, mEventQueue);
}
}
nsWaylandDisplay::~nsWaylandDisplay() {
MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
// Owned by Gtk+, we don't need to release
mDisplay = nullptr;
wl_registry_destroy(mRegistry);
mRegistry = nullptr;
if (mEventQueue) {
wl_event_queue_destroy(mEventQueue);
mEventQueue = nullptr;

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

@ -20,11 +20,10 @@ namespace widget {
// Our general connection to Wayland display server,
// holds our display connection and runs event loop.
class nsWaylandDisplay : public nsISupports {
NS_DECL_THREADSAFE_ISUPPORTS
class nsWaylandDisplay {
public:
explicit nsWaylandDisplay(wl_display* aDisplay);
virtual ~nsWaylandDisplay();
bool DisplayLoop();
bool Matches(wl_display* aDisplay);
@ -41,7 +40,6 @@ class nsWaylandDisplay : public nsISupports {
return mPrimarySelectionDeviceManager;
};
public:
void SetShm(wl_shm* aShm);
void SetSubcompositor(wl_subcompositor* aSubcompositor);
void SetDataDeviceManager(wl_data_device_manager* aDataDeviceManager);
@ -49,9 +47,7 @@ class nsWaylandDisplay : public nsISupports {
void SetPrimarySelectionDeviceManager(
gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager);
private:
virtual ~nsWaylandDisplay();
private:
PRThread* mThreadId;
wl_display* mDisplay;
wl_event_queue* mEventQueue;
@ -60,10 +56,10 @@ class nsWaylandDisplay : public nsISupports {
wl_seat* mSeat;
wl_shm* mShm;
gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager;
wl_registry *mRegistry;
};
nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
void WaylandDisplayRelease(nsWaylandDisplay* aDisplay);
} // namespace widget
} // namespace mozilla