Bug 1692971 [wpt PR 27638] - WebKit export of https://bugs.webkit.org/show_bug.cgi...
[gecko.git] / widget / VsyncDispatcher.cpp
blobccb7151ee7f07b4b6e2740efc67cfb3bf8115c22
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/. */
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"
14 using namespace mozilla::layers;
16 namespace mozilla {
18 CompositorVsyncDispatcher::CompositorVsyncDispatcher()
19 : mVsyncSource(gfxPlatform::GetPlatform()->GetHardwareVsync()),
20 mCompositorObserverLock("CompositorObserverLock"),
21 mDidShutdown(false) {
22 MOZ_ASSERT(XRE_IsParentProcess());
23 MOZ_ASSERT(NS_IsMainThread());
25 mVsyncSource->RegisterCompositorVsyncDispatcher(this);
28 CompositorVsyncDispatcher::CompositorVsyncDispatcher(
29 RefPtr<gfx::VsyncSource> aVsyncSource)
30 : mVsyncSource(std::move(aVsyncSource)),
31 mCompositorObserverLock("CompositorObserverLock"),
32 mDidShutdown(false) {
33 MOZ_ASSERT(XRE_IsParentProcess());
34 MOZ_ASSERT(NS_IsMainThread());
36 mVsyncSource->RegisterCompositorVsyncDispatcher(this);
39 CompositorVsyncDispatcher::~CompositorVsyncDispatcher() {
40 MOZ_ASSERT(XRE_IsParentProcess());
41 // We auto remove this vsync dispatcher from the vsync source in the
42 // nsBaseWidget
45 void CompositorVsyncDispatcher::NotifyVsync(const VsyncEvent& aVsync) {
46 // In vsync thread
47 layers::CompositorBridgeParent::PostInsertVsyncProfilerMarker(aVsync.mTime);
49 MutexAutoLock lock(mCompositorObserverLock);
50 if (mCompositorVsyncObserver) {
51 mCompositorVsyncObserver->NotifyVsync(aVsync);
55 void CompositorVsyncDispatcher::MoveToSource(
56 const RefPtr<gfx::VsyncSource>& aVsyncSource) {
57 MOZ_ASSERT(NS_IsMainThread());
58 MOZ_ASSERT(XRE_IsParentProcess());
59 mVsyncSource = aVsyncSource;
62 void CompositorVsyncDispatcher::ObserveVsync(bool aEnable) {
63 MOZ_ASSERT(NS_IsMainThread());
64 MOZ_ASSERT(XRE_IsParentProcess());
65 if (mDidShutdown) {
66 return;
69 if (aEnable) {
70 mVsyncSource->EnableCompositorVsyncDispatcher(this);
71 } else {
72 mVsyncSource->DisableCompositorVsyncDispatcher(this);
76 void CompositorVsyncDispatcher::SetCompositorVsyncObserver(
77 VsyncObserver* aVsyncObserver) {
78 // When remote compositing or running gtests, vsync observation is
79 // initiated on the main thread. Otherwise, it is initiated from the
80 // compositor thread.
81 MOZ_ASSERT(NS_IsMainThread() ||
82 CompositorThreadHolder::IsInCompositorThread());
84 { // scope lock
85 MutexAutoLock lock(mCompositorObserverLock);
86 mCompositorVsyncObserver = aVsyncObserver;
89 bool observeVsync = aVsyncObserver != nullptr;
90 nsCOMPtr<nsIRunnable> vsyncControl = NewRunnableMethod<bool>(
91 "CompositorVsyncDispatcher::ObserveVsync", this,
92 &CompositorVsyncDispatcher::ObserveVsync, observeVsync);
93 NS_DispatchToMainThread(vsyncControl);
96 void CompositorVsyncDispatcher::Shutdown() {
97 // Need to explicitly remove CompositorVsyncDispatcher when the nsBaseWidget
98 // shuts down. Otherwise, we would get dead vsync notifications between when
99 // the nsBaseWidget shuts down and the CompositorBridgeParent shuts down.
100 MOZ_ASSERT(XRE_IsParentProcess());
101 MOZ_ASSERT(NS_IsMainThread());
102 MOZ_ASSERT(!mDidShutdown);
103 ObserveVsync(false);
104 mDidShutdown = true;
105 { // scope lock
106 MutexAutoLock lock(mCompositorObserverLock);
107 mCompositorVsyncObserver = nullptr;
109 mVsyncSource->DeregisterCompositorVsyncDispatcher(this);
110 mVsyncSource = nullptr;
113 RefreshTimerVsyncDispatcher::RefreshTimerVsyncDispatcher(
114 gfx::VsyncSource::Display* aDisplay)
115 : mDisplay(aDisplay), mRefreshTimersLock("RefreshTimers lock") {
116 MOZ_ASSERT(XRE_IsParentProcess());
117 MOZ_ASSERT(NS_IsMainThread());
120 RefreshTimerVsyncDispatcher::~RefreshTimerVsyncDispatcher() {
121 MOZ_ASSERT(XRE_IsParentProcess());
122 MOZ_ASSERT(NS_IsMainThread());
125 void RefreshTimerVsyncDispatcher::MoveToDisplay(
126 gfx::VsyncSource::Display* aDisplay) {
127 MOZ_ASSERT(NS_IsMainThread());
128 mDisplay = aDisplay;
131 void RefreshTimerVsyncDispatcher::NotifyVsync(const VsyncEvent& aVsync) {
132 MutexAutoLock lock(mRefreshTimersLock);
134 for (size_t i = 0; i < mChildRefreshTimers.Length(); i++) {
135 mChildRefreshTimers[i]->NotifyVsync(aVsync);
138 if (mParentRefreshTimer) {
139 mParentRefreshTimer->NotifyVsync(aVsync);
143 void RefreshTimerVsyncDispatcher::SetParentRefreshTimer(
144 VsyncObserver* aVsyncObserver) {
145 MOZ_ASSERT(NS_IsMainThread());
146 { // lock scope because UpdateVsyncStatus runs on main thread and will
147 // deadlock
148 MutexAutoLock lock(mRefreshTimersLock);
149 mParentRefreshTimer = aVsyncObserver;
152 UpdateVsyncStatus();
155 void RefreshTimerVsyncDispatcher::AddChildRefreshTimer(
156 VsyncObserver* aVsyncObserver) {
157 { // scope lock - called on pbackground thread
158 MutexAutoLock lock(mRefreshTimersLock);
159 MOZ_ASSERT(aVsyncObserver);
160 if (!mChildRefreshTimers.Contains(aVsyncObserver)) {
161 mChildRefreshTimers.AppendElement(aVsyncObserver);
165 UpdateVsyncStatus();
168 void RefreshTimerVsyncDispatcher::RemoveChildRefreshTimer(
169 VsyncObserver* aVsyncObserver) {
170 { // scope lock - called on pbackground thread
171 MutexAutoLock lock(mRefreshTimersLock);
172 MOZ_ASSERT(aVsyncObserver);
173 mChildRefreshTimers.RemoveElement(aVsyncObserver);
176 UpdateVsyncStatus();
179 void RefreshTimerVsyncDispatcher::UpdateVsyncStatus() {
180 if (!NS_IsMainThread()) {
181 NS_DispatchToMainThread(NewRunnableMethod(
182 "RefreshTimerVsyncDispatcher::UpdateVsyncStatus", this,
183 &RefreshTimerVsyncDispatcher::UpdateVsyncStatus));
184 return;
187 mDisplay->NotifyRefreshTimerVsyncStatus(NeedsVsync());
190 bool RefreshTimerVsyncDispatcher::NeedsVsync() {
191 MOZ_ASSERT(NS_IsMainThread());
192 MutexAutoLock lock(mRefreshTimersLock);
193 return (mParentRefreshTimer != nullptr) || !mChildRefreshTimers.IsEmpty();
196 } // namespace mozilla