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/. */
5 
6 #ifndef _WaylandVsyncSource_h_
7 #define _WaylandVsyncSource_h_
8 
9 #include "base/thread.h"
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/Mutex.h"
12 #include "mozilla/Monitor.h"
13 #include "mozilla/layers/NativeLayerWayland.h"
14 #include "MozContainer.h"
15 #include "nsWaylandDisplay.h"
16 #include "VsyncSource.h"
17 
18 namespace mozilla {
19 
20 using layers::NativeLayerRootWayland;
21 
22 /*
23  * WaylandVsyncSource
24  *
25  * This class provides a per-widget VsyncSource under Wayland, emulated using
26  * frame callbacks on the widget surface with empty surface commits.
27  *
28  * Wayland does not expose vsync/vblank, as it considers that an implementation
29  * detail the clients should not concern themselves with. Instead, frame
30  * callbacks are provided whenever the compositor believes it is a good time to
31  * start drawing the next frame for a particular surface, giving us as much
32  * time as possible to do so.
33  *
34  * Note that the compositor sends frame callbacks only when it sees fit, and
35  * when that may be is entirely up to the compositor. One cannot expect a
36  * certain rate of callbacks, or any callbacks at all. Examples of common
37  * variations would be surfaces moved between outputs with different refresh
38  * rates, and surfaces that are hidden and therefore do not receieve any
39  * callbacks at all. Other hypothetical scenarios of variation could be
40  * throttling to conserve power, or because a user has requested it.
41  *
42  */
43 class WaylandVsyncSource final : public gfx::VsyncSource {
44  public:
WaylandVsyncSource()45   WaylandVsyncSource() { mGlobalDisplay = new WaylandDisplay(); }
46 
~WaylandVsyncSource()47   virtual ~WaylandVsyncSource() { MOZ_ASSERT(NS_IsMainThread()); }
48 
GetGlobalDisplay()49   virtual Display& GetGlobalDisplay() override { return *mGlobalDisplay; }
50 
51   class WaylandDisplay final : public mozilla::gfx::VsyncSource::Display {
52    public:
53     WaylandDisplay();
54 
55     void MaybeUpdateSource(MozContainer* aContainer);
56     void MaybeUpdateSource(
57         const RefPtr<NativeLayerRootWayland>& aNativeLayerRoot);
58 
59     void EnableMonitor();
60     void DisableMonitor();
61 
62     void FrameCallback(uint32_t timestampTime);
63     void Notify();
64 
65     TimeDuration GetVsyncRate() override;
66 
67     virtual void EnableVsync() override;
68 
69     virtual void DisableVsync() override;
70 
71     virtual bool IsVsyncEnabled() override;
72 
73     virtual void Shutdown() override;
74 
75    private:
76     virtual ~WaylandDisplay() = default;
77     void Refresh();
78     void SetupFrameCallback();
79     void ClearFrameCallback();
80     void CalculateVsyncRate(TimeStamp vsyncTimestamp);
81 
82     Mutex mMutex;
83     bool mIsShutdown;
84     bool mVsyncEnabled;
85     bool mMonitorEnabled;
86     bool mCallbackRequested;
87     struct wl_display* mDisplay;
88     MozContainer* mContainer;
89     RefPtr<NativeLayerRootWayland> mNativeLayerRoot;
90     TimeDuration mVsyncRate;
91     TimeStamp mLastVsyncTimeStamp;
92   };
93 
94  private:
95   // We need a refcounted VsyncSource::Display to use chromium IPC runnables.
96   RefPtr<WaylandDisplay> mGlobalDisplay;
97 };
98 
99 }  // namespace mozilla
100 
101 #endif  // _WaylandVsyncSource_h_
102