Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / gfx / thebes / SoftwareVsyncSource.cpp
blobb8e12390e73cd66a02332754c94022d15d678e3e
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
7 #include "SoftwareVsyncSource.h"
8 #include "base/task.h"
9 #include "gfxPlatform.h"
10 #include "nsThreadUtils.h"
12 namespace mozilla::gfx {
14 SoftwareVsyncSource::SoftwareVsyncSource(const TimeDuration& aInitialVsyncRate)
15 : mVsyncEnabled(false),
16 mVsyncRate(TimeDuration{aInitialVsyncRate},
17 "SoftwareVsyncSource::mVsyncRate") {
18 MOZ_ASSERT(NS_IsMainThread());
19 mVsyncThread = new base::Thread("SoftwareVsyncThread");
20 MOZ_RELEASE_ASSERT(mVsyncThread->Start(),
21 "GFX: Could not start software vsync thread");
24 SoftwareVsyncSource::~SoftwareVsyncSource() {
25 MOZ_ASSERT(NS_IsMainThread());
26 if (mVsyncThread) {
27 mVsyncThread->Stop();
28 delete mVsyncThread;
32 void SoftwareVsyncSource::EnableVsync() {
33 MOZ_ASSERT(mVsyncThread->IsRunning());
34 if (NS_IsMainThread()) {
35 if (mVsyncEnabled) {
36 return;
38 mVsyncEnabled = true;
40 mVsyncThread->message_loop()->PostTask(
41 NewRunnableMethod("SoftwareVsyncSource::EnableVsync", this,
42 &SoftwareVsyncSource::EnableVsync));
43 return;
46 MOZ_ASSERT(IsInSoftwareVsyncThread());
47 TimeStamp vsyncTime = TimeStamp::Now();
48 TimeStamp outputTime = vsyncTime + GetVsyncRate();
49 NotifyVsync(vsyncTime, outputTime);
52 void SoftwareVsyncSource::DisableVsync() {
53 MOZ_ASSERT(mVsyncThread->IsRunning());
54 if (NS_IsMainThread()) {
55 if (!mVsyncEnabled) {
56 return;
58 mVsyncEnabled = false;
60 mVsyncThread->message_loop()->PostTask(
61 NewRunnableMethod("SoftwareVsyncSource::DisableVsync", this,
62 &SoftwareVsyncSource::DisableVsync));
63 return;
66 MOZ_ASSERT(IsInSoftwareVsyncThread());
67 if (mCurrentVsyncTask) {
68 mCurrentVsyncTask->Cancel();
69 mCurrentVsyncTask = nullptr;
73 bool SoftwareVsyncSource::IsVsyncEnabled() {
74 MOZ_ASSERT(NS_IsMainThread());
75 return mVsyncEnabled;
78 bool SoftwareVsyncSource::IsInSoftwareVsyncThread() {
79 return mVsyncThread->thread_id() == PlatformThread::CurrentId();
82 void SoftwareVsyncSource::NotifyVsync(const TimeStamp& aVsyncTimestamp,
83 const TimeStamp& aOutputTimestamp) {
84 MOZ_ASSERT(IsInSoftwareVsyncThread());
86 TimeStamp displayVsyncTime = aVsyncTimestamp;
87 TimeStamp now = TimeStamp::Now();
88 // Posted tasks can only have integer millisecond delays
89 // whereas TimeDurations can have floating point delays.
90 // Thus the vsync timestamp can be in the future, which large parts
91 // of the system can't handle, including animations. Force the timestamp to be
92 // now.
93 if (aVsyncTimestamp > now) {
94 displayVsyncTime = now;
97 VsyncSource::NotifyVsync(displayVsyncTime, aOutputTimestamp);
99 // Prevent skew by still scheduling based on the original
100 // vsync timestamp
101 ScheduleNextVsync(aVsyncTimestamp);
104 TimeDuration SoftwareVsyncSource::GetVsyncRate() {
105 auto rate = mVsyncRate.Lock();
106 return *rate;
109 void SoftwareVsyncSource::SetVsyncRate(const TimeDuration& aNewRate) {
110 auto rate = mVsyncRate.Lock();
111 *rate = aNewRate;
114 void SoftwareVsyncSource::ScheduleNextVsync(TimeStamp aVsyncTimestamp) {
115 MOZ_ASSERT(IsInSoftwareVsyncThread());
116 TimeDuration vsyncRate = GetVsyncRate();
117 TimeStamp nextVsync = aVsyncTimestamp + vsyncRate;
118 TimeDuration delay = nextVsync - TimeStamp::Now();
119 if (delay.ToMilliseconds() < 0) {
120 delay = TimeDuration::FromMilliseconds(0);
121 nextVsync = TimeStamp::Now();
124 TimeStamp outputTime = nextVsync + vsyncRate;
126 mCurrentVsyncTask = NewCancelableRunnableMethod<TimeStamp, TimeStamp>(
127 "SoftwareVsyncSource::NotifyVsync", this,
128 &SoftwareVsyncSource::NotifyVsync, nextVsync, outputTime);
130 RefPtr<Runnable> addrefedTask = mCurrentVsyncTask;
131 mVsyncThread->message_loop()->PostDelayedTask(addrefedTask.forget(),
132 delay.ToMilliseconds());
135 void SoftwareVsyncSource::Shutdown() {
136 MOZ_ASSERT(NS_IsMainThread());
137 DisableVsync();
138 mVsyncThread->Stop();
139 delete mVsyncThread;
140 mVsyncThread = nullptr;
143 } // namespace mozilla::gfx