diff options
author | 2022-02-03 10:26:59 -0800 | |
---|---|---|
committer | 2022-02-09 19:26:04 -0800 | |
commit | 9dada820366f73c702224aaaddd4e7237e5035b3 (patch) | |
tree | 848d056a9e738f0bcbec0bac9633a7971cf1664e | |
parent | de549d4fe45b5af63bed7ac93adeb9a2715464db (diff) |
SF: check the correct layer state flags for latch unsignaled
A few bug fixes when processing unsignaled buffers.
Bug: 198190384
Test: SF unit tests
Change-Id: I67de78bda55e8f69a54bbd7417bd7446fde4b910
-rw-r--r-- | libs/gui/include/gui/HdrMetadata.h | 1 | ||||
-rw-r--r-- | libs/ui/include/ui/StretchEffect.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/BufferStateLayer.cpp | 179 | ||||
-rw-r--r-- | services/surfaceflinger/BufferStateLayer.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 227 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 32 | ||||
-rw-r--r-- | services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp | 1063 |
9 files changed, 991 insertions, 519 deletions
diff --git a/libs/gui/include/gui/HdrMetadata.h b/libs/gui/include/gui/HdrMetadata.h index 1e9c3e7102..0bdffac5c6 100644 --- a/libs/gui/include/gui/HdrMetadata.h +++ b/libs/gui/include/gui/HdrMetadata.h @@ -44,6 +44,7 @@ struct HdrMetadata : public LightFlattenable<HdrMetadata> { status_t unflatten(void const* buffer, size_t size); bool operator==(const HdrMetadata& rhs) const; + bool operator!=(const HdrMetadata& rhs) const { return !(*this == rhs); } }; } // namespace android diff --git a/libs/ui/include/ui/StretchEffect.h b/libs/ui/include/ui/StretchEffect.h index cf08acb359..123b27568f 100644 --- a/libs/ui/include/ui/StretchEffect.h +++ b/libs/ui/include/ui/StretchEffect.h @@ -44,6 +44,8 @@ struct StretchEffect : public LightFlattenablePod<StretchEffect> { mappedChildBounds == other.mappedChildBounds; } + bool operator!=(const StretchEffect& other) const { return !(*this == other); } + static bool isZero(float value) { constexpr float NON_ZERO_EPSILON = 0.001f; return fabsf(value) <= NON_ZERO_EPSILON; diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 40fc342ec8..fccd8f149a 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -918,4 +918,183 @@ Rect BufferStateLayer::getInputBounds() const { return mDrawingState.transform.transform(bufferBounds); } +bool BufferStateLayer::simpleBufferUpdate(const layer_state_t& s) const { + const uint64_t requiredFlags = layer_state_t::eBufferChanged; + + const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged | + layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged | + layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged | + layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged | + layer_state_t::eReparent; + + const uint64_t allowedFlags = layer_state_t::eHasListenerCallbacksChanged | + layer_state_t::eFrameRateSelectionPriority | layer_state_t::eFrameRateChanged | + layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eApiChanged | + layer_state_t::eMetadataChanged | layer_state_t::eDropInputModeChanged | + layer_state_t::eInputInfoChanged; + + if ((s.what & requiredFlags) != requiredFlags) { + ALOGV("%s: false [missing required flags 0x%" PRIx64 "]", __func__, + (s.what | requiredFlags) & ~s.what); + return false; + } + + if (s.what & deniedFlags) { + ALOGV("%s: false [has denied flags 0x%" PRIx64 "]", __func__, s.what & deniedFlags); + return false; + } + + if (s.what & allowedFlags) { + ALOGV("%s: [has allowed flags 0x%" PRIx64 "]", __func__, s.what & allowedFlags); + } + + if (s.what & layer_state_t::ePositionChanged) { + if (mRequestedTransform.tx() != s.x || mRequestedTransform.ty() != s.y) { + ALOGV("%s: false [ePositionChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eAlphaChanged) { + if (mDrawingState.color.a != s.alpha) { + ALOGV("%s: false [eAlphaChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eColorTransformChanged) { + if (mDrawingState.colorTransform != s.colorTransform) { + ALOGV("%s: false [eColorTransformChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eBackgroundColorChanged) { + if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) { + ALOGV("%s: false [eBackgroundColorChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eMatrixChanged) { + if (mRequestedTransform.dsdx() != s.matrix.dsdx || + mRequestedTransform.dtdy() != s.matrix.dtdy || + mRequestedTransform.dtdx() != s.matrix.dtdx || + mRequestedTransform.dsdy() != s.matrix.dsdy) { + ALOGV("%s: false [eMatrixChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eCornerRadiusChanged) { + if (mDrawingState.cornerRadius != s.cornerRadius) { + ALOGV("%s: false [eCornerRadiusChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eBackgroundBlurRadiusChanged) { + if (mDrawingState.backgroundBlurRadius != static_cast<int>(s.backgroundBlurRadius)) { + ALOGV("%s: false [eBackgroundBlurRadiusChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eTransformChanged) { + if (mDrawingState.bufferTransform != s.transform) { + ALOGV("%s: false [eTransformChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eTransformToDisplayInverseChanged) { + if (mDrawingState.transformToDisplayInverse != s.transformToDisplayInverse) { + ALOGV("%s: false [eTransformToDisplayInverseChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eCropChanged) { + if (mDrawingState.crop != s.crop) { + ALOGV("%s: false [eCropChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eDataspaceChanged) { + if (mDrawingState.dataspace != s.dataspace) { + ALOGV("%s: false [eDataspaceChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eHdrMetadataChanged) { + if (mDrawingState.hdrMetadata != s.hdrMetadata) { + ALOGV("%s: false [eHdrMetadataChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eSidebandStreamChanged) { + if (mDrawingState.sidebandStream != s.sidebandStream) { + ALOGV("%s: false [eSidebandStreamChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eColorSpaceAgnosticChanged) { + if (mDrawingState.colorSpaceAgnostic != s.colorSpaceAgnostic) { + ALOGV("%s: false [eColorSpaceAgnosticChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eShadowRadiusChanged) { + if (mDrawingState.shadowRadius != s.shadowRadius) { + ALOGV("%s: false [eShadowRadiusChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eFixedTransformHintChanged) { + if (mDrawingState.fixedTransformHint != s.fixedTransformHint) { + ALOGV("%s: false [eFixedTransformHintChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eTrustedOverlayChanged) { + if (mDrawingState.isTrustedOverlay != s.isTrustedOverlay) { + ALOGV("%s: false [eTrustedOverlayChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eStretchChanged) { + StretchEffect temp = s.stretchEffect; + temp.sanitize(); + if (mDrawingState.stretchEffect != temp) { + ALOGV("%s: false [eStretchChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eBufferCropChanged) { + if (mDrawingState.bufferCrop != s.bufferCrop) { + ALOGV("%s: false [eBufferCropChanged changed]", __func__); + return false; + } + } + + if (s.what & layer_state_t::eDestinationFrameChanged) { + if (mDrawingState.destinationFrame != s.destinationFrame) { + ALOGV("%s: false [eDestinationFrameChanged changed]", __func__); + return false; + } + } + + ALOGV("%s: true", __func__); + return true; +} + } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 248e013ef3..42562126ae 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -136,6 +136,8 @@ private: bool bufferNeedsFiltering() const override; + bool simpleBufferUpdate(const layer_state_t& s) const override; + ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; uint64_t mPreviousReleasedFrameNumber = 0; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ddcd641461..e51af1e10e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -897,6 +897,8 @@ public: virtual std::string getPendingBufferCounterName() { return ""; } virtual bool updateGeometry() { return false; } + virtual bool simpleBufferUpdate(const layer_state_t&) const { return false; } + protected: friend class impl::SurfaceInterceptor; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b76233c59f..98199f1a20 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -498,8 +498,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mRefreshRateOverlaySpinner = property_get_bool("sf.debug.show_refresh_rate_overlay_spinner", 0); - enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); - if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) { mTransactionTracing.emplace(); } @@ -508,11 +506,13 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) { return LatchUnsignaledConfig::Always; - } else if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) { - return LatchUnsignaledConfig::Auto; - } else { - return LatchUnsignaledConfig::Disabled; } + + if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) { + return LatchUnsignaledConfig::AutoSingleLayer; + } + + return LatchUnsignaledConfig::Disabled; } SurfaceFlinger::~SurfaceFlinger() = default; @@ -853,6 +853,8 @@ void SurfaceFlinger::init() { mCompositionEngine->getHwComposer().setCallback(*this); ClientCache::getInstance().setRenderEngine(&getRenderEngine()); + enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); + if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) { enableHalVirtualDisplays(true); } @@ -3640,6 +3642,19 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule return old; } +bool SurfaceFlinger::stopTransactionProcessing( + const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& + applyTokensWithUnsignaledTransactions) const { + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { + // if we are in LatchUnsignaledConfig::AutoSingleLayer + // then we should have only one applyToken for processing. + // so we can stop further transactions on this applyToken. + return !applyTokensWithUnsignaledTransactions.empty(); + } + + return false; +} + bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer @@ -3647,44 +3662,42 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { std::vector<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_set<sp<IBinder>, SpHash<IBinder>> bufferLayersReadyToPresent; + std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); - // allowLatchUnsignaled acts as a filter condition when latch unsignaled is either auto - // or always. auto: in this case we let buffer latch unsignaled if we have only one - // applyToken and if only first transaction is latch unsignaled. If more than one - // applyToken we don't latch unsignaled. - bool allowLatchUnsignaled = allowedLatchUnsignaled(); - bool isFirstUnsignaledTransactionApplied = false; // Collect transactions from pending transaction queue. auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; while (!transactionQueue.empty()) { + if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { + break; + } + auto& transaction = transactionQueue.front(); - if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo, - transaction.isAutoTimestamp, - transaction.desiredPresentTime, - transaction.originUid, transaction.states, - bufferLayersReadyToPresent, - allowLatchUnsignaled)) { + const auto ready = + transactionIsReadyToBeApplied(transaction.frameTimelineInfo, + transaction.isAutoTimestamp, + transaction.desiredPresentTime, + transaction.originUid, transaction.states, + bufferLayersReadyToPresent, + transactions.size()); + if (ready == TransactionReadiness::NotReady) { setTransactionFlags(eTransactionFlushNeeded); break; } transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { bufferLayersReadyToPresent.insert(state.surface); }); + const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); + if (appliedUnsignaled) { + applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); + } + transactions.emplace_back(std::move(transaction)); transactionQueue.pop(); - if (allowLatchUnsignaled && - enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) { - // if allowLatchUnsignaled && we are in LatchUnsignaledConfig::Auto - // then we should have only one applyToken for processing. - // so we can stop further transactions on this applyToken. - isFirstUnsignaledTransactionApplied = true; - break; - } } if (transactionQueue.empty()) { @@ -3702,25 +3715,34 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // Case 3: others are the transactions that are ready to apply. while (!mTransactionQueue.empty()) { auto& transaction = mTransactionQueue.front(); - bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != + const bool pendingTransactions = + mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); - if (isFirstUnsignaledTransactionApplied || pendingTransactions || - !transactionIsReadyToBeApplied(transaction.frameTimelineInfo, - transaction.isAutoTimestamp, - transaction.desiredPresentTime, - transaction.originUid, transaction.states, - bufferLayersReadyToPresent, - allowLatchUnsignaled)) { + const auto ready = [&]() REQUIRES(mStateLock) { + if (pendingTransactions || + stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { + return TransactionReadiness::NotReady; + } + + return transactionIsReadyToBeApplied(transaction.frameTimelineInfo, + transaction.isAutoTimestamp, + transaction.desiredPresentTime, + transaction.originUid, transaction.states, + bufferLayersReadyToPresent, + transactions.size()); + }(); + + if (ready == TransactionReadiness::NotReady) { mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } else { transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { bufferLayersReadyToPresent.insert(state.surface); }); - transactions.emplace_back(std::move(transaction)); - if (allowLatchUnsignaled && - enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) { - isFirstUnsignaledTransactionApplied = true; + const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); + if (appliedUnsignaled) { + applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); } + transactions.emplace_back(std::move(transaction)); } mTransactionQueue.pop_front(); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); @@ -3757,62 +3779,6 @@ bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactio return needsTraversal; } -bool SurfaceFlinger::allowedLatchUnsignaled() { - if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { - return false; - } - // Always mode matches the current latch unsignaled behavior. - // This behavior is currently used by the partners and we would like - // to keep it until we are completely migrated to Auto mode successfully - // and we we have our fallback based implementation in place. - if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) { - return true; - } - - // if enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto - // we don't latch unsignaled if more than one applyToken, as it can backpressure - // the other transactions. - if (mPendingTransactionQueues.size() > 1) { - return false; - } - std::optional<sp<IBinder>> applyToken = std::nullopt; - bool isPendingTransactionQueuesItem = false; - if (!mPendingTransactionQueues.empty()) { - applyToken = mPendingTransactionQueues.begin()->first; - isPendingTransactionQueuesItem = true; - } - - for (const auto& item : mTransactionQueue) { - if (!applyToken.has_value()) { - applyToken = item.applyToken; - } else if (applyToken.has_value() && applyToken != item.applyToken) { - return false; - } - } - - if (isPendingTransactionQueuesItem) { - return checkTransactionCanLatchUnsignaled( - mPendingTransactionQueues.begin()->second.front()); - } else if (applyToken.has_value()) { - return checkTransactionCanLatchUnsignaled((mTransactionQueue.front())); - } - return false; -} - -bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) { - if (transaction.states.size() == 1) { - const auto& state = transaction.states.begin()->state; - if ((state.flags & ~layer_state_t::eBufferChanged) == 0 && - state.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && - state.bufferData->acquireFence && - state.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) { - ATRACE_NAME("transactionCanLatchUnsignaled"); - return true; - } - } - return false; -} - bool SurfaceFlinger::transactionFlushNeeded() { Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); @@ -3839,12 +3805,46 @@ bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) return prediction->presentTime >= expectedPresentTime && prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold; } +bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state, + size_t numStates, size_t totalTXapplied) { + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { + ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__); + return false; + } + + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) { + ALOGV("%s: true (LatchUnsignaledConfig::Always)", __func__); + return true; + } + + // We only want to latch unsignaled when a single layer is updated in this + // transaction (i.e. not a blast sync transaction). + if (numStates != 1) { + ALOGV("%s: false (numStates=%zu)", __func__, numStates); + return false; + } + + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer && + totalTXapplied > 0) { + ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", __func__, + totalTXapplied); + return false; + } + + if (!layer->simpleBufferUpdate(state)) { + ALOGV("%s: false (!simpleBufferUpdate)", __func__); + return false; + } + + ALOGV("%s: true", __func__); + return true; +} -bool SurfaceFlinger::transactionIsReadyToBeApplied( +auto SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, - bool allowLatchUnsignaled) const { + size_t totalTXapplied) const -> TransactionReadiness { ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second @@ -3852,31 +3852,24 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime && desiredPresentTime < expectedPresentTime + s2ns(1)) { ATRACE_NAME("not current"); - return false; + return TransactionReadiness::NotReady; } if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) { ATRACE_NAME("!isVsyncValid"); - return false; + 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(expectedPresentTime, info.vsyncId)) { ATRACE_NAME("frameIsEarly"); - return false; + return TransactionReadiness::NotReady; } + bool fenceUnsignaled = false; for (const ComposerState& state : states) { const layer_state_t& s = state.state; - const bool acquireFenceChanged = s.bufferData && - s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged); - if (acquireFenceChanged && s.bufferData->acquireFence && !allowLatchUnsignaled && - s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled) { - ATRACE_NAME("fence unsignaled"); - return false; - } - sp<Layer> layer = nullptr; if (s.surface) { layer = fromHandle(s.surface).promote(); @@ -3890,6 +3883,22 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( ATRACE_NAME(layer->getName().c_str()); + const bool allowLatchUnsignaled = + shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); + ATRACE_INT("allowLatchUnsignaled", allowLatchUnsignaled); + + 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) { + 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. @@ -3897,11 +3906,11 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end(); if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); - return false; + return TransactionReadiness::NotReady; } } } - return true; + return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready; } void SurfaceFlinger::queueTransaction(TransactionState& state) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b95cd9118a..aecd43a7ae 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -137,7 +137,20 @@ enum { eTransactionMask = 0x1f, }; -enum class LatchUnsignaledConfig { Always, Auto, Disabled }; +// Latch Unsignaled buffer behaviours +enum class LatchUnsignaledConfig { + // All buffers are latched signaled. + Disabled, + + // Latch unsignaled is permitted when a single layer is updated in a frame, + // and the update includes just a buffer update (i.e. no sync transactions + // or geometry changes). + AutoSingleLayer, + + // All buffers are latched unsignaled. This behaviour is discouraged as it + // can break sync transactions, stall the display and cause undesired side effects. + Always, +}; using DisplayColorSetting = compositionengine::OutputColorSetting; @@ -749,16 +762,21 @@ private: uint32_t setTransactionFlags(uint32_t mask, TransactionSchedule, const sp<IBinder>& applyToken = {}); void commitOffscreenLayers(); - bool transactionIsReadyToBeApplied( + enum class TransactionReadiness { + NotReady, + Ready, + ReadyUnsignaled, + }; + TransactionReadiness transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, - bool allowLatchUnsignaled) const REQUIRES(mStateLock); + size_t totalTXapplied) const REQUIRES(mStateLock); static LatchUnsignaledConfig getLatchUnsignaledConfig(); - bool latchUnsignaledIsAllowed(std::vector<TransactionState>& transactions) REQUIRES(mStateLock); - bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock); - bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction) - REQUIRES(mStateLock); + static bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, + size_t numStates, size_t totalTXapplied); + bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& + applyTokensWithUnsignaledTransactions) const; bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index 4f89cd9a45..30a6fbd416 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -25,7 +25,7 @@ namespace android::fuzz { static constexpr LatchUnsignaledConfig kLatchUnsignaledConfig[] = { LatchUnsignaledConfig::Always, - LatchUnsignaledConfig::Auto, + LatchUnsignaledConfig::AutoSingleLayer, LatchUnsignaledConfig::Disabled, }; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ed23176718..4683c5132f 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -72,13 +72,6 @@ public: EXPECT_CALL(*mVSyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*mFenceUnsignaled, getStatus()) - .WillRepeatedly(Return(Fence::Status::Unsignaled)); - EXPECT_CALL(*mFenceUnsignaled2, getStatus()) - .WillRepeatedly(Return(Fence::Status::Unsignaled)); - EXPECT_CALL(*mFenceSignaled, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled)); - EXPECT_CALL(*mFenceSignaled2, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled)); - mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController), std::unique_ptr<mock::VSyncTracker>(mVSyncTracker), @@ -89,10 +82,6 @@ public: mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); - sp<mock::MockFence> mFenceUnsignaled = sp<mock::MockFence>::make(); - sp<mock::MockFence> mFenceSignaled = sp<mock::MockFence>::make(); - sp<mock::MockFence> mFenceUnsignaled2 = sp<mock::MockFence>::make(); - sp<mock::MockFence> mFenceSignaled2 = sp<mock::MockFence>::make(); struct TransactionInfo { Vector<ComposerState> states; @@ -129,15 +118,6 @@ public: transaction.frameTimelineInfo = frameTimelineInfo; } - void setupSingleWithComposer(TransactionInfo& transaction, uint32_t flags, - bool syncInputWindows, int64_t desiredPresentTime, - bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo, - const Vector<ComposerState>* states) { - setupSingle(transaction, flags, syncInputWindows, desiredPresentTime, isAutoTimestamp, - frameTimelineInfo); - transaction.states = *states; - } - void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); @@ -263,189 +243,6 @@ public: EXPECT_EQ(0u, transactionQueue.size()); } - void Flush_removesUnsignaledFromTheQueue(Vector<ComposerState> state1, - Vector<ComposerState> state2, - bool updateApplyToken = true) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - - TransactionInfo transactionA; - setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state1); - - mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, - transactionA.displays, transactionA.flags, - transactionA.applyToken, transactionA.inputWindowCommands, - transactionA.desiredPresentTime, transactionA.isAutoTimestamp, - transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transactionA.id); - - TransactionInfo transactionB; - if (updateApplyToken) { - transactionB.applyToken = sp<IBinder>(); - } - setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state2); - mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, - transactionB.displays, transactionB.flags, - transactionB.applyToken, transactionB.inputWindowCommands, - transactionB.desiredPresentTime, transactionB.isAutoTimestamp, - transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transactionB.id); - - mFlinger.flushTransactionQueues(); - EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size()); - } - - void Flush_removesFromTheQueue(const Vector<ComposerState>& state) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); - - TransactionInfo transaction; - setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state); - - mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, - transaction.displays, transaction.flags, - transaction.applyToken, transaction.inputWindowCommands, - transaction.desiredPresentTime, transaction.isAutoTimestamp, - transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transaction.id); - - mFlinger.flushTransactionQueues(); - EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_EQ(1u, mFlinger.getTransactionCommittedSignals().size()); - } - - void Flush_keepsInTheQueue(const Vector<ComposerState>& state) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); - - TransactionInfo transaction; - setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state); - - mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, - transaction.displays, transaction.flags, - transaction.applyToken, transaction.inputWindowCommands, - transaction.desiredPresentTime, transaction.isAutoTimestamp, - transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transaction.id); - - mFlinger.flushTransactionQueues(); - EXPECT_EQ(1u, mFlinger.getPendingTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); - } - - void Flush_KeepsUnsignaledInTheQueue(const Vector<ComposerState>& state1, - const Vector<ComposerState>& state2, - bool updateApplyToken = true, - uint32_t pendingTransactionQueueSize = 1u) { - EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - auto time = systemTime(); - TransactionInfo transactionA; - TransactionInfo transactionB; - setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state1); - setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state2); - mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, - transactionA.displays, transactionA.flags, - transactionA.applyToken, transactionA.inputWindowCommands, - transactionA.desiredPresentTime, transactionA.isAutoTimestamp, - transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transactionA.id); - if (updateApplyToken) { - transactionB.applyToken = sp<IBinder>(); - } - mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, - transactionB.displays, transactionB.flags, - transactionB.applyToken, transactionB.inputWindowCommands, - transactionB.desiredPresentTime, transactionB.isAutoTimestamp, - transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transactionB.id); - - mFlinger.flushTransactionQueues(); - EXPECT_EQ(pendingTransactionQueueSize, mFlinger.getPendingTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); - } - - void Flush_removesSignaledFromTheQueue(const Vector<ComposerState>& state1, - const Vector<ComposerState>& state2) { - ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); - - auto time = systemTime(); - TransactionInfo transactionA; - TransactionInfo transactionB; - setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state1); - setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, - /*syncInputWindows*/ false, - /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, - FrameTimelineInfo{}, &state2); - mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, - transactionA.displays, transactionA.flags, - transactionA.applyToken, transactionA.inputWindowCommands, - transactionA.desiredPresentTime, transactionA.isAutoTimestamp, - transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transactionA.id); - mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, - transactionB.displays, transactionB.flags, - transactionB.applyToken, transactionB.inputWindowCommands, - transactionB.desiredPresentTime, transactionB.isAutoTimestamp, - transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, - transactionB.id); - - mFlinger.flushTransactionQueues(); - EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); - EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); - EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size()); - } - - static Vector<ComposerState> createComposerStateVector(const ComposerState& state1, - const ComposerState& state2) { - Vector<ComposerState> states; - states.push_back(state1); - states.push_back(state2); - return states; - } - - static Vector<ComposerState> createComposerStateVector(const ComposerState& state) { - Vector<ComposerState> states; - states.push_back(state); - return states; - } - - static ComposerState createComposerState(int layerId, sp<Fence> fence, - uint32_t stateFlags = layer_state_t::eBufferChanged) { - ComposerState composer_state; - composer_state.state.bufferData = std::make_shared<BufferData>(); - composer_state.state.bufferData->acquireFence = std::move(fence); - composer_state.state.layerId = layerId; - composer_state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged; - composer_state.state.flags = stateFlags; - return composer_state; - } - bool mHasListenerCallbacks = false; std::vector<ListenerCallbacks> mCallbacks; int mTransactionNumber = 0; @@ -529,215 +326,677 @@ TEST_F(TransactionApplicationTest, FromHandle) { EXPECT_EQ(nullptr, ret.promote().get()); } -TEST_F(TransactionApplicationTest, Flush_RemovesSingleSignaledFromTheQueue_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_removesFromTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); -} - -TEST_F(TransactionApplicationTest, Flush_RemovesSingleUnSignaledFromTheQueue_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_removesFromTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); -} - -TEST_F(TransactionApplicationTest, - Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_keepsInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceUnsignaled, layer_state_t::eCropChanged))); -} - -TEST_F(TransactionApplicationTest, - Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_keepsInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceUnsignaled, - layer_state_t::eCropChanged | layer_state_t::eBufferChanged))); -} - -TEST_F(TransactionApplicationTest, - Flush_KeepsInTheQueueSameApplyTokenMultiState_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_keepsInTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), - createComposerState(/*layerId*/ 1, mFenceSignaled))); -} +class LatchUnsignaledTest : public TransactionApplicationTest { +public: + void TearDown() override { + // Clear all transaction queues to release all transactions we sent + // in the tests. Otherwise, gmock complains about memory leaks. + mFlinger.getTransactionQueue().clear(); + mFlinger.getPendingTransactionQueue().clear(); + mFlinger.getTransactionCommittedSignals().clear(); + mFlinger.commitTransactionsLocked(eTransactionMask); + mFlinger.mutableCurrentState().layersSortedByZ.clear(); + mFlinger.mutableDrawingState().layersSortedByZ.clear(); + } -TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_MultipleStateTransaction_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_keepsInTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), - createComposerState(/*layerId*/ 2, mFenceSignaled))); -} + static sp<Fence> fence(Fence::Status status) { + const auto fence = sp<mock::MockFence>::make(); + EXPECT_CALL(*fence, getStatus()).WillRepeatedly(Return(status)); + return fence; + } -TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_removesSignaledFromTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceSignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceSignaled2))); -} + ComposerState createComposerState(int layerId, sp<Fence> fence, uint64_t what) { + ComposerState state; + state.state.bufferData = std::make_shared<BufferData>(); + state.state.bufferData->acquireFence = std::move(fence); + state.state.layerId = layerId; + state.state.surface = + sp<BufferStateLayer>::make( + LayerCreationArgs(mFlinger.flinger(), nullptr, "TestLayer", 0, {})) + ->getHandle(); + state.state.bufferData->flags = BufferData::BufferDataChange::fenceChanged; + + state.state.what = what; + if (what & layer_state_t::eCropChanged) { + state.state.crop = Rect(1, 2, 3, 4); + } + return state; + } -TEST_F(TransactionApplicationTest, Flush_RemoveSignaledWithUnsignaledIntact_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceSignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceUnsignaled))); - EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); -} + TransactionInfo createTransactionInfo(const sp<IBinder>& applyToken, + const std::vector<ComposerState>& states) { + TransactionInfo transaction; + const uint32_t kFlags = ISurfaceComposer::eSynchronous; + const bool kSyncInputWindows = false; + const nsecs_t kDesiredPresentTime = systemTime(); + const bool kIsAutoTimestamp = true; + const auto kFrameTimelineInfo = FrameTimelineInfo{}; + + setupSingle(transaction, kFlags, kSyncInputWindows, kDesiredPresentTime, kIsAutoTimestamp, + kFrameTimelineInfo); + transaction.applyToken = applyToken; + for (const auto& state : states) { + transaction.states.push_back(state); + } -TEST_F(TransactionApplicationTest, - Flush_KeepsTransactionInTheQueueSameApplyToken_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceUnsignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceSignaled)), - /*updateApplyToken*/ false); - EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); -} + return transaction; + } -TEST_F(TransactionApplicationTest, Flush_KeepsTransactionInTheQueue_LatchUnsignaled_Auto) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; - Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceUnsignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceUnsignaled)), - /*updateApplyToken*/ true, - /*pendingTransactionQueueSize*/ 2u); - EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); -} + void setTransactionStates(const std::vector<TransactionInfo>& transactions, + size_t expectedTransactionsApplied, + size_t expectedTransactionsPending) { + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); -TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_removesFromTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); -} + for (const auto& transaction : transactions) { + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.applyToken, transaction.inputWindowCommands, + transaction.desiredPresentTime, + transaction.isAutoTimestamp, transaction.uncacheBuffer, + mHasListenerCallbacks, mCallbacks, transaction.id); + } + mFlinger.flushTransactionQueues(); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size()); + } +}; -TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_LatchUnsignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_keepsInTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); -} +class LatchUnsignaledAutoSingleLayerTest : public LatchUnsignaledTest { +public: + void SetUp() override { + LatchUnsignaledTest::SetUp(); + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::AutoSingleLayer; + } +}; -TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueSameLayerId_LatchUnsignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_keepsInTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), - createComposerState(/*layerId*/ 1, mFenceUnsignaled))); -} +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleSignaledFromTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + {createComposerState(kLayerId, fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged)}); + setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSingleUnSignaledFromTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eCropChanged), + }); + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eCropChanged | + layer_state_t:: + eBufferChanged), + }); + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueueSameApplyTokenMultiState) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto mixedTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + createComposerState(kLayerId, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsInTheQueue_MultipleStateTransaction) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto mixedTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + createComposerState(kLayerId2, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSignaledFromTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 2u; + const auto kExpectedTransactionsPending = 0u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + const auto signaledTransaction2 = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId2, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledIntact) { + const sp<IBinder> kApplyToken1 = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 1u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken1, + { + createComposerState(kLayerId1, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken2, + { + createComposerState(kLayerId2, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId2, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueue) { + const sp<IBinder> kApplyToken1 = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken1, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + const auto unsignaledTransaction2 = + createTransactionInfo(kApplyToken2, + { + createComposerState(kLayerId2, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction, unsignaledTransaction2}, + kExpectedTransactionsApplied, kExpectedTransactionsPending); +} + +class LatchUnsignaledDisabledTest : public LatchUnsignaledTest { +public: + void SetUp() override { + LatchUnsignaledTest::SetUp(); + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + } +}; -TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueDifferentLayerId_LatchUnsignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_keepsInTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), - createComposerState(/*layerId*/ 2, mFenceUnsignaled))); -} - -TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_removesSignaledFromTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceSignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceSignaled2))); -} - -TEST_F(TransactionApplicationTest, - Flush_KeepInTheQueueDifferentApplyToken_LatchUnsignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceUnsignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceSignaled))); - EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); -} - -TEST_F(TransactionApplicationTest, Flush_KeepInTheQueueSameApplyToken_LatchUnsignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceSignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceUnsignaled)), - /*updateApplyToken*/ false); - EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); -} - -TEST_F(TransactionApplicationTest, Flush_KeepInTheUnsignaledTheQueue_LatchUnsignaled_Disabled) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; - Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceUnsignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceUnsignaled)), - /*updateApplyToken*/ false); - EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); -} - -TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesFromTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); -} - -TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueue_LatchUnsignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesFromTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); -} - -TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueueSameLayerId_LatchUnsignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesFromTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), - createComposerState(/*layerId*/ 1, mFenceSignaled))); -} - -TEST_F(TransactionApplicationTest, - Flush_RemovesFromTheQueueDifferentLayerId_LatchUnsignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesFromTheQueue( - createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), - createComposerState(/*layerId*/ 2, mFenceSignaled))); -} - -TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesSignaledFromTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceSignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceSignaled2))); -} +TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + {createComposerState(kLayerId, fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged)}); + setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueSameLayerId) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + createComposerState(kLayerId, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledDisabledTest, Flush_KeepsInTheQueueDifferentLayerId) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + createComposerState(kLayerId2, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledDisabledTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 2u; + const auto kExpectedTransactionsPending = 0u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + const auto signaledTransaction2 = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId2, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueDifferentApplyToken) { + const sp<IBinder> kApplyToken1 = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken1, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + const auto signaledTransaction = + createTransactionInfo(kApplyToken2, + { + createComposerState(kLayerId2, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheQueueSameApplyToken) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 1u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId2, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheUnsignaledTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 0u; + const auto kExpectedTransactionsPending = 1u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + const auto unsignaledTransaction2 = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId2, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction, unsignaledTransaction2}, + kExpectedTransactionsApplied, kExpectedTransactionsPending); +} + +class LatchUnsignaledAlwaysTest : public LatchUnsignaledTest { +public: + void SetUp() override { + LatchUnsignaledTest::SetUp(); + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + } +}; -TEST_F(TransactionApplicationTest, - Flush_RemovesFromTheQueueDifferentApplyToken_LatchUnsignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesUnsignaledFromTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, mFenceSignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, - mFenceUnsignaled))); -} - -TEST_F(TransactionApplicationTest, - Flush_RemovesUnsignaledFromTheQueueSameApplyToken_LatchUnsignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesUnsignaledFromTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, - mFenceUnsignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, mFenceSignaled)), - /*updateApplyToken*/ false); -} - -TEST_F(TransactionApplicationTest, Flush_RemovesUnsignaledFromTheQueue_LatchUnsignaled_Always) { - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - Flush_removesUnsignaledFromTheQueue(createComposerStateVector( - createComposerState(/*layerId*/ 1, - mFenceUnsignaled)), - createComposerStateVector( - createComposerState(/*layerId*/ 2, - mFenceUnsignaled))); +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + {createComposerState(kLayerId, fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged)}); + setTransactionStates({signaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueue) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + {createComposerState(kLayerId, fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged)}); + setTransactionStates({unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueSameLayerId) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId = 1; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto mixedTransaction = + createTransactionInfo(kApplyToken, + {createComposerState(kLayerId, fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + createComposerState(kLayerId, fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged)}); + setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentLayerId) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 1u; + const auto kExpectedTransactionsPending = 0u; + + const auto mixedTransaction = + createTransactionInfo(kApplyToken, + {createComposerState(kLayerId1, fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + createComposerState(kLayerId2, fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged)}); + setTransactionStates({mixedTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 2u; + const auto kExpectedTransactionsPending = 0u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + const auto signaledTransaction2 = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId2, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentApplyToken) { + const sp<IBinder> kApplyToken1 = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 2u; + const auto kExpectedTransactionsPending = 0u; + + const auto signaledTransaction = + createTransactionInfo(kApplyToken1, + { + createComposerState(kLayerId1, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken2, + { + createComposerState(kLayerId2, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueueSameApplyToken) { + const sp<IBinder> kApplyToken = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 2u; + const auto kExpectedTransactionsPending = 0u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + const auto signaledTransaction = + createTransactionInfo(kApplyToken, + { + createComposerState(kLayerId2, + fence(Fence::Status::Signaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction, signaledTransaction}, kExpectedTransactionsApplied, + kExpectedTransactionsPending); +} + +TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueue) { + const sp<IBinder> kApplyToken1 = + IInterface::asBinder(TransactionCompletedListener::getIInstance()); + const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); + const auto kLayerId1 = 1; + const auto kLayerId2 = 2; + const auto kExpectedTransactionsApplied = 2u; + const auto kExpectedTransactionsPending = 0u; + + const auto unsignaledTransaction = + createTransactionInfo(kApplyToken1, + { + createComposerState(kLayerId1, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + const auto unsignaledTransaction2 = + createTransactionInfo(kApplyToken2, + { + createComposerState(kLayerId2, + fence(Fence::Status::Unsignaled), + layer_state_t::eBufferChanged), + }); + setTransactionStates({unsignaledTransaction, unsignaledTransaction2}, + kExpectedTransactionsApplied, kExpectedTransactionsPending); } } // namespace android |