Home | History | Annotate | Download | only in Scheduler
      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 <cinttypes>
     22 #include <mutex>
     23 
     24 #include "Scheduler.h"
     25 
     26 namespace android {
     27 
     28 /*
     29  * Modulates the vsync-offsets depending on current SurfaceFlinger state.
     30  */
     31 class VSyncModulator {
     32 private:
     33     // Number of frames we'll keep the early phase offsets once they are activated for a
     34     // transaction. This acts as a low-pass filter in case the client isn't quick enough in
     35     // sending new transactions.
     36     const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
     37 
     38 public:
     39     struct Offsets {
     40         nsecs_t sf;
     41         nsecs_t app;
     42     };
     43 
     44     // Sets the phase offsets
     45     //
     46     // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
     47     //          as early. May be the same as late, in which case we don't shift offsets.
     48     // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
     49     //            and the transaction was marked as early, we'll use sfEarly.
     50     // sfLate: The regular SF vsync phase offset.
     51     // appEarly: Like sfEarly, but for the app-vsync
     52     // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
     53     // appLate: The regular app vsync phase offset.
     54     void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
     55         mEarlyOffsets = early;
     56         mEarlyGlOffsets = earlyGl;
     57         mLateOffsets = late;
     58 
     59         if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
     60             mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
     61         }
     62 
     63         if (mAppConnectionHandle && late.app != mOffsets.load().app) {
     64             mScheduler->setPhaseOffset(mAppConnectionHandle, late.app);
     65         }
     66 
     67         mOffsets = late;
     68     }
     69 
     70     Offsets getEarlyOffsets() const { return mEarlyOffsets; }
     71 
     72     Offsets getEarlyGlOffsets() const { return mEarlyGlOffsets; }
     73 
     74     void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
     75         mSfEventThread = sfEventThread;
     76         mAppEventThread = appEventThread;
     77     }
     78 
     79     void setSchedulerAndHandles(Scheduler* scheduler,
     80                                 Scheduler::ConnectionHandle* appConnectionHandle,
     81                                 Scheduler::ConnectionHandle* sfConnectionHandle) {
     82         mScheduler = scheduler;
     83         mAppConnectionHandle = appConnectionHandle;
     84         mSfConnectionHandle = sfConnectionHandle;
     85     }
     86 
     87     void setTransactionStart(Scheduler::TransactionStart transactionStart) {
     88         if (transactionStart == Scheduler::TransactionStart::EARLY) {
     89             mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION;
     90         }
     91 
     92         // An early transaction stays an early transaction.
     93         if (transactionStart == mTransactionStart ||
     94             mTransactionStart == Scheduler::TransactionStart::EARLY) {
     95             return;
     96         }
     97         mTransactionStart = transactionStart;
     98         updateOffsets();
     99     }
    100 
    101     void onTransactionHandled() {
    102         if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
    103         mTransactionStart = Scheduler::TransactionStart::NORMAL;
    104         updateOffsets();
    105     }
    106 
    107     // Called when we send a refresh rate change to hardware composer, so that
    108     // we can move into early offsets.
    109     void onRefreshRateChangeInitiated() {
    110         if (mRefreshRateChangePending) {
    111             return;
    112         }
    113         mRefreshRateChangePending = true;
    114         updateOffsets();
    115     }
    116 
    117     // Called when we detect from vsync signals that the refresh rate changed.
    118     // This way we can move out of early offsets if no longer necessary.
    119     void onRefreshRateChangeDetected() {
    120         if (!mRefreshRateChangePending) {
    121             return;
    122         }
    123         mRefreshRateChangePending = false;
    124         updateOffsets();
    125     }
    126 
    127     void onRefreshed(bool usedRenderEngine) {
    128         bool updateOffsetsNeeded = false;
    129         if (mRemainingEarlyFrameCount > 0) {
    130             mRemainingEarlyFrameCount--;
    131             updateOffsetsNeeded = true;
    132         }
    133         if (usedRenderEngine != mLastFrameUsedRenderEngine) {
    134             mLastFrameUsedRenderEngine = usedRenderEngine;
    135             updateOffsetsNeeded = true;
    136         }
    137         if (updateOffsetsNeeded) {
    138             updateOffsets();
    139         }
    140     }
    141 
    142     Offsets getOffsets() {
    143         // Early offsets are used if we're in the middle of a refresh rate
    144         // change, or if we recently begin a transaction.
    145         if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
    146             mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) {
    147             return mEarlyOffsets;
    148         } else if (mLastFrameUsedRenderEngine) {
    149             return mEarlyGlOffsets;
    150         } else {
    151             return mLateOffsets;
    152         }
    153     }
    154 
    155 private:
    156     void updateOffsets() {
    157         const Offsets desired = getOffsets();
    158         const Offsets current = mOffsets;
    159 
    160         bool changed = false;
    161         if (desired.sf != current.sf) {
    162             if (mSfConnectionHandle != nullptr) {
    163                 mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
    164             } else {
    165                 mSfEventThread->setPhaseOffset(desired.sf);
    166             }
    167             changed = true;
    168         }
    169         if (desired.app != current.app) {
    170             if (mAppConnectionHandle != nullptr) {
    171                 mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
    172             } else {
    173                 mAppEventThread->setPhaseOffset(desired.app);
    174             }
    175             changed = true;
    176         }
    177 
    178         if (changed) {
    179             mOffsets = desired;
    180         }
    181     }
    182 
    183     Offsets mLateOffsets;
    184     Offsets mEarlyOffsets;
    185     Offsets mEarlyGlOffsets;
    186 
    187     EventThread* mSfEventThread = nullptr;
    188     EventThread* mAppEventThread = nullptr;
    189 
    190     Scheduler* mScheduler = nullptr;
    191     Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
    192     Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
    193 
    194     std::atomic<Offsets> mOffsets;
    195 
    196     std::atomic<Scheduler::TransactionStart> mTransactionStart =
    197             Scheduler::TransactionStart::NORMAL;
    198     std::atomic<bool> mLastFrameUsedRenderEngine = false;
    199     std::atomic<bool> mRefreshRateChangePending = false;
    200     std::atomic<int> mRemainingEarlyFrameCount = 0;
    201 };
    202 
    203 } // namespace android
    204