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 <chrono>
20 #include <mutex>
21 
22 #include "Scheduler.h"
23 
24 namespace android::scheduler {
25 
26 /*
27  * Modulates the vsync-offsets depending on current SurfaceFlinger state.
28  */
29 class VSyncModulator {
30 private:
31     // Number of frames we'll keep the early phase offsets once they are activated for a
32     // transaction. This acts as a low-pass filter in case the client isn't quick enough in
33     // sending new transactions.
34     static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
35 
36     // Number of frames we'll keep the early gl phase offsets once they are activated.
37     // This acts as a low-pass filter to avoid scenarios where we rapidly
38     // switch in and out of gl composition.
39     static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
40 
41     // Margin used to account for potential data races
42     static const constexpr std::chrono::nanoseconds MARGIN_FOR_TX_APPLY = 1ms;
43 
44 public:
45     // Wrapper for a collection of surfaceflinger/app offsets for a particular
46     // configuration.
47     struct Offsets {
48         nsecs_t sf;
49         nsecs_t app;
50 
51         bool operator==(const Offsets& other) const { return sf == other.sf && app == other.app; }
52 
53         bool operator!=(const Offsets& other) const { return !(*this == other); }
54     };
55 
56     struct OffsetsConfig {
57         Offsets early;   // For transactions with the eEarlyWakeup flag.
58         Offsets earlyGl; // As above but while compositing with GL.
59         Offsets late;    // Default.
60 
61         bool operator==(const OffsetsConfig& other) const {
62             return early == other.early && earlyGl == other.earlyGl && late == other.late;
63         }
64 
65         bool operator!=(const OffsetsConfig& other) const { return !(*this == other); }
66     };
67 
68     VSyncModulator(IPhaseOffsetControl&, ConnectionHandle appConnectionHandle,
69                    ConnectionHandle sfConnectionHandle, const OffsetsConfig&);
70 
71     void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
72 
73     // Signals that a transaction has started, and changes offsets accordingly.
74     void setTransactionStart(Scheduler::TransactionStart transactionStart);
75 
76     // Signals that a transaction has been completed, so that we can finish
77     // special handling for a transaction.
78     void onTransactionHandled();
79 
80     // Called when we send a refresh rate change to hardware composer, so that
81     // we can move into early offsets.
82     void onRefreshRateChangeInitiated();
83 
84     // Called when we detect from vsync signals that the refresh rate changed.
85     // This way we can move out of early offsets if no longer necessary.
86     void onRefreshRateChangeCompleted();
87 
88     // Called when the display is presenting a new frame. usedRenderEngine
89     // should be set to true if RenderEngine was involved with composing the new
90     // frame.
91     void onRefreshed(bool usedRenderEngine);
92 
93     // Returns the offsets that we are currently using
94     Offsets getOffsets() const EXCLUDES(mMutex);
95 
96 private:
97     friend class VSyncModulatorTest;
98     // Returns the next offsets that we should be using
99     const Offsets& getNextOffsets() const REQUIRES(mMutex);
100     // Updates offsets and persists them into the scheduler framework.
101     void updateOffsets() EXCLUDES(mMutex);
102     void updateOffsetsLocked() REQUIRES(mMutex);
103 
104     IPhaseOffsetControl& mPhaseOffsetControl;
105     const ConnectionHandle mAppConnectionHandle;
106     const ConnectionHandle mSfConnectionHandle;
107 
108     mutable std::mutex mMutex;
109     OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex);
110 
GUARDED_BY(mMutex)111     Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
112 
113     std::atomic<Scheduler::TransactionStart> mTransactionStart =
114             Scheduler::TransactionStart::Normal;
115     std::atomic<bool> mRefreshRateChangePending = false;
116     std::atomic<bool> mExplicitEarlyWakeup = false;
117     std::atomic<int> mRemainingEarlyFrameCount = 0;
118     std::atomic<int> mRemainingRenderEngineUsageCount = 0;
119     std::atomic<std::chrono::steady_clock::time_point> mEarlyTxnStartTime = {};
120     std::atomic<std::chrono::steady_clock::time_point> mTxnAppliedTime = {};
121 
122     bool mTraceDetailedInfo = false;
123 };
124 
125 } // namespace android::scheduler
126