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() {
15 MOZ_ASSERT(NS_IsMainThread());
16 mGlobalDisplay
= new SoftwareDisplay();
19 SoftwareVsyncSource::~SoftwareVsyncSource() {
20 MOZ_ASSERT(NS_IsMainThread());
21 mGlobalDisplay
= nullptr;
24 SoftwareDisplay::SoftwareDisplay() : mVsyncEnabled(false) {
26 MOZ_ASSERT(NS_IsMainThread());
27 const double rate
= 1000.0 / (double)gfxPlatform::GetSoftwareVsyncRate();
28 mVsyncRate
= mozilla::TimeDuration::FromMilliseconds(rate
);
29 mVsyncThread
= new base::Thread("SoftwareVsyncThread");
30 MOZ_RELEASE_ASSERT(mVsyncThread
->Start(),
31 "GFX: Could not start software vsync thread");
34 SoftwareDisplay::~SoftwareDisplay() = default;
36 void SoftwareDisplay::EnableVsync() {
37 MOZ_ASSERT(mVsyncThread
->IsRunning());
38 if (NS_IsMainThread()) {
44 mVsyncThread
->message_loop()->PostTask(NewRunnableMethod(
45 "SoftwareDisplay::EnableVsync", this, &SoftwareDisplay::EnableVsync
));
49 MOZ_ASSERT(IsInSoftwareVsyncThread());
50 TimeStamp vsyncTime
= TimeStamp::Now();
51 TimeStamp outputTime
= vsyncTime
+ mVsyncRate
;
52 NotifyVsync(vsyncTime
, outputTime
);
55 void SoftwareDisplay::DisableVsync() {
56 MOZ_ASSERT(mVsyncThread
->IsRunning());
57 if (NS_IsMainThread()) {
61 mVsyncEnabled
= false;
63 mVsyncThread
->message_loop()->PostTask(NewRunnableMethod(
64 "SoftwareDisplay::DisableVsync", this, &SoftwareDisplay::DisableVsync
));
68 MOZ_ASSERT(IsInSoftwareVsyncThread());
69 if (mCurrentVsyncTask
) {
70 mCurrentVsyncTask
->Cancel();
71 mCurrentVsyncTask
= nullptr;
75 bool SoftwareDisplay::IsVsyncEnabled() {
76 MOZ_ASSERT(NS_IsMainThread());
80 bool SoftwareDisplay::IsInSoftwareVsyncThread() {
81 return mVsyncThread
->thread_id() == PlatformThread::CurrentId();
84 void SoftwareDisplay::NotifyVsync(const mozilla::TimeStamp
& aVsyncTimestamp
,
85 const mozilla::TimeStamp
& aOutputTimestamp
) {
86 MOZ_ASSERT(IsInSoftwareVsyncThread());
88 mozilla::TimeStamp displayVsyncTime
= aVsyncTimestamp
;
89 mozilla::TimeStamp now
= mozilla::TimeStamp::Now();
90 // Posted tasks can only have integer millisecond delays
91 // whereas TimeDurations can have floating point delays.
92 // Thus the vsync timestamp can be in the future, which large parts
93 // of the system can't handle, including animations. Force the timestamp to be
95 if (aVsyncTimestamp
> now
) {
96 displayVsyncTime
= now
;
99 Display::NotifyVsync(displayVsyncTime
, aOutputTimestamp
);
101 // Prevent skew by still scheduling based on the original
103 ScheduleNextVsync(aVsyncTimestamp
);
106 mozilla::TimeDuration
SoftwareDisplay::GetVsyncRate() { return mVsyncRate
; }
108 void SoftwareDisplay::ScheduleNextVsync(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 "SoftwareDisplay::NotifyVsync", this, &SoftwareDisplay::NotifyVsync
,
122 nextVsync
, outputTime
);
124 RefPtr
<Runnable
> addrefedTask
= mCurrentVsyncTask
;
125 mVsyncThread
->message_loop()->PostDelayedTask(addrefedTask
.forget(),
126 delay
.ToMilliseconds());
129 void SoftwareDisplay::Shutdown() {
130 MOZ_ASSERT(NS_IsMainThread());
132 mVsyncThread
->Stop();