• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     using GetVsyncPeriod = std::function<nsecs_t()>;
54 
55     // Enum to indicate whether to start the transaction early, or at vsync time.
56     enum class TransactionStart { EARLY, NORMAL };
57 
58     /* The scheduler handle is a BBinder object passed to the client from which we can extract
59      * an ID for subsequent operations.
60      */
61     class ConnectionHandle : public BBinder {
62     public:
ConnectionHandle(int64_t id)63         ConnectionHandle(int64_t id) : id(id) {}
64 
65         ~ConnectionHandle() = default;
66 
67         const int64_t id;
68     };
69 
70     class Connection {
71     public:
Connection(sp<ConnectionHandle> handle,sp<EventThreadConnection> eventConnection,std::unique_ptr<EventThread> eventThread)72         Connection(sp<ConnectionHandle> handle, sp<EventThreadConnection> eventConnection,
73                    std::unique_ptr<EventThread> eventThread)
74               : handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
75 
76         ~Connection() = default;
77 
78         sp<ConnectionHandle> handle;
79         sp<EventThreadConnection> eventConnection;
80         const std::unique_ptr<EventThread> thread;
81     };
82 
83     // Stores per-display state about VSYNC.
84     struct VsyncState {
VsyncStateVsyncState85         explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {}
86 
87         void resync(const GetVsyncPeriod&);
88 
89         Scheduler& scheduler;
90         std::atomic<nsecs_t> lastResyncTime = 0;
91     };
92 
93     explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
94                        const scheduler::RefreshRateConfigs& refreshRateConfig);
95 
96     virtual ~Scheduler();
97 
98     /** Creates an EventThread connection. */
99     sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
100                                           ResyncCallback,
101                                           impl::EventThread::InterceptVSyncsCallback);
102 
103     sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
104                                                              ResyncCallback);
105 
106     // Getter methods.
107     EventThread* getEventThread(const sp<ConnectionHandle>& handle);
108 
109     // Provides access to the DispSync object for the primary display.
110     void withPrimaryDispSync(std::function<void(DispSync&)> const& fn);
111 
112     sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
113 
114     // Should be called when receiving a hotplug event.
115     void hotplugReceived(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
116                          bool connected);
117 
118     // Should be called after the screen is turned on.
119     void onScreenAcquired(const sp<ConnectionHandle>& handle);
120 
121     // Should be called before the screen is turned off.
122     void onScreenReleased(const sp<ConnectionHandle>& handle);
123 
124     // Should be called when display config changed
125     void onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
126                          int32_t configId);
127 
128     // Should be called when dumpsys command is received.
129     void dump(const sp<ConnectionHandle>& handle, std::string& result) const;
130 
131     // Offers ability to modify phase offset in the event thread.
132     void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
133 
134     void getDisplayStatInfo(DisplayStatInfo* stats);
135 
136     void enableHardwareVsync();
137     void disableHardwareVsync(bool makeUnavailable);
138     void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
139     // Creates a callback for resyncing.
140     ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
141     void setRefreshSkipCount(int count);
142     // Passes a vsync sample to DispSync. periodChange will be true if DipSync
143     // detected that the vsync period changed, and false otherwise.
144     void addResyncSample(const nsecs_t timestamp, bool* periodChanged);
145     void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
146     void setIgnorePresentFences(bool ignore);
147     nsecs_t expectedPresentTime();
148     // Registers the layer in the scheduler, and returns the handle for future references.
149     std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name,
150                                                                         int windowType);
151 
152     // Stores present time for a layer.
153     void addLayerPresentTimeAndHDR(
154             const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
155             nsecs_t presentTime, bool isHDR);
156     // Stores visibility for a layer.
157     void setLayerVisibility(
158             const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible);
159     // Updates FPS based on the most content presented.
160     void updateFpsBasedOnContent();
161     // Callback that gets invoked when Scheduler wants to change the refresh rate.
162     void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);
163     void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod);
164 
165     // Returns whether idle timer is enabled or not
isIdleTimerEnabled()166     bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
167 
168     // Function that resets the idle timer.
169     void resetIdleTimer();
170 
171     // Function that resets the touch timer.
172     void notifyTouchEvent();
173 
174     // Returns relevant information about Scheduler for dumpsys purposes.
175     std::string doDump();
176 
177     // calls DispSync::dump() on primary disp sync
178     void dumpPrimaryDispSync(std::string& result) const;
179 
180 protected:
181     virtual std::unique_ptr<EventThread> makeEventThread(
182             const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
183             impl::EventThread::InterceptVSyncsCallback interceptCallback);
184 
185 private:
186     friend class TestableScheduler;
187 
188     // In order to make sure that the features don't override themselves, we need a state machine
189     // to keep track which feature requested the config change.
190     enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF };
191     enum class IdleTimerState { EXPIRED, RESET };
192     enum class TouchState { INACTIVE, ACTIVE };
193 
194     // Creates a connection on the given EventThread and forwards the given callbacks.
195     sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
196 
197     nsecs_t calculateAverage() const;
198     void updateFrameSkipping(const int64_t skipCount);
199 
200     // Function that is called when the timer resets.
201     void resetTimerCallback();
202     // Function that is called when the timer expires.
203     void expiredTimerCallback();
204     // Function that is called when the timer resets when paired with a display
205     // driver timeout in the kernel. This enables hardware vsync when we move
206     // out from idle.
207     void resetKernelTimerCallback();
208     // Function that is called when the timer expires when paired with a display
209     // driver timeout in the kernel. This disables hardware vsync when we move
210     // into idle.
211     void expiredKernelTimerCallback();
212     // Function that is called when the touch timer resets.
213     void resetTouchTimerCallback();
214     // Function that is called when the touch timer expires.
215     void expiredTouchTimerCallback();
216     // Sets vsync period.
217     void setVsyncPeriod(const nsecs_t period);
218     // Idle timer feature's function to change the refresh rate.
219     void timerChangeRefreshRate(IdleTimerState idleTimerState);
220     // Touch timer feature's function to change the refresh rate.
221     void touchChangeRefreshRate(TouchState touchState);
222     // Calculate the new refresh rate type
223     RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
224     // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
225     void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent);
226 
227     // Helper function to calculate error frames
228     float getErrorFrames(float contentFps, float configFps);
229 
230     // If fences from sync Framework are supported.
231     const bool mHasSyncFramework;
232 
233     // The offset in nanoseconds to use, when DispSync timestamps present fence
234     // signaling time.
235     nsecs_t mDispSyncPresentTimeOffset;
236 
237     // Each connection has it's own ID. This variable keeps track of the count.
238     static std::atomic<int64_t> sNextId;
239 
240     // Connections are stored in a map <connection ID, connection> for easy retrieval.
241     std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
242 
243     std::mutex mHWVsyncLock;
244     bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
245     bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
246     const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
247 
248     std::unique_ptr<DispSync> mPrimaryDispSync;
249     std::unique_ptr<EventControlThread> mEventControlThread;
250 
251     // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
252     // a proof of concept. We turn on frame skipping if the difference between the timestamps
253     // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
254     nsecs_t mPreviousFrameTimestamp = 0;
255     // Keeping track of whether we are skipping the refresh count. If we want to
256     // simulate 30Hz rendering, we skip every other frame, and this variable is set
257     // to 1.
258     int64_t mSkipCount = 0;
259     std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
260     size_t mCounter = 0;
261 
262     // Historical information about individual layers. Used for predicting the refresh rate.
263     scheduler::LayerHistory mLayerHistory;
264 
265     // Timer that records time between requests for next vsync. If the time is higher than a given
266     // interval, a callback is fired. Set this variable to >0 to use this feature.
267     int64_t mSetIdleTimerMs = 0;
268     std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
269     // Enables whether to use idle timer callbacks that support the kernel
270     // timer.
271     bool mSupportKernelTimer;
272 
273     // Timer used to monitor touch events.
274     int64_t mSetTouchTimerMs = 0;
275     std::unique_ptr<scheduler::IdleTimer> mTouchTimer;
276 
277     std::mutex mCallbackLock;
278     ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
279     GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock);
280 
281     // In order to make sure that the features don't override themselves, we need a state machine
282     // to keep track which feature requested the config change.
283     std::mutex mFeatureStateLock;
284     ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) =
285             ContentFeatureState::CONTENT_DETECTION_OFF;
286     IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
287     TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE;
288     uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock);
289     RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock);
290     bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false;
291 
292     const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
293 
294     // Global config to force HDR content to work on DEFAULT refreshRate
295     static constexpr bool mForceHDRContentToDefaultRefreshRate = true;
296 };
297 
298 } // namespace android
299