Bug 1732219 - Add API for fetching the preview image. r=geckoview-reviewers,agi,mconley
[gecko.git] / gfx / thebes / VsyncSource.cpp
blobba678254e053e2d40c39f207d1c1d8e2ddef66f1
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/. */
6 #include "VsyncSource.h"
7 #include "nsThreadUtils.h"
8 #include "nsXULAppAPI.h"
9 #include "mozilla/VsyncDispatcher.h"
10 #include "MainThreadUtils.h"
12 namespace mozilla {
13 namespace gfx {
15 void VsyncSource::EnableCompositorVsyncDispatcher(
16 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
17 MOZ_ASSERT(XRE_IsParentProcess());
18 MOZ_ASSERT(NS_IsMainThread());
19 // Just use the global display until we have enough information to get the
20 // corresponding display for compositor.
21 GetGlobalDisplay().EnableCompositorVsyncDispatcher(
22 aCompositorVsyncDispatcher);
25 void VsyncSource::DisableCompositorVsyncDispatcher(
26 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
27 MOZ_ASSERT(XRE_IsParentProcess());
28 MOZ_ASSERT(NS_IsMainThread());
29 // See also EnableCompositorVsyncDispatcher().
30 GetGlobalDisplay().DisableCompositorVsyncDispatcher(
31 aCompositorVsyncDispatcher);
34 void VsyncSource::RegisterCompositorVsyncDispatcher(
35 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
36 MOZ_ASSERT(XRE_IsParentProcess());
37 MOZ_ASSERT(NS_IsMainThread());
38 GetGlobalDisplay().RegisterCompositorVsyncDispatcher(
39 aCompositorVsyncDispatcher);
42 void VsyncSource::DeregisterCompositorVsyncDispatcher(
43 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
44 MOZ_ASSERT(XRE_IsParentProcess());
45 MOZ_ASSERT(NS_IsMainThread());
46 GetGlobalDisplay().DeregisterCompositorVsyncDispatcher(
47 aCompositorVsyncDispatcher);
50 void VsyncSource::AddGenericObserver(VsyncObserver* aObserver) {
51 MOZ_ASSERT(XRE_IsParentProcess());
52 MOZ_ASSERT(NS_IsMainThread());
54 GetGlobalDisplay().AddGenericObserver(aObserver);
57 void VsyncSource::RemoveGenericObserver(VsyncObserver* aObserver) {
58 MOZ_ASSERT(XRE_IsParentProcess());
59 MOZ_ASSERT(NS_IsMainThread());
61 GetGlobalDisplay().RemoveGenericObserver(aObserver);
64 void VsyncSource::MoveListenersToNewSource(
65 const RefPtr<VsyncSource>& aNewSource) {
66 GetGlobalDisplay().MoveListenersToNewSource(aNewSource);
69 RefPtr<RefreshTimerVsyncDispatcher>
70 VsyncSource::GetRefreshTimerVsyncDispatcher() {
71 MOZ_ASSERT(XRE_IsParentProcess());
72 // See also AddCompositorVsyncDispatcher().
73 return GetGlobalDisplay().GetRefreshTimerVsyncDispatcher();
76 VsyncSource::Display::Display()
77 : mDispatcherLock("display dispatcher lock"),
78 mRefreshTimerNeedsVsync(false),
79 mHasGenericObservers(false) {
80 MOZ_ASSERT(NS_IsMainThread());
81 mRefreshTimerVsyncDispatcher = new RefreshTimerVsyncDispatcher(this);
84 VsyncSource::Display::~Display() {
85 MOZ_ASSERT(NS_IsMainThread());
86 MutexAutoLock lock(mDispatcherLock);
87 mRefreshTimerVsyncDispatcher = nullptr;
88 MOZ_ASSERT(mRegisteredCompositorVsyncDispatchers.Length() == 0);
89 MOZ_ASSERT(mEnabledCompositorVsyncDispatchers.Length() == 0);
92 void VsyncSource::Display::NotifyVsync(const TimeStamp& aVsyncTimestamp,
93 const TimeStamp& aOutputTimestamp) {
94 // Called on the vsync thread
95 MutexAutoLock lock(mDispatcherLock);
97 // mRefreshTimerVsyncDispatcher might be null here if MoveListenersToNewSource
98 // was called concurrently with this function and won the race to acquire
99 // mDispatcherLock. In this case the new VsyncSource that is replacing this
100 // one will handle notifications from now on, so we can abort.
101 if (!mRefreshTimerVsyncDispatcher) {
102 return;
105 // If the task posted to the main thread from the last NotifyVsync call
106 // hasn't been processed yet, then don't send another one. Otherwise we might
107 // end up flooding the main thread.
108 bool dispatchToMainThread =
109 mHasGenericObservers &&
110 (mLastVsyncIdSentToMainThread == mLastMainThreadProcessedVsyncId);
112 mVsyncId = mVsyncId.Next();
113 const VsyncEvent event(mVsyncId, aVsyncTimestamp, aOutputTimestamp);
115 for (size_t i = 0; i < mEnabledCompositorVsyncDispatchers.Length(); i++) {
116 mEnabledCompositorVsyncDispatchers[i]->NotifyVsync(event);
119 mRefreshTimerVsyncDispatcher->NotifyVsync(event);
121 if (dispatchToMainThread) {
122 mLastVsyncIdSentToMainThread = mVsyncId;
123 NS_DispatchToMainThread(NewRunnableMethod<VsyncEvent>(
124 "VsyncSource::Display::NotifyGenericObservers", this,
125 &VsyncSource::Display::NotifyGenericObservers, event));
129 void VsyncSource::Display::NotifyGenericObservers(VsyncEvent aEvent) {
130 MOZ_ASSERT(NS_IsMainThread());
131 for (size_t i = 0; i < mGenericObservers.Length(); i++) {
132 mGenericObservers[i]->NotifyVsync(aEvent);
135 { // Scope lock
136 MutexAutoLock lock(mDispatcherLock);
137 mLastMainThreadProcessedVsyncId = aEvent.mId;
141 TimeDuration VsyncSource::Display::GetVsyncRate() {
142 // If hardware queries fail / are unsupported, we have to just guess.
143 return TimeDuration::FromMilliseconds(1000.0 / 60.0);
146 void VsyncSource::Display::RegisterCompositorVsyncDispatcher(
147 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
148 MOZ_ASSERT(NS_IsMainThread());
149 MOZ_ASSERT(aCompositorVsyncDispatcher);
150 { // scope lock
151 MutexAutoLock lock(mDispatcherLock);
152 mRegisteredCompositorVsyncDispatchers.AppendElement(
153 aCompositorVsyncDispatcher);
157 void VsyncSource::Display::DeregisterCompositorVsyncDispatcher(
158 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
159 MOZ_ASSERT(NS_IsMainThread());
160 MOZ_ASSERT(aCompositorVsyncDispatcher);
161 { // Scope lock
162 MutexAutoLock lock(mDispatcherLock);
163 mRegisteredCompositorVsyncDispatchers.RemoveElement(
164 aCompositorVsyncDispatcher);
168 void VsyncSource::Display::EnableCompositorVsyncDispatcher(
169 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
170 MOZ_ASSERT(NS_IsMainThread());
171 MOZ_ASSERT(aCompositorVsyncDispatcher);
172 { // scope lock
173 MutexAutoLock lock(mDispatcherLock);
174 if (!mEnabledCompositorVsyncDispatchers.Contains(
175 aCompositorVsyncDispatcher)) {
176 mEnabledCompositorVsyncDispatchers.AppendElement(
177 aCompositorVsyncDispatcher);
180 UpdateVsyncStatus();
183 void VsyncSource::Display::DisableCompositorVsyncDispatcher(
184 CompositorVsyncDispatcher* aCompositorVsyncDispatcher) {
185 MOZ_ASSERT(NS_IsMainThread());
186 MOZ_ASSERT(aCompositorVsyncDispatcher);
187 { // Scope lock
188 MutexAutoLock lock(mDispatcherLock);
189 if (mEnabledCompositorVsyncDispatchers.Contains(
190 aCompositorVsyncDispatcher)) {
191 mEnabledCompositorVsyncDispatchers.RemoveElement(
192 aCompositorVsyncDispatcher);
195 UpdateVsyncStatus();
198 void VsyncSource::Display::AddGenericObserver(VsyncObserver* aObserver) {
199 MOZ_ASSERT(NS_IsMainThread());
200 MOZ_ASSERT(aObserver);
201 mGenericObservers.AppendElement(aObserver);
203 UpdateVsyncStatus();
206 void VsyncSource::Display::RemoveGenericObserver(VsyncObserver* aObserver) {
207 MOZ_ASSERT(NS_IsMainThread());
208 MOZ_ASSERT(aObserver);
209 mGenericObservers.RemoveElement(aObserver);
211 UpdateVsyncStatus();
214 void VsyncSource::Display::MoveListenersToNewSource(
215 const RefPtr<VsyncSource>& aNewSource) {
216 MOZ_ASSERT(NS_IsMainThread());
217 VsyncSource::Display& aNewDisplay = aNewSource->GetGlobalDisplay();
218 MutexAutoLock lock(mDispatcherLock);
219 MutexAutoLock newLock(aNewDisplay.mDispatcherLock);
220 aNewDisplay.mRegisteredCompositorVsyncDispatchers.AppendElements(
221 std::move(mRegisteredCompositorVsyncDispatchers));
222 aNewDisplay.mEnabledCompositorVsyncDispatchers.AppendElements(
223 std::move(mEnabledCompositorVsyncDispatchers));
224 aNewDisplay.mGenericObservers.AppendElements(std::move(mGenericObservers));
226 for (size_t i = 0;
227 i < aNewDisplay.mRegisteredCompositorVsyncDispatchers.Length(); i++) {
228 aNewDisplay.mRegisteredCompositorVsyncDispatchers[i]->MoveToSource(
229 aNewSource);
232 aNewDisplay.mRefreshTimerVsyncDispatcher = mRefreshTimerVsyncDispatcher;
233 mRefreshTimerVsyncDispatcher->MoveToDisplay(&aNewDisplay);
234 mRefreshTimerVsyncDispatcher = nullptr;
237 void VsyncSource::Display::NotifyRefreshTimerVsyncStatus(bool aEnable) {
238 MOZ_ASSERT(NS_IsMainThread());
239 mRefreshTimerNeedsVsync = aEnable;
240 UpdateVsyncStatus();
243 void VsyncSource::Display::UpdateVsyncStatus() {
244 MOZ_ASSERT(NS_IsMainThread());
245 // WARNING: This function SHOULD NOT BE CALLED WHILE HOLDING LOCKS
246 // NotifyVsync grabs a lock to dispatch vsync events
247 // When disabling vsync, we wait for the underlying thread to stop on some
248 // platforms We can deadlock if we wait for the underlying vsync thread to
249 // stop while the vsync thread is in NotifyVsync.
250 bool enableVsync = false;
251 { // scope lock
252 MutexAutoLock lock(mDispatcherLock);
253 enableVsync = !mEnabledCompositorVsyncDispatchers.IsEmpty() ||
254 mRefreshTimerNeedsVsync || !mGenericObservers.IsEmpty();
255 mHasGenericObservers = !mGenericObservers.IsEmpty();
258 if (enableVsync) {
259 EnableVsync();
260 } else {
261 DisableVsync();
264 if (IsVsyncEnabled() != enableVsync) {
265 NS_WARNING("Vsync status did not change.");
269 RefPtr<RefreshTimerVsyncDispatcher>
270 VsyncSource::Display::GetRefreshTimerVsyncDispatcher() {
271 return mRefreshTimerVsyncDispatcher;
274 void VsyncSource::Shutdown() { GetGlobalDisplay().Shutdown(); }
276 } // namespace gfx
277 } // namespace mozilla