Home | History | Annotate | Download | only in surfaceflinger
      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 <utils/Errors.h>
     20 
     21 #include <mutex>
     22 
     23 using namespace android::surfaceflinger;
     24 
     25 namespace android {
     26 
     27 /*
     28  * Modulates the vsync-offsets depending on current SurfaceFlinger state.
     29  */
     30 class VSyncModulator {
     31 private:
     32 
     33     // Number of frames we'll keep the early phase offsets once they are activated. This acts as a
     34     // low-pass filter in case the client isn't quick enough in sending new transactions.
     35     const int MIN_EARLY_FRAME_COUNT = 2;
     36 
     37 public:
     38 
     39     enum TransactionStart {
     40         EARLY,
     41         NORMAL
     42     };
     43 
     44     // Sets the phase offsets
     45     //
     46     // early: the phase offset when waking up early. May be the same as late, in which case we don't
     47     //        shift offsets.
     48     // late: the regular sf phase offset.
     49     void setPhaseOffsets(nsecs_t early, nsecs_t late) {
     50         mEarlyPhaseOffset = early;
     51         mLatePhaseOffset = late;
     52         mPhaseOffset = late;
     53     }
     54 
     55     nsecs_t getEarlyPhaseOffset() const {
     56         return mEarlyPhaseOffset;
     57     }
     58 
     59     void setEventThread(EventThread* eventThread) {
     60         mEventThread = eventThread;
     61     }
     62 
     63     void setTransactionStart(TransactionStart transactionStart) {
     64 
     65         if (transactionStart == TransactionStart::EARLY) {
     66             mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT;
     67         }
     68 
     69         // An early transaction stays an early transaction.
     70         if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) {
     71             return;
     72         }
     73         mTransactionStart = transactionStart;
     74         updatePhaseOffsets();
     75     }
     76 
     77     void onTransactionHandled() {
     78         if (mTransactionStart == TransactionStart::NORMAL) return;
     79         mTransactionStart = TransactionStart::NORMAL;
     80         updatePhaseOffsets();
     81     }
     82 
     83     void onRefreshed(bool usedRenderEngine) {
     84         bool updatePhaseOffsetsNeeded = false;
     85         if (mRemainingEarlyFrameCount > 0) {
     86             mRemainingEarlyFrameCount--;
     87             updatePhaseOffsetsNeeded = true;
     88         }
     89         if (usedRenderEngine != mLastFrameUsedRenderEngine) {
     90             mLastFrameUsedRenderEngine = usedRenderEngine;
     91             updatePhaseOffsetsNeeded = true;
     92         }
     93         if (updatePhaseOffsetsNeeded) {
     94             updatePhaseOffsets();
     95         }
     96     }
     97 
     98 private:
     99 
    100     void updatePhaseOffsets() {
    101 
    102         // Do not change phase offsets if disabled.
    103         if (mEarlyPhaseOffset == mLatePhaseOffset) return;
    104 
    105         if (shouldUseEarlyOffset()) {
    106             if (mPhaseOffset != mEarlyPhaseOffset) {
    107                 if (mEventThread) {
    108                     mEventThread->setPhaseOffset(mEarlyPhaseOffset);
    109                 }
    110                 mPhaseOffset = mEarlyPhaseOffset;
    111             }
    112         } else {
    113             if (mPhaseOffset != mLatePhaseOffset) {
    114                 if (mEventThread) {
    115                     mEventThread->setPhaseOffset(mLatePhaseOffset);
    116                 }
    117                 mPhaseOffset = mLatePhaseOffset;
    118             }
    119         }
    120     }
    121 
    122     bool shouldUseEarlyOffset() {
    123         return mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine
    124                 || mRemainingEarlyFrameCount > 0;
    125     }
    126 
    127     nsecs_t mLatePhaseOffset = 0;
    128     nsecs_t mEarlyPhaseOffset = 0;
    129     EventThread* mEventThread = nullptr;
    130     std::atomic<nsecs_t> mPhaseOffset = 0;
    131     std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
    132     std::atomic<bool> mLastFrameUsedRenderEngine = false;
    133     std::atomic<int> mRemainingEarlyFrameCount = 0;
    134 };
    135 
    136 } // namespace android
    137