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"
11 #include "gfxPlatform.h"
14 # include "WaylandVsyncSource.h"
20 VsyncSource::VsyncSource() : mState("VsyncSource::State") {
21 MOZ_ASSERT(NS_IsMainThread());
24 VsyncSource::~VsyncSource() { MOZ_ASSERT(NS_IsMainThread()); }
26 // Called on the vsync thread
27 void VsyncSource::NotifyVsync(const TimeStamp
& aVsyncTimestamp
,
28 const TimeStamp
& aOutputTimestamp
) {
30 nsTArray
<DispatcherRefWithCount
> dispatchers
;
33 auto state
= mState
.Lock();
34 vsyncId
= state
->mVsyncId
.Next();
35 dispatchers
= state
->mDispatchers
.Clone();
36 state
->mVsyncId
= vsyncId
;
39 // Notify our listeners, outside of the lock.
40 const VsyncEvent
event(vsyncId
, aVsyncTimestamp
, aOutputTimestamp
);
41 for (const auto& dispatcher
: dispatchers
) {
42 dispatcher
.mDispatcher
->NotifyVsync(event
);
46 void VsyncSource::AddVsyncDispatcher(VsyncDispatcher
* aVsyncDispatcher
) {
47 MOZ_ASSERT(aVsyncDispatcher
);
49 auto state
= mState
.Lock();
51 // Find the dispatcher in mDispatchers. If it is already present, increment
52 // the count. If not, add it with a count of 1.
54 for (auto& dispatcherRefWithCount
: state
->mDispatchers
) {
55 if (dispatcherRefWithCount
.mDispatcher
== aVsyncDispatcher
) {
56 dispatcherRefWithCount
.mCount
++;
62 state
->mDispatchers
.AppendElement(
63 DispatcherRefWithCount
{aVsyncDispatcher
, 1});
70 void VsyncSource::RemoveVsyncDispatcher(VsyncDispatcher
* aVsyncDispatcher
) {
71 MOZ_ASSERT(aVsyncDispatcher
);
73 auto state
= mState
.Lock();
75 // Find the dispatcher in mDispatchers. If found, decrement the count.
76 // If the count becomes zero, remove it from mDispatchers.
77 for (auto it
= state
->mDispatchers
.begin(); it
!= state
->mDispatchers
.end();
79 if (it
->mDispatcher
== aVsyncDispatcher
) {
81 if (it
->mCount
== 0) {
82 state
->mDispatchers
.RemoveElementAt(it
);
88 // In the future we should probably MOZ_RELEASE_ASSERT here that we don't
89 // try to remove a dispatcher which isn't in mDispatchers.
95 // This is the base class implementation. Subclasses override this method.
96 TimeDuration
VsyncSource::GetVsyncRate() {
97 // If hardware queries fail / are unsupported, we have to just guess.
98 return TimeDuration::FromMilliseconds(1000.0 / 60.0);
101 void VsyncSource::UpdateVsyncStatus() {
102 if (!NS_IsMainThread()) {
103 NS_DispatchToMainThread(NS_NewRunnableFunction(
104 "VsyncSource::UpdateVsyncStatus",
105 [self
= RefPtr
{this}] { self
->UpdateVsyncStatus(); }));
109 MOZ_ASSERT(NS_IsMainThread());
110 // WARNING: This function SHOULD NOT BE CALLED WHILE HOLDING LOCKS
111 // NotifyVsync grabs a lock to dispatch vsync events
112 // When disabling vsync, we wait for the underlying thread to stop on some
113 // platforms We can deadlock if we wait for the underlying vsync thread to
114 // stop while the vsync thread is in NotifyVsync.
115 bool enableVsync
= false;
117 auto state
= mState
.Lock();
118 enableVsync
= !state
->mDispatchers
.IsEmpty();
127 if (IsVsyncEnabled() != enableVsync
) {
128 NS_WARNING("Vsync status did not change.");
133 Maybe
<TimeDuration
> VsyncSource::GetFastestVsyncRate() {
134 Maybe
<TimeDuration
> retVal
;
135 if (!gfxPlatform::Initialized()) {
139 RefPtr
<VsyncDispatcher
> vsyncDispatcher
=
140 gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher();
141 RefPtr
<VsyncSource
> vsyncSource
= vsyncDispatcher
->GetCurrentVsyncSource();
142 if (vsyncSource
->IsVsyncEnabled()) {
143 retVal
.emplace(vsyncSource
->GetVsyncRate());
145 Maybe
<TimeDuration
> waylandRate
= WaylandVsyncSource::GetFastestVsyncRate();
148 retVal
.emplace(*waylandRate
);
149 } else if (*waylandRate
< *retVal
) {
150 retVal
= waylandRate
;
160 } // namespace mozilla