/src/mozilla-central/widget/VsyncDispatcher.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; 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 | | #include "MainThreadUtils.h" |
7 | | #include "VsyncDispatcher.h" |
8 | | #include "VsyncSource.h" |
9 | | #include "gfxPlatform.h" |
10 | | #include "mozilla/layers/Compositor.h" |
11 | | #include "mozilla/layers/CompositorBridgeParent.h" |
12 | | #include "mozilla/layers/CompositorThread.h" |
13 | | |
14 | | using namespace mozilla::layers; |
15 | | |
16 | | namespace mozilla { |
17 | | |
18 | | CompositorVsyncDispatcher::CompositorVsyncDispatcher() |
19 | | : mCompositorObserverLock("CompositorObserverLock") |
20 | | , mDidShutdown(false) |
21 | 0 | { |
22 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
23 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
24 | 0 | } |
25 | | |
26 | | CompositorVsyncDispatcher::~CompositorVsyncDispatcher() |
27 | 0 | { |
28 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
29 | 0 | // We auto remove this vsync dispatcher from the vsync source in the nsBaseWidget |
30 | 0 | } |
31 | | |
32 | | void |
33 | | CompositorVsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp) |
34 | 0 | { |
35 | 0 | // In vsync thread |
36 | 0 | layers::CompositorBridgeParent::PostInsertVsyncProfilerMarker(aVsyncTimestamp); |
37 | 0 |
|
38 | 0 | MutexAutoLock lock(mCompositorObserverLock); |
39 | 0 | if (mCompositorVsyncObserver) { |
40 | 0 | mCompositorVsyncObserver->NotifyVsync(aVsyncTimestamp); |
41 | 0 | } |
42 | 0 | } |
43 | | |
44 | | void |
45 | | CompositorVsyncDispatcher::ObserveVsync(bool aEnable) |
46 | 0 | { |
47 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
48 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
49 | 0 | if (mDidShutdown) { |
50 | 0 | return; |
51 | 0 | } |
52 | 0 | |
53 | 0 | if (aEnable) { |
54 | 0 | gfxPlatform::GetPlatform()->GetHardwareVsync()->AddCompositorVsyncDispatcher(this); |
55 | 0 | } else { |
56 | 0 | gfxPlatform::GetPlatform()->GetHardwareVsync()->RemoveCompositorVsyncDispatcher(this); |
57 | 0 | } |
58 | 0 | } |
59 | | |
60 | | void |
61 | | CompositorVsyncDispatcher::SetCompositorVsyncObserver(VsyncObserver* aVsyncObserver) |
62 | 0 | { |
63 | 0 | // When remote compositing or running gtests, vsync observation is |
64 | 0 | // initiated on the main thread. Otherwise, it is initiated from the compositor |
65 | 0 | // thread. |
66 | 0 | MOZ_ASSERT(NS_IsMainThread() || CompositorThreadHolder::IsInCompositorThread()); |
67 | 0 |
|
68 | 0 | { // scope lock |
69 | 0 | MutexAutoLock lock(mCompositorObserverLock); |
70 | 0 | mCompositorVsyncObserver = aVsyncObserver; |
71 | 0 | } |
72 | 0 |
|
73 | 0 | bool observeVsync = aVsyncObserver != nullptr; |
74 | 0 | nsCOMPtr<nsIRunnable> vsyncControl = |
75 | 0 | NewRunnableMethod<bool>("CompositorVsyncDispatcher::ObserveVsync", |
76 | 0 | this, |
77 | 0 | &CompositorVsyncDispatcher::ObserveVsync, |
78 | 0 | observeVsync); |
79 | 0 | NS_DispatchToMainThread(vsyncControl); |
80 | 0 | } |
81 | | |
82 | | void |
83 | | CompositorVsyncDispatcher::Shutdown() |
84 | 0 | { |
85 | 0 | // Need to explicitly remove CompositorVsyncDispatcher when the nsBaseWidget shuts down. |
86 | 0 | // Otherwise, we would get dead vsync notifications between when the nsBaseWidget |
87 | 0 | // shuts down and the CompositorBridgeParent shuts down. |
88 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
89 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
90 | 0 | ObserveVsync(false); |
91 | 0 | mDidShutdown = true; |
92 | 0 | { // scope lock |
93 | 0 | MutexAutoLock lock(mCompositorObserverLock); |
94 | 0 | mCompositorVsyncObserver = nullptr; |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | RefreshTimerVsyncDispatcher::RefreshTimerVsyncDispatcher() |
99 | | : mRefreshTimersLock("RefreshTimers lock") |
100 | 0 | { |
101 | 0 | MOZ_ASSERT(XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()); |
102 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
103 | 0 | } |
104 | | |
105 | | RefreshTimerVsyncDispatcher::~RefreshTimerVsyncDispatcher() |
106 | 0 | { |
107 | 0 | MOZ_ASSERT(XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()); |
108 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
109 | 0 | } |
110 | | |
111 | | void |
112 | | RefreshTimerVsyncDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp) |
113 | 0 | { |
114 | 0 | MutexAutoLock lock(mRefreshTimersLock); |
115 | 0 |
|
116 | 0 | for (size_t i = 0; i < mChildRefreshTimers.Length(); i++) { |
117 | 0 | mChildRefreshTimers[i]->NotifyVsync(aVsyncTimestamp); |
118 | 0 | } |
119 | 0 |
|
120 | 0 | if (mParentRefreshTimer) { |
121 | 0 | mParentRefreshTimer->NotifyVsync(aVsyncTimestamp); |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | void |
126 | | RefreshTimerVsyncDispatcher::SetParentRefreshTimer(VsyncObserver* aVsyncObserver) |
127 | 0 | { |
128 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
129 | 0 | { // lock scope because UpdateVsyncStatus runs on main thread and will deadlock |
130 | 0 | MutexAutoLock lock(mRefreshTimersLock); |
131 | 0 | mParentRefreshTimer = aVsyncObserver; |
132 | 0 | } |
133 | 0 |
|
134 | 0 | UpdateVsyncStatus(); |
135 | 0 | } |
136 | | |
137 | | void |
138 | | RefreshTimerVsyncDispatcher::AddChildRefreshTimer(VsyncObserver* aVsyncObserver) |
139 | 0 | { |
140 | 0 | { // scope lock - called on pbackground thread |
141 | 0 | MutexAutoLock lock(mRefreshTimersLock); |
142 | 0 | MOZ_ASSERT(aVsyncObserver); |
143 | 0 | if (!mChildRefreshTimers.Contains(aVsyncObserver)) { |
144 | 0 | mChildRefreshTimers.AppendElement(aVsyncObserver); |
145 | 0 | } |
146 | 0 | } |
147 | 0 |
|
148 | 0 | UpdateVsyncStatus(); |
149 | 0 | } |
150 | | |
151 | | void |
152 | | RefreshTimerVsyncDispatcher::RemoveChildRefreshTimer(VsyncObserver* aVsyncObserver) |
153 | 0 | { |
154 | 0 | { // scope lock - called on pbackground thread |
155 | 0 | MutexAutoLock lock(mRefreshTimersLock); |
156 | 0 | MOZ_ASSERT(aVsyncObserver); |
157 | 0 | mChildRefreshTimers.RemoveElement(aVsyncObserver); |
158 | 0 | } |
159 | 0 |
|
160 | 0 | UpdateVsyncStatus(); |
161 | 0 | } |
162 | | |
163 | | void |
164 | | RefreshTimerVsyncDispatcher::UpdateVsyncStatus() |
165 | 0 | { |
166 | 0 | if (!NS_IsMainThread()) { |
167 | 0 | NS_DispatchToMainThread( |
168 | 0 | NewRunnableMethod("RefreshTimerVsyncDispatcher::UpdateVsyncStatus", |
169 | 0 | this, |
170 | 0 | &RefreshTimerVsyncDispatcher::UpdateVsyncStatus)); |
171 | 0 | return; |
172 | 0 | } |
173 | 0 | |
174 | 0 | gfx::VsyncSource::Display& display = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay(); |
175 | 0 | display.NotifyRefreshTimerVsyncStatus(NeedsVsync()); |
176 | 0 | } |
177 | | |
178 | | bool |
179 | | RefreshTimerVsyncDispatcher::NeedsVsync() |
180 | 0 | { |
181 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
182 | 0 | MutexAutoLock lock(mRefreshTimersLock); |
183 | 0 | return (mParentRefreshTimer != nullptr) || !mChildRefreshTimers.IsEmpty(); |
184 | 0 | } |
185 | | |
186 | | } // namespace mozilla |