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/.
7 #include "SoftwareVsyncSource.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());
32 void SoftwareVsyncSource::EnableVsync() {
33 MOZ_ASSERT(mVsyncThread
->IsRunning());
34 if (NS_IsMainThread()) {
40 mVsyncThread
->message_loop()->PostTask(
41 NewRunnableMethod("SoftwareVsyncSource::EnableVsync", this,
42 &SoftwareVsyncSource::EnableVsync
));
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()) {
58 mVsyncEnabled
= false;
60 mVsyncThread
->message_loop()->PostTask(
61 NewRunnableMethod("SoftwareVsyncSource::DisableVsync", this,
62 &SoftwareVsyncSource::DisableVsync
));
66 MOZ_ASSERT(IsInSoftwareVsyncThread());
67 if (mCurrentVsyncTask
) {
68 mCurrentVsyncTask
->Cancel();
69 mCurrentVsyncTask
= nullptr;
73 bool SoftwareVsyncSource::IsVsyncEnabled() {
74 MOZ_ASSERT(NS_IsMainThread());
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
93 if (aVsyncTimestamp
> now
) {
94 displayVsyncTime
= now
;
97 VsyncSource::NotifyVsync(displayVsyncTime
, aOutputTimestamp
);
99 // Prevent skew by still scheduling based on the original
101 ScheduleNextVsync(aVsyncTimestamp
);
104 TimeDuration
SoftwareVsyncSource::GetVsyncRate() {
105 auto rate
= mVsyncRate
.Lock();
109 void SoftwareVsyncSource::SetVsyncRate(const TimeDuration
& aNewRate
) {
110 auto rate
= mVsyncRate
.Lock();
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());
138 mVsyncThread
->Stop();
140 mVsyncThread
= nullptr;
143 } // namespace mozilla::gfx