Loading libs/gui/SurfaceComposerClient.cpp +31 −0 Original line number Original line Diff line number Diff line Loading @@ -353,6 +353,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), mEarlyWakeup(other.mEarlyWakeup), mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart), mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd), mContainsBuffer(other.mContainsBuffer), mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mDisplayStates = other.mDisplayStates; Loading @@ -375,6 +377,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const uint32_t transactionNestCount = parcel->readUint32(); const uint32_t transactionNestCount = parcel->readUint32(); const bool animation = parcel->readBool(); const bool animation = parcel->readBool(); const bool earlyWakeup = parcel->readBool(); const bool earlyWakeup = parcel->readBool(); const bool explicitEarlyWakeupStart = parcel->readBool(); const bool explicitEarlyWakeupEnd = parcel->readBool(); const bool containsBuffer = parcel->readBool(); const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const int64_t desiredPresentTime = parcel->readInt64(); Loading Loading @@ -443,6 +447,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mTransactionNestCount = transactionNestCount; mTransactionNestCount = transactionNestCount; mAnimation = animation; mAnimation = animation; mEarlyWakeup = earlyWakeup; mEarlyWakeup = earlyWakeup; mExplicitEarlyWakeupStart = explicitEarlyWakeupStart; mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd; mContainsBuffer = containsBuffer; mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mDesiredPresentTime = desiredPresentTime; mDisplayStates = displayStates; mDisplayStates = displayStates; Loading Loading @@ -470,6 +476,8 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeUint32(mTransactionNestCount); parcel->writeUint32(mTransactionNestCount); parcel->writeBool(mAnimation); parcel->writeBool(mAnimation); parcel->writeBool(mEarlyWakeup); parcel->writeBool(mEarlyWakeup); parcel->writeBool(mExplicitEarlyWakeupStart); parcel->writeBool(mExplicitEarlyWakeupEnd); parcel->writeBool(mContainsBuffer); parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeInt64(mDesiredPresentTime); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); Loading Loading @@ -545,6 +553,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mContainsBuffer |= other.mContainsBuffer; mContainsBuffer |= other.mContainsBuffer; mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart; mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; other.clear(); other.clear(); return *this; return *this; } } Loading @@ -559,6 +569,8 @@ void SurfaceComposerClient::Transaction::clear() { mTransactionNestCount = 0; mTransactionNestCount = 0; mAnimation = false; mAnimation = false; mEarlyWakeup = false; mEarlyWakeup = false; mExplicitEarlyWakeupStart = false; mExplicitEarlyWakeupEnd = false; mDesiredPresentTime = -1; mDesiredPresentTime = -1; } } Loading Loading @@ -682,9 +694,20 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { flags |= ISurfaceComposer::eEarlyWakeup; flags |= ISurfaceComposer::eEarlyWakeup; } } // If both mExplicitEarlyWakeupStart and mExplicitEarlyWakeupEnd are set // it is equivalent for none if (mExplicitEarlyWakeupStart && !mExplicitEarlyWakeupEnd) { flags |= ISurfaceComposer::eExplicitEarlyWakeupStart; } if (mExplicitEarlyWakeupEnd && !mExplicitEarlyWakeupStart) { flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd; } mForceSynchronous = false; mForceSynchronous = false; mAnimation = false; mAnimation = false; mEarlyWakeup = false; mEarlyWakeup = false; mExplicitEarlyWakeupStart = false; mExplicitEarlyWakeupEnd = false; sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, Loading Loading @@ -731,6 +754,14 @@ void SurfaceComposerClient::Transaction::setEarlyWakeup() { mEarlyWakeup = true; mEarlyWakeup = true; } } void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupStart() { mExplicitEarlyWakeupStart = true; } void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupEnd() { mExplicitEarlyWakeupEnd = true; } layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) { layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) { if (mComposerStates.count(handle) == 0) { if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list // we don't have it, add an initialized layer_state to our list Loading libs/gui/include/gui/ISurfaceComposer.h +14 −6 Original line number Original line Diff line number Diff line Loading @@ -83,10 +83,18 @@ public: eSynchronous = 0x01, eSynchronous = 0x01, eAnimation = 0x02, eAnimation = 0x02, // Indicates that this transaction will likely result in a lot of layers being composed, and // DEPRECATED - use eExplicitEarlyWakeup[Start|End] // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this eEarlyWakeup = 0x04, // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns) eEarlyWakeup = 0x04 // Explicit indication that this transaction and others to follow will likely result in a // lot of layers being composed, and thus, SurfaceFlinger should wake-up earlier to avoid // missing frame deadlines. In this case SurfaceFlinger will wake up at // (sf vsync offset - debug.sf.early_phase_offset_ns). SurfaceFlinger will continue to be // in the early configuration until it receives eExplicitEarlyWakeupEnd. These flags are // expected to be used by WindowManager only and are guarded by // android.permission.ACCESS_SURFACE_FLINGER eExplicitEarlyWakeupStart = 0x08, eExplicitEarlyWakeupEnd = 0x10, }; }; enum VsyncSource { enum VsyncSource { Loading libs/gui/include/gui/SurfaceComposerClient.h +8 −4 Original line number Original line Diff line number Diff line Loading @@ -349,6 +349,8 @@ public: uint32_t mTransactionNestCount = 0; uint32_t mTransactionNestCount = 0; bool mAnimation = false; bool mAnimation = false; bool mEarlyWakeup = false; bool mEarlyWakeup = false; bool mExplicitEarlyWakeupStart = false; bool mExplicitEarlyWakeupEnd = false; // Indicates that the Transaction contains a buffer that should be cached // Indicates that the Transaction contains a buffer that should be cached bool mContainsBuffer = false; bool mContainsBuffer = false; Loading Loading @@ -547,6 +549,8 @@ public: void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); void setAnimationTransaction(); void setAnimationTransaction(); void setEarlyWakeup(); void setEarlyWakeup(); void setExplicitEarlyWakeupStart(); void setExplicitEarlyWakeupEnd(); }; }; status_t clearLayerFrameStats(const sp<IBinder>& token) const; status_t clearLayerFrameStats(const sp<IBinder>& token) const; Loading services/surfaceflinger/Scheduler/Scheduler.h +14 −3 Original line number Original line Diff line number Diff line Loading @@ -55,13 +55,24 @@ public: virtual void kernelTimerChanged(bool expired) = 0; virtual void kernelTimerChanged(bool expired) = 0; }; }; class Scheduler { class IPhaseOffsetControl { public: virtual ~IPhaseOffsetControl() = default; virtual void setPhaseOffset(scheduler::ConnectionHandle, nsecs_t phaseOffset) = 0; }; class Scheduler : public IPhaseOffsetControl { public: public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; using ConfigEvent = scheduler::RefreshRateConfigEvent; // Indicates whether to start the transaction early, or at vsync time. // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; 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, Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, Loading Loading @@ -90,7 +101,7 @@ public: void onScreenReleased(ConnectionHandle); void onScreenReleased(ConnectionHandle); // Modifies phase offset in the event thread. // Modifies phase offset in the event thread. void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset); void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset) override; void getDisplayStatInfo(DisplayStatInfo* stats); void getDisplayStatInfo(DisplayStatInfo* stats); Loading services/surfaceflinger/Scheduler/VSyncModulator.cpp +33 −13 Original line number Original line Diff line number Diff line Loading @@ -31,11 +31,11 @@ namespace android::scheduler { namespace android::scheduler { VSyncModulator::VSyncModulator(Scheduler& scheduler, VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl, Scheduler::ConnectionHandle appConnectionHandle, Scheduler::ConnectionHandle appConnectionHandle, Scheduler::ConnectionHandle sfConnectionHandle, Scheduler::ConnectionHandle sfConnectionHandle, const OffsetsConfig& config) const OffsetsConfig& config) : mScheduler(scheduler), : mPhaseOffsetControl(phaseOffsetControl), mAppConnectionHandle(appConnectionHandle), mAppConnectionHandle(appConnectionHandle), mSfConnectionHandle(sfConnectionHandle), mSfConnectionHandle(sfConnectionHandle), mOffsetsConfig(config) { mOffsetsConfig(config) { Loading @@ -51,14 +51,35 @@ void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) { } } void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { if (transactionStart == Scheduler::TransactionStart::EARLY) { switch (transactionStart) { case Scheduler::TransactionStart::EarlyStart: ALOGW_IF(mExplicitEarlyWakeup, "Already in TransactionStart::EarlyStart"); mExplicitEarlyWakeup = true; break; case Scheduler::TransactionStart::EarlyEnd: ALOGW_IF(!mExplicitEarlyWakeup, "Not in TransactionStart::EarlyStart"); mExplicitEarlyWakeup = false; break; case Scheduler::TransactionStart::Normal: case Scheduler::TransactionStart::Early: // Non explicit don't change the explicit early wakeup state break; } if (mTraceDetailedInfo) { ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup); } if (!mExplicitEarlyWakeup && (transactionStart == Scheduler::TransactionStart::Early || transactionStart == Scheduler::TransactionStart::EarlyEnd)) { mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; mEarlyTxnStartTime = std::chrono::steady_clock::now(); mEarlyTxnStartTime = std::chrono::steady_clock::now(); } } // An early transaction stays an early transaction. // An early transaction stays an early transaction. if (transactionStart == mTransactionStart || if (transactionStart == mTransactionStart || mTransactionStart == Scheduler::TransactionStart::EARLY) { mTransactionStart == Scheduler::TransactionStart::EarlyEnd) { return; return; } } mTransactionStart = transactionStart; mTransactionStart = transactionStart; Loading @@ -67,8 +88,8 @@ void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transaction void VSyncModulator::onTransactionHandled() { void VSyncModulator::onTransactionHandled() { mTxnAppliedTime = std::chrono::steady_clock::now(); mTxnAppliedTime = std::chrono::steady_clock::now(); if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; if (mTransactionStart == Scheduler::TransactionStart::Normal) return; mTransactionStart = Scheduler::TransactionStart::NORMAL; mTransactionStart = Scheduler::TransactionStart::Normal; updateOffsets(); updateOffsets(); } } Loading @@ -91,11 +112,10 @@ void VSyncModulator::onRefreshRateChangeCompleted() { void VSyncModulator::onRefreshed(bool usedRenderEngine) { void VSyncModulator::onRefreshed(bool usedRenderEngine) { bool updateOffsetsNeeded = false; bool updateOffsetsNeeded = false; // Apply a 1ms margin to account for potential data races // Apply a margin to account for potential data races // This might make us stay in early offsets for one // This might make us stay in early offsets for one // additional frame but it's better to be conservative here. // additional frame but it's better to be conservative here. static const constexpr std::chrono::nanoseconds kMargin = 1ms; if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) { if ((mEarlyTxnStartTime.load() + kMargin) < mTxnAppliedTime.load()) { if (mRemainingEarlyFrameCount > 0) { if (mRemainingEarlyFrameCount > 0) { mRemainingEarlyFrameCount--; mRemainingEarlyFrameCount--; updateOffsetsNeeded = true; updateOffsetsNeeded = true; Loading @@ -121,8 +141,8 @@ VSyncModulator::Offsets VSyncModulator::getOffsets() const { const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { // Early offsets are used if we're in the middle of a refresh rate // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. // change, or if we recently begin a transaction. if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || if (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd || mRefreshRateChangePending) { mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { return mOffsetsConfig.early; return mOffsetsConfig.early; } else if (mRemainingRenderEngineUsageCount > 0) { } else if (mRemainingRenderEngineUsageCount > 0) { return mOffsetsConfig.earlyGl; return mOffsetsConfig.earlyGl; Loading @@ -139,8 +159,8 @@ void VSyncModulator::updateOffsets() { void VSyncModulator::updateOffsetsLocked() { void VSyncModulator::updateOffsetsLocked() { const Offsets& offsets = getNextOffsets(); const Offsets& offsets = getNextOffsets(); mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf); mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf); mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app); mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app); mOffsets = offsets; mOffsets = offsets; Loading Loading
libs/gui/SurfaceComposerClient.cpp +31 −0 Original line number Original line Diff line number Diff line Loading @@ -353,6 +353,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), mEarlyWakeup(other.mEarlyWakeup), mExplicitEarlyWakeupStart(other.mExplicitEarlyWakeupStart), mExplicitEarlyWakeupEnd(other.mExplicitEarlyWakeupEnd), mContainsBuffer(other.mContainsBuffer), mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mDisplayStates = other.mDisplayStates; Loading @@ -375,6 +377,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const uint32_t transactionNestCount = parcel->readUint32(); const uint32_t transactionNestCount = parcel->readUint32(); const bool animation = parcel->readBool(); const bool animation = parcel->readBool(); const bool earlyWakeup = parcel->readBool(); const bool earlyWakeup = parcel->readBool(); const bool explicitEarlyWakeupStart = parcel->readBool(); const bool explicitEarlyWakeupEnd = parcel->readBool(); const bool containsBuffer = parcel->readBool(); const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const int64_t desiredPresentTime = parcel->readInt64(); Loading Loading @@ -443,6 +447,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mTransactionNestCount = transactionNestCount; mTransactionNestCount = transactionNestCount; mAnimation = animation; mAnimation = animation; mEarlyWakeup = earlyWakeup; mEarlyWakeup = earlyWakeup; mExplicitEarlyWakeupStart = explicitEarlyWakeupStart; mExplicitEarlyWakeupEnd = explicitEarlyWakeupEnd; mContainsBuffer = containsBuffer; mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mDesiredPresentTime = desiredPresentTime; mDisplayStates = displayStates; mDisplayStates = displayStates; Loading Loading @@ -470,6 +476,8 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeUint32(mTransactionNestCount); parcel->writeUint32(mTransactionNestCount); parcel->writeBool(mAnimation); parcel->writeBool(mAnimation); parcel->writeBool(mEarlyWakeup); parcel->writeBool(mEarlyWakeup); parcel->writeBool(mExplicitEarlyWakeupStart); parcel->writeBool(mExplicitEarlyWakeupEnd); parcel->writeBool(mContainsBuffer); parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeInt64(mDesiredPresentTime); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); Loading Loading @@ -545,6 +553,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mContainsBuffer |= other.mContainsBuffer; mContainsBuffer |= other.mContainsBuffer; mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup; mExplicitEarlyWakeupStart = mExplicitEarlyWakeupStart || other.mExplicitEarlyWakeupStart; mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; other.clear(); other.clear(); return *this; return *this; } } Loading @@ -559,6 +569,8 @@ void SurfaceComposerClient::Transaction::clear() { mTransactionNestCount = 0; mTransactionNestCount = 0; mAnimation = false; mAnimation = false; mEarlyWakeup = false; mEarlyWakeup = false; mExplicitEarlyWakeupStart = false; mExplicitEarlyWakeupEnd = false; mDesiredPresentTime = -1; mDesiredPresentTime = -1; } } Loading Loading @@ -682,9 +694,20 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { flags |= ISurfaceComposer::eEarlyWakeup; flags |= ISurfaceComposer::eEarlyWakeup; } } // If both mExplicitEarlyWakeupStart and mExplicitEarlyWakeupEnd are set // it is equivalent for none if (mExplicitEarlyWakeupStart && !mExplicitEarlyWakeupEnd) { flags |= ISurfaceComposer::eExplicitEarlyWakeupStart; } if (mExplicitEarlyWakeupEnd && !mExplicitEarlyWakeupStart) { flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd; } mForceSynchronous = false; mForceSynchronous = false; mAnimation = false; mAnimation = false; mEarlyWakeup = false; mEarlyWakeup = false; mExplicitEarlyWakeupStart = false; mExplicitEarlyWakeupEnd = false; sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, Loading Loading @@ -731,6 +754,14 @@ void SurfaceComposerClient::Transaction::setEarlyWakeup() { mEarlyWakeup = true; mEarlyWakeup = true; } } void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupStart() { mExplicitEarlyWakeupStart = true; } void SurfaceComposerClient::Transaction::setExplicitEarlyWakeupEnd() { mExplicitEarlyWakeupEnd = true; } layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) { layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) { if (mComposerStates.count(handle) == 0) { if (mComposerStates.count(handle) == 0) { // we don't have it, add an initialized layer_state to our list // we don't have it, add an initialized layer_state to our list Loading
libs/gui/include/gui/ISurfaceComposer.h +14 −6 Original line number Original line Diff line number Diff line Loading @@ -83,10 +83,18 @@ public: eSynchronous = 0x01, eSynchronous = 0x01, eAnimation = 0x02, eAnimation = 0x02, // Indicates that this transaction will likely result in a lot of layers being composed, and // DEPRECATED - use eExplicitEarlyWakeup[Start|End] // thus, SurfaceFlinger should wake-up earlier to avoid missing frame deadlines. In this eEarlyWakeup = 0x04, // case SurfaceFlinger will wake up at (sf vsync offset - debug.sf.early_phase_offset_ns) eEarlyWakeup = 0x04 // Explicit indication that this transaction and others to follow will likely result in a // lot of layers being composed, and thus, SurfaceFlinger should wake-up earlier to avoid // missing frame deadlines. In this case SurfaceFlinger will wake up at // (sf vsync offset - debug.sf.early_phase_offset_ns). SurfaceFlinger will continue to be // in the early configuration until it receives eExplicitEarlyWakeupEnd. These flags are // expected to be used by WindowManager only and are guarded by // android.permission.ACCESS_SURFACE_FLINGER eExplicitEarlyWakeupStart = 0x08, eExplicitEarlyWakeupEnd = 0x10, }; }; enum VsyncSource { enum VsyncSource { Loading
libs/gui/include/gui/SurfaceComposerClient.h +8 −4 Original line number Original line Diff line number Diff line Loading @@ -349,6 +349,8 @@ public: uint32_t mTransactionNestCount = 0; uint32_t mTransactionNestCount = 0; bool mAnimation = false; bool mAnimation = false; bool mEarlyWakeup = false; bool mEarlyWakeup = false; bool mExplicitEarlyWakeupStart = false; bool mExplicitEarlyWakeupEnd = false; // Indicates that the Transaction contains a buffer that should be cached // Indicates that the Transaction contains a buffer that should be cached bool mContainsBuffer = false; bool mContainsBuffer = false; Loading Loading @@ -547,6 +549,8 @@ public: void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height); void setAnimationTransaction(); void setAnimationTransaction(); void setEarlyWakeup(); void setEarlyWakeup(); void setExplicitEarlyWakeupStart(); void setExplicitEarlyWakeupEnd(); }; }; status_t clearLayerFrameStats(const sp<IBinder>& token) const; status_t clearLayerFrameStats(const sp<IBinder>& token) const; Loading
services/surfaceflinger/Scheduler/Scheduler.h +14 −3 Original line number Original line Diff line number Diff line Loading @@ -55,13 +55,24 @@ public: virtual void kernelTimerChanged(bool expired) = 0; virtual void kernelTimerChanged(bool expired) = 0; }; }; class Scheduler { class IPhaseOffsetControl { public: virtual ~IPhaseOffsetControl() = default; virtual void setPhaseOffset(scheduler::ConnectionHandle, nsecs_t phaseOffset) = 0; }; class Scheduler : public IPhaseOffsetControl { public: public: using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; using ConfigEvent = scheduler::RefreshRateConfigEvent; // Indicates whether to start the transaction early, or at vsync time. // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; 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, Scheduler(impl::EventControlThread::SetVSyncEnabledFunction, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback, Loading Loading @@ -90,7 +101,7 @@ public: void onScreenReleased(ConnectionHandle); void onScreenReleased(ConnectionHandle); // Modifies phase offset in the event thread. // Modifies phase offset in the event thread. void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset); void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset) override; void getDisplayStatInfo(DisplayStatInfo* stats); void getDisplayStatInfo(DisplayStatInfo* stats); Loading
services/surfaceflinger/Scheduler/VSyncModulator.cpp +33 −13 Original line number Original line Diff line number Diff line Loading @@ -31,11 +31,11 @@ namespace android::scheduler { namespace android::scheduler { VSyncModulator::VSyncModulator(Scheduler& scheduler, VSyncModulator::VSyncModulator(IPhaseOffsetControl& phaseOffsetControl, Scheduler::ConnectionHandle appConnectionHandle, Scheduler::ConnectionHandle appConnectionHandle, Scheduler::ConnectionHandle sfConnectionHandle, Scheduler::ConnectionHandle sfConnectionHandle, const OffsetsConfig& config) const OffsetsConfig& config) : mScheduler(scheduler), : mPhaseOffsetControl(phaseOffsetControl), mAppConnectionHandle(appConnectionHandle), mAppConnectionHandle(appConnectionHandle), mSfConnectionHandle(sfConnectionHandle), mSfConnectionHandle(sfConnectionHandle), mOffsetsConfig(config) { mOffsetsConfig(config) { Loading @@ -51,14 +51,35 @@ void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) { } } void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transactionStart) { if (transactionStart == Scheduler::TransactionStart::EARLY) { switch (transactionStart) { case Scheduler::TransactionStart::EarlyStart: ALOGW_IF(mExplicitEarlyWakeup, "Already in TransactionStart::EarlyStart"); mExplicitEarlyWakeup = true; break; case Scheduler::TransactionStart::EarlyEnd: ALOGW_IF(!mExplicitEarlyWakeup, "Not in TransactionStart::EarlyStart"); mExplicitEarlyWakeup = false; break; case Scheduler::TransactionStart::Normal: case Scheduler::TransactionStart::Early: // Non explicit don't change the explicit early wakeup state break; } if (mTraceDetailedInfo) { ATRACE_INT("mExplicitEarlyWakeup", mExplicitEarlyWakeup); } if (!mExplicitEarlyWakeup && (transactionStart == Scheduler::TransactionStart::Early || transactionStart == Scheduler::TransactionStart::EarlyEnd)) { mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; mEarlyTxnStartTime = std::chrono::steady_clock::now(); mEarlyTxnStartTime = std::chrono::steady_clock::now(); } } // An early transaction stays an early transaction. // An early transaction stays an early transaction. if (transactionStart == mTransactionStart || if (transactionStart == mTransactionStart || mTransactionStart == Scheduler::TransactionStart::EARLY) { mTransactionStart == Scheduler::TransactionStart::EarlyEnd) { return; return; } } mTransactionStart = transactionStart; mTransactionStart = transactionStart; Loading @@ -67,8 +88,8 @@ void VSyncModulator::setTransactionStart(Scheduler::TransactionStart transaction void VSyncModulator::onTransactionHandled() { void VSyncModulator::onTransactionHandled() { mTxnAppliedTime = std::chrono::steady_clock::now(); mTxnAppliedTime = std::chrono::steady_clock::now(); if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return; if (mTransactionStart == Scheduler::TransactionStart::Normal) return; mTransactionStart = Scheduler::TransactionStart::NORMAL; mTransactionStart = Scheduler::TransactionStart::Normal; updateOffsets(); updateOffsets(); } } Loading @@ -91,11 +112,10 @@ void VSyncModulator::onRefreshRateChangeCompleted() { void VSyncModulator::onRefreshed(bool usedRenderEngine) { void VSyncModulator::onRefreshed(bool usedRenderEngine) { bool updateOffsetsNeeded = false; bool updateOffsetsNeeded = false; // Apply a 1ms margin to account for potential data races // Apply a margin to account for potential data races // This might make us stay in early offsets for one // This might make us stay in early offsets for one // additional frame but it's better to be conservative here. // additional frame but it's better to be conservative here. static const constexpr std::chrono::nanoseconds kMargin = 1ms; if ((mEarlyTxnStartTime.load() + MARGIN_FOR_TX_APPLY) < mTxnAppliedTime.load()) { if ((mEarlyTxnStartTime.load() + kMargin) < mTxnAppliedTime.load()) { if (mRemainingEarlyFrameCount > 0) { if (mRemainingEarlyFrameCount > 0) { mRemainingEarlyFrameCount--; mRemainingEarlyFrameCount--; updateOffsetsNeeded = true; updateOffsetsNeeded = true; Loading @@ -121,8 +141,8 @@ VSyncModulator::Offsets VSyncModulator::getOffsets() const { const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const { // Early offsets are used if we're in the middle of a refresh rate // Early offsets are used if we're in the middle of a refresh rate // change, or if we recently begin a transaction. // change, or if we recently begin a transaction. if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 || if (mExplicitEarlyWakeup || mTransactionStart == Scheduler::TransactionStart::EarlyEnd || mRefreshRateChangePending) { mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { return mOffsetsConfig.early; return mOffsetsConfig.early; } else if (mRemainingRenderEngineUsageCount > 0) { } else if (mRemainingRenderEngineUsageCount > 0) { return mOffsetsConfig.earlyGl; return mOffsetsConfig.earlyGl; Loading @@ -139,8 +159,8 @@ void VSyncModulator::updateOffsets() { void VSyncModulator::updateOffsetsLocked() { void VSyncModulator::updateOffsetsLocked() { const Offsets& offsets = getNextOffsets(); const Offsets& offsets = getNextOffsets(); mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf); mPhaseOffsetControl.setPhaseOffset(mSfConnectionHandle, offsets.sf); mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app); mPhaseOffsetControl.setPhaseOffset(mAppConnectionHandle, offsets.app); mOffsets = offsets; mOffsets = offsets; Loading