Loading libs/gui/LayerState.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -634,7 +634,7 @@ bool layer_state_t::hasBufferChanges() const { } bool layer_state_t::hasValidBuffer() const { return bufferData && (bufferData->buffer || bufferData->cachedBuffer.isValid()); return bufferData && (bufferData->hasBuffer() || bufferData->cachedBuffer.isValid()); } status_t layer_state_t::matrix22_t::write(Parcel& output) const { Loading libs/gui/include/gui/fake/BufferData.h 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <gui/LayerState.h> namespace android::fake { // Class which exposes buffer properties from BufferData without holding on to an actual buffer class BufferData : public android::BufferData { public: BufferData(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat, uint64_t outUsage) : mBufferId(bufferId), mWidth(width), mHeight(height), mPixelFormat(pixelFormat), mOutUsage(outUsage) {} bool hasBuffer() const override { return mBufferId != 0; } bool hasSameBuffer(const android::BufferData& other) const override { return getId() == other.getId() && frameNumber == other.frameNumber; } uint32_t getWidth() const override { return mWidth; } uint32_t getHeight() const override { return mHeight; } uint64_t getId() const override { return mBufferId; } PixelFormat getPixelFormat() const override { return mPixelFormat; } uint64_t getUsage() const override { return mOutUsage; } private: uint64_t mBufferId; uint32_t mWidth; uint32_t mHeight; int32_t mPixelFormat; uint64_t mOutUsage; }; } // namespace android::fake services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ filegroup { "Tracing/TransactionTracing.cpp", "Tracing/TransactionProtoParser.cpp", "TransactionCallbackInvoker.cpp", "TransactionHandler.cpp", "TunnelModeEnabledReporter.cpp", ], } Loading services/surfaceflinger/Layer.h +3 −1 Original line number Diff line number Diff line Loading @@ -881,7 +881,9 @@ public: bool mPendingHWCDestroy{false}; bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; } bool backpressureEnabled() const { return mDrawingState.flags & layer_state_t::eEnableBackpressure; } bool setStretchEffect(const StretchEffect& effect); StretchEffect getStretchEffect() const; Loading services/surfaceflinger/SurfaceFlinger.cpp +112 −220 Original line number Diff line number Diff line Loading @@ -129,14 +129,11 @@ #include "LayerVector.h" #include "MutexUtils.h" #include "NativeWindowSurface.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSyncSource.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" #include "Scheduler/VsyncController.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" Loading Loading @@ -747,6 +744,7 @@ chooseRenderEngineTypeViaSysProp() { void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); addTransactionReadyFilters(); Mutex::Autolock lock(mStateLock); // Get a RenderEngine for the given display / config (can't fail) Loading Loading @@ -3649,124 +3647,119 @@ void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule sche } } int SurfaceFlinger::flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, bool tryApplyUnsignaled) { std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; int transactionsPendingBarrier = 0; auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; while (!transactionQueue.empty()) { // if we are in LatchUnsignaledConfig::AutoSingleLayer // then we should have only one applyToken for processing. // so we can stop further transactions on this applyToken. if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer && !applyTokensWithUnsignaledTransactions.empty()) { ATRACE_NAME("stopTransactionProcessing"); break; TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelineCheck( const TransactionHandler::TransactionFlushState& flushState) { using TransactionReadiness = TransactionHandler::TransactionReadiness; const auto& transaction = *flushState.transaction; ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, transaction.frameTimelineInfo.vsyncId); TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime); // Do not present if the desiredPresentTime has not passed unless it is more than // one second in the future. We ignore timestamps more than 1 second in the future // for stability reasons. if (!transaction.isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime && desiredPresentTime < mExpectedPresentTime + 1s) { ATRACE_NAME("not current"); return TransactionReadiness::NotReady; } auto& transaction = transactionQueue.front(); const auto ready = transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo, transaction.isAutoTimestamp, TimePoint::fromNs(transaction.desiredPresentTime), transaction.originUid, transaction.states, bufferLayersReadyToPresent, transactions.size(), tryApplyUnsignaled); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); if (ready == TransactionReadiness::NotReady) { setTransactionFlags(eTransactionFlushNeeded); break; if (!mScheduler->isVsyncValid(mExpectedPresentTime, transaction.originUid)) { ATRACE_NAME("!isVsyncValid"); return TransactionReadiness::NotReady; } if (ready == TransactionReadiness::NotReadyBarrier) { transactionsPendingBarrier++; setTransactionFlags(eTransactionFlushNeeded); break; // If the client didn't specify desiredPresentTime, use the vsyncId to determine the // expected present time of this transaction. if (transaction.isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{transaction.frameTimelineInfo.vsyncId})) { ATRACE_NAME("frameIsEarly"); return TransactionReadiness::NotReady; } transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { const bool frameNumberChanged = state.bufferData->flags.test( BufferData::BufferDataChange::frameNumberChanged); if (frameNumberChanged) { bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber; } else { // Barrier function only used for BBQ which always includes a frame number bufferLayersReadyToPresent[state.surface] = std::numeric_limits<uint64_t>::max(); return TransactionReadiness::Ready; } TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck( const TransactionHandler::TransactionFlushState& flushState) { using TransactionReadiness = TransactionHandler::TransactionReadiness; auto ready = TransactionReadiness::Ready; flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const layer_state_t& s) -> bool { sp<Layer> layer = Layer::fromHandle(s.surface).promote(); const auto& transaction = *flushState.transaction; // check for barrier frames if (s.bufferData->hasBarrier && ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { const bool willApplyBarrierFrame = flushState.bufferLayersReadyToPresent.contains(s.surface.get()) && (flushState.bufferLayersReadyToPresent.get(s.surface.get()) >= s.bufferData->barrierFrameNumber); if (!willApplyBarrierFrame) { ATRACE_NAME("NotReadyBarrier"); ready = TransactionReadiness::NotReadyBarrier; return false; } }); const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); if (appliedUnsignaled) { applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); } transactions.emplace_back(std::move(transaction)); transactionQueue.pop(); mPendingTransactionCount--; ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); // If backpressure is enabled and we already have a buffer to commit, keep // the transaction in the queue. const bool hasPendingBuffer = flushState.bufferLayersReadyToPresent.contains(s.surface.get()); if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); ready = TransactionReadiness::NotReady; return false; } if (transactionQueue.empty()) { it = mPendingTransactionQueues.erase(it); } else { it = std::next(it, 1); // check fence status const bool allowLatchUnsignaled = shouldLatchUnsignaled(layer, s, transaction.states.size(), flushState.firstTransaction); ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), allowLatchUnsignaled ? "true" : "false"); const bool acquireFenceChanged = s.bufferData && s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && s.bufferData->acquireFence; const bool fenceSignaled = (!acquireFenceChanged || s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled); if (!fenceSignaled) { if (!allowLatchUnsignaled) { ready = TransactionReadiness::NotReady; auto& listener = s.bufferData->releaseBufferListener; if (listener && (flushState.queueProcessTime - transaction.postTime) > std::chrono::nanoseconds(4s).count()) { mTransactionHandler.onTransactionQueueStalled(transaction, listener); } return false; } ready = enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer ? TransactionReadiness::ReadyUnsignaledSingle : TransactionReadiness::ReadyUnsignaled; } return transactionsPendingBarrier; return true; }); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); return ready; } void SurfaceFlinger::addTransactionReadyFilters() { mTransactionHandler.addTransactionReadyFilter( std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1)); mTransactionHandler.addTransactionReadyFilter( std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1)); } bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) { // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock std::vector<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>> bufferLayersReadyToPresent; std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions(); { Mutex::Autolock _l(mStateLock); { while (!mLocklessTransactionQueue.isEmpty()) { auto maybeTransaction = mLocklessTransactionQueue.pop(); if (!maybeTransaction.has_value()) { break; } auto transaction = maybeTransaction.value(); mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } // Transactions with a buffer pending on a barrier may be on a different applyToken // than the transaction which satisfies our barrier. In fact this is the exact use case // that the primitive is designed for. This means we may first process // the barrier dependent transaction, determine it ineligible to complete // and then satisfy in a later inner iteration of flushPendingTransactionQueues. // The barrier dependent transaction was eligible to be presented in this frame // but we would have prevented it without case. To fix this we continually // loop through flushPendingTransactionQueues until we perform an iteration // where the number of transactionsPendingBarrier doesn't change. This way // we can continue to resolve dependency chains of barriers as far as possible. int lastTransactionsPendingBarrier = 0; int transactionsPendingBarrier = 0; do { lastTransactionsPendingBarrier = transactionsPendingBarrier; transactionsPendingBarrier = flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, /*tryApplyUnsignaled*/ false); } while (lastTransactionsPendingBarrier != transactionsPendingBarrier); // We collected all transactions that could apply without latching unsignaled buffers. // If we are allowing latch unsignaled of some form, now it's the time to go over the // transactions that were not applied and try to apply them unsignaled. if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, /*tryApplyUnsignaled*/ true); } return applyTransactions(transactions, vsyncId); } } } bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions, VsyncId vsyncId) { Loading @@ -3791,7 +3784,7 @@ bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactio } bool SurfaceFlinger::transactionFlushNeeded() { return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty(); return mTransactionHandler.hasPendingTransactions(); } bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId) const { Loading @@ -3817,7 +3810,7 @@ bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId } bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state, size_t numStates, size_t totalTXapplied) const { size_t numStates, bool firstTransaction) const { if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__); return false; Loading @@ -3836,9 +3829,9 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s } if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { if (totalTXapplied > 0) { ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", __func__, totalTXapplied); if (!firstTransaction) { ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; not first transaction)", __func__); return false; } Loading @@ -3862,116 +3855,6 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s return true; } auto SurfaceFlinger::transactionIsReadyToBeApplied( TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp, TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness { ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. if (!isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime && desiredPresentTime < mExpectedPresentTime + 1s) { ATRACE_NAME("not current"); return TransactionReadiness::NotReady; } if (!mScheduler->isVsyncValid(mExpectedPresentTime, originUid)) { ATRACE_NAME("!isVsyncValid"); return TransactionReadiness::NotReady; } // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected // present time of this transaction. if (isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{info.vsyncId})) { ATRACE_NAME("frameIsEarly"); return TransactionReadiness::NotReady; } bool fenceUnsignaled = false; auto queueProcessTime = systemTime(); for (const ComposerState& state : states) { const layer_state_t& s = state.state; sp<Layer> layer = nullptr; if (s.surface) { layer = fromHandle(s.surface).promote(); } else if (s.hasBufferChanges()) { ALOGW("Transaction with buffer, but no Layer?"); continue; } if (!layer) { continue; } if (s.hasBufferChanges() && s.bufferData->hasBarrier && ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { const bool willApplyBarrierFrame = (bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end()) && (bufferLayersReadyToPresent.at(s.surface) >= s.bufferData->barrierFrameNumber); if (!willApplyBarrierFrame) { ATRACE_NAME("NotReadyBarrier"); return TransactionReadiness::NotReadyBarrier; } } const bool allowLatchUnsignaled = tryApplyUnsignaled && shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), allowLatchUnsignaled ? "true" : "false"); const bool acquireFenceChanged = s.bufferData && s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && s.bufferData->acquireFence; fenceUnsignaled = fenceUnsignaled || (acquireFenceChanged && s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled); if (fenceUnsignaled && !allowLatchUnsignaled) { if (!transaction.sentFenceTimeoutWarning && queueProcessTime - transaction.postTime > std::chrono::nanoseconds(4s).count()) { transaction.sentFenceTimeoutWarning = true; auto listener = s.bufferData->releaseBufferListener; if (listener) { listener->onTransactionQueueStalled(); } } ATRACE_NAME("fence unsignaled"); return TransactionReadiness::NotReady; } if (s.hasBufferChanges()) { // If backpressure is enabled and we already have a buffer to commit, keep the // transaction in the queue. const bool hasPendingBuffer = bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end(); if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); return TransactionReadiness::NotReady; } } } return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready; } void SurfaceFlinger::queueTransaction(TransactionState& state) { mLocklessTransactionQueue.push(state); mPendingTransactionCount++; ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); const auto schedule = [](uint32_t flags) { if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart; return TransactionSchedule::Late; }(state.flags); const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); } status_t SurfaceFlinger::setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, Loading Loading @@ -4022,7 +3905,16 @@ status_t SurfaceFlinger::setTransactionState( if (mTransactionTracing) { mTransactionTracing->addQueuedTransaction(state); } queueTransaction(state); const auto schedule = [](uint32_t flags) { if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart; return TransactionSchedule::Late; }(state.flags); const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); mTransactionHandler.queueTransaction(std::move(state)); return NO_ERROR; } Loading Loading
libs/gui/LayerState.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -634,7 +634,7 @@ bool layer_state_t::hasBufferChanges() const { } bool layer_state_t::hasValidBuffer() const { return bufferData && (bufferData->buffer || bufferData->cachedBuffer.isValid()); return bufferData && (bufferData->hasBuffer() || bufferData->cachedBuffer.isValid()); } status_t layer_state_t::matrix22_t::write(Parcel& output) const { Loading
libs/gui/include/gui/fake/BufferData.h 0 → 100644 +51 −0 Original line number Diff line number Diff line /* * Copyright 2022 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 <gui/LayerState.h> namespace android::fake { // Class which exposes buffer properties from BufferData without holding on to an actual buffer class BufferData : public android::BufferData { public: BufferData(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat, uint64_t outUsage) : mBufferId(bufferId), mWidth(width), mHeight(height), mPixelFormat(pixelFormat), mOutUsage(outUsage) {} bool hasBuffer() const override { return mBufferId != 0; } bool hasSameBuffer(const android::BufferData& other) const override { return getId() == other.getId() && frameNumber == other.frameNumber; } uint32_t getWidth() const override { return mWidth; } uint32_t getHeight() const override { return mHeight; } uint64_t getId() const override { return mBufferId; } PixelFormat getPixelFormat() const override { return mPixelFormat; } uint64_t getUsage() const override { return mOutUsage; } private: uint64_t mBufferId; uint32_t mWidth; uint32_t mHeight; int32_t mPixelFormat; uint64_t mOutUsage; }; } // namespace android::fake
services/surfaceflinger/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -194,6 +194,7 @@ filegroup { "Tracing/TransactionTracing.cpp", "Tracing/TransactionProtoParser.cpp", "TransactionCallbackInvoker.cpp", "TransactionHandler.cpp", "TunnelModeEnabledReporter.cpp", ], } Loading
services/surfaceflinger/Layer.h +3 −1 Original line number Diff line number Diff line Loading @@ -881,7 +881,9 @@ public: bool mPendingHWCDestroy{false}; bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; } bool backpressureEnabled() const { return mDrawingState.flags & layer_state_t::eEnableBackpressure; } bool setStretchEffect(const StretchEffect& effect); StretchEffect getStretchEffect() const; Loading
services/surfaceflinger/SurfaceFlinger.cpp +112 −220 Original line number Diff line number Diff line Loading @@ -129,14 +129,11 @@ #include "LayerVector.h" #include "MutexUtils.h" #include "NativeWindowSurface.h" #include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" #include "Scheduler/DispSyncSource.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" #include "Scheduler/VsyncController.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" Loading Loading @@ -747,6 +744,7 @@ chooseRenderEngineTypeViaSysProp() { void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); addTransactionReadyFilters(); Mutex::Autolock lock(mStateLock); // Get a RenderEngine for the given display / config (can't fail) Loading Loading @@ -3649,124 +3647,119 @@ void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule sche } } int SurfaceFlinger::flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, bool tryApplyUnsignaled) { std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; int transactionsPendingBarrier = 0; auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; while (!transactionQueue.empty()) { // if we are in LatchUnsignaledConfig::AutoSingleLayer // then we should have only one applyToken for processing. // so we can stop further transactions on this applyToken. if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer && !applyTokensWithUnsignaledTransactions.empty()) { ATRACE_NAME("stopTransactionProcessing"); break; TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelineCheck( const TransactionHandler::TransactionFlushState& flushState) { using TransactionReadiness = TransactionHandler::TransactionReadiness; const auto& transaction = *flushState.transaction; ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, transaction.frameTimelineInfo.vsyncId); TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime); // Do not present if the desiredPresentTime has not passed unless it is more than // one second in the future. We ignore timestamps more than 1 second in the future // for stability reasons. if (!transaction.isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime && desiredPresentTime < mExpectedPresentTime + 1s) { ATRACE_NAME("not current"); return TransactionReadiness::NotReady; } auto& transaction = transactionQueue.front(); const auto ready = transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo, transaction.isAutoTimestamp, TimePoint::fromNs(transaction.desiredPresentTime), transaction.originUid, transaction.states, bufferLayersReadyToPresent, transactions.size(), tryApplyUnsignaled); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); if (ready == TransactionReadiness::NotReady) { setTransactionFlags(eTransactionFlushNeeded); break; if (!mScheduler->isVsyncValid(mExpectedPresentTime, transaction.originUid)) { ATRACE_NAME("!isVsyncValid"); return TransactionReadiness::NotReady; } if (ready == TransactionReadiness::NotReadyBarrier) { transactionsPendingBarrier++; setTransactionFlags(eTransactionFlushNeeded); break; // If the client didn't specify desiredPresentTime, use the vsyncId to determine the // expected present time of this transaction. if (transaction.isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{transaction.frameTimelineInfo.vsyncId})) { ATRACE_NAME("frameIsEarly"); return TransactionReadiness::NotReady; } transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { const bool frameNumberChanged = state.bufferData->flags.test( BufferData::BufferDataChange::frameNumberChanged); if (frameNumberChanged) { bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber; } else { // Barrier function only used for BBQ which always includes a frame number bufferLayersReadyToPresent[state.surface] = std::numeric_limits<uint64_t>::max(); return TransactionReadiness::Ready; } TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck( const TransactionHandler::TransactionFlushState& flushState) { using TransactionReadiness = TransactionHandler::TransactionReadiness; auto ready = TransactionReadiness::Ready; flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const layer_state_t& s) -> bool { sp<Layer> layer = Layer::fromHandle(s.surface).promote(); const auto& transaction = *flushState.transaction; // check for barrier frames if (s.bufferData->hasBarrier && ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { const bool willApplyBarrierFrame = flushState.bufferLayersReadyToPresent.contains(s.surface.get()) && (flushState.bufferLayersReadyToPresent.get(s.surface.get()) >= s.bufferData->barrierFrameNumber); if (!willApplyBarrierFrame) { ATRACE_NAME("NotReadyBarrier"); ready = TransactionReadiness::NotReadyBarrier; return false; } }); const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); if (appliedUnsignaled) { applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); } transactions.emplace_back(std::move(transaction)); transactionQueue.pop(); mPendingTransactionCount--; ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); // If backpressure is enabled and we already have a buffer to commit, keep // the transaction in the queue. const bool hasPendingBuffer = flushState.bufferLayersReadyToPresent.contains(s.surface.get()); if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); ready = TransactionReadiness::NotReady; return false; } if (transactionQueue.empty()) { it = mPendingTransactionQueues.erase(it); } else { it = std::next(it, 1); // check fence status const bool allowLatchUnsignaled = shouldLatchUnsignaled(layer, s, transaction.states.size(), flushState.firstTransaction); ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), allowLatchUnsignaled ? "true" : "false"); const bool acquireFenceChanged = s.bufferData && s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && s.bufferData->acquireFence; const bool fenceSignaled = (!acquireFenceChanged || s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled); if (!fenceSignaled) { if (!allowLatchUnsignaled) { ready = TransactionReadiness::NotReady; auto& listener = s.bufferData->releaseBufferListener; if (listener && (flushState.queueProcessTime - transaction.postTime) > std::chrono::nanoseconds(4s).count()) { mTransactionHandler.onTransactionQueueStalled(transaction, listener); } return false; } ready = enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer ? TransactionReadiness::ReadyUnsignaledSingle : TransactionReadiness::ReadyUnsignaled; } return transactionsPendingBarrier; return true; }); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); return ready; } void SurfaceFlinger::addTransactionReadyFilters() { mTransactionHandler.addTransactionReadyFilter( std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1)); mTransactionHandler.addTransactionReadyFilter( std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1)); } bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) { // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock std::vector<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>> bufferLayersReadyToPresent; std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions(); { Mutex::Autolock _l(mStateLock); { while (!mLocklessTransactionQueue.isEmpty()) { auto maybeTransaction = mLocklessTransactionQueue.pop(); if (!maybeTransaction.has_value()) { break; } auto transaction = maybeTransaction.value(); mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } // Transactions with a buffer pending on a barrier may be on a different applyToken // than the transaction which satisfies our barrier. In fact this is the exact use case // that the primitive is designed for. This means we may first process // the barrier dependent transaction, determine it ineligible to complete // and then satisfy in a later inner iteration of flushPendingTransactionQueues. // The barrier dependent transaction was eligible to be presented in this frame // but we would have prevented it without case. To fix this we continually // loop through flushPendingTransactionQueues until we perform an iteration // where the number of transactionsPendingBarrier doesn't change. This way // we can continue to resolve dependency chains of barriers as far as possible. int lastTransactionsPendingBarrier = 0; int transactionsPendingBarrier = 0; do { lastTransactionsPendingBarrier = transactionsPendingBarrier; transactionsPendingBarrier = flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, /*tryApplyUnsignaled*/ false); } while (lastTransactionsPendingBarrier != transactionsPendingBarrier); // We collected all transactions that could apply without latching unsignaled buffers. // If we are allowing latch unsignaled of some form, now it's the time to go over the // transactions that were not applied and try to apply them unsignaled. if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, /*tryApplyUnsignaled*/ true); } return applyTransactions(transactions, vsyncId); } } } bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions, VsyncId vsyncId) { Loading @@ -3791,7 +3784,7 @@ bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactio } bool SurfaceFlinger::transactionFlushNeeded() { return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty(); return mTransactionHandler.hasPendingTransactions(); } bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId) const { Loading @@ -3817,7 +3810,7 @@ bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId } bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state, size_t numStates, size_t totalTXapplied) const { size_t numStates, bool firstTransaction) const { if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__); return false; Loading @@ -3836,9 +3829,9 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s } if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { if (totalTXapplied > 0) { ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", __func__, totalTXapplied); if (!firstTransaction) { ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; not first transaction)", __func__); return false; } Loading @@ -3862,116 +3855,6 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_s return true; } auto SurfaceFlinger::transactionIsReadyToBeApplied( TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp, TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent, size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness { ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. if (!isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime && desiredPresentTime < mExpectedPresentTime + 1s) { ATRACE_NAME("not current"); return TransactionReadiness::NotReady; } if (!mScheduler->isVsyncValid(mExpectedPresentTime, originUid)) { ATRACE_NAME("!isVsyncValid"); return TransactionReadiness::NotReady; } // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected // present time of this transaction. if (isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{info.vsyncId})) { ATRACE_NAME("frameIsEarly"); return TransactionReadiness::NotReady; } bool fenceUnsignaled = false; auto queueProcessTime = systemTime(); for (const ComposerState& state : states) { const layer_state_t& s = state.state; sp<Layer> layer = nullptr; if (s.surface) { layer = fromHandle(s.surface).promote(); } else if (s.hasBufferChanges()) { ALOGW("Transaction with buffer, but no Layer?"); continue; } if (!layer) { continue; } if (s.hasBufferChanges() && s.bufferData->hasBarrier && ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { const bool willApplyBarrierFrame = (bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end()) && (bufferLayersReadyToPresent.at(s.surface) >= s.bufferData->barrierFrameNumber); if (!willApplyBarrierFrame) { ATRACE_NAME("NotReadyBarrier"); return TransactionReadiness::NotReadyBarrier; } } const bool allowLatchUnsignaled = tryApplyUnsignaled && shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), allowLatchUnsignaled ? "true" : "false"); const bool acquireFenceChanged = s.bufferData && s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && s.bufferData->acquireFence; fenceUnsignaled = fenceUnsignaled || (acquireFenceChanged && s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled); if (fenceUnsignaled && !allowLatchUnsignaled) { if (!transaction.sentFenceTimeoutWarning && queueProcessTime - transaction.postTime > std::chrono::nanoseconds(4s).count()) { transaction.sentFenceTimeoutWarning = true; auto listener = s.bufferData->releaseBufferListener; if (listener) { listener->onTransactionQueueStalled(); } } ATRACE_NAME("fence unsignaled"); return TransactionReadiness::NotReady; } if (s.hasBufferChanges()) { // If backpressure is enabled and we already have a buffer to commit, keep the // transaction in the queue. const bool hasPendingBuffer = bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end(); if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); return TransactionReadiness::NotReady; } } } return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready; } void SurfaceFlinger::queueTransaction(TransactionState& state) { mLocklessTransactionQueue.push(state); mPendingTransactionCount++; ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); const auto schedule = [](uint32_t flags) { if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart; return TransactionSchedule::Late; }(state.flags); const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); } status_t SurfaceFlinger::setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, Loading Loading @@ -4022,7 +3905,16 @@ status_t SurfaceFlinger::setTransactionState( if (mTransactionTracing) { mTransactionTracing->addQueuedTransaction(state); } queueTransaction(state); const auto schedule = [](uint32_t flags) { if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart; return TransactionSchedule::Late; }(state.flags); const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); mTransactionHandler.queueTransaction(std::move(state)); return NO_ERROR; } Loading