Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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 "VsyncSource.h"
7 : #include "nsThreadUtils.h"
8 : #include "nsXULAppAPI.h"
9 : #include "mozilla/VsyncDispatcher.h"
10 : #include "MainThreadUtils.h"
11 :
12 : namespace mozilla {
13 : namespace gfx {
14 :
15 : void
16 8 : VsyncSource::AddCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
17 : {
18 8 : MOZ_ASSERT(XRE_IsParentProcess());
19 8 : MOZ_ASSERT(NS_IsMainThread());
20 : // Just use the global display until we have enough information to get the
21 : // corresponding display for compositor.
22 8 : GetGlobalDisplay().AddCompositorVsyncDispatcher(aCompositorVsyncDispatcher);
23 8 : }
24 :
25 : void
26 8 : VsyncSource::RemoveCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
27 : {
28 8 : MOZ_ASSERT(XRE_IsParentProcess());
29 8 : MOZ_ASSERT(NS_IsMainThread());
30 : // See also AddCompositorVsyncDispatcher().
31 8 : GetGlobalDisplay().RemoveCompositorVsyncDispatcher(aCompositorVsyncDispatcher);
32 8 : }
33 :
34 : RefPtr<RefreshTimerVsyncDispatcher>
35 2 : VsyncSource::GetRefreshTimerVsyncDispatcher()
36 : {
37 2 : MOZ_ASSERT(XRE_IsParentProcess());
38 : // See also AddCompositorVsyncDispatcher().
39 2 : return GetGlobalDisplay().GetRefreshTimerVsyncDispatcher();
40 : }
41 :
42 1 : VsyncSource::Display::Display()
43 : : mDispatcherLock("display dispatcher lock")
44 1 : , mRefreshTimerNeedsVsync(false)
45 : {
46 1 : MOZ_ASSERT(NS_IsMainThread());
47 1 : mRefreshTimerVsyncDispatcher = new RefreshTimerVsyncDispatcher();
48 1 : }
49 :
50 0 : VsyncSource::Display::~Display()
51 : {
52 0 : MOZ_ASSERT(NS_IsMainThread());
53 0 : MutexAutoLock lock(mDispatcherLock);
54 0 : mRefreshTimerVsyncDispatcher = nullptr;
55 0 : mCompositorVsyncDispatchers.Clear();
56 0 : }
57 :
58 : void
59 519 : VsyncSource::Display::NotifyVsync(TimeStamp aVsyncTimestamp)
60 : {
61 : // Called on the vsync thread
62 1038 : MutexAutoLock lock(mDispatcherLock);
63 :
64 821 : for (size_t i = 0; i < mCompositorVsyncDispatchers.Length(); i++) {
65 302 : mCompositorVsyncDispatchers[i]->NotifyVsync(aVsyncTimestamp);
66 : }
67 :
68 519 : mRefreshTimerVsyncDispatcher->NotifyVsync(aVsyncTimestamp);
69 519 : }
70 :
71 : TimeDuration
72 0 : VsyncSource::Display::GetVsyncRate()
73 : {
74 : // If hardware queries fail / are unsupported, we have to just guess.
75 0 : return TimeDuration::FromMilliseconds(1000.0 / 60.0);
76 : }
77 :
78 : void
79 8 : VsyncSource::Display::AddCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
80 : {
81 8 : MOZ_ASSERT(NS_IsMainThread());
82 8 : MOZ_ASSERT(aCompositorVsyncDispatcher);
83 : { // scope lock
84 16 : MutexAutoLock lock(mDispatcherLock);
85 8 : if (!mCompositorVsyncDispatchers.Contains(aCompositorVsyncDispatcher)) {
86 8 : mCompositorVsyncDispatchers.AppendElement(aCompositorVsyncDispatcher);
87 : }
88 : }
89 8 : UpdateVsyncStatus();
90 8 : }
91 :
92 : void
93 8 : VsyncSource::Display::RemoveCompositorVsyncDispatcher(CompositorVsyncDispatcher* aCompositorVsyncDispatcher)
94 : {
95 8 : MOZ_ASSERT(NS_IsMainThread());
96 8 : MOZ_ASSERT(aCompositorVsyncDispatcher);
97 : { // Scope lock
98 16 : MutexAutoLock lock(mDispatcherLock);
99 8 : if (mCompositorVsyncDispatchers.Contains(aCompositorVsyncDispatcher)) {
100 8 : mCompositorVsyncDispatchers.RemoveElement(aCompositorVsyncDispatcher);
101 : }
102 : }
103 8 : UpdateVsyncStatus();
104 8 : }
105 :
106 : void
107 12 : VsyncSource::Display::NotifyRefreshTimerVsyncStatus(bool aEnable)
108 : {
109 12 : MOZ_ASSERT(NS_IsMainThread());
110 12 : mRefreshTimerNeedsVsync = aEnable;
111 12 : UpdateVsyncStatus();
112 12 : }
113 :
114 : void
115 28 : VsyncSource::Display::UpdateVsyncStatus()
116 : {
117 28 : MOZ_ASSERT(NS_IsMainThread());
118 : // WARNING: This function SHOULD NOT BE CALLED WHILE HOLDING LOCKS
119 : // NotifyVsync grabs a lock to dispatch vsync events
120 : // When disabling vsync, we wait for the underlying thread to stop on some platforms
121 : // We can deadlock if we wait for the underlying vsync thread to stop
122 : // while the vsync thread is in NotifyVsync.
123 28 : bool enableVsync = false;
124 : { // scope lock
125 56 : MutexAutoLock lock(mDispatcherLock);
126 28 : enableVsync = !mCompositorVsyncDispatchers.IsEmpty() || mRefreshTimerNeedsVsync;
127 : }
128 :
129 28 : if (enableVsync) {
130 25 : EnableVsync();
131 : } else {
132 3 : DisableVsync();
133 : }
134 :
135 28 : if (IsVsyncEnabled() != enableVsync) {
136 0 : NS_WARNING("Vsync status did not change.");
137 : }
138 28 : }
139 :
140 : RefPtr<RefreshTimerVsyncDispatcher>
141 2 : VsyncSource::Display::GetRefreshTimerVsyncDispatcher()
142 : {
143 2 : return mRefreshTimerVsyncDispatcher;
144 : }
145 :
146 : void
147 0 : VsyncSource::Shutdown()
148 : {
149 0 : GetGlobalDisplay().Shutdown();
150 0 : }
151 :
152 : } //namespace gfx
153 : } //namespace mozilla
|