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