Bug 1799258 - Fix constexpr issue on base toolchain builds. r=gfx-reviewers,lsalzman
[gecko.git] / gfx / thebes / VsyncSource.cpp
blobd7cfb339aa64d89ed2bcff9e0d14507d044d57c4
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"
13 #ifdef MOZ_WAYLAND
14 # include "WaylandVsyncSource.h"
15 #endif
17 namespace mozilla {
18 namespace gfx {
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) {
29 VsyncId vsyncId;
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.
53 bool found = false;
54 for (auto& dispatcherRefWithCount : state->mDispatchers) {
55 if (dispatcherRefWithCount.mDispatcher == aVsyncDispatcher) {
56 dispatcherRefWithCount.mCount++;
57 found = true;
58 break;
61 if (!found) {
62 state->mDispatchers.AppendElement(
63 DispatcherRefWithCount{aVsyncDispatcher, 1});
67 UpdateVsyncStatus();
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();
78 ++it) {
79 if (it->mDispatcher == aVsyncDispatcher) {
80 it->mCount--;
81 if (it->mCount == 0) {
82 state->mDispatchers.RemoveElementAt(it);
84 break;
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.
92 UpdateVsyncStatus();
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(); }));
106 return;
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;
116 { // scope lock
117 auto state = mState.Lock();
118 enableVsync = !state->mDispatchers.IsEmpty();
121 if (enableVsync) {
122 EnableVsync();
123 } else {
124 DisableVsync();
127 if (IsVsyncEnabled() != enableVsync) {
128 NS_WARNING("Vsync status did not change.");
132 // static
133 Maybe<TimeDuration> VsyncSource::GetFastestVsyncRate() {
134 Maybe<TimeDuration> retVal;
135 if (!gfxPlatform::Initialized()) {
136 return retVal;
139 RefPtr<VsyncDispatcher> vsyncDispatcher =
140 gfxPlatform::GetPlatform()->GetGlobalVsyncDispatcher();
141 RefPtr<VsyncSource> vsyncSource = vsyncDispatcher->GetCurrentVsyncSource();
142 if (vsyncSource->IsVsyncEnabled()) {
143 retVal.emplace(vsyncSource->GetVsyncRate());
144 #ifdef MOZ_WAYLAND
145 Maybe<TimeDuration> waylandRate = WaylandVsyncSource::GetFastestVsyncRate();
146 if (waylandRate) {
147 if (!retVal) {
148 retVal.emplace(*waylandRate);
149 } else if (*waylandRate < *retVal) {
150 retVal = waylandRate;
153 #endif
156 return retVal;
159 } // namespace gfx
160 } // namespace mozilla