From 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:47:29 +0200 Subject: Adding upstream version 115.8.0esr. Signed-off-by: Daniel Baumann --- gfx/thebes/SoftwareVsyncSource.cpp | 143 +++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 gfx/thebes/SoftwareVsyncSource.cpp (limited to 'gfx/thebes/SoftwareVsyncSource.cpp') diff --git a/gfx/thebes/SoftwareVsyncSource.cpp b/gfx/thebes/SoftwareVsyncSource.cpp new file mode 100644 index 0000000000..b8e12390e7 --- /dev/null +++ b/gfx/thebes/SoftwareVsyncSource.cpp @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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/. + */ + +#include "SoftwareVsyncSource.h" +#include "base/task.h" +#include "gfxPlatform.h" +#include "nsThreadUtils.h" + +namespace mozilla::gfx { + +SoftwareVsyncSource::SoftwareVsyncSource(const TimeDuration& aInitialVsyncRate) + : mVsyncEnabled(false), + mVsyncRate(TimeDuration{aInitialVsyncRate}, + "SoftwareVsyncSource::mVsyncRate") { + MOZ_ASSERT(NS_IsMainThread()); + mVsyncThread = new base::Thread("SoftwareVsyncThread"); + MOZ_RELEASE_ASSERT(mVsyncThread->Start(), + "GFX: Could not start software vsync thread"); +} + +SoftwareVsyncSource::~SoftwareVsyncSource() { + MOZ_ASSERT(NS_IsMainThread()); + if (mVsyncThread) { + mVsyncThread->Stop(); + delete mVsyncThread; + } +}; + +void SoftwareVsyncSource::EnableVsync() { + MOZ_ASSERT(mVsyncThread->IsRunning()); + if (NS_IsMainThread()) { + if (mVsyncEnabled) { + return; + } + mVsyncEnabled = true; + + mVsyncThread->message_loop()->PostTask( + NewRunnableMethod("SoftwareVsyncSource::EnableVsync", this, + &SoftwareVsyncSource::EnableVsync)); + return; + } + + MOZ_ASSERT(IsInSoftwareVsyncThread()); + TimeStamp vsyncTime = TimeStamp::Now(); + TimeStamp outputTime = vsyncTime + GetVsyncRate(); + NotifyVsync(vsyncTime, outputTime); +} + +void SoftwareVsyncSource::DisableVsync() { + MOZ_ASSERT(mVsyncThread->IsRunning()); + if (NS_IsMainThread()) { + if (!mVsyncEnabled) { + return; + } + mVsyncEnabled = false; + + mVsyncThread->message_loop()->PostTask( + NewRunnableMethod("SoftwareVsyncSource::DisableVsync", this, + &SoftwareVsyncSource::DisableVsync)); + return; + } + + MOZ_ASSERT(IsInSoftwareVsyncThread()); + if (mCurrentVsyncTask) { + mCurrentVsyncTask->Cancel(); + mCurrentVsyncTask = nullptr; + } +} + +bool SoftwareVsyncSource::IsVsyncEnabled() { + MOZ_ASSERT(NS_IsMainThread()); + return mVsyncEnabled; +} + +bool SoftwareVsyncSource::IsInSoftwareVsyncThread() { + return mVsyncThread->thread_id() == PlatformThread::CurrentId(); +} + +void SoftwareVsyncSource::NotifyVsync(const TimeStamp& aVsyncTimestamp, + const TimeStamp& aOutputTimestamp) { + MOZ_ASSERT(IsInSoftwareVsyncThread()); + + TimeStamp displayVsyncTime = aVsyncTimestamp; + TimeStamp now = TimeStamp::Now(); + // Posted tasks can only have integer millisecond delays + // whereas TimeDurations can have floating point delays. + // Thus the vsync timestamp can be in the future, which large parts + // of the system can't handle, including animations. Force the timestamp to be + // now. + if (aVsyncTimestamp > now) { + displayVsyncTime = now; + } + + VsyncSource::NotifyVsync(displayVsyncTime, aOutputTimestamp); + + // Prevent skew by still scheduling based on the original + // vsync timestamp + ScheduleNextVsync(aVsyncTimestamp); +} + +TimeDuration SoftwareVsyncSource::GetVsyncRate() { + auto rate = mVsyncRate.Lock(); + return *rate; +} + +void SoftwareVsyncSource::SetVsyncRate(const TimeDuration& aNewRate) { + auto rate = mVsyncRate.Lock(); + *rate = aNewRate; +} + +void SoftwareVsyncSource::ScheduleNextVsync(TimeStamp aVsyncTimestamp) { + MOZ_ASSERT(IsInSoftwareVsyncThread()); + TimeDuration vsyncRate = GetVsyncRate(); + TimeStamp nextVsync = aVsyncTimestamp + vsyncRate; + TimeDuration delay = nextVsync - TimeStamp::Now(); + if (delay.ToMilliseconds() < 0) { + delay = TimeDuration::FromMilliseconds(0); + nextVsync = TimeStamp::Now(); + } + + TimeStamp outputTime = nextVsync + vsyncRate; + + mCurrentVsyncTask = NewCancelableRunnableMethod( + "SoftwareVsyncSource::NotifyVsync", this, + &SoftwareVsyncSource::NotifyVsync, nextVsync, outputTime); + + RefPtr addrefedTask = mCurrentVsyncTask; + mVsyncThread->message_loop()->PostDelayedTask(addrefedTask.forget(), + delay.ToMilliseconds()); +} + +void SoftwareVsyncSource::Shutdown() { + MOZ_ASSERT(NS_IsMainThread()); + DisableVsync(); + mVsyncThread->Stop(); + delete mVsyncThread; + mVsyncThread = nullptr; +} + +} // namespace mozilla::gfx -- cgit v1.2.3