Line data Source code
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 : */
6 :
7 : #include "SoftwareVsyncSource.h"
8 : #include "base/task.h"
9 : #include "gfxPlatform.h"
10 : #include "nsThreadUtils.h"
11 :
12 : using namespace mozilla;
13 :
14 1 : SoftwareVsyncSource::SoftwareVsyncSource()
15 : {
16 1 : MOZ_ASSERT(NS_IsMainThread());
17 1 : mGlobalDisplay = new SoftwareDisplay();
18 1 : }
19 :
20 0 : SoftwareVsyncSource::~SoftwareVsyncSource()
21 : {
22 0 : MOZ_ASSERT(NS_IsMainThread());
23 0 : mGlobalDisplay = nullptr;
24 0 : }
25 :
26 1 : SoftwareDisplay::SoftwareDisplay()
27 1 : : mVsyncEnabled(false)
28 : {
29 : // Mimic 60 fps
30 1 : MOZ_ASSERT(NS_IsMainThread());
31 1 : const double rate = 1000.0 / (double) gfxPlatform::GetSoftwareVsyncRate();
32 1 : mVsyncRate = mozilla::TimeDuration::FromMilliseconds(rate);
33 1 : mVsyncThread = new base::Thread("SoftwareVsyncThread");
34 1 : MOZ_RELEASE_ASSERT(mVsyncThread->Start(), "GFX: Could not start software vsync thread");
35 1 : }
36 :
37 0 : SoftwareDisplay::~SoftwareDisplay() {}
38 :
39 : void
40 28 : SoftwareDisplay::EnableVsync()
41 : {
42 28 : MOZ_ASSERT(mVsyncThread->IsRunning());
43 28 : if (NS_IsMainThread()) {
44 25 : if (mVsyncEnabled) {
45 22 : return;
46 : }
47 3 : mVsyncEnabled = true;
48 :
49 6 : mVsyncThread->message_loop()->PostTask(NewRunnableMethod(
50 3 : "SoftwareDisplay::EnableVsync", this, &SoftwareDisplay::EnableVsync));
51 3 : return;
52 : }
53 :
54 3 : MOZ_ASSERT(IsInSoftwareVsyncThread());
55 3 : NotifyVsync(mozilla::TimeStamp::Now());
56 : }
57 :
58 : void
59 6 : SoftwareDisplay::DisableVsync()
60 : {
61 6 : MOZ_ASSERT(mVsyncThread->IsRunning());
62 6 : if (NS_IsMainThread()) {
63 3 : if (!mVsyncEnabled) {
64 0 : return;
65 : }
66 3 : mVsyncEnabled = false;
67 :
68 6 : mVsyncThread->message_loop()->PostTask(NewRunnableMethod(
69 3 : "SoftwareDisplay::DisableVsync", this, &SoftwareDisplay::DisableVsync));
70 3 : return;
71 : }
72 :
73 3 : MOZ_ASSERT(IsInSoftwareVsyncThread());
74 3 : if (mCurrentVsyncTask) {
75 3 : mCurrentVsyncTask->Cancel();
76 3 : mCurrentVsyncTask = nullptr;
77 : }
78 : }
79 :
80 : bool
81 28 : SoftwareDisplay::IsVsyncEnabled()
82 : {
83 28 : MOZ_ASSERT(NS_IsMainThread());
84 28 : return mVsyncEnabled;
85 : }
86 :
87 : bool
88 1044 : SoftwareDisplay::IsInSoftwareVsyncThread()
89 : {
90 1044 : return mVsyncThread->thread_id() == PlatformThread::CurrentId();
91 : }
92 :
93 : void
94 519 : SoftwareDisplay::NotifyVsync(mozilla::TimeStamp aVsyncTimestamp)
95 : {
96 519 : MOZ_ASSERT(IsInSoftwareVsyncThread());
97 :
98 519 : mozilla::TimeStamp displayVsyncTime = aVsyncTimestamp;
99 519 : mozilla::TimeStamp now = mozilla::TimeStamp::Now();
100 : // Posted tasks can only have integer millisecond delays
101 : // whereas TimeDurations can have floating point delays.
102 : // Thus the vsync timestamp can be in the future, which large parts
103 : // of the system can't handle, including animations. Force the timestamp to be now.
104 519 : if (aVsyncTimestamp > now) {
105 465 : displayVsyncTime = now;
106 : }
107 :
108 519 : Display::NotifyVsync(displayVsyncTime);
109 :
110 : // Prevent skew by still scheduling based on the original
111 : // vsync timestamp
112 519 : ScheduleNextVsync(aVsyncTimestamp);
113 519 : }
114 :
115 : mozilla::TimeDuration
116 3 : SoftwareDisplay::GetVsyncRate()
117 : {
118 3 : return mVsyncRate;
119 : }
120 :
121 : void
122 519 : SoftwareDisplay::ScheduleNextVsync(mozilla::TimeStamp aVsyncTimestamp)
123 : {
124 519 : MOZ_ASSERT(IsInSoftwareVsyncThread());
125 519 : mozilla::TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
126 519 : mozilla::TimeDuration delay = nextVsync - mozilla::TimeStamp::Now();
127 519 : if (delay.ToMilliseconds() < 0) {
128 0 : delay = mozilla::TimeDuration::FromMilliseconds(0);
129 0 : nextVsync = mozilla::TimeStamp::Now();
130 : }
131 :
132 1038 : mCurrentVsyncTask = NewCancelableRunnableMethod<mozilla::TimeStamp>(
133 : "SoftwareDisplay::NotifyVsync",
134 : this,
135 : &SoftwareDisplay::NotifyVsync,
136 519 : nextVsync);
137 :
138 1038 : RefPtr<Runnable> addrefedTask = mCurrentVsyncTask;
139 1557 : mVsyncThread->message_loop()->PostDelayedTask(
140 1038 : addrefedTask.forget(),
141 1038 : delay.ToMilliseconds());
142 519 : }
143 :
144 : void
145 0 : SoftwareDisplay::Shutdown()
146 : {
147 0 : MOZ_ASSERT(NS_IsMainThread());
148 0 : DisableVsync();
149 0 : mVsyncThread->Stop();
150 0 : delete mVsyncThread;
151 0 : }
|