Bug 1708422: part 17) Rename `words` to `normalizedWords` in `mozInlineSpellChecker...
[gecko.git] / widget / gtk / WaylandVsyncSource.cpp
blobe7e63ab21b4eea767c46a1a717bdd840dba9eba5
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifdef MOZ_WAYLAND
9 # include "WaylandVsyncSource.h"
10 # include "nsThreadUtils.h"
11 # include "nsISupportsImpl.h"
12 # include "MainThreadUtils.h"
14 # include <gdk/gdkwayland.h>
16 using namespace mozilla::widget;
18 namespace mozilla {
20 static void WaylandVsyncSourceCallbackHandler(void* data,
21 struct wl_callback* callback,
22 uint32_t time) {
23 WaylandVsyncSource::WaylandDisplay* context =
24 (WaylandVsyncSource::WaylandDisplay*)data;
25 wl_callback_destroy(callback);
26 context->FrameCallback(time);
29 static const struct wl_callback_listener WaylandVsyncSourceCallbackListener = {
30 WaylandVsyncSourceCallbackHandler};
32 WaylandVsyncSource::WaylandDisplay::WaylandDisplay(MozContainer* container)
33 : mEnabledLock("WaylandVsyncEnabledLock"),
34 mIsShutdown(false),
35 mVsyncEnabled(false),
36 mMonitorEnabled(false),
37 mCallback(nullptr),
38 mContainer(container),
39 mLastVsyncTimeStamp(TimeStamp::Now()) {
40 MOZ_ASSERT(NS_IsMainThread());
42 // We store the display here so all the frame callbacks won't have to look it
43 // up all the time.
44 mDisplay = WaylandDisplayGetWLDisplay();
46 mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
49 void WaylandVsyncSource::WaylandDisplay::ClearFrameCallback() {
50 if (mCallback) {
51 wl_callback_destroy(mCallback);
52 mCallback = nullptr;
56 void WaylandVsyncSource::WaylandDisplay::Refresh() {
57 TimeStamp outputTimestamp;
59 MutexAutoLock lock(mEnabledLock);
60 if (!mMonitorEnabled || !mVsyncEnabled || mCallback) {
61 // We don't need to do anything because:
62 // * We are unwanted by our widget or monitor, or
63 // * The last frame callback hasn't yet run to see that it had been shut
64 // down, so we can reuse it after having set mVsyncEnabled to true.
65 return;
68 struct wl_surface* surface = moz_container_wayland_surface_lock(mContainer);
69 if (!surface) {
70 // The surface hasn't been created yet. Try again when the surface is
71 // ready.
72 RefPtr<WaylandVsyncSource::WaylandDisplay> self(this);
73 moz_container_wayland_add_initial_draw_callback(
74 mContainer, [self]() -> void { self->Refresh(); });
75 return;
77 moz_container_wayland_surface_unlock(mContainer, &surface);
79 // Vsync is enabled, but we don't have a callback configured. Set one up so
80 // we can get to work.
81 SetupFrameCallback();
82 mLastVsyncTimeStamp = TimeStamp::Now();
83 outputTimestamp = mLastVsyncTimeStamp + GetVsyncRate();
85 NotifyVsync(mLastVsyncTimeStamp, outputTimestamp);
88 void WaylandVsyncSource::WaylandDisplay::EnableMonitor() {
90 MutexAutoLock lock(mEnabledLock);
91 if (mMonitorEnabled) {
92 return;
94 mMonitorEnabled = true;
96 Refresh();
99 void WaylandVsyncSource::WaylandDisplay::DisableMonitor() {
100 MutexAutoLock lock(mEnabledLock);
101 if (!mMonitorEnabled) {
102 return;
104 mMonitorEnabled = false;
105 ClearFrameCallback();
108 void WaylandVsyncSource::WaylandDisplay::SetupFrameCallback() {
109 MOZ_ASSERT(mCallback == nullptr);
110 struct wl_surface* surface = moz_container_wayland_surface_lock(mContainer);
111 if (!surface) {
112 // We don't have a surface, either due to being called before it was made
113 // available in the mozcontainer, or after it was destroyed. We're all done
114 // regardless.
115 ClearFrameCallback();
116 return;
119 mCallback = wl_surface_frame(surface);
120 wl_callback_add_listener(mCallback, &WaylandVsyncSourceCallbackListener,
121 this);
122 wl_surface_commit(surface);
123 wl_display_flush(mDisplay);
124 moz_container_wayland_surface_unlock(mContainer, &surface);
127 void WaylandVsyncSource::WaylandDisplay::FrameCallback(uint32_t timestampTime) {
128 TimeStamp outputTimestamp;
130 MutexAutoLock lock(mEnabledLock);
131 mCallback = nullptr;
133 if (!mVsyncEnabled || !mMonitorEnabled) {
134 // We are unwanted by either our creator or our consumer, so we just stop
135 // here without setting up a new frame callback.
136 return;
139 // Configure our next frame callback.
140 SetupFrameCallback();
142 int64_t tick =
143 BaseTimeDurationPlatformUtils::TicksFromMilliseconds(timestampTime);
144 TimeStamp callbackTimeStamp = TimeStamp::FromSystemTime(tick);
145 double duration = (TimeStamp::Now() - callbackTimeStamp).ToMilliseconds();
147 TimeStamp vsyncTimestamp;
148 if (duration < 50 && duration > -50) {
149 vsyncTimestamp = callbackTimeStamp;
150 } else {
151 vsyncTimestamp = TimeStamp::Now();
154 CalculateVsyncRate(vsyncTimestamp);
155 mLastVsyncTimeStamp = vsyncTimestamp;
156 outputTimestamp = vsyncTimestamp + GetVsyncRate();
158 NotifyVsync(mLastVsyncTimeStamp, outputTimestamp);
161 TimeDuration WaylandVsyncSource::WaylandDisplay::GetVsyncRate() {
162 return mVsyncRate;
165 void WaylandVsyncSource::WaylandDisplay::CalculateVsyncRate(
166 TimeStamp vsyncTimestamp) {
167 double duration = (vsyncTimestamp - mLastVsyncTimeStamp).ToMilliseconds();
168 double curVsyncRate = mVsyncRate.ToMilliseconds();
169 double correction;
171 if (duration > curVsyncRate) {
172 correction = fmin(curVsyncRate, (duration - curVsyncRate) / 10);
173 mVsyncRate += TimeDuration::FromMilliseconds(correction);
174 } else {
175 correction = fmin(curVsyncRate / 2, (curVsyncRate - duration) / 10);
176 mVsyncRate -= TimeDuration::FromMilliseconds(correction);
180 void WaylandVsyncSource::WaylandDisplay::EnableVsync() {
181 MOZ_ASSERT(NS_IsMainThread());
183 MutexAutoLock lock(mEnabledLock);
184 if (mVsyncEnabled || mIsShutdown) {
185 return;
187 mVsyncEnabled = true;
189 Refresh();
192 void WaylandVsyncSource::WaylandDisplay::DisableVsync() {
193 MutexAutoLock lock(mEnabledLock);
194 mVsyncEnabled = false;
195 ClearFrameCallback();
198 bool WaylandVsyncSource::WaylandDisplay::IsVsyncEnabled() {
199 MutexAutoLock lock(mEnabledLock);
200 return mVsyncEnabled;
203 void WaylandVsyncSource::WaylandDisplay::Shutdown() {
204 MOZ_ASSERT(NS_IsMainThread());
205 MutexAutoLock lock(mEnabledLock);
206 mIsShutdown = true;
207 mVsyncEnabled = false;
208 ClearFrameCallback();
211 } // namespace mozilla
213 #endif // MOZ_WAYLAND