/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=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/. */
#ifdef MOZ_WAYLAND
# include "WaylandVsyncSource.h" # include "mozilla/UniquePtr.h" # include "nsThreadUtils.h" # include "nsISupportsImpl.h" # include "MainThreadUtils.h" # include "mozilla/ScopeExit.h" # include "nsGtkUtils.h" # include "mozilla/StaticPrefs_layout.h" # include "mozilla/StaticPrefs_widget.h" # include "nsWindow.h"
Maybe<TimeDuration> WaylandVsyncSource::GetFastestVsyncRate() {
Maybe<TimeDuration> retVal; for (auto* source : gWaylandVsyncSources) { auto rate = source->GetVsyncRateIfEnabled(); if (!rate) { continue;
} if (!retVal.isSome()) {
retVal.emplace(*rate);
} elseif (*rate < *retVal) {
retVal.ref() = *rate;
}
}
return retVal;
}
// Lint forces us to take this reference outside of constructor void WaylandVsyncSource::Init() {
MutexAutoLock lock(mMutex);
WaylandSurfaceLock surfaceLock(mWaylandSurface);
// mWaylandSurface is shared and referenced by nsWindow, // MozContained and WaylandVsyncSource. // // All references are explicitly removed at nsWindow::Destroy() // by WaylandVsyncSource::Shutdown() and // releases mWaylandSurface / MozContainer release. // // WaylandVsyncSource can be used by layour code after // nsWindow::Destroy()/WaylandVsyncSource::Shutdown() but // only as an empty shell.
mWaylandSurface->AddPersistentFrameCallbackLocked(
surfaceLock,
[this, self = RefPtr{this}](wl_callback* aCallback,
uint32_t aTime) -> void {
{
MutexAutoLock lock(mMutex); if (!mVsyncSourceEnabled || !mVsyncEnabled || !mWaylandSurface) { return;
} if (aTime && mLastFrameTime == aTime) { return;
}
mLastFrameTime = aTime;
}
LOG("WaylandVsyncSource frame callback, routed %d time %d", !aCallback,
aTime);
VisibleWindowCallback(aTime);
// If attached WaylandSurface becomes hidden/obscured or unmapped, // we will not get any regular frame callback any more and we will // not get any notification of it. // So always set up hidden window callback to catch it up.
SetHiddenWindowVSync();
}, /* aEmulateFrameCallback */ true);
}
void WaylandVsyncSource::SetHiddenWindowVSync() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); if (!mHiddenWindowTimerID) {
LOG("WaylandVsyncSource::SetHiddenWindowVSync()");
mHiddenWindowTimerID = g_timeout_add(
mHiddenWindowTimeout,
[](void* data) -> gint {
RefPtr vsync = static_cast<WaylandVsyncSource*>(data); if (vsync->HiddenWindowCallback()) { // We want to fire again, so don't clear mHiddenWindowTimerID return G_SOURCE_CONTINUE;
} // No need for g_source_remove, caller does it for us.
vsync->mHiddenWindowTimerID = 0; return G_SOURCE_REMOVE;
}, this);
}
}
if (!mVsyncSourceEnabled || !mVsyncEnabled) { // We are unwanted by either our creator or our consumer, so we just stop // here without setting up a new frame callback.
LOG("WaylandVsyncSource::HiddenWindowCallback(): quit, mVsyncEnabled %d " "mWaylandSurface %p",
mVsyncEnabled && mVsyncSourceEnabled, mWaylandSurface.get()); returnfalse;
}
constauto now = TimeStamp::Now(); constauto timeSinceLastVSync = now - mLastVsyncTimeStamp; if (timeSinceLastVSync.ToMilliseconds() < mHiddenWindowTimeout) { // We're not hidden, keep firing the callback to monitor window state. // If we become hidden we want set window occlusion state from this // callback. returntrue;
}
LOG("WaylandVsyncSource::HiddenWindowCallback() we're hidden, time since " "last VSync %d ms",
(int)timeSinceLastVSync.ToMilliseconds());
// This could disable vsync.
window->NotifyOcclusionState(OcclusionState::OCCLUDED);
if (window->IsDestroyed()) { returnfalse;
}
// Make sure to fire vsync now even if we get disabled afterwards. // This gives an opportunity to clean up after the visibility state change. // FIXME: Do we really need to do this?
NotifyVsync(lastVSync, outputTimestamp); return StaticPrefs::widget_wayland_vsync_keep_firing_at_idle();
}
{ // This might enable vsync.
RefPtr window = mWindow;
window->NotifyOcclusionState(OcclusionState::VISIBLE); // NotifyOcclusionState can destroy us. if (window->IsDestroyed()) { return;
}
}
MutexAutoLock lock(mMutex); if (!mVsyncEnabled || !mVsyncSourceEnabled) { // We are unwanted by either our creator or our consumer, so we just stop // here without setting up a new frame callback.
LOG(" quit, mVsyncEnabled %d mWaylandSurface %p",
mVsyncEnabled && mVsyncSourceEnabled, mWaylandSurface.get()); return;
}
constauto now = TimeStamp::Now();
TimeStamp vsyncTimestamp; if (aTime) { constauto callbackTimeStamp = TimeStamp::FromSystemTime(
BaseTimeDurationPlatformUtils::TicksFromMilliseconds(aTime)); // If the callback timestamp is close enough to our timestamp, use it, // otherwise use the current time.
vsyncTimestamp = std::abs((now - callbackTimeStamp).ToMilliseconds()) < 50.0
? callbackTimeStamp
: now;
} else {
vsyncTimestamp = now;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.