1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <cstdint>
20 #include <functional>
21 #include <memory>
22 
23 #include <ui/DisplayStatInfo.h>
24 #include <ui/GraphicTypes.h>
25 
26 #include "DispSync.h"
27 #include "EventControlThread.h"
28 #include "EventThread.h"
29 #include "IdleTimer.h"
30 #include "InjectVSyncSource.h"
31 #include "LayerHistory.h"
32 #include "RefreshRateConfigs.h"
33 #include "SchedulerUtils.h"
34 
35 namespace android {
36 
37 class EventControlThread;
38 
39 class Scheduler {
40 public:
41     // Enum to keep track of whether we trigger event to notify choreographer of config changes.
42     enum class ConfigEvent { None, Changed };
43 
44     // logical or operator with the semantics of at least one of the events is Changed
45     friend ConfigEvent operator|(const ConfigEvent& first, const ConfigEvent& second) {
46         if (first == ConfigEvent::Changed) return ConfigEvent::Changed;
47         if (second == ConfigEvent::Changed) return ConfigEvent::Changed;
48         return ConfigEvent::None;
49     }
50 
51     using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
52     using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
53 
54     // Enum to indicate whether to start the transaction early, or at vsync time.
55     enum class TransactionStart { EARLY, NORMAL };
56 
57     /* The scheduler handle is a BBinder object passed to the client from which we can extract
58      * an ID for subsequent operations.
59      */
60     class ConnectionHandle : public BBinder {
61     public:
ConnectionHandle(int64_t id)62         ConnectionHandle(int64_t id) : id(id) {}
63 
64         ~ConnectionHandle() = default;
65 
66         const int64_t id;
67     };
68 
69     class Connection {
70     public:
Connection(sp<ConnectionHandle> handle,sp<EventThreadConnection> eventConnection,std::unique_ptr<EventThread> eventThread)71         Connection(sp<ConnectionHandle> handle, sp<EventThreadConnection> eventConnection,
72                    std::unique_ptr<EventThread> eventThread)
73               : handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
74 
75         ~Connection() = default;
76 
77         sp<ConnectionHandle> handle;
78         sp<EventThreadConnection> eventConnection;
79         const std::unique_ptr<EventThread> thread;
80     };
81 
82     explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
83                        const scheduler::RefreshRateConfigs& refreshRateConfig);
84 
85     virtual ~Scheduler();
86 
87     /** Creates an EventThread connection. */
88     sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
89                                           nsecs_t offsetThresholdForNextVsync,
90                                           impl::EventThread::InterceptVSyncsCallback);
91 
92     sp<IDisplayEventConnection> createDisplayEventConnection(
93             const sp<ConnectionHandle>& handle, ISurfaceComposer::ConfigChanged configChanged);
94 
95     // Getter methods.
96     EventThread* getEventThread(const sp<ConnectionHandle>& handle);
97 
98     // Provides access to the DispSync object for the primary display.
99     void withPrimaryDispSync(std::function<void(DispSync&)> const& fn);
100 
101     sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
102 
103     // Should be called when receiving a hotplug event.
104     void hotplugReceived(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
105                          bool connected);
106 
107     // Should be called after the screen is turned on.
108     void onScreenAcquired(const sp<ConnectionHandle>& handle);
109 
110     // Should be called before the screen is turned off.
111     void onScreenReleased(const sp<ConnectionHandle>& handle);
112 
113     // Should be called when display config changed
114     void onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
115                          int32_t configId);
116 
117     // Should be called when dumpsys command is received.
118     void dump(const sp<ConnectionHandle>& handle, std::string& result) const;
119 
120     // Offers ability to modify phase offset in the event thread.
121     void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
122 
123     void getDisplayStatInfo(DisplayStatInfo* stats);
124 
125     void enableHardwareVsync();
126     void disableHardwareVsync(bool makeUnavailable);
127     // Resyncs the scheduler to hardware vsync.
128     // If makeAvailable is true, then hardware vsync will be turned on.
129     // Otherwise, if hardware vsync is not already enabled then this method will
130     // no-op.
131     // The period is the vsync period from the current display configuration.
132     void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
133     void resync();
134     void setRefreshSkipCount(int count);
135     // Passes a vsync sample to DispSync. periodFlushed will be true if
136     // DispSync detected that the vsync period changed, and false otherwise.
137     void addResyncSample(const nsecs_t timestamp, bool* periodFlushed);
138     void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
139     void setIgnorePresentFences(bool ignore);
140     nsecs_t getDispSyncExpectedPresentTime();
141     // Registers the layer in the scheduler, and returns the handle for future references.
142     std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name,
143                                                                         int windowType);
144 
145     // Stores present time for a layer.
146     void addLayerPresentTimeAndHDR(
147             const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
148             nsecs_t presentTime, bool isHDR);
149     // Stores visibility for a layer.
150     void setLayerVisibility(
151             const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible);
152     // Updates FPS based on the most content presented.
153     void updateFpsBasedOnContent();
154     // Callback that gets invoked when Scheduler wants to change the refresh rate.
155     void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback);
156 
157     // Returns whether idle timer is enabled or not
isIdleTimerEnabled()158     bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
159 
160     // Function that resets the idle timer.
161     void resetIdleTimer();
162 
163     // Function that resets the touch timer.
164     void notifyTouchEvent();
165 
166     // Function that sets whether display power mode is normal or not.
167     void setDisplayPowerState(bool normal);
168 
169     // Returns relevant information about Scheduler for dumpsys purposes.
170     std::string doDump();
171 
172     // calls DispSync::dump() on primary disp sync
173     void dumpPrimaryDispSync(std::string& result) const;
174 
175 protected:
176     virtual std::unique_ptr<EventThread> makeEventThread(
177             const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
178             nsecs_t offsetThresholdForNextVsync,
179             impl::EventThread::InterceptVSyncsCallback interceptCallback);
180 
181 private:
182     friend class TestableScheduler;
183 
184     // In order to make sure that the features don't override themselves, we need a state machine
185     // to keep track which feature requested the config change.
186     enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF };
187     enum class IdleTimerState { EXPIRED, RESET };
188     enum class TouchState { INACTIVE, ACTIVE };
189     enum class DisplayPowerTimerState { EXPIRED, RESET };
190 
191     // Creates a connection on the given EventThread and forwards the given callbacks.
192     sp<EventThreadConnection> createConnectionInternal(EventThread*,
193                                                        ISurfaceComposer::ConfigChanged);
194 
195     nsecs_t calculateAverage() const;
196     void updateFrameSkipping(const int64_t skipCount);
197 
198     // Function that is called when the timer resets.
199     void resetTimerCallback();
200     // Function that is called when the timer expires.
201     void expiredTimerCallback();
202     // Function that is called when the timer resets when paired with a display
203     // driver timeout in the kernel. This enables hardware vsync when we move
204     // out from idle.
205     void resetKernelTimerCallback();
206     // Function that is called when the timer expires when paired with a display
207     // driver timeout in the kernel. This disables hardware vsync when we move
208     // into idle.
209     void expiredKernelTimerCallback();
210     // Function that is called when the touch timer resets.
211     void resetTouchTimerCallback();
212     // Function that is called when the touch timer expires.
213     void expiredTouchTimerCallback();
214     // Function that is called when the display power timer resets.
215     void resetDisplayPowerTimerCallback();
216     // Function that is called when the display power timer expires.
217     void expiredDisplayPowerTimerCallback();
218     // Sets vsync period.
219     void setVsyncPeriod(const nsecs_t period);
220     // handles various timer features to change the refresh rate.
221     template <class T>
222     void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection);
223     // Calculate the new refresh rate type
224     RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
225     // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
226     void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent);
227 
228     // Helper function to calculate error frames
229     float getErrorFrames(float contentFps, float configFps);
230 
231     // If fences from sync Framework are supported.
232     const bool mHasSyncFramework;
233 
234     // The offset in nanoseconds to use, when DispSync timestamps present fence
235     // signaling time.
236     nsecs_t mDispSyncPresentTimeOffset;
237 
238     // Each connection has it's own ID. This variable keeps track of the count.
239     static std::atomic<int64_t> sNextId;
240 
241     // Connections are stored in a map <connection ID, connection> for easy retrieval.
242     std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
243 
244     std::mutex mHWVsyncLock;
245     bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
246     bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
247 
248     std::atomic<nsecs_t> mLastResyncTime = 0;
249 
250     std::unique_ptr<DispSync> mPrimaryDispSync;
251     std::unique_ptr<EventControlThread> mEventControlThread;
252 
253     // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
254     // a proof of concept. We turn on frame skipping if the difference between the timestamps
255     // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
256     nsecs_t mPreviousFrameTimestamp = 0;
257     // Keeping track of whether we are skipping the refresh count. If we want to
258     // simulate 30Hz rendering, we skip every other frame, and this variable is set
259     // to 1.
260     int64_t mSkipCount = 0;
261     std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
262     size_t mCounter = 0;
263 
264     // Historical information about individual layers. Used for predicting the refresh rate.
265     scheduler::LayerHistory mLayerHistory;
266 
267     // Timer that records time between requests for next vsync. If the time is higher than a given
268     // interval, a callback is fired. Set this variable to >0 to use this feature.
269     int64_t mSetIdleTimerMs = 0;
270     std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
271     // Enables whether to use idle timer callbacks that support the kernel
272     // timer.
273     bool mSupportKernelTimer;
274 
275     // Timer used to monitor touch events.
276     int64_t mSetTouchTimerMs = 0;
277     std::unique_ptr<scheduler::IdleTimer> mTouchTimer;
278 
279     // Timer used to monitor display power mode.
280     int64_t mSetDisplayPowerTimerMs = 0;
281     std::unique_ptr<scheduler::IdleTimer> mDisplayPowerTimer;
282 
283     std::mutex mCallbackLock;
284     ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
285 
286     // In order to make sure that the features don't override themselves, we need a state machine
287     // to keep track which feature requested the config change.
288     std::mutex mFeatureStateLock;
289     ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) =
290             ContentFeatureState::CONTENT_DETECTION_OFF;
291     IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
292     TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE;
293     DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) =
294             DisplayPowerTimerState::EXPIRED;
295     uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock);
296     RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock);
297     bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false;
298     bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true;
299 
300     const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
301 
302     // Global config to force HDR content to work on DEFAULT refreshRate
303     static constexpr bool mForceHDRContentToDefaultRefreshRate = false;
304 };
305 
306 } // namespace android
307