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 using namespace mozilla
;
14 SoftwareVsyncSource::SoftwareVsyncSource() : mVsyncEnabled(false) {
16 MOZ_ASSERT(NS_IsMainThread());
17 const double rate
= 1000.0 / (double)gfxPlatform::GetSoftwareVsyncRate();
18 mVsyncRate
= mozilla::TimeDuration::FromMilliseconds(rate
);
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
+ mVsyncRate
;
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(
83 const mozilla::TimeStamp
& aVsyncTimestamp
,
84 const mozilla::TimeStamp
& aOutputTimestamp
) {
85 MOZ_ASSERT(IsInSoftwareVsyncThread());
87 mozilla::TimeStamp displayVsyncTime
= aVsyncTimestamp
;
88 mozilla::TimeStamp now
= mozilla::TimeStamp::Now();
89 // Posted tasks can only have integer millisecond delays
90 // whereas TimeDurations can have floating point delays.
91 // Thus the vsync timestamp can be in the future, which large parts
92 // of the system can't handle, including animations. Force the timestamp to be
94 if (aVsyncTimestamp
> now
) {
95 displayVsyncTime
= now
;
98 VsyncSource::NotifyVsync(displayVsyncTime
, aOutputTimestamp
);
100 // Prevent skew by still scheduling based on the original
102 ScheduleNextVsync(aVsyncTimestamp
);
105 mozilla::TimeDuration
SoftwareVsyncSource::GetVsyncRate() { return mVsyncRate
; }
107 void SoftwareVsyncSource::ScheduleNextVsync(
108 mozilla::TimeStamp aVsyncTimestamp
) {
109 MOZ_ASSERT(IsInSoftwareVsyncThread());
110 mozilla::TimeStamp nextVsync
= aVsyncTimestamp
+ mVsyncRate
;
111 mozilla::TimeDuration delay
= nextVsync
- mozilla::TimeStamp::Now();
112 if (delay
.ToMilliseconds() < 0) {
113 delay
= mozilla::TimeDuration::FromMilliseconds(0);
114 nextVsync
= mozilla::TimeStamp::Now();
117 TimeStamp outputTime
= nextVsync
+ mVsyncRate
;
120 NewCancelableRunnableMethod
<mozilla::TimeStamp
, mozilla::TimeStamp
>(
121 "SoftwareVsyncSource::NotifyVsync", this,
122 &SoftwareVsyncSource::NotifyVsync
, nextVsync
, outputTime
);
124 RefPtr
<Runnable
> addrefedTask
= mCurrentVsyncTask
;
125 mVsyncThread
->message_loop()->PostDelayedTask(addrefedTask
.forget(),
126 delay
.ToMilliseconds());
129 void SoftwareVsyncSource::Shutdown() {
130 MOZ_ASSERT(NS_IsMainThread());
132 mVsyncThread
->Stop();
134 mVsyncThread
= nullptr;