Bug 1796130 [Wayland] Track and release Vsync frame callbacks so we don't get frame callback after nsWindow::Destroy() r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D160364
This commit is contained in:
stransky 2022-11-08 15:26:25 +00:00
parent ca6356c35d
commit 35f7c05de1
2 changed files with 24 additions and 13 deletions

View File

@ -38,19 +38,18 @@ namespace mozilla {
static void WaylandVsyncSourceCallbackHandler(void* aData, static void WaylandVsyncSourceCallbackHandler(void* aData,
struct wl_callback* aCallback, struct wl_callback* aCallback,
uint32_t aTime) { uint32_t aTime) {
WaylandVsyncSource* context = (WaylandVsyncSource*)aData; RefPtr<WaylandVsyncSource> context(static_cast<WaylandVsyncSource*>(aData));
wl_callback_destroy(aCallback); context->FrameCallback(aCallback, aTime);
context->FrameCallback(aTime);
}
static void WaylandVsyncSourceCallbackHandler(void* aData, uint32_t aTime) {
WaylandVsyncSource* context = (WaylandVsyncSource*)aData;
context->FrameCallback(aTime);
} }
static const struct wl_callback_listener WaylandVsyncSourceCallbackListener = { static const struct wl_callback_listener WaylandVsyncSourceCallbackListener = {
WaylandVsyncSourceCallbackHandler}; WaylandVsyncSourceCallbackHandler};
static void NativeLayerRootWaylandVsyncCallback(void* aData, uint32_t aTime) {
RefPtr<WaylandVsyncSource> context(static_cast<WaylandVsyncSource*>(aData));
context->FrameCallback(nullptr, aTime);
}
static float GetFPS(TimeDuration aVsyncRate) { static float GetFPS(TimeDuration aVsyncRate) {
return 1000.0 / aVsyncRate.ToMilliseconds(); return 1000.0 / aVsyncRate.ToMilliseconds();
} }
@ -207,7 +206,7 @@ void WaylandVsyncSource::SetupFrameCallback(const MutexAutoLock& aProofOfLock) {
if (mNativeLayerRoot) { if (mNativeLayerRoot) {
LOG(" use mNativeLayerRoot"); LOG(" use mNativeLayerRoot");
mNativeLayerRoot->RequestFrameCallback(&WaylandVsyncSourceCallbackHandler, mNativeLayerRoot->RequestFrameCallback(&NativeLayerRootWaylandVsyncCallback,
this); this);
} else { } else {
MozContainerSurfaceLock lock(mContainer); MozContainerSurfaceLock lock(mContainer);
@ -222,8 +221,9 @@ void WaylandVsyncSource::SetupFrameCallback(const MutexAutoLock& aProofOfLock) {
} }
LOG(" register frame callback"); LOG(" register frame callback");
wl_callback* callback = wl_surface_frame(surface); MozClearPointer(mCallback, wl_callback_destroy);
wl_callback_add_listener(callback, &WaylandVsyncSourceCallbackListener, mCallback = wl_surface_frame(surface);
wl_callback_add_listener(mCallback, &WaylandVsyncSourceCallbackListener,
this); this);
wl_surface_commit(surface); wl_surface_commit(surface);
wl_display_flush(WaylandDisplayGet()->GetDisplay()); wl_display_flush(WaylandDisplayGet()->GetDisplay());
@ -286,7 +286,7 @@ void WaylandVsyncSource::IdleCallback() {
} }
} }
void WaylandVsyncSource::FrameCallback(uint32_t aTime) { void WaylandVsyncSource::FrameCallback(wl_callback* aCallback, uint32_t aTime) {
LOG("WaylandVsyncSource::FrameCallback"); LOG("WaylandVsyncSource::FrameCallback");
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
@ -294,11 +294,20 @@ void WaylandVsyncSource::FrameCallback(uint32_t aTime) {
// This might enable vsync. // This might enable vsync.
RefPtr window = mWindow; RefPtr window = mWindow;
window->NotifyOcclusionState(OcclusionState::VISIBLE); window->NotifyOcclusionState(OcclusionState::VISIBLE);
// NotifyOcclusionState can destroy us.
if (window->IsDestroyed()) {
return;
}
} }
MutexAutoLock lock(mMutex); MutexAutoLock lock(mMutex);
mCallbackRequested = false; mCallbackRequested = false;
if (aCallback) {
MOZ_RELEASE_ASSERT(aCallback == mCallback);
MozClearPointer(mCallback, wl_callback_destroy);
}
if (!mVsyncEnabled || !mMonitorEnabled) { if (!mVsyncEnabled || !mMonitorEnabled) {
// We are unwanted by either our creator or our consumer, so we just stop // We are unwanted by either our creator or our consumer, so we just stop
// here without setting up a new frame callback. // here without setting up a new frame callback.
@ -404,6 +413,7 @@ void WaylandVsyncSource::Shutdown() {
mVsyncEnabled = false; mVsyncEnabled = false;
mCallbackRequested = false; mCallbackRequested = false;
MozClearHandleID(mIdleTimerID, g_source_remove); MozClearHandleID(mIdleTimerID, g_source_remove);
MozClearPointer(mCallback, wl_callback_destroy);
} }
} // namespace mozilla } // namespace mozilla

View File

@ -55,7 +55,7 @@ class WaylandVsyncSource final : public gfx::VsyncSource {
void EnableMonitor(); void EnableMonitor();
void DisableMonitor(); void DisableMonitor();
void FrameCallback(uint32_t aTime); void FrameCallback(wl_callback* aCallback, uint32_t aTime);
void IdleCallback(); void IdleCallback();
TimeDuration GetVsyncRate() override; TimeDuration GetVsyncRate() override;
@ -87,6 +87,7 @@ class WaylandVsyncSource final : public gfx::VsyncSource {
TimeDuration mVsyncRate MOZ_GUARDED_BY(mMutex); TimeDuration mVsyncRate MOZ_GUARDED_BY(mMutex);
TimeStamp mLastVsyncTimeStamp MOZ_GUARDED_BY(mMutex); TimeStamp mLastVsyncTimeStamp MOZ_GUARDED_BY(mMutex);
guint mIdleTimerID MOZ_GUARDED_BY(mMutex) = 0; guint mIdleTimerID MOZ_GUARDED_BY(mMutex) = 0;
wl_callback* mCallback MOZ_GUARDED_BY(mMutex) = nullptr;
nsWindow* const mWindow; // Main thread only, except for logging. nsWindow* const mWindow; // Main thread only, except for logging.
const guint mIdleTimeout; const guint mIdleTimeout;