summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/Scheduler/Scheduler.h
blob: 730ea8f0c88a006d32cab05a17fb920ebada8447 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <unordered_map>

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#include <ui/GraphicTypes.h>
#pragma clang diagnostic pop

#include "EventControlThread.h"
#include "EventThread.h"
#include "LayerHistory.h"
#include "OneShotTimer.h"
#include "RefreshRateConfigs.h"
#include "SchedulerUtils.h"

namespace android {

using namespace std::chrono_literals;
using scheduler::LayerHistory;

class DispSync;
class FenceTime;
class InjectVSyncSource;
struct DisplayStateInfo;

class ISchedulerCallback {
public:
    virtual ~ISchedulerCallback() = default;
    virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
                                   scheduler::RefreshRateConfigEvent) = 0;
    virtual void repaintEverythingForHWC() = 0;
    virtual void kernelTimerChanged(bool expired) = 0;
};

class IPhaseOffsetControl {
public:
    virtual ~IPhaseOffsetControl() = default;
    virtual void setPhaseOffset(scheduler::ConnectionHandle, nsecs_t phaseOffset) = 0;
};

class Scheduler : public IPhaseOffsetControl {
public:
    using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
    using ConfigEvent = scheduler::RefreshRateConfigEvent;

    // Indicates whether to start the transaction early, or at vsync time.
    enum class TransactionStart {
        Early,      // DEPRECATED. Start the transaction early. Times out on its own
        EarlyStart, // Start the transaction early and keep this config until EarlyEnd
        EarlyEnd,   // End the early config started at EarlyStart
        Normal      // Start the transaction at the normal time
    };

    Scheduler(impl::EventControlThread::SetVSyncEnabledFunction,
              const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback,
              bool useContentDetectionV2, bool useContentDetection);

    virtual ~Scheduler();

    DispSync& getPrimaryDispSync();

    using ConnectionHandle = scheduler::ConnectionHandle;
    ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
                                      impl::EventThread::InterceptVSyncsCallback);

    sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle,
                                                             ISurfaceComposer::ConfigChanged);

    sp<EventThreadConnection> getEventConnection(ConnectionHandle);

    void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
    void onPrimaryDisplayConfigChanged(ConnectionHandle, PhysicalDisplayId,
                                       HwcConfigIndexType configId, nsecs_t vsyncPeriod)
            EXCLUDES(mFeatureStateLock);
    void onNonPrimaryDisplayConfigChanged(ConnectionHandle, PhysicalDisplayId,
                                          HwcConfigIndexType configId, nsecs_t vsyncPeriod);
    void onScreenAcquired(ConnectionHandle);
    void onScreenReleased(ConnectionHandle);

    // Modifies phase offset in the event thread.
    void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset) override;

    void getDisplayStatInfo(DisplayStatInfo* stats);

    // Returns injector handle if injection has toggled, or an invalid handle otherwise.
    ConnectionHandle enableVSyncInjection(bool enable);

    // Returns false if injection is disabled.
    bool injectVSync(nsecs_t when, nsecs_t expectedVSyncTime);

    void enableHardwareVsync();
    void disableHardwareVsync(bool makeUnavailable);

    // Resyncs the scheduler to hardware vsync.
    // If makeAvailable is true, then hardware vsync will be turned on.
    // Otherwise, if hardware vsync is not already enabled then this method will
    // no-op.
    // The period is the vsync period from the current display configuration.
    void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
    void resync();

    // Passes a vsync sample to DispSync. periodFlushed will be true if
    // DispSync detected that the vsync period changed, and false otherwise.
    void addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
                         bool* periodFlushed);
    void addPresentFence(const std::shared_ptr<FenceTime>&);
    void setIgnorePresentFences(bool ignore);
    nsecs_t getDispSyncExpectedPresentTime(nsecs_t now);

    // Layers are registered on creation, and unregistered when the weak reference expires.
    void registerLayer(Layer*);
    void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
    void setConfigChangePending(bool pending);

    // Detects content using layer history, and selects a matching refresh rate.
    void chooseRefreshRateForContent();

    bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
    void resetIdleTimer();

    // Function that resets the touch timer.
    void notifyTouchEvent();

    void setDisplayPowerState(bool normal);

    void dump(std::string&) const;
    void dump(ConnectionHandle, std::string&) const;

    // Get the appropriate refresh for current conditions.
    std::optional<HwcConfigIndexType> getPreferredConfigId();

    // Notifies the scheduler about a refresh rate timeline change.
    void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);

    // Notifies the scheduler when the display was refreshed
    void onDisplayRefreshed(nsecs_t timestamp);

    // Notifies the scheduler when the display size has changed. Called from SF's main thread
    void onPrimaryDisplayAreaChanged(uint32_t displayArea);

    size_t getEventThreadConnectionCount(ConnectionHandle handle);

private:
    friend class TestableScheduler;

    // In order to make sure that the features don't override themselves, we need a state machine
    // to keep track which feature requested the config change.
    enum class ContentDetectionState { Off, On };
    enum class TimerState { Reset, Expired };
    enum class TouchState { Inactive, Active };

    // Used by tests to inject mocks.
    Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
              const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback,
              bool useContentDetectionV2, bool useContentDetection);

    std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs);

    // Create a connection on the given EventThread.
    ConnectionHandle createConnection(std::unique_ptr<EventThread>);
    sp<EventThreadConnection> createConnectionInternal(EventThread*,
                                                       ISurfaceComposer::ConfigChanged);

    // Update feature state machine to given state when corresponding timer resets or expires.
    void kernelIdleTimerCallback(TimerState);
    void idleTimerCallback(TimerState);
    void touchTimerCallback(TimerState);
    void displayPowerTimerCallback(TimerState);

    // handles various timer features to change the refresh rate.
    template <class T>
    bool handleTimerStateChanged(T* currentState, T newState);

    void setVsyncPeriod(nsecs_t period);

    // This function checks whether individual features that are affecting the refresh rate
    // selection were initialized, prioritizes them, and calculates the HwcConfigIndexType
    // for the suggested refresh rate.
    HwcConfigIndexType calculateRefreshRateConfigIndexType(
            scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr)
            REQUIRES(mFeatureStateLock);

    void dispatchCachedReportedConfig() REQUIRES(mFeatureStateLock);

    // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
    struct Connection {
        sp<EventThreadConnection> connection;
        std::unique_ptr<EventThread> thread;
    };

    ConnectionHandle::Id mNextConnectionHandleId = 0;
    std::unordered_map<ConnectionHandle, Connection> mConnections;

    bool mInjectVSyncs = false;
    InjectVSyncSource* mVSyncInjector = nullptr;
    ConnectionHandle mInjectorConnectionHandle;

    std::mutex mHWVsyncLock;
    bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false;
    bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false;

    std::atomic<nsecs_t> mLastResyncTime = 0;

    // Whether to use idle timer callbacks that support the kernel timer.
    const bool mSupportKernelTimer;

    std::unique_ptr<DispSync> mPrimaryDispSync;
    std::unique_ptr<EventControlThread> mEventControlThread;

    // Used to choose refresh rate if content detection is enabled.
    std::unique_ptr<LayerHistory> mLayerHistory;

    // Timer that records time between requests for next vsync.
    std::optional<scheduler::OneShotTimer> mIdleTimer;
    // Timer used to monitor touch events.
    std::optional<scheduler::OneShotTimer> mTouchTimer;
    // Timer used to monitor display power mode.
    std::optional<scheduler::OneShotTimer> mDisplayPowerTimer;

    ISchedulerCallback& mSchedulerCallback;

    // In order to make sure that the features don't override themselves, we need a state machine
    // to keep track which feature requested the config change.
    std::mutex mFeatureStateLock;

    struct {
        ContentDetectionState contentDetectionV1 = ContentDetectionState::Off;
        TimerState idleTimer = TimerState::Reset;
        TouchState touch = TouchState::Inactive;
        TimerState displayPowerTimer = TimerState::Expired;

        std::optional<HwcConfigIndexType> configId;
        LayerHistory::Summary contentRequirements;

        bool isDisplayPowerStateNormal = true;

        // Used to cache the last parameters of onPrimaryDisplayConfigChanged
        struct ConfigChangedParams {
            ConnectionHandle handle;
            PhysicalDisplayId displayId;
            HwcConfigIndexType configId;
            nsecs_t vsyncPeriod;
        };

        std::optional<ConfigChangedParams> cachedConfigChangedParams;
    } mFeatures GUARDED_BY(mFeatureStateLock);

    const scheduler::RefreshRateConfigs& mRefreshRateConfigs;

    std::mutex mVsyncTimelineLock;
    std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
            GUARDED_BY(mVsyncTimelineLock);
    static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;

    // This variable indicates whether to use the content detection feature at all.
    const bool mUseContentDetection;
    // This variable indicates whether to use V2 version of the content detection.
    const bool mUseContentDetectionV2;
};

} // namespace android